Beniamino Galvani 2019-10-15 08:47:01 +02:00
commit 495ae4a676
10 changed files with 338 additions and 181 deletions

View file

@ -4502,6 +4502,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 (

View file

@ -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.")
@ -64,8 +65,8 @@
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE1_PEAPLABEL N_("Forces use of the new PEAP label during key derivation. Some RADIUS servers may require forcing the new PEAP label to interoperate with PEAPv1. Set to \"1\" to force use of the new PEAP label. See the wpa_supplicant documentation for more details.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE1_PEAPVER N_("Forces which PEAP version is used when PEAP is set as the EAP method in the \"eap\" property. When unset, the version reported by the server will be used. Sometimes when using older RADIUS servers, it is necessary to force the client to use a particular PEAP version. To do so, this property may be set to \"0\" or \"1\" to force that specific PEAP version.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES N_("List of strings to be matched against the altSubjectName of the certificate presented by the authentication server during the inner \"phase 2\" authentication. If the list is empty, no verification of the server certificate's altSubjectName is performed.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_AUTH N_("Specifies the allowed \"phase 2\" inner non-EAP authentication methods when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Recognized non-EAP \"phase 2\" methods are \"pap\", \"chap\", \"mschap\", \"mschapv2\", \"gtc\", \"otp\", \"md5\", and \"tls\". Each \"phase 2\" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_AUTHEAP N_("Specifies the allowed \"phase 2\" inner EAP-based authentication methods when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Recognized EAP-based \"phase 2\" methods are \"md5\", \"mschapv2\", \"otp\", \"gtc\", and \"tls\". Each \"phase 2\" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_AUTH N_("Specifies the allowed \"phase 2\" inner non-EAP authentication method when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Recognized non-EAP \"phase 2\" methods are \"pap\", \"chap\", \"mschap\", \"mschapv2\", \"gtc\", \"otp\", \"md5\", and \"tls\". Each \"phase 2\" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_AUTHEAP N_("Specifies the allowed \"phase 2\" inner EAP-based authentication method when an EAP method that uses an inner TLS tunnel is specified in the \"eap\" property. Recognized EAP-based \"phase 2\" methods are \"md5\", \"mschapv2\", \"otp\", \"gtc\", and \"tls\". Each \"phase 2\" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CA_CERT N_("Contains the \"phase 2\" CA certificate if used by the EAP method specified in the \"phase2-auth\" or \"phase2-autheap\" properties. Certificate data is specified using a \"scheme\"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string \"file://\" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD N_("The password used to access the \"phase2\" CA certificate stored in \"phase2-ca-cert\" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login.")
#define DESCRIBE_DOC_NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS N_("Flags indicating how to handle the \"phase2-ca-cert-password\" property.")

View file

@ -124,6 +124,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSetting8021x,
PROP_PIN,
PROP_PIN_FLAGS,
PROP_SYSTEM_CA_CERTS,
PROP_OPTIONAL,
PROP_AUTH_TIMEOUT,
);
@ -172,6 +173,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)
@ -2415,6 +2417,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.22
**/
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
@ -2801,6 +2822,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,
@ -3141,6 +3173,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;
@ -3319,6 +3354,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;
@ -3797,7 +3835,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/**
* NMSetting8021x:phase2-auth:
*
* Specifies the allowed "phase 2" inner non-EAP authentication methods when
* Specifies the allowed "phase 2" inner non-EAP authentication method when
* an EAP method that uses an inner TLS tunnel is specified in the
* #NMSetting8021x:eap property. Recognized non-EAP "phase 2" methods are
* "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", and "tls".
@ -3822,7 +3860,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *klass)
/**
* NMSetting8021x:phase2-autheap:
*
* Specifies the allowed "phase 2" inner EAP-based authentication methods
* Specifies the allowed "phase 2" inner EAP-based authentication method
* when an EAP method that uses an inner TLS tunnel is specified in the
* #NMSetting8021x:eap property. Recognized EAP-based "phase 2" methods are
* "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method
@ -4388,6 +4426,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.22
**/
/* ---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);

View file

@ -137,6 +137,7 @@ typedef enum { /*< flags, 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.
@ -346,6 +347,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_22
gboolean nm_setting_802_1x_get_optional (NMSetting8021x *setting);
G_END_DECLS

View file

@ -1634,5 +1634,6 @@ global:
nm_client_reload;
nm_client_reload_finish;
nm_manager_reload_flags_get_type;
nm_setting_802_1x_get_optional;
nm_setting_gsm_get_auto_config;
} libnm_1_20_0;

View file

@ -51,6 +51,7 @@ typedef struct Supplicant {
/* signal handler ids */
gulong iface_state_id;
gulong auth_state_id;
/* Timeouts and idles */
guint con_timeout_id;
@ -401,6 +402,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);
@ -408,6 +410,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,
@ -437,12 +495,11 @@ 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);
wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_NO_SECRETS);
return;
}
supplicant_interface_release (self);
nm_device_activate_schedule_stage1_device_prepare (device);
}
@ -494,9 +551,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;
}
@ -516,7 +571,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);
@ -525,7 +581,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;
}
@ -640,11 +696,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;
@ -673,6 +726,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));
@ -698,12 +760,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,
@ -712,10 +770,8 @@ supplicant_connection_timeout_cb (gpointer user_data)
if (nm_settings_connection_get_timestamp (connection, &timestamp))
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;
}

