summary refs log tree commit diff
path: root/src/core/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/devices')
-rw-r--r--src/core/devices/nm-device-ethernet.c11
-rw-r--r--src/core/devices/nm-device-macsec.c11
-rw-r--r--src/core/devices/nm-device-private.h2
-rw-r--r--src/core/devices/nm-device-utils.c3
-rw-r--r--src/core/devices/nm-device.c127
-rw-r--r--src/core/devices/wifi/nm-device-wifi.c4
6 files changed, 151 insertions, 7 deletions
diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c
index 4034fdaa..db1245b3 100644
--- a/src/core/devices/nm-device-ethernet.c
+++ b/src/core/devices/nm-device-ethernet.c
@@ -630,10 +630,17 @@ build_supplicant_config(NMDeviceEthernet *self, GError **error)
     mtu      = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)),
                                    nm_device_get_ifindex(NM_DEVICE(self)));
 
-    config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE);
+    config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE,
+                                      nm_utils_get_connection_first_permissions_user(connection));
 
     security = nm_connection_get_setting_802_1x(connection);
-    if (!nm_supplicant_config_add_setting_8021x(config, security, con_uuid, mtu, TRUE, error)) {
+    if (!nm_supplicant_config_add_setting_8021x(config,
+                                                security,
+                                                con_uuid,
+                                                mtu,
+                                                TRUE,
+                                                nm_device_get_private_files(NM_DEVICE(self)),
+                                                error)) {
         g_prefix_error(error, "802-1x-setting: ");
         g_clear_object(&config);
     }
diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c
index 2ff1eeb3..1659ea05 100644
--- a/src/core/devices/nm-device-macsec.c
+++ b/src/core/devices/nm-device-macsec.c
@@ -201,7 +201,8 @@ build_supplicant_config(NMDeviceMacsec *self, GError **error)
     mtu      = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)),
                                    nm_device_get_ifindex(NM_DEVICE(self)));
 
-    config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE);
+    config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE,
+                                      nm_utils_get_connection_first_permissions_user(connection));
 
     s_macsec = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_MACSEC);
 
