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>2020-10-05 22:27:18 +0200
committerMichael Biebl <biebl@debian.org>2020-10-05 22:27:18 +0200
commitaafc1dbe4712c86189bbc1d4d54ad8cb4c69be7e (patch)
treea2a9bb4d007339a0b1304540388230ccedac32bd /src/settings/plugins/keyfile/nms-keyfile-utils.c
parente7b44ef4c80907346ec7492a09c45277459924fc (diff)
New upstream version 1.27.90 upstream/1.27.90
Diffstat (limited to 'src/settings/plugins/keyfile/nms-keyfile-utils.c')
-rw-r--r--src/settings/plugins/keyfile/nms-keyfile-utils.c641
1 files changed, 331 insertions, 310 deletions
diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c
index bc8dfd12..851e7815 100644
--- a/src/settings/plugins/keyfile/nms-keyfile-utils.c
+++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright (C) 2010 - 2018 Red Hat, Inc.
  */
@@ -20,349 +20,370 @@
 
 /*****************************************************************************/
 
-#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"
+#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)
+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;
+    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_nmmeta_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;
+    char  filename[250];
+    char *s;
 
-	nm_assert (dirname && dirname[0] == '/');
-	nm_assert (   nm_utils_is_uuid (uuid)
-	           && !strchr (uuid, '/'));
+    nm_assert(dirname && dirname[0] == '/');
+    nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/'));
 
-	if (g_snprintf (filename,
-	                sizeof (filename),
-	                "%s%s%s",
-	                uuid,
-	                NM_KEYFILE_PATH_SUFFIX_NMMETA,
-	                temporary ? "~" : "") >= sizeof (filename)) {
-		/* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always
-		 * be large enough. */
-		nm_assert_not_reached ();
-	}
+    if (g_snprintf(filename,
+                   sizeof(filename),
+                   "%s%s%s",
+                   uuid,
+                   NM_KEYFILE_PATH_SUFFIX_NMMETA,
+                   temporary ? "~" : "")
+        >= sizeof(filename)) {
+        /* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always
+         * be large enough. */
+        nm_assert_not_reached();
+    }
 
-	s = g_build_filename (dirname, filename, NULL);
+    s = g_build_filename(dirname, filename, NULL);
 
-	nm_assert (nm_keyfile_utils_ignore_filename (s, FALSE));
+    nm_assert(nm_keyfile_utils_ignore_filename(s, FALSE));
 
-	return s;
+    return s;
 }
 
 gboolean
-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)
+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;
-	guint uuid_len;
-	gs_free char *full_filename = 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, '/'));
-
-	uuid = nms_keyfile_nmmeta_check_filename (filename, &uuid_len);
-	if (!uuid)
-		return FALSE;
-
-	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;
-
-	if (S_ISREG (st->st_mode)) {
-		gs_unref_keyfile GKeyFile *kf = NULL;
-		gs_free char *v_uuid = NULL;
-
-		kf = g_key_file_new ();
-
-		if (!g_key_file_load_from_file (kf, full_filename, G_KEY_FILE_NONE, NULL))
-			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;
-
-		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 (   !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;
-		}
-
-	} else {
-		loaded_path = nm_utils_read_link_absolute (full_filename, NULL);
-		if (!loaded_path)
-			return FALSE;
-	}
-
-	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 (&loaded_path));
-	NM_SET_OUT (out_shadowed_storage, g_steal_pointer (&shadowed_storage));
-	return TRUE;
+    const char *  uuid;
+    guint         uuid_len;
+    gs_free char *full_filename    = 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, '/'));
+
+    uuid = nms_keyfile_nmmeta_check_filename(filename, &uuid_len);
+    if (!uuid)
+        return FALSE;
+
+    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;
+
+    if (S_ISREG(st->st_mode)) {
+        nm_auto_unref_keyfile GKeyFile *kf     = NULL;
+        gs_free char *                  v_uuid = NULL;
+
+        kf = g_key_file_new();
+
+        if (!g_key_file_load_from_file(kf, full_filename, G_KEY_FILE_NONE, NULL))
+            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;
+
+        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 (!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;
+        }
+
+    } else {
+        loaded_path = nm_utils_read_link_absolute(full_filename, NULL);
+        if (!loaded_path)
+            return FALSE;
+    }
+
+    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(&loaded_path));
+    NM_SET_OUT(out_shadowed_storage, g_steal_pointer(&shadowed_storage));
+    return TRUE;
 }
 
 gboolean
