diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index ac61737e47..1287b7a2f0 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -136,6 +136,13 @@ char ** _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy); GPtrArray * _nm_utils_strv_to_ptrarray (char **strv); char ** _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray); +gboolean _nm_utils_check_file (const char *filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + struct stat *out_st, + GError **error); + #define NM_UTILS_UUID_TYPE_LEGACY 0 #define NM_UTILS_UUID_TYPE_VARIANT3 1 diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index fec3999bce..91bde5059e 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "nm-glib.h" #include "nm-utils.h" @@ -2409,6 +2410,76 @@ nm_utils_file_is_pkcs12 (const char *filename) /**********************************************************************************************/ +gboolean +_nm_utils_check_file (const char *filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + struct stat *out_st, + GError **error) +{ + struct stat st_backup; + + if (!out_st) + out_st = &st_backup; + + if (stat (filename, out_st) != 0) { + int errsv = errno; + + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("failed stat file %s: %s"), filename, strerror (errsv)); + return FALSE; + } + + /* ignore non-files. */ + if (!S_ISREG (out_st->st_mode)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("not a file (%s)"), filename); + return FALSE; + } + + /* with check_owner enabled, check that the file belongs to the + * owner or root. */ + if ( check_owner >= 0 + && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("invalid file owner %d for %s"), out_st->st_uid, filename); + return FALSE; + } + + /* with check_owner enabled, check that the file cannot be modified + * by other users (except root). */ + if ( check_owner >= 0 + && NM_FLAGS_ANY (out_st->st_mode, S_IWGRP | S_IWOTH | S_ISUID)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("file permissions for %s"), filename); + return FALSE; + } + + if ( check_file + && !check_file (filename, out_st, user_data, error)) { + if (error && !*error) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("reject %s"), filename); + } + return FALSE; + } + + return TRUE; +} + +/**********************************************************************************************/ + /** * nm_utils_file_search_in_paths: * @progname: the helper program name, like "iptables" diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index c9a01d6e6e..64e57e875a 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -128,6 +128,10 @@ gboolean nm_utils_file_is_pkcs12 (const char *filename); typedef gboolean (*NMUtilsFileSearchInPathsPredicate) (const char *filename, gpointer user_data); +struct stat; + +typedef gboolean (*NMUtilsCheckFilePredicate) (const char *filename, const struct stat *stat, gpointer user_data, GError **error); + const char *nm_utils_file_search_in_paths (const char *progname, const char *try_first, const char *const *paths,