about summary refs log tree commit diff
path: root/src/settings/plugins/keyfile/nms-keyfile-utils.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
committerMichael Biebl <biebl@debian.org>2019-07-31 10:51:42 +0200
commit2e5fa45ddfbb5cffa1e78221f1cea706e2f298af (patch)
tree86f69d36c56de3074280456eddc854a780b8e04b /src/settings/plugins/keyfile/nms-keyfile-utils.c
parent85563b7fc7ec2cd21e38debb9b28db342e2e8e7c (diff)
New upstream version 1.19.90 upstream/1.19.90
Diffstat (limited to 'src/settings/plugins/keyfile/nms-keyfile-utils.c')
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.c282
1 files changed, 169 insertions, 113 deletions
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c
index 3c4b0288..ea03e1b6 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c
@@ -1,4 +1,3 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
 /* NetworkManager system settings service
  *
  * This program is free software; you can redistribute it and/or modify
@@ -15,7 +14,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * (C) Copyright 2010 Red Hat, Inc.
+ * (C) Copyright 2010 - 2018 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -25,6 +24,7 @@
 #include <stdlib.h>
 #include <sys/stat.h>
 
+#include "nm-glib-aux/nm-io-utils.h"
 #include "nm-keyfile-internal.h"
 #include "nm-utils.h"
 #include "nm-setting-wired.h"
@@ -34,108 +34,155 @@
 
 /*****************************************************************************/
 
+#define NMMETA_KF_GROUP_NAME_NMMETA                 "nmmeta"
+#define NMMETA_KF_KEY_NAME_NMMETA_UUID              "uuid"
+#define NMMETA_KF_KEY_NAME_NMMETA_LOADED_PATH       "loaded-path"
+#define NMMETA_KF_KEY_NAME_NMMETA_SHADOWED_STORAGE  "shadowed-storage"
+
+/*****************************************************************************/
+
+const char *
+nms_keyfile_nmmeta_check_filename (const char *filename,
+                                   guint *out_uuid_len)
+{
+	const char *uuid;
+	const char *s;
+	gsize len;
+
+	s = strrchr (filename, '/');
+	if (s)
+		filename = &s[1];
+
+	len = strlen (filename);
+	if (   len <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)
+	    || memcmp (&filename[len - NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)],
+	               NM_KEYFILE_PATH_SUFFIX_NMMETA,
+	               NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)) != 0) {
+		/* the filename does not have the right suffix. */
+		return NULL;
+	}
+
+	len -= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA);
+
+	if (!NM_IN_SET (len, 36, 40)) {
+		/* the remaining part of the filename has not the right length to
+		 * contain a UUID (according to nm_utils_is_uuid()). */
+		return NULL;
+	}
+
+	uuid = nm_strndup_a (100, filename, len, NULL);
+	if (!nm_utils_is_uuid (uuid))
+		return NULL;
+
+	NM_SET_OUT (out_uuid_len, len);
+	return filename;
+}
+
 char *
-nms_keyfile_loaded_uuid_filename (const char *dirname,
-                                  const char *uuid,
-                                  gboolean temporary)
+nms_keyfile_nmmeta_filename (const char *dirname,
+                             const char *uuid,
+                             gboolean temporary)
 {
 	char filename[250];
+	char *s;
 
 	nm_assert (dirname && dirname[0] == '/');
-	nm_assert (uuid && nm_utils_is_uuid (uuid) && !strchr (uuid, '/'));
+	nm_assert (   nm_utils_is_uuid (uuid)
+	           && !strchr (uuid, '/'));
 
 	if (g_snprintf (filename,
 	                sizeof (filename),
-	                "%s%s%s%s",
-	                NM_KEYFILE_PATH_PREFIX_NMLOADED,
+	                "%s%s%s",
 	                uuid,
-	                NM_KEYFILE_PATH_SUFFIX_NMCONNECTION,
+	                NM_KEYFILE_PATH_SUFFIX_NMMETA,
 	                temporary ? "~" : "") >= sizeof (filename)) {
-		/* valid uuids are limited in length. The buffer should always be large
-		 * enough. */
+		/* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always
+		 * be large enough. */
 		nm_assert_not_reached ();
-		return NULL;
 	}
 
-	return g_build_filename (dirname, filename, NULL);
+	s = g_build_filename (dirname, filename, NULL);
+
+	nm_assert (nm_keyfile_utils_ignore_filename (s, FALSE));
+
+	return s;
 }
 
 gboolean