-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)
+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;
-
-	nm_assert (full_filename && full_filename[0] == '/');
-
-	filename = g_path_get_basename (full_filename);
-	dirname = g_path_get_dirname (full_filename);
-
-	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));
-	NM_SET_OUT (out_filename, g_steal_pointer (&filename));
-	return TRUE;
+    gs_free char *dirname  = NULL;
+    gs_free char *filename = NULL;
+
+    nm_assert(full_filename && full_filename[0] == '/');
+
+    filename = g_path_get_basename(full_filename);
+    dirname  = g_path_get_dirname(full_filename);
+
+    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));
+    NM_SET_OUT(out_filename, g_steal_pointer(&filename));
+    return TRUE;
 }
 
 int
-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)
+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;
-	int errsv;
-
-	nm_assert (dirname && dirname[0] == '/');
-	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_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));
-
-	(void) unlink (full_filename_tmp);
-
-	if (!loaded_path) {
-		full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
-		errsv = 0;
-		if (unlink (full_filename_tmp) != 0) {
-			errsv = -NM_ERRNO_NATIVE (errno);
-			if (errsv == -ENOENT)
-				errsv = 0;
-		}
-		NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-		return errsv;
-	}
-
-	if (loaded_path_allow_relative) {
-		const char *f;
-
-		f = nm_utils_file_is_in_path (loaded_path, dirname);
-		if (f) {
-			/* @loaded_path points to a file directly in @dirname.
-			 * Don't use absolute paths. */
-			loaded_path = f;
-		}
-	}
-
-	full_filename = g_strndup (full_filename_tmp, strlen (full_filename_tmp) - 1);
-
-	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,
-		                                 &errsv,
-		                                 NULL)) {
-			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-			return -NM_ERRNO_NATIVE (errsv);
-		}
-	} 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) {
-			errsv = -NM_ERRNO_NATIVE (errno);
-			full_filename_tmp[strlen (full_filename_tmp) - 1] = '\0';
-			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename_tmp));
-			return errsv;
-		}
-
-		if (rename (full_filename_tmp, full_filename) != 0) {
-			errsv = -NM_ERRNO_NATIVE (errno);
-			(void) unlink (full_filename_tmp);
-			NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-			return errsv;
-		}
-	}
-
-	NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
-	return 0;
+    gs_free char *full_filename_tmp = NULL;
+    gs_free char *full_filename     = NULL;
+    int           errsv;
+
+    nm_assert(dirname && dirname[0] == '/');
+    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_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));
+
+    (void) unlink(full_filename_tmp);
+
+    if (!loaded_path) {
+        full_filename_tmp[strlen(full_filename_tmp) - 1] = '\0';
+        errsv                                            = 0;
+        if (unlink(full_filename_tmp) != 0) {
+            errsv = -NM_ERRNO_NATIVE(errno);
+            if (errsv == -ENOENT)
+                errsv = 0;
+        }
+        NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp));
+        return errsv;
+    }
+
+    if (loaded_path_allow_relative) {
+        const char *f;
+
+        f = nm_utils_file_is_in_path(loaded_path, dirname);
+        if (f) {
+            /* @loaded_path points to a file directly in @dirname.
+             * Don't use absolute paths. */
+            loaded_path = f;
+        }
+    }
+
+    full_filename = g_strndup(full_filename_tmp, strlen(full_filename_tmp) - 1);
+
+    if (shadowed_storage) {
+        nm_auto_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, &errsv, NULL)) {
+            NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp));
+            return -NM_ERRNO_NATIVE(errsv);
+        }
+    } 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 amount of information.
+         * No need to bother with a keyfile. */
+        if (symlink(loaded_path, full_filename_tmp) != 0) {
+            errsv                                            = -NM_ERRNO_NATIVE(errno);
+            full_filename_tmp[strlen(full_filename_tmp) - 1] = '\0';
+            NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp));
+            return errsv;
+        }
+
+        if (rename(full_filename_tmp, full_filename) != 0) {
+            errsv = -NM_ERRNO_NATIVE(errno);
+            (void) unlink(full_filename_tmp);
+            NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename));
+            return errsv;
+        }
+    }
+
+    NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename));
+    return 0;
 }
 
 /*****************************************************************************/
 
 gboolean
