about summary refs log tree commit diff
path: root/src/settings/plugins/keyfile/nms-keyfile-writer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings/plugins/keyfile/nms-keyfile-writer.c')
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-writer.c173
1 files changed, 105 insertions, 68 deletions
diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c
index 2e06aeb9..5fbbb7a1 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-writer.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /* NetworkManager system settings service - keyfile plugin
  *
  * This program is free software; you can redistribute it and/or modify
@@ -169,6 +168,10 @@ _handler_write (NMConnection *connection,
 
 static gboolean
 _internal_write_connection (NMConnection *connection,
+                            gboolean is_nm_generated,
+                            gboolean is_volatile,
+                            const char *shadowed_storage,
+                            gboolean shadowed_owned,
                             const char *keyfile_dir,
                             const char *profile_dir,
                             gboolean with_extension,
@@ -177,6 +180,8 @@ _internal_write_connection (NMConnection *connection,
                             const char *existing_path,
                             gboolean existing_path_read_only,
                             gboolean force_rename,
+                            NMSKeyfileWriterAllowFilenameCb allow_filename_cb,
+                            gpointer allow_filename_user_data,
                             char **out_path,
                             NMConnection **out_reread,
                             gboolean *out_reread_same,
@@ -191,33 +196,57 @@ _internal_write_connection (NMConnection *connection,
 	GError *local_err = NULL;
 	int errsv;
 	gboolean rename;
+	int i_path;
 
 	g_return_val_if_fail (!out_path || !*out_path, FALSE);
 	g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE);
 
+	nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS);
+
+	nm_assert (!shadowed_owned || shadowed_storage);
+
 	rename =    force_rename
 	         || existing_path_read_only
 	         || (   existing_path
 	             && !nm_utils_file_is_in_path (existing_path, keyfile_dir));
 
-	switch (_nm_connection_verify (connection, error)) {
-	case NM_SETTING_VERIFY_NORMALIZABLE:
-		nm_assert_not_reached ();
-		/* fall-through */
-	case NM_SETTING_VERIFY_SUCCESS:
-		break;
-	default:
-		g_return_val_if_reached (FALSE);
-	}
-
 	id = nm_connection_get_id (connection);
-	g_assert (id && *id);
+	nm_assert (id && *id);
 
 	info.keyfile_dir = keyfile_dir;
 
 	kf_file = nm_keyfile_write (connection, _handler_write, &info, error);
 	if (!kf_file)
 		return FALSE;
+
+	if (is_nm_generated) {
+		g_key_file_set_boolean (kf_file,
+		                        NM_KEYFILE_GROUP_NMMETA,
+		                        NM_KEYFILE_KEY_NMMETA_NM_GENERATED,
+		                        TRUE);
+	}
+
+	if (is_volatile) {
+		g_key_file_set_boolean (kf_file,
+		                        NM_KEYFILE_GROUP_NMMETA,
+		                        NM_KEYFILE_KEY_NMMETA_VOLATILE,
+		                        TRUE);
+	}
+
+	if (shadowed_storage) {
+		g_key_file_set_string (kf_file,
+		                       NM_KEYFILE_GROUP_NMMETA,
+		                       NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE,
+		                       shadowed_storage);
+	}
+
+	if (shadowed_owned) {
+		g_key_file_set_boolean (kf_file,
+		                        NM_KEYFILE_GROUP_NMMETA,
+		                        NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED,
+		                        TRUE);
+	}
+
 	kf_content_buf = g_key_file_to_data (kf_file, &kf_content_len, error);
 	if (!kf_content_buf)
 		return FALSE;