View file

@ -2739,7 +2739,7 @@ add_one_wep_key (shvarFile *ifcfg,
/* Hexadecimal WEP key */
if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid hexadecimal WEP key.");
"Invalid hexadecimal WEP key");
return FALSE;
}
key = value;
@ -2748,7 +2748,7 @@ add_one_wep_key (shvarFile *ifcfg,
/* ASCII key */
if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid ASCII WEP key.");
"Invalid ASCII WEP key");
return FALSE;
}
@ -2764,7 +2764,7 @@ add_one_wep_key (shvarFile *ifcfg,
if (!key) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Invalid WEP key length.");
"Invalid WEP key length");
return FALSE;
}
@ -2911,7 +2911,7 @@ make_wep_setting (shvarFile *ifcfg,
if (auth_alg && !strcmp (auth_alg, "shared")) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"WEP Shared Key authentication is invalid for "
"unencrypted connections.");
"unencrypted connections");
return NULL;
}
@ -3144,6 +3144,89 @@ eap_tls_reader (const char *eap_method,
return TRUE;
}
static gboolean
parse_8021x_phase2_auth (shvarFile *ifcfg,
shvarFile *keys_ifcfg,
NMSetting8021x *s_8021x,
GError **error)
{
gs_free char *inner_auth = NULL;
gs_free char *v_free = NULL;
const char *v;
gs_free const char **list = NULL;
const char *const *iter;
guint num_auth = 0;
guint num_autheap = 0;
v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &v_free);
if (!v) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_INNER_AUTH_METHODS");
return FALSE;
}
inner_auth = g_ascii_strdown (v, -1);
list = nm_utils_strsplit_set (inner_auth, " ");
for (iter = list; iter && *iter; iter++) {
if (NM_IN_STRSET (*iter, "pap",
"chap",
"mschap",
"mschapv2",
"gtc",
"otp",
"md5")) {
if (num_auth == 0) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
}
num_auth++;
} else if (nm_streq (*iter, "tls")) {
if (num_auth == 0) {
if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, "tls", NULL);
}
num_auth++;
} else if (NM_IN_STRSET (*iter, "eap-md5",
"eap-mschapv2",
"eap-otp",
"eap-gtc")) {
if (num_autheap == 0) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL);
}
num_autheap++;
} else if (nm_streq (*iter, "eap-tls")) {
if (num_autheap == 0) {
if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
}
num_autheap++;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'",
*iter);
return FALSE;
}
}
if (num_auth > 1)
PARSE_WARNING ("Discarded extra phase2 authentication methods");
if (num_auth > 1)
PARSE_WARNING ("Discarded extra phase2 EAP authentication methods");
if (!num_auth && !num_autheap) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No phase2 authentication method found");
return FALSE;
}
return TRUE;
}
static gboolean
eap_peap_reader (const char *eap_method,
shvarFile *ifcfg,
@ -3154,8 +3237,6 @@ eap_peap_reader (const char *eap_method,
{
gs_free char *value = NULL;
const char *v;
gs_free const char **list = NULL;
const char *const *iter;
if (!_cert_set_from_ifcfg (s_8021x,
ifcfg,
@ -3193,46 +3274,8 @@ eap_peap_reader (const char *eap_method,
if (v)
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL);
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value);
if (!v) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_INNER_AUTH_METHODS.");
if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
return FALSE;
}
/* Handle options for the inner auth method */
list = nm_utils_strsplit_set (v, " ");
iter = list;
if (iter) {
if (NM_IN_STRSET (*iter, "MSCHAPV2",
"MD5",
"GTC")) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
} else if (nm_streq (*iter, "TLS")) {
if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
return FALSE;
}
{
gs_free char *lower = NULL;
lower = g_ascii_strdown (*iter, -1);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
}
}
if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid IEEE_8021X_INNER_AUTH_METHODS found.");
return FALSE;
}
return TRUE;
}
@ -3245,11 +3288,8 @@ eap_ttls_reader (const char *eap_method,
gboolean phase2,
GError **error)
{
gs_free char *inner_auth = NULL;
gs_free char *value = NULL;
const char *v;
gs_free const char **list = NULL;
const char *const *iter;
if (!_cert_set_from_ifcfg (s_8021x,
ifcfg,
@ -3269,44 +3309,8 @@ eap_ttls_reader (const char *eap_method,
if (v)
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, v, NULL);
nm_clear_g_free (&value);
v = svGetValueStr (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", &value);
if (!v) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_INNER_AUTH_METHODS.");
if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
return FALSE;
}
inner_auth = g_ascii_strdown (v, -1);
/* Handle options for the inner auth method */
list = nm_utils_strsplit_set (inner_auth, " ");
iter = list;
if (iter) {
if (NM_IN_STRSET (*iter, "mschapv2",
"mschap",
"pap",
"chap")) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
} else if (nm_streq (*iter, "eap-tls")) {
if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
} else if (NM_IN_STRSET (*iter, "eap-mschapv2",
"eap-md5",
"eap-gtc")) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
return FALSE;
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL);
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
return FALSE;
}
}
return TRUE;
}
@ -3319,17 +3323,13 @@ eap_fast_reader (const char *eap_method,
gboolean phase2,
GError **error)
{
char *anon_ident = NULL;
char *pac_file = NULL;
char *real_pac_path = NULL;
char *inner_auth = NULL;
char *fast_provisioning = NULL;
char *lower;
gs_free const char **list = NULL;
gs_free char *anon_ident = NULL;
gs_free char *pac_file = NULL;
gs_free char *real_pac_path = NULL;
gs_free char *fast_provisioning = NULL;
const char *const *iter;
const char *pac_prov_str;
gboolean allow_unauth = FALSE, allow_auth = FALSE;
gboolean success = FALSE;
pac_file = svGetValueStr_cp (ifcfg, "IEEE_8021X_PAC_FILE");
if (pac_file) {
@ -3339,10 +3339,10 @@ eap_fast_reader (const char *eap_method,
fast_provisioning = svGetValueStr_cp (ifcfg, "IEEE_8021X_FAST_PROVISIONING");
if (fast_provisioning) {
gs_free const char **list1 = NULL;
gs_free const char **list = NULL;
list1 = nm_utils_strsplit_set (fast_provisioning, " \t");
for (iter = list1; iter && *iter; iter++) {
list = nm_utils_strsplit_set (fast_provisioning, " \t");
for (iter = list; iter && *iter; iter++) {
if (strcmp (*iter, "allow-unauth") == 0)
allow_unauth = TRUE;
else if (strcmp (*iter, "allow-auth") == 0)
@ -3359,56 +3359,18 @@ eap_fast_reader (const char *eap_method,
if (!pac_file && !(allow_unauth || allow_auth)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
goto done;
"IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled");
return FALSE;
}
anon_ident = svGetValueStr_cp (ifcfg, "IEEE_8021X_ANON_IDENTITY");
if (anon_ident)
g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
inner_auth = svGetValueStr_cp (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS");
if (!inner_auth) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing IEEE_8021X_INNER_AUTH_METHODS.");
goto done;
}
if (!parse_8021x_phase2_auth (ifcfg, keys_ifcfg, s_8021x, error))
return FALSE;
/* Handle options for the inner auth method */
list = nm_utils_strsplit_set (inner_auth, " ");
iter = list;
if (iter) {
if ( !strcmp (*iter, "MSCHAPV2")
|| !strcmp (*iter, "GTC")) {
if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error))
goto done;
} else {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
*iter);
goto done;
}
lower = g_ascii_strdown (*iter, -1);
g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
g_free (lower);
}
if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid IEEE_8021X_INNER_AUTH_METHODS found.");
goto done;
}
success = TRUE;
done:
g_free (inner_auth);
g_free (fast_provisioning);
g_free (real_pac_path);
g_free (pac_file);
g_free (anon_ident);
return success;
return TRUE;
}
typedef struct {
@ -3507,7 +3469,7 @@ fill_8021x (shvarFile *ifcfg,
* used with TTLS or PEAP or whatever.
*/
if (wifi && eap->wifi_phase2_only) {
PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
PARSE_WARNING ("ignored invalid IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi",
lower);
goto next;
}
@ -3525,12 +3487,12 @@ next:
}
if (!found)
PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'.", lower);
PARSE_WARNING ("ignored unknown IEEE_8021X_EAP_METHOD '%s'", lower);
}
if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
"No valid EAP methods found in IEEE_8021X_EAP_METHODS");
return NULL;
}
@ -3565,6 +3527,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);
}
@ -4094,7 +4061,7 @@ wireless_connection_from_ifcfg (const char *file,
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -4613,7 +4580,7 @@ make_wired_setting (shvarFile *ifcfg,
g_set_error (error,
NM_UTILS_ERROR,
NM_UTILS_ERROR_SETTING_MISSING,
"The setting is missing.");
"The setting is missing");
return NULL;
}
@ -4639,7 +4606,7 @@ wired_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -4717,7 +4684,7 @@ parse_infiniband_p_key (shvarFile *ifcfg,
if (!ret) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create InfiniBand setting.");
"Failed to create InfiniBand setting");
}
return ret;
}
@ -4791,7 +4758,7 @@ infiniband_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -4895,7 +4862,7 @@ bond_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -4968,7 +4935,7 @@ team_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -5250,7 +5217,7 @@ bridge_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -5418,7 +5385,7 @@ make_vlan_setting (shvarFile *ifcfg,
iface_name = svGetValueStr_cp (ifcfg, "DEVICE");
if (!iface_name && vlan_id < 0) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Missing DEVICE property; cannot determine VLAN ID.");
"Missing DEVICE property; cannot determine VLAN ID");
return NULL;
}
@ -5461,7 +5428,7 @@ make_vlan_setting (shvarFile *ifcfg,
if (vlan_id < 0) {
g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to determine VLAN ID from DEVICE or VLAN_ID.");
"Failed to determine VLAN ID from DEVICE or VLAN_ID");
return NULL;
}
g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
@ -5532,7 +5499,7 @@ vlan_connection_from_ifcfg (const char *file,
con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
if (!con_setting) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Failed to create connection setting.");
"Failed to create connection setting");
g_object_unref (connection);
return NULL;
}
@ -5675,7 +5642,7 @@ connection_from_file_full (const char *filename,
ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
if (!ifcfg_name) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring connection '%s' because it's not an ifcfg file.", filename);
"Ignoring connection '%s' because it's not an ifcfg file", filename);
return NULL;
}
@ -5753,14 +5720,14 @@ connection_from_file_full (const char *filename,
device = svGetValueStr_cp (main_ifcfg, "DEVICE");
if (!device) {
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"File '%s' had neither TYPE nor DEVICE keys.", filename);
"File '%s' had neither TYPE nor DEVICE keys", filename);
return NULL;
}
if (!strcmp (device, "lo")) {
NM_SET_OUT (out_ignore_error, TRUE);
g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Ignoring loopback device config.");
"Ignoring loopback device config");
g_free (device);
return NULL;
}

View file

@ -524,6 +524,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;

View file

@ -108,6 +108,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface,
PROP_WFD_SUPPORT,
PROP_FT_SUPPORT,
PROP_SHA384_SUPPORT,
PROP_AUTH_STATE,
);
typedef struct {
@ -161,6 +162,7 @@ typedef struct {
gint64 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_ms() */
NMSupplicantAuthState auth_state;
} NMSupplicantInterfacePrivate;
struct _NMSupplicantInterface {
@ -819,6 +821,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)
@ -1329,6 +1337,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,
@ -1671,6 +1707,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,
@ -2747,6 +2785,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;
@ -3039,6 +3080,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);

View file

@ -31,6 +31,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))
@ -57,6 +65,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"
@ -201,4 +210,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__ */