core: introduce device 'allowed-connections' property
Configuration can have [device*] and [connection*] settings and both can include a 'match-device=' key, which is a list of device-specs. Introduce a new 'allowed-connections' key for [device*] sections, which specifies a list of connection-specs to indicate which connections can be activated on the device. With this, it becomes possible to have a device configuration like: [device-enp1s0] match-device=interface-name:enp1s0 allowed-connections=except:origin:nm-initrd-generator so that NM in the real root ignores connections created by the nm-initrd-generator, and starts activating a persistent connection. This requires also setting 'keep-configuration=no' to not generate an assumed connection.
This commit is contained in:
@@ -1188,6 +1188,25 @@ managed=1
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="allowed-connections">
|
||||
<term><varname>allowed-connections</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A list of connections that can be activated on the
|
||||
device. See <xref linkend="connection-spec"/> for the
|
||||
syntax to specify a connection. If this option is not
|
||||
specified, all connections can be potentially activated
|
||||
on the device, provided that the connection type and
|
||||
other settings match.
|
||||
</para>
|
||||
<para>
|
||||
A notable use case for this is to filter which
|
||||
connections can be activated based on how they were
|
||||
created; see the <literal>origin</literal> keyword in
|
||||
<xref linkend="connection-spec"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>wifi.scan-rand-mac-address</varname></term>
|
||||
<listitem>
|
||||
|
@@ -7507,6 +7507,8 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e
|
||||
gs_free char * conn_iface = NULL;
|
||||
NMDeviceClass * klass;
|
||||
NMSettingMatch * s_match;
|
||||
const GSList * specs;
|
||||
gboolean has_match = FALSE;
|
||||
|
||||
klass = NM_DEVICE_GET_CLASS(self);
|
||||
if (klass->connection_type_check_compatible) {
|
||||
@@ -7583,6 +7585,15 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e
|
||||
}
|
||||
}
|
||||
|
||||
specs =
|
||||
nm_config_data_get_device_allowed_connections_specs(NM_CONFIG_GET_DATA, self, &has_match);
|
||||
if (has_match && !nm_utils_connection_match_spec_list(connection, specs, FALSE)) {
|
||||
nm_utils_error_set_literal(error,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED,
|
||||
"device configuration doesn't allow this connection");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,15 @@ typedef struct {
|
||||
gboolean has;
|
||||
GSList * spec;
|
||||
} match_device;
|
||||
union {
|
||||
struct {
|
||||
GSList * allowed_connections;
|
||||
gboolean allowed_connections_has;
|
||||
} device;
|
||||
};
|
||||
gboolean is_device;
|
||||
|
||||
/* List of key/value pairs in the section, sorted by key */
|
||||
gsize lookup_len;
|
||||
const NMUtilsNamedValue *lookup_idx;
|
||||
} MatchSectionInfo;
|
||||
@@ -1436,13 +1445,13 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
|
||||
match = TRUE;
|
||||
|
||||
if (match) {
|
||||
*out_value = value;
|
||||
NM_SET_OUT(out_value, value);
|
||||
return match_section_infos;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*out_value = NULL;
|
||||
NM_SET_OUT(out_value, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1538,6 +1547,37 @@ nm_config_data_get_device_config_int64(const NMConfigData *self,
|
||||
return _nm_utils_ascii_str_to_int64(value, base, min, max, val_invalid);
|
||||
}
|
||||
|
||||
const GSList *
|
||||
nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
|
||||
NMDevice * device,
|
||||
gboolean * has_match)
|
||||
{
|
||||
const NMConfigDataPrivate *priv;
|
||||
const MatchSectionInfo * connection_info;
|
||||
const GSList * ret = NULL;
|
||||
|
||||
g_return_val_if_fail(self, NULL);
|
||||
|
||||
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
||||
|
||||
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
|
||||
priv->keyfile,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
|
||||
device,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (connection_info) {
|
||||
nm_assert(connection_info->device.allowed_connections_has);
|
||||
ret = connection_info->device.allowed_connections;
|
||||
NM_SET_OUT(has_match, TRUE);
|
||||
} else
|
||||
NM_SET_OUT(has_match, FALSE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_config_data_get_connection_default(const NMConfigData *self,
|
||||
const char * property,
|
||||
@@ -1610,7 +1650,10 @@ _match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const
|
||||
}
|
||||
|
||||
static void
|
||||
_match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group)
|
||||
_match_section_info_init(MatchSectionInfo *connection_info,
|
||||
GKeyFile * keyfile,
|
||||
char * group,
|
||||
gboolean is_device)
|
||||
{
|
||||
char ** keys = NULL;
|
||||
gsize n_keys;
|
||||
@@ -1629,6 +1672,14 @@ _match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, c
|
||||
connection_info->stop_match =
|
||||
nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE);
|
||||
|
||||
if (is_device) {
|
||||
connection_info->device.allowed_connections =
|
||||
nm_config_get_match_spec(keyfile,
|
||||
group,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
|
||||
&connection_info->device.allowed_connections_has);
|
||||
}
|
||||
|
||||
keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL);
|
||||
nm_utils_strv_sort(keys, n_keys);
|
||||
|
||||
@@ -1680,9 +1731,13 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos)
|
||||
|
||||
if (!match_section_infos)
|
||||
return;
|
||||
|
||||
for (m = match_section_infos; m->group_name; m++) {
|
||||
g_free(m->group_name);
|
||||
g_slist_free_full(m->match_device.spec, g_free);
|
||||
if (m->is_device) {
|
||||
g_slist_free_full(m->device.allowed_connections, g_free);
|
||||
}
|
||||
for (i = 0; i < m->lookup_len; i++) {
|
||||
g_free(m->lookup_idx[i].name_mutable);
|
||||
g_free(m->lookup_idx[i].value_str_mutable);
|
||||
@@ -1693,12 +1748,16 @@ _match_section_infos_free(MatchSectionInfo *match_section_infos)
|
||||
}
|
||||
|
||||
static MatchSectionInfo *
|
||||
_match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
|
||||
_match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
|
||||
{
|
||||
char ** groups;
|
||||
gsize i, j, ngroups;
|
||||
char * connection_tag = NULL;
|
||||
MatchSectionInfo *match_section_infos = NULL;
|
||||
const char * prefix;
|
||||
|
||||
prefix =
|
||||
is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE : NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
|
||||
|
||||
/* get the list of existing [connection.\+]/[device.\+] sections.
|
||||
*
|
||||
@@ -1730,13 +1789,17 @@ _match_section_infos_construct(GKeyFile *keyfile, const char *prefix)
|
||||
}
|
||||
|
||||
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0));
|
||||
match_section_infos->is_device = is_device;
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
/* pass ownership of @group on... */
|
||||
_match_section_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]);
|
||||
_match_section_info_init(&match_section_infos[i],
|
||||
keyfile,
|
||||
groups[ngroups - i - 1],
|
||||
is_device);
|
||||
}
|
||||
if (connection_tag) {
|
||||
/* pass ownership of @connection_tag on... */
|
||||
_match_section_info_init(&match_section_infos[i], keyfile, connection_tag);
|
||||
_match_section_info_init(&match_section_infos[i], keyfile, connection_tag, is_device);
|
||||
}
|
||||
g_free(groups);
|
||||
|
||||
@@ -1950,10 +2013,8 @@ constructed(GObject *object)
|
||||
|
||||
priv->keyfile = _merge_keyfiles(priv->keyfile_user, priv->keyfile_intern);
|
||||
|
||||
priv->connection_infos =
|
||||
_match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
|
||||
priv->device_infos =
|
||||
_match_section_infos_construct(priv->keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
|
||||
priv->connection_infos = _match_section_infos_construct(priv->keyfile, FALSE);
|
||||
priv->device_infos = _match_section_infos_construct(priv->keyfile, TRUE);
|
||||
|
||||
priv->connectivity.enabled =
|
||||
nm_config_keyfile_get_boolean(priv->keyfile,
|
||||
|
@@ -243,6 +243,10 @@ gint64 nm_config_data_get_device_config_int64(const NMConfigData *self,
|
||||
gint64 val_no_match,
|
||||
gint64 val_invalid);
|
||||
|
||||
const GSList *nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
|
||||
NMDevice * device,
|
||||
gboolean * has_match);
|
||||
|
||||
char ** nm_config_data_get_groups(const NMConfigData *self);
|
||||
char ** nm_config_data_get_keys(const NMConfigData *self, const char *group);
|
||||
gboolean nm_config_data_is_intern_atomic_group(const NMConfigData *self, const char *group);
|
||||
|
@@ -796,6 +796,7 @@ static gboolean
|
||||
_setting_is_device_spec(const char *group, const char *key)
|
||||
{
|
||||
#define _IS(group_v, key_v) (nm_streq(group, "" group_v "") && nm_streq(key, "" key_v ""))
|
||||
|
||||
return _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT)
|
||||
|| _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER)
|
||||
|| _IS(NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY)
|
||||
@@ -806,6 +807,13 @@ _setting_is_device_spec(const char *group, const char *key)
|
||||
&& nm_streq(key, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_setting_is_connection_spec(const char *group, const char *key)
|
||||
{
|
||||
return NM_STR_HAS_PREFIX(group, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)
|
||||
&& nm_streq(key, NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_setting_is_string_list(const char *group, const char *key)
|
||||
{
|
||||
@@ -879,6 +887,7 @@ static const ConfigGroup config_groups[] = {
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK,
|
||||
@@ -1060,7 +1069,8 @@ read_config(GKeyFile * keyfile,
|
||||
|
||||
is_string_list = _setting_is_string_list(group, base_key);
|
||||
|
||||
if (is_string_list || _setting_is_device_spec(group, base_key)) {
|
||||
if (is_string_list || _setting_is_device_spec(group, base_key)
|
||||
|| _setting_is_connection_spec(group, base_key)) {
|
||||
gs_unref_ptrarray GPtrArray *new = g_ptr_array_new_with_free_func(g_free);
|
||||
char ** iter_val;
|
||||
gs_strfreev char **old_val = NULL;
|
||||
|
@@ -498,6 +498,8 @@ _startup_complete_check_is_ready(NMSettings * self,
|
||||
conn = nm_settings_connection_get_connection(sett_conn);
|
||||
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst) {
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
if (!nm_device_is_real(device))
|
||||
continue;
|
||||
|
||||
@@ -508,7 +510,13 @@ _startup_complete_check_is_ready(NMSettings * self,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!nm_device_check_connection_compatible(device, conn, NULL))
|
||||
/* Check that device is compatible with the device. We are also happy
|
||||
* with a device compatible but for which the connection is disallowed
|
||||
* by NM configuration. */
|
||||
if (!nm_device_check_connection_compatible(device, conn, &error)
|
||||
&& !g_error_matches(error,
|
||||
NM_UTILS_ERROR,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED))
|
||||
continue;
|
||||
|
||||
return TRUE;
|
||||
|
@@ -63,6 +63,7 @@
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION "keep-configuration"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS "allowed-connections"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND "wifi.backend"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS "wifi.scan-rand-mac-address"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK \
|
||||
|
@@ -1274,6 +1274,7 @@ typedef enum {
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED,
|
||||
|
||||
NM_UTILS_ERROR_SETTING_MISSING,
|
||||
|
||||
|
Reference in New Issue
Block a user