@@ -225,64 +254,59 @@ _internal_write_connection (NMConnection *connection,
 	if (!g_file_test (keyfile_dir, G_FILE_TEST_IS_DIR))
 		(void) g_mkdir_with_parents (keyfile_dir, 0755);
 
-	/* If we have existing file path, use it. Else generate one from
-	 * connection's ID.
-	 */
-	if (   existing_path
-	    && !rename)
-		path = g_strdup (existing_path);
-	else {
-		gs_free char *filename_escaped = NULL;
+	for (i_path = -2; i_path < 10000; i_path++) {
+		gs_free char *path_candidate = NULL;
+		gboolean is_existing_path;
 
-		filename_escaped = nm_keyfile_utils_create_filename (id, with_extension);
-		path = g_build_filename (keyfile_dir, filename_escaped, NULL);
-	}
-
-	/* If a file with this path already exists (but isn't the existing path
-	 * of the connection) then we need another name.  Multiple connections
-	 * can have the same ID (ie if two connections with the same ID are visible
-	 * to different users) but of course can't have the same path.  Yeah,
-	 * there's a race here, but there's not a lot we can do about it, and
-	 * we shouldn't get more than one connection with the same UUID either.
-	 */
-	if (   !nm_streq0 (path, existing_path)
-	    && g_file_test (path, G_FILE_TEST_EXISTS)) {
-		guint i;
-		gboolean name_found = FALSE;
+		if (i_path == -2) {
+			if (   !existing_path
+			    || rename)
+				continue;
+			path_candidate = g_strdup (existing_path);
+		} else if (i_path == -1) {
+			gs_free char *filename_escaped = NULL;
 
-		/* A keyfile with this connection's ID already exists. Pick another name. */
-		for (i = 0; i < 100; i++) {
+			filename_escaped = nm_keyfile_utils_create_filename (id, with_extension);
+			path_candidate = g_build_filename (keyfile_dir, filename_escaped, NULL);
+		} else {
 			gs_free char *filename_escaped = NULL;
 			gs_free char *filename = NULL;
 
-			if (i == 0)
+			if (i_path == 0)
 				filename = g_strdup_printf ("%s-%s", id, nm_connection_get_uuid (connection));
 			else
-				filename = g_strdup_printf ("%s-%s-%u", id, nm_connection_get_uuid (connection), i);
+				filename = g_strdup_printf ("%s-%s-%d", id, nm_connection_get_uuid (connection), i_path);
 
 			filename_escaped = nm_keyfile_utils_create_filename (filename, with_extension);
 
-			g_free (path);
-			path = g_strdup_printf ("%s/%s", keyfile_dir, filename_escaped);
-
-			if (   nm_streq0 (path, existing_path)
-			    || !g_file_test (path, G_FILE_TEST_EXISTS)) {
-				name_found = TRUE;
-				break;
-			}
+			path_candidate = g_strdup_printf ("%s/%s", keyfile_dir, filename_escaped);
 		}
-		if (!name_found) {
-			if (existing_path_read_only || !existing_path) {
-				/* this really should not happen, we tried hard to find an unused name... bail out. */
-				g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
-				                    "could not find suitable keyfile file name (%s already used)", path);
-				return FALSE;
-			}
-			/* Both our preferred path based on connection id and id-uuid are taken.
-			 * Fallback to @existing_path */
-			g_free (path);
-			path = g_strdup (existing_path);
+
+		is_existing_path =    existing_path
+		                   && nm_streq (existing_path, path_candidate);
+
+		if (   is_existing_path
+		    && rename)
+			continue;
+
+		if (   allow_filename_cb
+		    && !allow_filename_cb (path_candidate, allow_filename_user_data))
+			continue;
+
+		if (!is_existing_path) {
+			if (g_file_test (path_candidate, G_FILE_TEST_EXISTS))
+				continue;
 		}
+
+		path = g_steal_pointer (&path_candidate);
+		break;
+	}
+
+	if (!path) {
+		/* this really should not happen, we tried hard to find an unused name... bail out. */
+		g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED,
+		                    "could not find suitable keyfile file name (%s already used)", path);
+		return FALSE;
 	}
 
 	nm_utils_file_set_contents (path, kf_content_buf, kf_content_len, 0600, &local_err);
@@ -348,30 +372,37 @@ _internal_write_connection (NMConnection *connection,
 
 gboolean
 nms_keyfile_writer_connection (NMConnection *connection,
-                               gboolean save_to_disk,
+                               gboolean is_nm_generated,
+                               gboolean is_volatile,
+                               const char *shadowed_storage,
+                               gboolean shadowed_owned,
+                               const char *keyfile_dir,
+                               const char *profile_dir,
                                const char *existing_path,
+                               gboolean existing_path_read_only,
                                gboolean force_rename,
+                               NMSKeyfileWriterAllowFilenameCb allow_filename_cb,
+                               gpointer allow_filename_user_data,
                                char **out_path,
                                NMConnection **out_reread,
                                gboolean *out_reread_same,
                                GError **error)
 {
-	const char *keyfile_dir;
-
-	if (save_to_disk)
-		keyfile_dir = nms_keyfile_utils_get_path ();
-	else
-		keyfile_dir = NM_KEYFILE_PATH_NAME_RUN;
-
 	return _internal_write_connection (connection,
+	                                   is_nm_generated,
+	                                   is_volatile,
+	                                   shadowed_storage,
+	                                   shadowed_owned,
 	                                   keyfile_dir,
-	                                   nms_keyfile_utils_get_path (),
+	                                   profile_dir,
 	                                   TRUE,
 	                                   0,
 	                                   0,
 	                                   existing_path,
-	                                   FALSE,
+	                                   existing_path_read_only,
 	                                   force_rename,
+	                                   allow_filename_cb,
+	                                   allow_filename_user_data,
 	                                   out_path,
 	                                   out_reread,
 	                                   out_reread_same,
@@ -389,6 +420,10 @@ nms_keyfile_writer_test_connection (NMConnection *connection,
                                     GError **error)
 {
 	return _internal_write_connection (connection,
+	                                   FALSE,
+	                                   FALSE,
+	                                   NULL,
+	                                   FALSE,
 	                                   keyfile_dir,
 	                                   keyfile_dir,
 	                                   FALSE,
@@ -397,6 +432,8 @@ nms_keyfile_writer_test_connection (NMConnection *connection,
 	                                   NULL,
 	                                   FALSE,
 	                                   FALSE,
+	                                   NULL,
+	                                   NULL,
 	                                   out_path,
 	                                   out_reread,
 	                                   out_reread_same,