-nms_keyfile_loaded_uuid_read (const char *dirname,
-                              const char *filename,
-                              char **out_full_filename,
-                              char **out_uuid,
-                              char **out_loaded_path)
+nms_keyfile_nmmeta_read (const char *dirname,
+                         const char *filename,
+                         char **out_full_filename,
+                         char **out_uuid,
+                         char **out_loaded_path,
+                         char **out_shadowed_storage,
+                         struct stat *out_st)
 {
 	const char *uuid;
-	const char *tmp;
-	gsize len;
+	guint uuid_len;
 	gs_free char *full_filename = NULL;
-	gs_free char *ln = NULL;
+	gs_free char *loaded_path = NULL;
+	gs_free char *shadowed_storage = NULL;
+	struct stat st_stack;
+	struct stat *st = out_st ?: &st_stack;
 
 	nm_assert (dirname && dirname[0] == '/');
 	nm_assert (filename && filename[0] && !strchr (filename, '/'));
 
-	if (filename[0] != '.') {
-		/* the hidden-uuid filename must start with '.'. That is,
-		 * so that it does not conflict with regular keyfiles according
-		 * to nm_keyfile_utils_ignore_filename(). */
+	uuid = nms_keyfile_nmmeta_check_filename (filename, &uuid_len);
+	if (!uuid)
 		return FALSE;
-	}
 
-	len = strlen (filename);
-	if (   len <= NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)
-	    || memcmp (filename, NM_KEYFILE_PATH_PREFIX_NMLOADED, NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)) != 0) {
-		/* the filename does not have the right prefix. */
+	full_filename = g_build_filename (dirname, filename, NULL);
+
+	if (!nms_keyfile_utils_check_file_permissions (NMS_KEYFILE_FILETYPE_NMMETA,
+	                                               full_filename,
+	                                               st,
+	                                               NULL))
 		return FALSE;
-	}
 
-	tmp = &filename[NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)];
-	len -= NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED);
+	if (S_ISREG (st->st_mode)) {
+		gs_unref_keyfile GKeyFile *kf = NULL;
+		gs_free char *v_uuid = NULL;
 
-	if (   len <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)
-	    || memcmp (&tmp[len - NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)],
-	               NM_KEYFILE_PATH_SUFFIX_NMCONNECTION,
-	               NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) != 0) {
-		/* the file does not have the right suffix. */
-		return FALSE;
-	}
-	len -= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION);
+		kf = g_key_file_new ();
 
-	if (!NM_IN_SET (len, 36, 40)) {
-		/* the remaining part of the filename has not the right length to
-		 * contain a UUID (according to nm_utils_is_uuid()). */
-		return FALSE;
-	}
+		if (!g_key_file_load_from_file (kf, full_filename, G_KEY_FILE_NONE, NULL))
+			return FALSE;
 
-	uuid = nm_strndup_a (100, tmp, len, NULL);
-	if (!nm_utils_is_uuid (uuid))
-		return FALSE;
+		v_uuid = g_key_file_get_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_UUID, NULL);
+		if (!nm_streq0 (v_uuid, uuid))
+			return FALSE;
 
-	full_filename = g_build_filename (dirname, filename, NULL);
+		loaded_path = g_key_file_get_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_LOADED_PATH, NULL);
+		shadowed_storage = g_key_file_get_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_SHADOWED_STORAGE, NULL);
 
-	if (!nms_keyfile_utils_check_file_permissions (NMS_KEYFILE_FILETYPE_NMLOADED,
-	                                               full_filename,
-	                                               NULL,
-	                                               NULL))
-		return FALSE;
+		if (   !loaded_path
+		    && !shadowed_storage) {
+			/* if there is no useful information in the file, it is the same as if
+			 * the file is not present. Signal failure. */
+			return FALSE;
+		}
 
