keyfile: write certificates and keys in a human-readable manner

Write actual paths, not integer lists.  When given certificate or
key blobs, write those out to files and put the path to that file
into the keyfile.
This commit is contained in:
Dan Williams 2011-03-02 23:08:15 -06:00
parent e3cddc8d9f
commit ecca85066d
2 changed files with 507 additions and 20 deletions

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2008 - 2010 Red Hat, Inc.
* Copyright (C) 2008 - 2011 Red Hat, Inc.
*/
#include <stdio.h>
@ -1965,7 +1965,7 @@ test_read_wired_8021x_tls_old_connection (void)
const char *tmp;
gboolean success;
connection = connection_from_file (TEST_WIRED_TLS_OLD_FILE, &error);
connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_OLD_FILE, &error);
if (connection == NULL) {
g_assert (error);
g_warning ("Failed to read %s: %s", TEST_WIRED_TLS_OLD_FILE, error->message);
@ -2021,7 +2021,7 @@ test_read_wired_8021x_tls_new_connection (void)
const char *tmp;
gboolean success;
connection = connection_from_file (TEST_WIRED_TLS_NEW_FILE, &error);
connection = nm_keyfile_plugin_connection_from_file (TEST_WIRED_TLS_NEW_FILE, &error);
if (connection == NULL) {
g_assert (error);
g_warning ("Failed to read %s: %s", TEST_WIRED_TLS_NEW_FILE, error->message);
@ -2066,9 +2066,249 @@ test_read_wired_8021x_tls_new_connection (void)
}
#define TEST_WIRED_TLS_CA_CERT TEST_KEYFILES_DIR"/test-ca-cert.pem"
#define TEST_WIRED_TLS_CLI_CERT TEST_KEYFILES_DIR"/test-key-and-cert.pem"
#define TEST_WIRED_TLS_CLIENT_CERT TEST_KEYFILES_DIR"/test-key-and-cert.pem"
#define TEST_WIRED_TLS_PRIVKEY TEST_KEYFILES_DIR"/test-key-and-cert.pem"
static NMConnection *
create_wired_tls_connection (NMSetting8021xCKScheme scheme)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingIP4Config *s_ip4;
NMSetting *s_wired;
NMSetting8021x *s_8021x;
char *uuid;
gboolean success;
GError *error = NULL;
connection = nm_connection_new ();
g_assert (connection != NULL);
/* Connection setting */
s_con = (NMSettingConnection *) nm_setting_connection_new ();
g_assert (s_con);
nm_connection_add_setting (connection, NM_SETTING (s_con));
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
NM_SETTING_CONNECTION_ID, "Wired Really Secure TLS",
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
NULL);
g_free (uuid);
/* IP4 setting */
s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
g_assert (s_ip4);
g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
nm_connection_add_setting (connection, NM_SETTING (s_ip4));
/* Wired setting */
s_wired = nm_setting_wired_new ();
g_assert (s_wired);
nm_connection_add_setting (connection, s_wired);
/* 802.1x setting */
s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
g_assert (s_8021x);
nm_connection_add_setting (connection, NM_SETTING (s_8021x));
nm_setting_802_1x_add_eap_method (s_8021x, "tls");
g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL);
success = nm_setting_802_1x_set_ca_cert (s_8021x,
TEST_WIRED_TLS_CA_CERT,
scheme,
NULL,
&error);
if (!success) {
g_assert (error);
g_warning ("Failed to set CA cert %s: %s", TEST_WIRED_TLS_CA_CERT, error->message);
g_assert (success);
}
success = nm_setting_802_1x_set_client_cert (s_8021x,
TEST_WIRED_TLS_CLIENT_CERT,
scheme,
NULL,
&error);
if (!success) {
g_assert (error);
g_warning ("Failed to set client cert %s: %s", TEST_WIRED_TLS_CA_CERT, error->message);
g_assert (success);
}
success = nm_setting_802_1x_set_private_key (s_8021x,
TEST_WIRED_TLS_PRIVKEY,
"test1",
scheme,
NULL,
&error);
if (!success) {
g_assert (error);
g_warning ("Failed to set private key %s: %s", TEST_WIRED_TLS_CA_CERT, error->message);
g_assert (success);
}
return connection;
}
static void
test_write_wired_8021x_tls_connection_path (void)
{
NMConnection *connection;
char *tmp;
gboolean success;
NMConnection *reread;
char *testfile = NULL;
GError *error = NULL;
GKeyFile *keyfile;
connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_PATH);
g_assert (connection != NULL);
/* Write out the connection */
success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, geteuid (), getegid (), &testfile, &error);
if (!success) {
g_assert (error);
g_warning ("Failed to write keyfile: %s", error->message);
g_assert (success);
}
g_assert (testfile);
/* Read the connection back in and compare it to the one we just wrote out */
reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
if (!reread) {
g_assert (error);
g_warning ("Failed to re-read test connection: %s", error->message);
g_assert (reread);
}
success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT);
if (!reread) {
g_warning ("Written and re-read connection weren't the same");
g_assert (success);
}
/* Ensure the cert and key values are properly written out */
keyfile = g_key_file_new ();
g_assert (keyfile);
success = g_key_file_load_from_file (keyfile, testfile, G_KEY_FILE_NONE, &error);
if (!success) {
g_assert (error);
g_warning ("Failed to re-read test file %s: %s", testfile, error->message);
g_assert (success);
}
/* CA cert */
tmp = g_key_file_get_string (keyfile,
NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_CA_CERT,
NULL);
g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_CA_CERT) == 0);
g_free (tmp);
/* Client cert */
tmp = g_key_file_get_string (keyfile,
NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_CLIENT_CERT,
NULL);
g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_CLIENT_CERT) == 0);
g_free (tmp);
/* Private key */
tmp = g_key_file_get_string (keyfile,
NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_PRIVATE_KEY,
NULL);
g_assert (g_strcmp0 (tmp, TEST_WIRED_TLS_PRIVKEY) == 0);
g_free (tmp);
g_key_file_free (keyfile);
unlink (testfile);
g_free (testfile);
g_object_unref (reread);
g_object_unref (connection);
}
static void
test_write_wired_8021x_tls_connection_blob (void)
{
NMConnection *connection;
NMSettingConnection *s_con;
NMSetting8021x *s_8021x;
gboolean success;
NMConnection *reread;
char *testfile = NULL;
char *new_ca_cert;
char *new_client_cert;
char *new_priv_key;
const char *uuid;
GError *error = NULL;
connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_BLOB);
g_assert (connection != NULL);
/* Write out the connection */
success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, geteuid (), getegid (), &testfile, &error);
if (!success) {
g_assert (error);
g_warning ("Failed to write keyfile: %s", error->message);
g_assert (success);
}
g_assert (testfile);
/* Check that the new certs got written out */
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
uuid = nm_setting_connection_get_uuid (s_con);
g_assert (uuid);
new_ca_cert = g_strdup_printf ("%s/%s-ca-cert.pem", TEST_SCRATCH_DIR, uuid);
g_assert (new_ca_cert);
g_assert (g_file_test (new_ca_cert, G_FILE_TEST_EXISTS));
new_client_cert = g_strdup_printf ("%s/%s-client-cert.pem", TEST_SCRATCH_DIR, uuid);
g_assert (new_client_cert);
g_assert (g_file_test (new_client_cert, G_FILE_TEST_EXISTS));
new_priv_key = g_strdup_printf ("%s/%s-private-key.pem", TEST_SCRATCH_DIR, uuid);
g_assert (new_priv_key);
g_assert (g_file_test (new_priv_key, G_FILE_TEST_EXISTS));
/* Read the connection back in and compare it to the one we just wrote out */
reread = nm_keyfile_plugin_connection_from_file (testfile, &error);
if (!reread) {
g_assert (error);
g_warning ("Failed to re-read test connection: %s", error->message);
g_assert (reread);
}
/* Ensure the re-read connection's certificates use the path scheme */
s_8021x = (NMSetting8021x *) nm_connection_get_setting (reread, NM_TYPE_SETTING_802_1X);
g_assert (s_8021x);
g_assert (nm_setting_802_1x_get_ca_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
g_assert (nm_setting_802_1x_get_client_cert_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
g_assert (nm_setting_802_1x_get_private_key_scheme (s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH);
unlink (testfile);
g_free (testfile);
/* Clean up written certs */
unlink (new_ca_cert);
g_free (new_ca_cert);
unlink (new_client_cert);
g_free (new_client_cert);
unlink (new_priv_key);
g_free (new_priv_key);
g_object_unref (reread);
g_object_unref (connection);
}
int main (int argc, char **argv)
{
GError *error = NULL;
@ -2102,6 +2342,8 @@ int main (int argc, char **argv)
test_read_wired_8021x_tls_old_connection ();
test_read_wired_8021x_tls_new_connection ();
test_write_wired_8021x_tls_connection_path ();
test_write_wired_8021x_tls_connection_blob ();
base = g_path_get_basename (argv[0]);
fprintf (stdout, "%s: SUCCESS\n", base);

View file

@ -19,9 +19,13 @@
* Copyright (C) 2008 - 2011 Red Hat, Inc.
*/
#include <config.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <dbus/dbus-glib.h>
#include <nm-setting.h>
#include <nm-setting-connection.h>
@ -32,6 +36,7 @@
#include <nm-setting-wireless.h>
#include <nm-setting-ip4-config.h>
#include <nm-setting-bluetooth.h>
#include <nm-setting-8021x.h>
#include <nm-utils.h>
#include <string.h>
#include <arpa/inet.h>
@ -67,6 +72,8 @@ write_array_of_uint (GKeyFile *file,
static void
ip4_dns_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -156,6 +163,8 @@ write_ip4_values (GKeyFile *file,
static void
ip4_addr_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -172,6 +181,8 @@ ip4_addr_writer (GKeyFile *file,
static void
ip4_route_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -188,6 +199,8 @@ ip4_route_writer (GKeyFile *file,
static void
ip6_dns_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -296,6 +309,8 @@ ip6_array_to_addr_prefix (GValueArray *values)
static void
ip6_addr_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -334,6 +349,8 @@ ip6_addr_writer (GKeyFile *file,
static void
ip6_route_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -389,6 +406,8 @@ ip6_route_writer (GKeyFile *file,
static void
mac_address_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -450,6 +469,8 @@ write_hash_of_string (GKeyFile *file,
static void
ssid_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
@ -491,10 +512,206 @@ ssid_writer (GKeyFile *file,
}
}
typedef struct ObjectType {
const char *key;
const char *suffix;
const char *privkey_pw_prop;
NMSetting8021xCKScheme (*scheme_func) (NMSetting8021x *setting);
NMSetting8021xCKFormat (*format_func) (NMSetting8021x *setting);
const char * (*path_func) (NMSetting8021x *setting);
const GByteArray * (*blob_func) (NMSetting8021x *setting);
} ObjectType;
static const ObjectType objtypes[10] = {
{ NM_SETTING_802_1X_CA_CERT,
"ca-cert",
NULL,
nm_setting_802_1x_get_ca_cert_scheme,
NULL,
nm_setting_802_1x_get_ca_cert_path,
nm_setting_802_1x_get_ca_cert_blob },
{ NM_SETTING_802_1X_PHASE2_CA_CERT,
"inner-ca-cert",
NULL,
nm_setting_802_1x_get_phase2_ca_cert_scheme,
NULL,
nm_setting_802_1x_get_phase2_ca_cert_path,
nm_setting_802_1x_get_phase2_ca_cert_blob },
{ NM_SETTING_802_1X_CLIENT_CERT,
"client-cert",
NULL,
nm_setting_802_1x_get_client_cert_scheme,
NULL,
nm_setting_802_1x_get_client_cert_path,
nm_setting_802_1x_get_client_cert_blob },
{ NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
"inner-client-cert",
NULL,
nm_setting_802_1x_get_phase2_client_cert_scheme,
NULL,
nm_setting_802_1x_get_phase2_client_cert_path,
nm_setting_802_1x_get_phase2_client_cert_blob },
{ NM_SETTING_802_1X_PRIVATE_KEY,
"private-key",
NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD,
nm_setting_802_1x_get_private_key_scheme,
nm_setting_802_1x_get_private_key_format,
nm_setting_802_1x_get_private_key_path,
nm_setting_802_1x_get_private_key_blob },
{ NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
"inner-private-key",
NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD,
nm_setting_802_1x_get_phase2_private_key_scheme,
nm_setting_802_1x_get_phase2_private_key_format,
nm_setting_802_1x_get_phase2_private_key_path,
nm_setting_802_1x_get_phase2_private_key_blob },
{ NULL },
};
static gboolean
write_cert_key_file (const char *path,
const GByteArray *data,
GError **error)
{
char *tmppath;
int fd = -1, written;
gboolean success = FALSE;
tmppath = g_malloc0 (strlen (path) + 10);
g_assert (tmppath);
memcpy (tmppath, path, strlen (path));
strcat (tmppath, ".XXXXXX");
errno = 0;
fd = mkstemp (tmppath);
if (fd < 0) {
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"Could not create temporary file for '%s': %d",
path, errno);
goto out;
}
/* Only readable by root */
errno = 0;
if (fchmod (fd, S_IRUSR | S_IWUSR) != 0) {
close (fd);
unlink (tmppath);
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"Could not set permissions for temporary file '%s': %d",
path, errno);
goto out;
}
errno = 0;
written = write (fd, data->data, data->len);
if (written != data->len) {
close (fd);
unlink (tmppath);
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"Could not write temporary file for '%s': %d",
path, errno);
goto out;
}
close (fd);
/* Try to rename */
errno = 0;
if (rename (tmppath, path) == 0)
success = TRUE;
else {
unlink (tmppath);
g_set_error (error, KEYFILE_PLUGIN_ERROR, 0,
"Could not rename temporary file to '%s': %d",
path, errno);
}
out:
g_free (tmppath);
return success;
}
static void
cert_writer (GKeyFile *file,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value)
{
const char *setting_name = nm_setting_get_name (setting);
NMSetting8021xCKScheme scheme;
NMSetting8021xCKFormat format;
const char *path = NULL, *ext = "pem";
const ObjectType *objtype = NULL;
int i;
for (i = 0; i < G_N_ELEMENTS (objtypes) && objtypes[i].key; i++) {
if (g_strcmp0 (objtypes[i].key, key) == 0) {
objtype = &objtypes[i];
break;
}
}
g_return_if_fail (objtype != NULL);
scheme = objtypes->scheme_func (NM_SETTING_802_1X (setting));
if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
path = objtype->path_func (NM_SETTING_802_1X (setting));
g_assert (path);
g_key_file_set_string (file, setting_name, key, path);
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
const GByteArray *blob;
gboolean success;
GError *error = NULL;
char *new_path;
blob = objtype->blob_func (NM_SETTING_802_1X (setting));
g_assert (blob);
if (objtype->format_func) {
/* Get the extension for a private key */
format = objtype->format_func (NM_SETTING_802_1X (setting));
if (format == NM_SETTING_802_1X_CK_FORMAT_PKCS12)
ext = "p12";
} else {
/* DER or PEM format certificate? */
if (blob->len > 2 && blob->data[0] == 0x30 && blob->data[1] == 0x82)
ext = "der";
}
/* Write the raw data out to the standard file so that we can use paths
* from now on instead of pushing around the certificate data.
*/
new_path = g_strdup_printf ("%s/%s-%s.%s", keyfile_dir, uuid, objtype->suffix, ext);
g_assert (new_path);
success = write_cert_key_file (new_path, blob, &error);
if (success) {
/* Write the path value to the keyfile */
g_key_file_set_string (file, setting_name, key, new_path);
} else {
g_warning ("Failed to write certificate/key %s: %s", new_path, error->message);
g_error_free (error);
}
g_free (new_path);
} else
g_assert_not_reached ();
}
typedef struct {
const char *setting_name;
const char *key;
void (*writer) (GKeyFile *keyfile, NMSetting *setting, const char *key, const GValue *value);
void (*writer) (GKeyFile *keyfile,
const char *keyfile_dir,
const char *uuid,
NMSetting *setting,
const char *key,
const GValue *value);
} KeyWriter;
/* A table of keys that require further parsing/conversion because they are
@ -543,9 +760,33 @@ static KeyWriter key_writers[] = {
{ NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_WIRELESS_SSID,
ssid_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_CA_CERT,
cert_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_CLIENT_CERT,
cert_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_PRIVATE_KEY,
cert_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_PHASE2_CA_CERT,
cert_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_PHASE2_CLIENT_CERT,
cert_writer },
{ NM_SETTING_802_1X_SETTING_NAME,
NM_SETTING_802_1X_PHASE2_PRIVATE_KEY,
cert_writer },
{ NULL, NULL, NULL }
};
typedef struct {
GKeyFile *keyfile;
const char *keyfile_dir;
const char *uuid;
} WriteInfo;
static void
write_setting_value (NMSetting *setting,
const char *key,
@ -553,7 +794,7 @@ write_setting_value (NMSetting *setting,
GParamFlags flag,
gpointer user_data)
{
GKeyFile *file = (GKeyFile *) user_data;
WriteInfo *info = user_data;
const char *setting_name;
GType type = G_VALUE_TYPE (value);
KeyWriter *writer = &key_writers[0];
@ -575,7 +816,7 @@ write_setting_value (NMSetting *setting,
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key);
if (pspec) {
if (g_param_value_defaults (pspec, (GValue *) value)) {
g_key_file_remove_key (file, setting_name, key, NULL);
g_key_file_remove_key (info->keyfile, setting_name, key, NULL);
return;
}
}
@ -591,7 +832,7 @@ write_setting_value (NMSetting *setting,
/* Look through the list of handlers for non-standard format key values */
while (writer->setting_name) {
if (!strcmp (writer->setting_name, setting_name) && !strcmp (writer->key, key)) {
(*writer->writer) (file, setting, key, value);
(*writer->writer) (info->keyfile, info->keyfile_dir, info->uuid, setting, key, value);
return;
}
writer++;
@ -602,21 +843,21 @@ write_setting_value (NMSetting *setting,
str = g_value_get_string (value);
if (str)
g_key_file_set_string (file, setting_name, key, str);
g_key_file_set_string (info->keyfile, setting_name, key, str);
} else if (type == G_TYPE_UINT)
g_key_file_set_integer (file, setting_name, key, (int) g_value_get_uint (value));
g_key_file_set_integer (info->keyfile, setting_name, key, (int) g_value_get_uint (value));
else if (type == G_TYPE_INT)
g_key_file_set_integer (file, setting_name, key, g_value_get_int (value));
g_key_file_set_integer (info->keyfile, setting_name, key, g_value_get_int (value));
else if (type == G_TYPE_UINT64) {
char *numstr;
numstr = g_strdup_printf ("%" G_GUINT64_FORMAT, g_value_get_uint64 (value));
g_key_file_set_value (file, setting_name, key, numstr);
g_key_file_set_value (info->keyfile, setting_name, key, numstr);
g_free (numstr);
} else if (type == G_TYPE_BOOLEAN) {
g_key_file_set_boolean (file, setting_name, key, g_value_get_boolean (value));
g_key_file_set_boolean (info->keyfile, setting_name, key, g_value_get_boolean (value));
} else if (type == G_TYPE_CHAR) {
g_key_file_set_integer (file, setting_name, key, (int) g_value_get_char (value));
g_key_file_set_integer (info->keyfile, setting_name, key, (int) g_value_get_char (value));
} else if (type == DBUS_TYPE_G_UCHAR_ARRAY) {
GByteArray *array;
@ -629,7 +870,7 @@ write_setting_value (NMSetting *setting,
for (i = 0; i < array->len; i++)
tmp_array[i] = (int) array->data[i];
g_key_file_set_integer_list (file, setting_name, key, tmp_array, array->len);
g_key_file_set_integer_list (info->keyfile, setting_name, key, tmp_array, array->len);
g_free (tmp_array);
}
} else if (type == DBUS_TYPE_G_LIST_OF_STRING) {
@ -645,13 +886,13 @@ write_setting_value (NMSetting *setting,
for (iter = list; iter; iter = iter->next)
array[i++] = iter->data;
g_key_file_set_string_list (file, setting_name, key, (const gchar **const) array, i);
g_key_file_set_string_list (info->keyfile, setting_name, key, (const gchar **const) array, i);
g_free (array);
}
} else if (type == DBUS_TYPE_G_MAP_OF_STRING) {
write_hash_of_string (file, setting, key, value);
write_hash_of_string (info->keyfile, setting, key, value);
} else if (type == DBUS_TYPE_G_UINT_ARRAY) {
if (!write_array_of_uint (file, setting, key, value)) {
if (!write_array_of_uint (info->keyfile, setting, key, value)) {
g_warning ("Unhandled setting property type (write) '%s/%s' : '%s'",
setting_name, key, g_type_name (type));
}
@ -696,6 +937,7 @@ _internal_write_connection (NMConnection *connection,
gboolean success = FALSE;
char *filename = NULL, *path;
const char *id;
WriteInfo info;
if (out_path)
g_return_val_if_fail (*out_path == NULL, FALSE);
@ -707,8 +949,11 @@ _internal_write_connection (NMConnection *connection,
return FALSE;
}
key_file = g_key_file_new ();
nm_connection_for_each_setting_value (connection, write_setting_value, key_file);
info.keyfile = key_file = g_key_file_new ();
info.keyfile_dir = keyfile_dir;
info.uuid = nm_connection_get_uuid (connection);
g_assert (info.uuid);
nm_connection_for_each_setting_value (connection, write_setting_value, &info);
data = g_key_file_to_data (key_file, &len, error);
if (!data)
goto out;