summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-10-19 10:21:53 +0200
committerThomas Haller <thaller@redhat.com>2018-10-23 10:32:53 +0200
commitf90b3adc153c78a828ad265aa8c65c0f7f54e023 (patch)
tree82ea76c72ebea201267c15249bb19cc634254014
parent9dce4a426ba82307cd27de23f3f3d8aed569d79b (diff)
downloadNetworkManager-f90b3adc153c78a828ad265aa8c65c0f7f54e023.tar.gz
core: add nm_utils_file_is_in_path() for checking paths
Add a helper function for the common check whether a file is inside a path. Also, this function handles special cases like repeated file separators. However, as it is still entirely text based, it also cannot recognize if two (literally) different paths reference the same inode/file.
-rw-r--r--src/NetworkManagerUtils.c60
-rw-r--r--src/NetworkManagerUtils.h6
-rw-r--r--src/nm-core-utils.c4
-rw-r--r--src/tests/test-general.c21
4 files changed, 91 insertions, 0 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 1404854d71..ae17ee5179 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -34,6 +34,7 @@
#include "platform/nm-platform.h"
#include "nm-auth-utils.h"
+#include "systemd/nm-sd-utils.h"
/*****************************************************************************/
@@ -998,3 +999,62 @@ nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle)
g_object_weak_unref (handle->watched_obj, _shutdown_waitobj_cb, handle);
_shutdown_waitobj_unregister (handle);
}
+
+/*****************************************************************************/
+
+/**
+ * nm_utils_file_is_in_path:
+ * @abs_filename: the absolute filename to test
+ * @abs_path: the absolute path, to check whether filename is in.
+ *
+ * This tests, whether @abs_filename is a file which lies inside @abs_path.
+ * Basically, this checks whether @abs_filename is the same as @abs_path +
+ * basename(@abs_filename). It allows simple normalizations, like coalescing
+ * multiple "//".
+ *
+ * However, beware that this function is purely filename based. That means,
+ * it will reject files that reference the same file (i.e. inode) via
+ * symlinks or bind mounts. Maybe one would like to check for file (inode)
+ * identity, but that is not really possible based on the file name alone.
+ *
+ * This means, that nm_utils_file_is_in_path("/var/run/some-file", "/var/run")
+ * will succeed, but nm_utils_file_is_in_path("/run/some-file", "/var/run")
+ * will not (although, it's well known that they reference the same path).
+ *
+ * Also, note that @abs_filename must not have trailing slashes itself.
+ * So, this will reject nm_utils_file_is_in_path("/usr/lib/", "/usr") as
+ * invalid, because the function searches for file names (and "lib/" is
+ * clearly a directory).
+ *
+ * Returns: if @abs_filename is a file inside @abs_path, returns the
+ * trailing part of @abs_filename which is the filename. Otherwise
+ * %NULL.
+ */
+const char *
+nm_utils_file_is_in_path (const char *abs_filename,
+ const char *abs_path)
+{
+ const char *path;
+
+ g_return_val_if_fail (abs_filename && abs_filename[0] == '/', NULL);
+ g_return_val_if_fail (abs_path && abs_path[0] == '/', NULL);
+
+ path = nm_sd_utils_path_startswith (abs_filename, abs_path);
+ if (!path)
+ return NULL;
+
+ nm_assert (path[0] != '/');
+ nm_assert (path > abs_filename);
+ nm_assert (path <= &abs_filename[strlen (abs_filename)]);
+
+ /* we require a non-empty remainder with no slashes. That is, only a filename.
+ *
+ * Note this will reject "/var/run/" as not being in "/var",
+ * while "/var/run" would pass. The function searches for files
+ * only, so a trailing slash (indicating a directory) is not allowed).
+ * This is despite that the function cannot determine whether "/var/run"
+ * is itself a file or a directory. "*/
+ return path[0] && !strchr (path, '/')
+ ? path
+ : NULL;
+}
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 26907243f6..93edb912dd 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -86,4 +86,10 @@ void nm_shutdown_wait_obj_unregister (NMShutdownWaitObjHandle *handle);
/*****************************************************************************/
+const char *
+nm_utils_file_is_in_path (const char *abs_filename,
+ const char *abs_path);
+
+/*****************************************************************************/
+
#endif /* __NETWORKMANAGER_UTILS_H__ */
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 50f127c090..75dd2e2c22 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -47,6 +47,10 @@
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
+#ifdef __NM_SD_UTILS_H__
+#error "nm-core-utils.c should stay independent of systemd utils. Are you looking for NetworkMangerUtils.c? "
+#endif
+
G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int));
static int _nm_utils_testing = 0;
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index d8586cc7f5..e436b36d3a 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -1845,6 +1845,25 @@ test_nm_utils_exp10 (void)
/*****************************************************************************/
+static void
+test_utils_file_is_in_path (void)
+{
+ g_assert (!nm_utils_file_is_in_path ("/", "/"));
+ g_assert (!nm_utils_file_is_in_path ("//", "/"));
+ g_assert (!nm_utils_file_is_in_path ("/a/", "/"));
+ g_assert ( nm_utils_file_is_in_path ("/a", "/"));
+ g_assert ( nm_utils_file_is_in_path ("///a", "/"));
+ g_assert ( nm_utils_file_is_in_path ("//b/a", "/b//"));
+ g_assert ( nm_utils_file_is_in_path ("//b///a", "/b//"));
+ g_assert (!nm_utils_file_is_in_path ("//b///a/", "/b//"));
+ g_assert (!nm_utils_file_is_in_path ("//b///a/", "/b/a/"));
+ g_assert (!nm_utils_file_is_in_path ("//b///a", "/b/a/"));
+ g_assert ( nm_utils_file_is_in_path ("//b///a/.", "/b/a/"));
+ g_assert ( nm_utils_file_is_in_path ("//b///a/..", "/b/a/"));
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE ();
int
@@ -1891,6 +1910,8 @@ main (int argc, char **argv)
g_test_add_func ("/general/stable-id/parse", test_stable_id_parse);
g_test_add_func ("/general/stable-id/generated-complete", test_stable_id_generated_complete);
+ g_test_add_func ("/general/test_utils_file_is_in_path", test_utils_file_is_in_path);
+
return g_test_run ();
}