-	ln = nm_utils_read_link_absolute (full_filename, NULL);
-	if (!ln)
-		return FALSE;
+	} else {
+		loaded_path = nm_utils_read_link_absolute (full_filename, NULL);
+		if (!loaded_path)
+			return FALSE;
+	}
 
-	NM_SET_OUT (out_uuid, g_strdup (uuid));
+	NM_SET_OUT (out_uuid, g_strndup (uuid, uuid_len));
 	NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-	NM_SET_OUT (out_loaded_path, g_steal_pointer (&ln));
+	NM_SET_OUT (out_loaded_path, g_steal_pointer (&loaded_path));
+	NM_SET_OUT (out_shadowed_storage, g_steal_pointer (&shadowed_storage));
 	return TRUE;
 }
 
 gboolean
-nms_keyfile_loaded_uuid_read_from_file (const char *full_filename,
-                                        char **out_dirname,
-                                        char **out_filename,
-                                        char **out_uuid,
-                                        char **out_loaded_path)
+nms_keyfile_nmmeta_read_from_file (const char *full_filename,
+                                   char **out_dirname,
+                                   char **out_filename,
+                                   char **out_uuid,
+                                   char **out_loaded_path,
+                                   char **out_shadowed_storage)
 {
 	gs_free char *dirname = NULL;
 	gs_free char *filename = NULL;
@@ -145,11 +192,13 @@ nms_keyfile_loaded_uuid_read_from_file (const char *full_filename,
 	filename = g_path_get_basename (full_filename);
 	dirname = g_path_get_dirname (full_filename);
 
-	if (!nms_keyfile_loaded_uuid_read (dirname,
-	                                   filename,
-	                                   NULL,
-	                                   out_uuid,
-	                                   out_loaded_path))
+	if (!nms_keyfile_nmmeta_read (dirname,
+	                              filename,
+	                              NULL,
+	                              out_uuid,
+	                              out_loaded_path,
+	                              out_shadowed_storage,
+	                              NULL))
 		return FALSE;
 
 	NM_SET_OUT (out_dirname, g_steal_pointer (&dirname));
@@ -158,20 +207,23 @@ nms_keyfile_loaded_uuid_read_from_file (const char *full_filename,
 }
 
 gboolean
-nms_keyfile_loaded_uuid_write (const char *dirname,
-                               const char *uuid,
-                               const char *loaded_path,
-                               gboolean allow_relative,
-                               char **out_full_filename)
+nms_keyfile_nmmeta_write (const char *dirname,
+                          const char *uuid,
+                          const char *loaded_path,
+                          gboolean loaded_path_allow_relative,
+                          const char *shadowed_storage,
+                          char **out_full_filename)
 {
 	gs_free char *full_filename_tmp = NULL;
 	gs_free char *full_filename = NULL;
 
 	nm_assert (dirname && dirname[0] == '/');
-	nm_assert (uuid && nm_utils_is_uuid (uuid) && !strchr (uuid, '/'));
+	nm_assert (   nm_utils_is_uuid (uuid)
+	           && !strchr (uuid, '/'));
 	nm_assert (!loaded_path || loaded_path[0] == '/');
+	nm_assert (!shadowed_storage || loaded_path);
 
-	full_filename_tmp = nms_keyfile_loaded_uuid_filename (dirname, uuid, TRUE);
+	full_filename_tmp = nms_keyfile_nmmeta_filename (dirname, uuid, TRUE);
 
 	nm_assert (g_str_has_suffix (full_filename_tmp, "~"));
 	nm_assert (nm_utils_file_is_in_path (full_filename_tmp, dirname));
@@ -188,7 +240,7 @@ nms_keyfile_loaded_uuid_write (const char *dirname,
 		return success;
 	}
 
-	if (allow_relative) {
+	if (loaded_path_allow_relative) {
 		const char *f;
 
 		f = nm_utils_file_is_in_path (loaded_path, dirname);
@@ -199,18 +251,40 @@ nms_keyfile_loaded_uuid_write (const char *dirname,
 		}
 	}
 
-	if (symlink (loaded_path, full_filename_tmp) != 0) {
-		full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
-		NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-		return FALSE;
-	}
+	full_filename = g_strndup (full_filename_tmp, strlen (full_filename_tmp) - 1);
 
-	full_filename = g_strdup (full_filename_tmp);
-	full_filename[strlen (full_filename) - 1] = '\0';
-	if (rename (full_filename_tmp, full_filename) != 0) {
-		(void) unlink (full_filename_tmp);
-		NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-		return FALSE;
+	if (shadowed_storage) {
+		gs_unref_keyfile GKeyFile *kf = NULL;
+		gs_free char *contents = NULL;
+		gsize length;
+
+		kf = g_key_file_new ();
+
+		g_key_file_set_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_UUID, uuid);
+		g_key_file_set_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_LOADED_PATH, loaded_path);
+		g_key_file_set_string (kf, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_SHADOWED_STORAGE, shadowed_storage);
+
+		contents = g_key_file_to_data (kf, &length, NULL);
+
+		if (!nm_utils_file_set_contents (full_filename, contents, length, 0600, NULL)) {
+			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
+			return FALSE;
+		}
+	} else {
+		/* we only have the "loaded_path" to store. That is commonly used for the tombstones to
+		 * link to /dev/null. A symlink is sufficient to store that ammount of information.
+		 * No need to bother with a keyfile. */
+		if (symlink (loaded_path, full_filename_tmp) != 0) {
+			full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
+			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
+			return FALSE;
+		}
+
+		if (rename (full_filename_tmp, full_filename) != 0) {
+			(void) unlink (full_filename_tmp);
+			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
+			return FALSE;
+		}
 	}
 
 	NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
@@ -232,10 +306,11 @@ nms_keyfile_utils_check_file_permissions_stat (NMSKeyfileFiletype filetype,
 			                     "file is not a regular file");
 			return FALSE;
 		}
-	} else if (filetype == NMS_KEYFILE_FILETYPE_NMLOADED) {
-		if (!S_ISLNK (st->st_mode)) {
+	} else if (filetype == NMS_KEYFILE_FILETYPE_NMMETA) {
+		if (   !S_ISLNK (st->st_mode)
+		    && !S_ISREG (st->st_mode)) {
 			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			                     "file is not a slink");
+			                     "file is neither a symlink nor a regular file");
 			return FALSE;
 		}
 	} else
