From e59f6f593f076946b1d0f894ea7f2567bb3643f0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 28 Aug 2019 16:03:02 +0200 Subject: [PATCH 1/4] device/trivial: rename local variable for device in "nm-device-{ethernet,macvlan}.c" This variable is commonly called "device", not "dev". Rename. (cherry picked from commit f42ced162ff59a3ae58747caaa259a853ce1d03c) --- src/devices/nm-device-ethernet.c | 26 +++++++++++++------------- src/devices/nm-device-macvlan.c | 9 +++++---- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 3e84847ed1..b1701c6988 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -496,17 +496,17 @@ link_timeout_cb (gpointer user_data) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - NMDevice *dev = NM_DEVICE (self); + NMDevice *device = NM_DEVICE (self); NMActRequest *req; NMConnection *applied_connection; const char *setting_name; priv->supplicant_timeout_id = 0; - req = nm_device_get_act_request (dev); + req = nm_device_get_act_request (device); - if (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed (dev, + if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); return FALSE; @@ -516,7 +516,7 @@ link_timeout_cb (gpointer user_data) * ARE checked - we are likely to have wrong key. Ask the user for * another one. */ - if (nm_device_get_state (dev) != NM_DEVICE_STATE_CONFIG) + if (nm_device_get_state (device) != NM_DEVICE_STATE_CONFIG) goto time_out; nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); @@ -530,14 +530,14 @@ link_timeout_cb (gpointer user_data) "Activation: (ethernet) disconnected during authentication, asking for new key."); supplicant_interface_release (self); - nm_device_state_changed (dev, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); return FALSE; time_out: _LOGW (LOGD_DEVICE | LOGD_ETHER, "link timed out."); - nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); return FALSE; } @@ -850,19 +850,19 @@ pppoe_reconnect_delay (gpointer user_data) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); + NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMActStageReturn ret; - ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (dev, out_failure_reason); + ret = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; - link_negotiation_set (dev); + link_negotiation_set (device); - if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE)) + if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) return NM_ACT_STAGE_RETURN_FAILURE; /* If we're re-activating a PPPoE connection a short while after @@ -874,7 +874,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) gint32 delay = nm_utils_get_monotonic_timestamp_s () - priv->last_pppoe_time; if ( delay < PPPOE_RECONNECT_DELAY - && nm_device_get_applied_setting (dev, NM_TYPE_SETTING_PPPOE)) { + && nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPPOE)) { _LOGI (LOGD_DEVICE, "delaying PPPoE reconnect for %d seconds to ensure peer is ready...", delay); g_assert (!priv->pppoe_wait_id); diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 709f98dab5..ee8b997460 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -270,7 +270,7 @@ create_and_realize (NMDevice *device, /*****************************************************************************/ static NMDeviceCapabilities -get_generic_capabilities (NMDevice *dev) +get_generic_capabilities (NMDevice *device) { /* We assume MACVLAN interfaces always support carrier detect */ return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; @@ -416,16 +416,17 @@ update_connection (NMDevice *device, NMConnection *connection) } static NMActStageReturn -act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret; - ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (dev, out_failure_reason); + ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; - if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE)) + if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) return NM_ACT_STAGE_RETURN_FAILURE; + return NM_ACT_STAGE_RETURN_SUCCESS; } From 2c9912d81234888859e267358bb849a113c16043 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 22 Aug 2019 10:19:24 +0200 Subject: [PATCH 2/4] supplicant: export authentication state Add a property to the supplicant to indicate the current state of the authentication process. (cherry picked from commit 5b4f4a4c30bf29757582e3c15b63ba2199daeece) --- src/supplicant/nm-supplicant-interface.c | 48 ++++++++++++++++++++++++ src/supplicant/nm-supplicant-interface.h | 11 ++++++ 2 files changed, 59 insertions(+) diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index a54b770c35..be4f65dcc6 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -122,6 +122,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_WFD_SUPPORT, PROP_FT_SUPPORT, PROP_SHA384_SUPPORT, + PROP_AUTH_STATE, ); typedef struct { @@ -175,6 +176,7 @@ typedef struct { gint64 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_ms() */ + NMSupplicantAuthState auth_state; } NMSupplicantInterfacePrivate; struct _NMSupplicantInterface { @@ -833,6 +835,12 @@ nm_supplicant_interface_get_sha384_support (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->sha384_support; } +NMSupplicantAuthState +nm_supplicant_interface_get_auth_state (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->auth_state; +} + void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, NMSupplicantFeature ap_support) @@ -1343,6 +1351,34 @@ wpas_iface_network_request (GDBusProxy *proxy, g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message); } +static void +eap_changed (GDBusProxy *proxy, + const char *status, + const char *parameter, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN; + + if (nm_streq0 (status, "started")) + auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED; + else if (nm_streq0 (status, "completion")) { + if (nm_streq0 (parameter, "success")) + auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS; + else if (nm_streq0 (parameter, "failure")) + auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE; + } + + /* the state eventually reaches one of started, success or failure + * so ignore any other intermediate (unknown) state change. */ + if ( auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN + && auth_state != priv->auth_state) { + priv->auth_state = auth_state; + _notify (self, PROP_AUTH_STATE); + } +} + static void props_changed_cb (GDBusProxy *proxy, GVariant *changed_properties, @@ -1685,6 +1721,8 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ G_CALLBACK (wpas_iface_bss_removed), self); _nm_dbus_signal_connect (priv->iface_proxy, "NetworkRequest", G_VARIANT_TYPE ("(oss)"), G_CALLBACK (wpas_iface_network_request), self); + _nm_dbus_signal_connect (priv->iface_proxy, "EAP", G_VARIANT_TYPE ("(ss)"), + G_CALLBACK (eap_changed), self); /* Scan result aging parameters */ g_dbus_proxy_call (priv->iface_proxy, @@ -2761,6 +2799,9 @@ get_property (GObject *object, case PROP_P2P_AVAILABLE: g_value_set_boolean (value, priv->p2p_capable && priv->p2p_proxy_acquired); break; + case PROP_AUTH_STATE: + g_value_set_uint (value, priv->auth_state); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3053,6 +3094,13 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_AUTH_STATE] = + g_param_spec_uint (NM_SUPPLICANT_INTERFACE_AUTH_STATE, "", "", + NM_SUPPLICANT_AUTH_STATE_UNKNOWN, + _NM_SUPPLICANT_AUTH_STATE_NUM - 1, + NM_SUPPLICANT_AUTH_STATE_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 653830dabf..e621f1a39b 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -45,6 +45,14 @@ typedef enum { NM_SUPPLICANT_INTERFACE_STATE_DOWN, } NMSupplicantInterfaceState; +typedef enum { + NM_SUPPLICANT_AUTH_STATE_UNKNOWN, + NM_SUPPLICANT_AUTH_STATE_STARTED, + NM_SUPPLICANT_AUTH_STATE_SUCCESS, + NM_SUPPLICANT_AUTH_STATE_FAILURE, + _NM_SUPPLICANT_AUTH_STATE_NUM, +} NMSupplicantAuthState; + #define NM_TYPE_SUPPLICANT_INTERFACE (nm_supplicant_interface_get_type ()) #define NM_SUPPLICANT_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterface)) #define NM_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass)) @@ -71,6 +79,7 @@ typedef enum { #define NM_SUPPLICANT_INTERFACE_WFD_SUPPORT "wfd-support" #define NM_SUPPLICANT_INTERFACE_FT_SUPPORT "ft-support" #define NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT "sha384-support" +#define NM_SUPPLICANT_INTERFACE_AUTH_STATE "auth-state" /* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" @@ -215,4 +224,6 @@ void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, void nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self); +NMSupplicantAuthState nm_supplicant_interface_get_auth_state (NMSupplicantInterface *self); + #endif /* __NM_SUPPLICANT_INTERFACE_H__ */ From 90671a30b771d418953bd021d50c3cc43f253e6e Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 11 Jul 2019 15:52:03 +0200 Subject: [PATCH 3/4] all: add 802-1x.optional property Introduce a 802-1x.optional boolean property that can be used to succeed the connection even after an authentication timeout or failure. (cherry picked from commit 8763e6da9c5adb3c4ccf3b2713dbcc25a91c5ede) --- clients/common/nm-meta-setting-desc.c | 3 + clients/common/settings-docs.h.in | 1 + libnm-core/nm-setting-8021x.c | 62 +++++++++++++++++++ libnm-core/nm-setting-8021x.h | 3 + libnm-core/nm-version.h | 7 +++ libnm/libnm.ver | 5 ++ shared/nm-version-macros.h.in | 1 + .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 5 ++ .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 5 ++ 9 files changed, 92 insertions(+) diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 5c71868d06..420f5d128d 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -4487,6 +4487,9 @@ static const NMMetaPropertyInfo *const property_infos_6LOWPAN[] = { #undef _CURRENT_NM_META_SETTING_TYPE #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_802_1X static const NMMetaPropertyInfo *const property_infos_802_1X[] = { + PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_OPTIONAL, + .property_type = &_pt_gobject_bool, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_EAP, .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index c4f16ad63f..b81cee712e 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -54,6 +54,7 @@ #define DESCRIBE_DOC_NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH N_("Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison.") #define DESCRIBE_DOC_NM_SETTING_802_1X_EAP N_("The allowed EAP method to be used when authenticating to the network with 802.1x. Valid methods are: \"leap\", \"md5\", \"tls\", \"peap\", \"ttls\", \"pwd\", and \"fast\". Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations.") #define DESCRIBE_DOC_NM_SETTING_802_1X_IDENTITY N_("Identity string for EAP authentication methods. Often the user's user or login name.") +#define DESCRIBE_DOC_NM_SETTING_802_1X_OPTIONAL N_("Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication.") #define DESCRIBE_DOC_NM_SETTING_802_1X_PAC_FILE N_("UTF-8 encoded file path containing PAC for EAP-FAST.") #define DESCRIBE_DOC_NM_SETTING_802_1X_PASSWORD N_("UTF-8 encoded password used for EAP authentication methods. If both the \"password\" property and the \"password-raw\" property are specified, \"password\" is preferred.") #define DESCRIBE_DOC_NM_SETTING_802_1X_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c index c571bca83d..5056847458 100644 --- a/libnm-core/nm-setting-8021x.c +++ b/libnm-core/nm-setting-8021x.c @@ -138,6 +138,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSetting8021x, PROP_PIN, PROP_PIN_FLAGS, PROP_SYSTEM_CA_CERTS, + PROP_OPTIONAL, PROP_AUTH_TIMEOUT, ); @@ -186,6 +187,7 @@ typedef struct { NMSettingSecretFlags phase2_private_key_password_flags; gboolean system_ca_certs; int auth_timeout; + gboolean optional; } NMSetting8021xPrivate; G_DEFINE_TYPE (NMSetting8021x, nm_setting_802_1x, NM_TYPE_SETTING) @@ -2429,6 +2431,25 @@ nm_setting_802_1x_get_auth_timeout (NMSetting8021x *setting) return NM_SETTING_802_1X_GET_PRIVATE (setting)->auth_timeout; } +/** + * nm_setting_802_1x_get_optional: + * @setting: the #NMSetting8021x + * + * Returns the value contained in the #NMSetting8021x:optional property. + * + * Returns: %TRUE if the activation should proceed even when the 802.1X + * authentication fails; %FALSE otherwise + * + * Since: 1.20.6 + **/ +gboolean +nm_setting_802_1x_get_optional (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), FALSE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->optional; +} + /*****************************************************************************/ static void @@ -2815,6 +2836,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) if (error) g_return_val_if_fail (*error == NULL, FALSE); + if ( connection + && priv->optional + && !nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_WIRED_SETTING_NAME)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can be enabled only on Ethernet connections")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_OPTIONAL); + return FALSE; + } + if (!priv->eap) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -3155,6 +3187,9 @@ get_property (GObject *object, guint prop_id, case PROP_AUTH_TIMEOUT: g_value_set_int (value, priv->auth_timeout); break; + case PROP_OPTIONAL: + g_value_set_boolean (value, priv->optional); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3333,6 +3368,9 @@ set_property (GObject *object, guint prop_id, case PROP_AUTH_TIMEOUT: priv->auth_timeout = g_value_get_int (value); break; + case PROP_OPTIONAL: + priv->optional = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -4402,6 +4440,30 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass) NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_STATIC_STRINGS); + /** + * NMSetting8021x:optional: + * + * Whether the 802.1X authentication is optional. If %TRUE, the activation + * will continue even after a timeout or an authentication failure. Setting + * the property to %TRUE is currently allowed only for Ethernet connections. + * If set to %FALSE, the activation can continue only after a successful + * authentication. + * + * Since: 1.20.6 + **/ + /* ---ifcfg-rh--- + * property: optional + * variable: IEEE_8021X_OPTIONAL(+) + * default=no + * description: whether the 802.1X authentication is optional + * ---end--- + */ + obj_properties[PROP_OPTIONAL] = + g_param_spec_boolean (NM_SETTING_802_1X_OPTIONAL, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_802_1X); diff --git a/libnm-core/nm-setting-8021x.h b/libnm-core/nm-setting-8021x.h index 5a5ae65042..394ea22bee 100644 --- a/libnm-core/nm-setting-8021x.h +++ b/libnm-core/nm-setting-8021x.h @@ -148,6 +148,7 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_auth_flags >*/ #define NM_SETTING_802_1X_PIN_FLAGS "pin-flags" #define NM_SETTING_802_1X_SYSTEM_CA_CERTS "system-ca-certs" #define NM_SETTING_802_1X_AUTH_TIMEOUT "auth-timeout" +#define NM_SETTING_802_1X_OPTIONAL "optional" /* PRIVATE KEY NOTE: when setting PKCS#12 private keys directly via properties * using the "blob" scheme, the data must be passed in PKCS#12 binary format. @@ -357,6 +358,8 @@ NM_AVAILABLE_IN_1_8 NMSetting8021xAuthFlags nm_setting_802_1x_get_phase1_auth_flags (NMSetting8021x *setting); NM_AVAILABLE_IN_1_8 int nm_setting_802_1x_get_auth_timeout (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_20_6 +gboolean nm_setting_802_1x_get_optional (NMSetting8021x *setting); G_END_DECLS diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h index ee6a1e7db7..61b4e6679e 100644 --- a/libnm-core/nm-version.h +++ b/libnm-core/nm-version.h @@ -215,4 +215,11 @@ # define NM_AVAILABLE_IN_1_20 #endif +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_20_6 +# define NM_AVAILABLE_IN_1_20_6 G_UNAVAILABLE(1,20.6) +#else +# define NM_AVAILABLE_IN_1_20_6 +#endif + + #endif /* NM_VERSION_H */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 51e0d87241..be05d647da 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1628,3 +1628,8 @@ global: nm_setting_wireguard_get_ip6_auto_default_route; nm_settings_add_connection2_flags_get_type; } libnm_1_18_0; + +libnm_1_20_6 { +global: + nm_setting_802_1x_get_optional; +} libnm_1_20_0; diff --git a/shared/nm-version-macros.h.in b/shared/nm-version-macros.h.in index 1af3a7b367..c65a1f887a 100644 --- a/shared/nm-version-macros.h.in +++ b/shared/nm-version-macros.h.in @@ -77,6 +77,7 @@ #define NM_VERSION_1_18 (NM_ENCODE_VERSION (1, 18, 0)) #define NM_VERSION_1_20 (NM_ENCODE_VERSION (1, 20, 0)) #define NM_VERSION_1_20_2 (NM_ENCODE_VERSION (1, 20, 2)) +#define NM_VERSION_1_20_6 (NM_ENCODE_VERSION (1, 20, 6)) /* For releases, NM_API_VERSION is equal to NM_VERSION. * diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 9c3ae10af8..020766c879 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -3604,6 +3604,11 @@ next: timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0); g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (int) timeout, NULL); + g_object_set (s_8021x, + NM_SETTING_802_1X_OPTIONAL, + svGetValueBoolean (ifcfg, "IEEE_8021X_OPTIONAL", FALSE), + NULL); + return g_steal_pointer (&s_8021x); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 38dc5c8dbb..f3cd71bdc9 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -537,6 +537,11 @@ write_8021x_setting (NMConnection *connection, vint = nm_setting_802_1x_get_auth_timeout (s_8021x); svSetValueInt64_cond (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", vint > 0, vint); + if (nm_setting_802_1x_get_optional (s_8021x)) + svSetValueBoolean (ifcfg, "IEEE_8021X_OPTIONAL", TRUE); + else + svUnsetValue (ifcfg, "IEEE_8021X_OPTIONAL"); + if (!write_8021x_certs (s_8021x, secrets, blobs, FALSE, ifcfg, error)) return FALSE; From 91ea7737fdf22e2b832a50844bfc3b2755209a6c Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 11 Jul 2019 22:13:50 +0200 Subject: [PATCH 4/4] ethernet: honor the 802-1x.optional property If the 802.1X authentication fails and 802-1x.optional is set, continue with activation. In this case, subscribe to the auth-state supplicant property so that any dynamic IP method can be restarted when the authentication succeeds. This is because upon authentication the switch could have changed the VLAN we are connected to. (cherry picked from commit 8afce75bf37eaf8ea7f7c52cf8d58ef2e7a7c180) --- src/devices/nm-device-ethernet.c | 104 ++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 23 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index b1701c6988..8571e526cb 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -65,6 +65,7 @@ typedef struct Supplicant { /* signal handler ids */ gulong iface_state_id; + gulong auth_state_id; /* Timeouts and idles */ guint con_timeout_id; @@ -415,6 +416,7 @@ supplicant_interface_release (NMDeviceEthernet *self) nm_clear_g_source (&priv->supplicant_timeout_id); nm_clear_g_source (&priv->supplicant.con_timeout_id); nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id); + nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.auth_state_id); if (priv->supplicant.iface) { nm_supplicant_interface_disconnect (priv->supplicant.iface); @@ -422,6 +424,62 @@ supplicant_interface_release (NMDeviceEthernet *self) } } +static void +supplicant_auth_state_changed (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceEthernet *self) +{ + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMSupplicantAuthState state; + + state = nm_supplicant_interface_get_auth_state (priv->supplicant.iface); + _LOGD (LOGD_CORE, "supplicant auth state changed to %u", (unsigned) state); + + if (state == NM_SUPPLICANT_AUTH_STATE_SUCCESS) { + nm_clear_g_signal_handler (priv->supplicant.iface, &priv->supplicant.iface_state_id); + nm_device_update_dynamic_ip_setup (NM_DEVICE (self)); + } +} + +static gboolean +wired_auth_is_optional (NMDeviceEthernet *self) +{ + NMSetting8021x *s_8021x; + + s_8021x = nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_802_1X); + g_return_val_if_fail (s_8021x, FALSE); + return nm_setting_802_1x_get_optional (s_8021x); +} + +static void +wired_auth_cond_fail (NMDeviceEthernet *self, NMDeviceStateReason reason) +{ + NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + if (wired_auth_is_optional (self)) { + _LOGI (LOGD_DEVICE | LOGD_ETHER, + "Activation: (ethernet) 802.1X authentication is optional, continuing after a failure"); + if (NM_IN_SET (nm_device_get_state (device), + NM_DEVICE_STATE_CONFIG, + NM_DEVICE_STATE_NEED_AUTH)) + nm_device_activate_schedule_stage3_ip_config_start (device); + + if (!priv->supplicant.auth_state_id) { + priv->supplicant.auth_state_id = g_signal_connect (priv->supplicant.iface, + "notify::" NM_SUPPLICANT_INTERFACE_AUTH_STATE, + G_CALLBACK (supplicant_auth_state_changed), + self); + } + return; + } + + supplicant_interface_release (self); + nm_device_state_changed (NM_DEVICE (self), + NM_DEVICE_STATE_FAILED, + reason); +} + static void wired_secrets_cb (NMActRequest *req, NMActRequestGetSecretsCallId *call_id, @@ -451,11 +509,12 @@ wired_secrets_cb (NMActRequest *req, if (error) { _LOGW (LOGD_ETHER, "%s", error->message); - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else - nm_device_activate_schedule_stage1_device_prepare (device); + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_NO_SECRETS); + return; + } + + supplicant_interface_release (self); + nm_device_activate_schedule_stage1_device_prepare (device); } static void @@ -506,9 +565,7 @@ link_timeout_cb (gpointer user_data) req = nm_device_get_act_request (device); if (nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); return FALSE; } @@ -528,7 +585,8 @@ link_timeout_cb (gpointer user_data) _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) disconnected during authentication, asking for new key."); - supplicant_interface_release (self); + if (!wired_auth_is_optional (self)) + supplicant_interface_release (self); nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); @@ -537,7 +595,7 @@ link_timeout_cb (gpointer user_data) time_out: _LOGW (LOGD_DEVICE | LOGD_ETHER, "link timed out."); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); return FALSE; } @@ -652,11 +710,8 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, case NM_SUPPLICANT_INTERFACE_STATE_DOWN: supplicant_interface_release (self); - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } + if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); break; default: break; @@ -685,6 +740,15 @@ handle_auth_or_fail (NMDeviceEthernet *self, return NM_ACT_STAGE_RETURN_FAILURE; } + _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) asking for new secrets"); + + /* Don't tear down supplicant if the authentication is optional + * because in case of a failure in getting new secrets we want to + * keep the supplicant alive. + */ + if (!wired_auth_is_optional (self)) + supplicant_interface_release (self); + wired_secrets_get_secrets (self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); @@ -710,12 +774,8 @@ supplicant_connection_timeout_cb (gpointer user_data) _LOGW (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) association took too long."); - supplicant_interface_release (self); req = nm_device_get_act_request (device); - g_assert (req); - connection = nm_act_request_get_settings_connection (req); - g_assert (connection); /* Ask for new secrets only if we've never activated this connection * before. If we've connected before, don't bother the user with dialogs, @@ -724,10 +784,8 @@ supplicant_connection_timeout_cb (gpointer user_data) if (nm_settings_connection_get_timestamp (connection, ×tamp)) new_secrets = !timestamp; - if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_POSTPONE) - _LOGW (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) asking for new secrets"); - else - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); + if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_FAILURE) + wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_NO_SECRETS); return FALSE; }