diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index ee50de5a81..5404ecb9ce 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -5667,47 +5667,19 @@ nm_utils_get_connection_first_permissions_user(NMConnection *connection) /*****************************************************************************/ -static void -get_8021x_private_files(NMConnection *connection, GPtrArray *files) -{ - const struct { - NMSetting8021xCKScheme (*get_scheme_func)(NMSetting8021x *); - const char *(*get_path_func)(NMSetting8021x *); - } funcs[] = { - {nm_setting_802_1x_get_ca_cert_scheme, nm_setting_802_1x_get_ca_cert_path}, - {nm_setting_802_1x_get_client_cert_scheme, nm_setting_802_1x_get_client_cert_path}, - {nm_setting_802_1x_get_private_key_scheme, nm_setting_802_1x_get_private_key_path}, - {nm_setting_802_1x_get_phase2_ca_cert_scheme, nm_setting_802_1x_get_phase2_ca_cert_path}, - {nm_setting_802_1x_get_phase2_client_cert_scheme, - nm_setting_802_1x_get_phase2_client_cert_path}, - {nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_path}, - }; - NMSetting8021x *s_8021x; - const char *path; - guint i; - - s_8021x = nm_connection_get_setting_802_1x(connection); - if (!s_8021x) - return; - - for (i = 0; i < G_N_ELEMENTS(funcs); i++) { - if (funcs[i].get_scheme_func(s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) { - path = funcs[i].get_path_func(s_8021x); - if (path) { - g_ptr_array_add(files, (gpointer) path); - } - } - } -} - const char ** nm_utils_get_connection_private_files_paths(NMConnection *connection) { - GPtrArray *files; + GPtrArray *files; + gs_free NMSetting **settings = NULL; + guint num_settings; + guint i; - files = g_ptr_array_new(); - get_8021x_private_files(connection, files); + files = g_ptr_array_new(); + settings = nm_connection_get_settings(connection, &num_settings); + for (i = 0; i < num_settings; i++) { + _nm_setting_get_private_files(settings[i], files); + } g_ptr_array_add(files, NULL); return (const char **) g_ptr_array_free(files, files->len == 1); diff --git a/src/libnm-core-impl/nm-setting-8021x.c b/src/libnm-core-impl/nm-setting-8021x.c index 4ea6072966..f933380333 100644 --- a/src/libnm-core-impl/nm-setting-8021x.c +++ b/src/libnm-core-impl/nm-setting-8021x.c @@ -3133,6 +3133,86 @@ need_secrets(NMSetting *setting, gboolean check_rerequest) /*****************************************************************************/ +static void +get_private_files(NMSetting *setting, GPtrArray *files) +{ + const struct { + const char *property; + NMSetting8021xCKScheme (*get_scheme_func)(NMSetting8021x *); + const char *(*get_path_func)(NMSetting8021x *); + } cert_props[] = { + {NM_SETTING_802_1X_CA_CERT, + nm_setting_802_1x_get_ca_cert_scheme, + nm_setting_802_1x_get_ca_cert_path}, + {NM_SETTING_802_1X_CLIENT_CERT, + nm_setting_802_1x_get_client_cert_scheme, + nm_setting_802_1x_get_client_cert_path}, + {NM_SETTING_802_1X_PRIVATE_KEY, + nm_setting_802_1x_get_private_key_scheme, + nm_setting_802_1x_get_private_key_path}, + {NM_SETTING_802_1X_PHASE2_CA_CERT, + nm_setting_802_1x_get_phase2_ca_cert_scheme, + nm_setting_802_1x_get_phase2_ca_cert_path}, + {NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + nm_setting_802_1x_get_phase2_client_cert_scheme, + nm_setting_802_1x_get_phase2_client_cert_path}, + {NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, + nm_setting_802_1x_get_phase2_private_key_scheme, + nm_setting_802_1x_get_phase2_private_key_path}, + }; + NMSetting8021x *s_8021x = NM_SETTING_802_1X(setting); + const char *path; + guint i; + + if (NM_MORE_ASSERT_ONCE(5)) { + GObjectClass *klass; + gs_free GParamSpec **properties = NULL; + guint n_properties; + gboolean found; + guint j; + + /* Check that all the properties in the setting with flag CERT_KEY_FILE + * are listed in the table, and vice versa. */ + + klass = G_OBJECT_GET_CLASS(setting); + + properties = g_object_class_list_properties(klass, &n_properties); + for (i = 0; i < n_properties; i++) { + if (!(properties[i]->flags & NM_SETTING_PARAM_CERT_KEY_FILE)) + continue; + + found = FALSE; + for (j = 0; j < G_N_ELEMENTS(cert_props); j++) { + if (nm_streq0(properties[i]->name, cert_props[j].property)) { + found = TRUE; + break; + } + } + + nm_assert(found); + } + + for (i = 0; i < G_N_ELEMENTS(cert_props); i++) { + GParamSpec *prop; + + prop = g_object_class_find_property(klass, cert_props[i].property); + nm_assert(prop); + nm_assert(prop->flags & NM_SETTING_PARAM_CERT_KEY_FILE); + } + } + + for (i = 0; i < G_N_ELEMENTS(cert_props); i++) { + if (cert_props[i].get_scheme_func(s_8021x) == NM_SETTING_802_1X_CK_SCHEME_PATH) { + path = cert_props[i].get_path_func(s_8021x); + if (path) { + g_ptr_array_add(files, (gpointer) path); + } + } + } +} + +/*****************************************************************************/ + static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -3223,8 +3303,9 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) object_class->set_property = set_property; object_class->finalize = finalize; - setting_class->verify = verify; - setting_class->need_secrets = need_secrets; + setting_class->verify = verify; + setting_class->need_secrets = need_secrets; + setting_class->get_private_files = get_private_files; /** * NMSetting8021x:eap: @@ -3359,7 +3440,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_CA_CERT, PROP_CA_CERT, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, ca_cert); @@ -3556,7 +3637,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_CLIENT_CERT, PROP_CLIENT_CERT, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, client_cert); @@ -3803,7 +3884,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_PHASE2_CA_CERT, PROP_PHASE2_CA_CERT, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, phase2_ca_cert); @@ -4006,7 +4087,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, PROP_PHASE2_CLIENT_CERT, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, phase2_client_cert); @@ -4175,7 +4256,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_PRIVATE_KEY, PROP_PRIVATE_KEY, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, private_key); @@ -4276,7 +4357,7 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) obj_properties, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, PROP_PHASE2_PRIVATE_KEY, - NM_SETTING_PARAM_NONE, + NM_SETTING_PARAM_CERT_KEY_FILE, NMSetting8021xPrivate, phase2_private_key); diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index 8ee770f471..61f9678936 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -154,6 +154,11 @@ struct _NMSettingClass { guint /* NMSettingParseFlags */ parse_flags, GError **error); + /* returns a list of certificate/key files referenced in the connection. + * When the connection is private, we need to verify that the owner of + * the connection has access to them. */ + void (*get_private_files)(NMSetting *setting, GPtrArray *files); + const struct _NMMetaSettingInfo *setting_info; }; @@ -334,6 +339,11 @@ struct _NMRange { */ #define NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS (1 << (7 + G_PARAM_USER_SHIFT)) +/* The property can refer to a certificate or key stored on disk. As such, + * special care is needed when accessing the file for private connections. + */ +#define NM_SETTING_PARAM_CERT_KEY_FILE (1 << (8 + G_PARAM_USER_SHIFT)) + extern const NMSettInfoPropertType nm_sett_info_propert_type_setting_name; extern const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_interface_name; extern const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_i; @@ -859,9 +869,10 @@ _nm_properties_override(GArray *properties_override, const NMSettInfoProperty *p { \ GParamSpec *_param_spec; \ \ - G_STATIC_ASSERT(!NM_FLAGS_ANY((param_flags), \ - ~(NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_INFERRABLE \ - | NM_SETTING_PARAM_FUZZY_IGNORE))); \ + G_STATIC_ASSERT( \ + !NM_FLAGS_ANY((param_flags), \ + ~(NM_SETTING_PARAM_SECRET | NM_SETTING_PARAM_INFERRABLE \ + | NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_CERT_KEY_FILE))); \ \ _param_spec = g_param_spec_boxed("" prop_name "", \ "", \ diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index 3b3aecf1a6..e87f39b200 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -2262,6 +2262,34 @@ init_from_dbus(NMSetting *setting, return TRUE; } +static void +get_private_files(NMSetting *setting, GPtrArray *files) +{ + if (NM_MORE_ASSERTS) { + GParamSpec **properties; + guint n_properties; + int i; + + properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(setting), &n_properties); + for (i = 0; i < n_properties; i++) { + if (properties[i]->flags & NM_SETTING_PARAM_CERT_KEY_FILE) { + /* Certificates and keys needs special handling, see setting 802.1X */ + nm_assert_not_reached(); + } + } + g_free(properties); + } +} + +void +_nm_setting_get_private_files(NMSetting *setting, GPtrArray *files) +{ + g_return_if_fail(NM_IS_SETTING(setting)); + g_return_if_fail(files); + + NM_SETTING_GET_CLASS(setting)->get_private_files(setting, files); +} + /** * nm_setting_get_dbus_property_type: * @setting: an #NMSetting @@ -4672,6 +4700,7 @@ nm_setting_class_init(NMSettingClass *setting_class) setting_class->enumerate_values = enumerate_values; setting_class->aggregate = aggregate; setting_class->init_from_dbus = init_from_dbus; + setting_class->get_private_files = get_private_files; /** * NMSetting:name: diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 6991185d39..b8df4d2e9d 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -1192,4 +1192,6 @@ const GPtrArray *_nm_setting_ovs_port_get_trunks_arr(NMSettingOvsPort *self); guint _nm_setting_connection_get_num_permissions_users(NMSettingConnection *setting); const char *_nm_setting_connection_get_first_permissions_user(NMSettingConnection *setting); +void _nm_setting_get_private_files(NMSetting *setting, GPtrArray *files); + #endif