-nms_keyfile_utils_check_file_permissions_stat (NMSKeyfileFiletype filetype,
-                                               const struct stat *st,
-                                               GError **error)
+nms_keyfile_utils_check_file_permissions_stat(NMSKeyfileFiletype filetype,
+                                              const struct stat *st,
+                                              GError **          error)
 {
-	g_return_val_if_fail (st, FALSE);
-
-	if (filetype == NMS_KEYFILE_FILETYPE_KEYFILE) {
-		if (!S_ISREG (st->st_mode)) {
-			g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			                     "file is not a regular file");
-			return FALSE;
-		}
-	} 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 neither a symlink nor a regular file");
-			return FALSE;
-		}
-	} else
-		g_return_val_if_reached (FALSE);
-
-	if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) {
-		if (st->st_uid != 0) {
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "File owner (%lld) is insecure",
-			             (long long) st->st_uid);
-			return FALSE;
-		}
-
-		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",
-			             st->st_mode);
-			return FALSE;
-		}
-	}
-
-	return TRUE;
+    g_return_val_if_fail(st, FALSE);
+
+    if (filetype == NMS_KEYFILE_FILETYPE_KEYFILE) {
+        if (!S_ISREG(st->st_mode)) {
+            g_set_error_literal(error,
+                                NM_SETTINGS_ERROR,
+                                NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                                "file is not a regular file");
+            return FALSE;
+        }
+    } 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 neither a symlink nor a regular file");
+            return FALSE;
+        }
+    } else
+        g_return_val_if_reached(FALSE);
+
+    if (!NM_FLAGS_HAS(nm_utils_get_testing(), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) {
+        if (st->st_uid != 0) {
+            g_set_error(error,
+                        NM_SETTINGS_ERROR,
+                        NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                        "File owner (%lld) is insecure",
+                        (long long) st->st_uid);
+            return FALSE;
+        }
+
+        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",
+                        st->st_mode);
+            return FALSE;
+        }
+    }
+
+    return TRUE;
 }
 
 gboolean
-nms_keyfile_utils_check_file_permissions (NMSKeyfileFiletype filetype,
-                                          const char *filename,
-                                          struct stat *out_st,
-                                          GError **error)
+nms_keyfile_utils_check_file_permissions(NMSKeyfileFiletype filetype,
+                                         const char *       filename,
+                                         struct stat *      out_st,
+                                         GError **          error)
 {
-	struct stat st;
-	int errsv;
-
-	g_return_val_if_fail (filename && filename[0] == '/', FALSE);
-
-	if (filetype == NMS_KEYFILE_FILETYPE_KEYFILE) {
-		if (stat (filename, &st) != 0) {
-			errsv = errno;
-			g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
-			             "cannot access file: %s", nm_strerror_native (errsv));
-			return FALSE;
-		}
-	} 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,
-			             "cannot access file: %s", nm_strerror_native (errsv));
-			return FALSE;
-		}
-	} else
-		g_return_val_if_reached (FALSE);
-
-	if (!nms_keyfile_utils_check_file_permissions_stat (filetype, &st, error))
-		return FALSE;
-
-	NM_SET_OUT (out_st, st);
-	return TRUE;
+    struct stat st;
+    int         errsv;
+
+    g_return_val_if_fail(filename && filename[0] == '/', FALSE);
+
+    if (filetype == NMS_KEYFILE_FILETYPE_KEYFILE) {
+        if (stat(filename, &st) != 0) {
+            errsv = errno;
+            g_set_error(error,
+                        NM_SETTINGS_ERROR,
+                        NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                        "cannot access file: %s",
+                        nm_strerror_native(errsv));
+            return FALSE;
+        }
+    } 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,
+                        "cannot access file: %s",
+                        nm_strerror_native(errsv));
+            return FALSE;
+        }
+    } else
+        g_return_val_if_reached(FALSE);
+
+    if (!nms_keyfile_utils_check_file_permissions_stat(filetype, &st, error))
+        return FALSE;
+
+    NM_SET_OUT(out_st, st);
+    return TRUE;
 }