@@ -227,7 +228,13 @@ build_supplicant_config(NMDeviceMacsec *self, GError **error)
 
     if (nm_setting_macsec_get_mode(s_macsec) == NM_SETTING_MACSEC_MODE_EAP) {
         s_8021x = nm_connection_get_setting_802_1x(connection);
-        if (!nm_supplicant_config_add_setting_8021x(config, s_8021x, con_uuid, mtu, TRUE, error)) {
+        if (!nm_supplicant_config_add_setting_8021x(config,
+                                                    s_8021x,
+                                                    con_uuid,
+                                                    mtu,
+                                                    TRUE,
+                                                    nm_device_get_private_files(NM_DEVICE(self)),
+                                                    error)) {
             g_prefix_error(error, "802-1x-setting: ");
             return NULL;
         }
diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h
index 2f73a01b..2568d9f1 100644
--- a/src/core/devices/nm-device-private.h
+++ b/src/core/devices/nm-device-private.h
@@ -179,4 +179,6 @@ void nm_device_auth_request(NMDevice                      *self,
 
 void nm_device_link_properties_set(NMDevice *self, gboolean reapply);
 
+GHashTable *nm_device_get_private_files(NMDevice *self);
+
 #endif /* NM_DEVICE_PRIVATE_H */
diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c
index a78499fb..3e86e2e8 100644
--- a/src/core/devices/nm-device-utils.c
+++ b/src/core/devices/nm-device-utils.c
@@ -237,7 +237,7 @@ resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data
     gs_free_error GError *error  = NULL;
     gs_free char         *output = NULL;
 
-    output = nm_utils_spawn_helper_finish(result, &error);
+    output = nm_utils_spawn_helper_finish_string(result, &error);
     if (nm_utils_error_is_cancelled(error))
         return;
 
@@ -276,6 +276,7 @@ resolve_addr_spawn_helper(ResolveAddrInfo *info, ResolveAddrService services)
     nm_inet_ntop(info->addr_family, &info->address, addr_str);
     _LOG2D(info, "start lookup via nm-daemon-helper using services: %s", str);
     nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str, str),
+                          FALSE,
                           g_task_get_cancellable(info->task),
                           resolve_addr_helper_cb,
                           info);
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 6bba982a..b0a3f780 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -335,6 +335,12 @@ typedef struct {
     int           addr_family;
 } HostnameResolver;
 
+typedef enum {
+    PRIVATE_FILES_STATE_UNKNOWN = 0,
+    PRIVATE_FILES_STATE_READING,
+    PRIVATE_FILES_STATE_DONE,
+} PrivateFilesState;
+
 /*****************************************************************************/
 
 enum {
@@ -771,6 +777,13 @@ typedef struct _NMDevicePrivate {
         guint64  rx_bytes;
     } stats;
 
+    struct {
+        GHashTable       *table;
+        GCancellable     *cancellable;
+        char             *user;
+        PrivateFilesState state;
+    } private_files;
+
     bool mtu_force_set_done : 1;
 
     bool needs_ip6_subnet : 1;
@@ -10807,6 +10820,49 @@ tc_commit(NMDevice *self)
     return TRUE;
 }
 
+static void
+read_private_files_cb(GObject *source_object, GAsyncResult *result, gpointer data)
+{
+    gs_unref_hashtable GHashTable *table = NULL;
+    gs_free_error GError          *error = NULL;
+    NMDevice                      *self;
+    NMDevicePrivate               *priv;
+
+    table = nm_utils_read_private_files_finish(result, &error);
+    if (nm_utils_error_is_cancelled(error))
+        return;
+
+    self = NM_DEVICE(data);
+    priv = NM_DEVICE_GET_PRIVATE(self);
+
+    if (error) {
+        NMConnection *connection = nm_device_get_applied_connection(self);
+
+        _LOGW(LOGD_DEVICE,
+              "could not read files for private connection %s owned by user '%s': %s",
+              connection ? nm_connection_get_uuid(connection) : NULL,
+              priv->private_files.user,
+              error->message);
+        nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+        return;
+    }
+
+    _LOGD(LOGD_DEVICE, "private files successfully read");
+
+    priv->private_files.state = PRIVATE_FILES_STATE_DONE;
+    priv->private_files.table = g_steal_pointer(&table);
+    g_clear_pointer(&priv->private_files.user, g_free);
+    g_clear_object(&priv->private_files.cancellable);
+
+    nm_device_activate_schedule_stage2_device_config(self, FALSE);
+}
+
+GHashTable *
+nm_device_get_private_files(NMDevice *self)
+{
+    return NM_DEVICE_GET_PRIVATE(self)->private_files.table;
+}
+
 /*
  * activate_stage2_device_config
  *
@@ -10819,6 +10875,7 @@ activate_stage2_device_config(NMDevice *self)
 {
     NMDevicePrivate *priv  = NM_DEVICE_GET_PRIVATE(self);
     NMDeviceClass   *klass = NM_DEVICE_GET_CLASS(self);
+    NMConnection    *applied;
     NMActStageReturn ret;
     NMSettingWired  *s_wired;
     gboolean         no_firmware = FALSE;
@@ -10827,6 +10884,68 @@ activate_stage2_device_config(NMDevice *self)
 
     nm_device_state_changed(self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
 
+    applied = nm_device_get_applied_connection(self);
+
+    /* If the connection is private (owned by a specific user), we need to
+     * verify that the user has permission to access any files specified in
+     * the connection, such as certificates and keys. We do that by calling
+     * nm_utils_read_private_files() and saving the file contents in a hash
+     * table that can be accessed later during the activation. It is important
+     * to never access the files again to avoid TOCTOU bugs.
+     */
+    switch (priv->private_files.state) {
+    case PRIVATE_FILES_STATE_UNKNOWN:
+    {
+        gs_free const char **paths = NULL;
+        NMSettingConnection *s_con;
+        const char          *user;
+
+        s_con = nm_connection_get_setting_connection(applied);
+        nm_assert(s_con);
+        user = _nm_setting_connection_get_first_permissions_user(s_con);
+
+        priv->private_files.user = g_strdup(user);
+        if (!priv->private_files.user) {
+            priv->private_files.state = PRIVATE_FILES_STATE_DONE;
+            break;
+        }
+
+        paths = nm_utils_get_connection_private_files_paths(applied);
+        if (!paths) {
+            priv->private_files.state = PRIVATE_FILES_STATE_DONE;
+            break;
+        }
+
+        if (_nm_setting_connection_get_num_permissions_users(s_con) > 1) {
+            _LOGW(LOGD_DEVICE,
+                  "private connections with multiple users are not allowed to reference "
+                  "certificates and keys on the filesystem. Specify only one user in the "
+                  "connection.permissions property.");
+            nm_device_state_changed(self,
+                                    NM_DEVICE_STATE_FAILED,
+                                    NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+            return;
+        }
+
+        priv->private_files.state       = PRIVATE_FILES_STATE_READING;
+        priv->private_files.cancellable = g_cancellable_new();
+
+        _LOGD(LOGD_DEVICE, "reading private files");
+        nm_utils_read_private_files(paths,
+                                    priv->private_files.user,
+                                    priv->private_files.cancellable,
+                                    read_private_files_cb,
+                                    self);
+        return;
+    }
+    case PRIVATE_FILES_STATE_READING:
+        /* wait */
+        return;
+    case PRIVATE_FILES_STATE_DONE:
+        /* proceed */
+        break;
+    }
+
     if (!nm_device_managed_type_is_external(self)) {
         _ethtool_state_set(self);
         nm_device_link_properties_set(self, FALSE);
@@ -10843,7 +10962,7 @@ activate_stage2_device_config(NMDevice *self)
         priv->tc_committed = TRUE;
     }
 
-    nm_routing_rules_sync(nm_device_get_applied_connection(self),
+    nm_routing_rules_sync(applied,
                           NM_TERNARY_TRUE,
                           klass->get_extra_rules,
                           self,
@@ -17154,6 +17273,12 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu
     if (klass->deactivate)
         klass->deactivate(self);
 
+    /* Clean up private files */
+    nm_clear_g_cancellable(&priv->private_files.cancellable);
+    g_clear_pointer(&priv->private_files.table, g_hash_table_unref);
+    g_clear_pointer(&priv->private_files.user, g_free);
+    priv->private_files.state = PRIVATE_FILES_STATE_UNKNOWN;
+
     ifindex = nm_device_get_ip_ifindex(self);
 
     if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c
index b890b110..148caa11 100644
--- a/src/core/devices/wifi/nm-device-wifi.c
+++ b/src/core/devices/wifi/nm-device-wifi.c
@@ -2946,7 +2946,8 @@ build_supplicant_config(NMDeviceWifi         *self,
     s_wireless = nm_connection_get_setting_wireless(connection);
     g_return_val_if_fail(s_wireless != NULL, NULL);
 
-    config = nm_supplicant_config_new(nm_supplicant_interface_get_capabilities(priv->sup_iface));
+    config = nm_supplicant_config_new(nm_supplicant_interface_get_capabilities(priv->sup_iface),
+                                      nm_utils_get_connection_first_permissions_user(connection));
 
     /* Warn if AP mode may not be supported */
     if (nm_streq0(nm_setting_wireless_get_mode(s_wireless), NM_SETTING_WIRELESS_MODE_AP)
@@ -3022,6 +3023,7 @@ build_supplicant_config(NMDeviceWifi         *self,
                 mtu,
                 pmf,
                 fils,
+                nm_device_get_private_files(NM_DEVICE(self)),
                 error)) {
             g_prefix_error(error, "802-11-wireless-security: ");
             goto error;