@@ -249,7 +324,7 @@ nms_keyfile_utils_check_file_permissions_stat (NMSKeyfileFiletype filetype,
 			return FALSE;
 		}
 
-		if (   filetype == NMS_KEYFILE_FILETYPE_KEYFILE
+		if (   S_ISREG (st->st_mode)
 		    && (st->st_mode & 0077)) {
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
 			             "File permissions (%03o) are insecure",
@@ -279,7 +354,7 @@ nms_keyfile_utils_check_file_permissions (NMSKeyfileFiletype filetype,
 			             "cannot access file: %s", nm_strerror_native (errsv));
 			return FALSE;
 		}
-	} else if (filetype == NMS_KEYFILE_FILETYPE_NMLOADED) {
+	} else if (filetype == NMS_KEYFILE_FILETYPE_NMMETA) {
 		if (lstat (filename, &st) != 0) {
 			errsv = errno;
 			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
@@ -295,22 +370,3 @@ nms_keyfile_utils_check_file_permissions (NMSKeyfileFiletype filetype,
 	NM_SET_OUT (out_st, st);
 	return TRUE;
 }
-
-/*****************************************************************************/
-
-const char *
-nms_keyfile_utils_get_path (void)
-{
-	static char *path = NULL;
-
-	if (G_UNLIKELY (!path)) {
-		path = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
-		                                 NM_CONFIG_KEYFILE_GROUP_KEYFILE,
-		                                 NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH,
-		                                 NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
-		if (!path)
-			path = g_strdup (""NM_KEYFILE_PATH_NAME_ETC_DEFAULT"");
-	}
-	return path;
-}
-