static gboolean
verify_adhoc (NMSettingWirelessSecurity *s_wsec,
              NMSetting8021x *s_8021x,
              gboolean adhoc,
              GError **error)
{
	const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;

	if (s_wsec) {
		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
		auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
		leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
	}

	if (adhoc) {
		if (key_mgmt && strcmp (key_mgmt, "wpa-none") && strcmp (key_mgmt, "none")) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "AP mode is Ad-Hoc but setting requires Infrastructure security");
			return FALSE;
		}

		if (s_8021x) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "Ad-Hoc mode incompatible with 802.1x security");
			return FALSE;
		}

		if (leap_username) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "Ad-Hoc mode incompatible with LEAP security");
			return FALSE;
		}

		if (auth_alg && strcmp (auth_alg, "open")) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "Ad-Hoc mode requires 'open' authentication");
			return FALSE;
		}
	} else {
		if (key_mgmt && !strcmp (key_mgmt, "wpa-none")) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "AP mode is Infrastructure but setting requires Ad-Hoc security");
			return FALSE;
		}
	}

	return TRUE;
}
static gboolean
verify_wpa_eap (NMSettingWirelessSecurity *s_wsec,
                NMSetting8021x *s_8021x,
                guint32 wpa_flags,
                guint32 rsn_flags,
                GError **error)
{
	const char *key_mgmt, *auth_alg;
	gboolean is_wpa_eap = FALSE;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);

	if (key_mgmt) {
		if (!strcmp (key_mgmt, "wpa-eap")) {
			if (!s_8021x) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA-EAP requires an 802.1x setting");
				return FALSE;
			}

			if (auth_alg && strcmp (auth_alg, "open")) {
				/* WPA must use "open" authentication */
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA-EAP requires 'open' authentication");
				return FALSE;
			}

			is_wpa_eap = TRUE;
		} else if (s_8021x) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "Setting requires 802.1x but does not use 'wpa-eap' key management");
			return FALSE;
		}
	}

	if (is_wpa_eap || s_8021x) {
		/* Make sure the AP's capabilities support WPA-EAP */
		if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
		    && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "AP does not support 802.1x but setting requires it");
			return FALSE;
		}
	}

	return TRUE;
}
static gboolean
add_wireless_secrets (NMSecretAgentSimpleRequest *request,
                      GPtrArray                  *secrets)
{
	NMSettingWirelessSecurity *s_wsec = nm_connection_get_setting_wireless_security (request->connection);
	const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	NMSecretAgentSimpleSecret *secret;

	if (!key_mgmt)
		return FALSE;

	if (!strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk")) {
		secret = nm_secret_agent_simple_secret_new (_("Password"),
		                                            NM_SETTING (s_wsec),
		                                            NM_SETTING_WIRELESS_SECURITY_PSK,
		                                            TRUE);
		g_ptr_array_add (secrets, secret);
		return TRUE;
	}

	if (!strcmp (key_mgmt, "none")) {
		int index;
		char *key;

		index = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec);
		key = g_strdup_printf ("wep-key%d", index);
		secret = nm_secret_agent_simple_secret_new (_("Key"),
		                                            NM_SETTING (s_wsec),
		                                            key,
		                                            TRUE);
		g_free (key);

		g_ptr_array_add (secrets, secret);
		return TRUE;
	}

	if (!strcmp (key_mgmt, "iee8021x")) {
		if (!g_strcmp0 (nm_setting_wireless_security_get_auth_alg (s_wsec), "leap")) {
			secret = nm_secret_agent_simple_secret_new (_("Password"),
			                                            NM_SETTING (s_wsec),
			                                            NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
			                                            TRUE);
			g_ptr_array_add (secrets, secret);
			return TRUE;
		} else
			return add_8021x_secrets (request, secrets);
	}

	if (!strcmp (key_mgmt, "wpa-eap"))
		return add_8021x_secrets (request, secrets);

	return FALSE;
}
Example #4
0
static GtkWidget *
create_info_label_security (NMConnection *connection)
{
	NMSettingConnection *s_con;
	char *label = NULL;
	GtkWidget *w;
	const char *connection_type;

	s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
	g_assert (s_con);

	connection_type = nm_setting_connection_get_connection_type (s_con);
	if (!strcmp (connection_type, NM_SETTING_WIRELESS_SETTING_NAME)) {
		NMSettingWireless *s_wireless;
		NMSettingWirelessSecurity *s_wireless_sec;
		NMSetting8021x *s_8021x;
		const char *security;

		s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
		s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, 
																				  NM_TYPE_SETTING_WIRELESS_SECURITY);
		s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
		security = s_wireless ? nm_setting_wireless_get_security (s_wireless) : NULL;

		if (security && !strcmp (security, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) && s_wireless_sec) {
			const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);

			if (!strcmp (key_mgmt, "none"))
				label = g_strdup (_("WEP"));
			else if (!strcmp (key_mgmt, "wpa-none"))
				label = g_strdup (_("WPA/WPA2"));
			else if (!strcmp (key_mgmt, "wpa-psk"))
				label = g_strdup (_("WPA/WPA2"));
			else
				label = get_eap_label (s_wireless_sec, s_8021x);
		} else {
			label = g_strdup (_("None"));
		}
	} else if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) {
		NMSetting8021x *s_8021x;

		s_8021x = (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
		if (s_8021x)
			label = get_eap_label (NULL, s_8021x);
		else
			label = g_strdup (_("None"));
	}

	w = create_info_label (label ? label : _("Unknown"), TRUE);
	g_free (label);

	return w;
}
static NMUtilsSecurityType
get_default_type_for_security (NMSettingWirelessSecurity *sec,
                               gboolean have_ap,
                               guint32 ap_flags,
                               guint32 dev_caps)
{
    const char *key_mgmt, *auth_alg;

    g_return_val_if_fail (sec != NULL, NMU_SEC_NONE);

    key_mgmt = nm_setting_wireless_security_get_key_mgmt (sec);
    auth_alg = nm_setting_wireless_security_get_auth_alg (sec);

    /* No IEEE 802.1x */
    if (!strcmp (key_mgmt, "none"))
        return NMU_SEC_STATIC_WEP;

    if (   !strcmp (key_mgmt, "ieee8021x")
           && (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY))) {
        if (auth_alg && !strcmp (auth_alg, "leap"))
            return NMU_SEC_LEAP;
        return NMU_SEC_DYNAMIC_WEP;
    }

    if (   !strcmp (key_mgmt, "wpa-none")
           || !strcmp (key_mgmt, "wpa-psk")) {
        if (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)) {
            if (find_proto (sec, "rsn"))
                return NMU_SEC_WPA2_PSK;
            else if (find_proto (sec, "wpa"))
                return NMU_SEC_WPA_PSK;
            else
                return NMU_SEC_WPA_PSK;
        }
    }

    if (   !strcmp (key_mgmt, "wpa-eap")
           && (!have_ap || (ap_flags & NM_802_11_AP_FLAGS_PRIVACY))) {
        if (find_proto (sec, "rsn"))
            return NMU_SEC_WPA2_ENTERPRISE;
        else if (find_proto (sec, "wpa"))
            return NMU_SEC_WPA_ENTERPRISE;
        else
            return NMU_SEC_WPA_ENTERPRISE;
    }

    return NMU_SEC_INVALID;
}
Example #6
0
static char *
get_eap_label (NMSettingWirelessSecurity *sec,
			   NMSetting8021x *s_8021x)
{
	GString *str = NULL;
	char *phase2_str = NULL;

	if (sec) {
		const char *key_mgmt = nm_setting_wireless_security_get_key_mgmt (sec);
		const char *auth_alg = nm_setting_wireless_security_get_auth_alg (sec);

		if (!strcmp (key_mgmt, "ieee8021x")) {
			if (auth_alg && !strcmp (auth_alg, "leap"))
				str = g_string_new (_("LEAP"));
			else
				str = g_string_new (_("Dynamic WEP"));
		} else if (!strcmp (key_mgmt, "wpa-eap"))
			str = g_string_new (_("WPA/WPA2"));
		else
			return NULL;
	} else if (s_8021x)
		str = g_string_new ("802.1x");

	if (!s_8021x)
		goto out;

	if (nm_setting_802_1x_get_num_eap_methods (s_8021x)) {
		char *eap_str = g_ascii_strup (nm_setting_802_1x_get_eap_method (s_8021x, 0), -1);
		g_string_append_printf (str, ", EAP-%s", eap_str);
		g_free (eap_str);
	}

	if (nm_setting_802_1x_get_phase2_auth (s_8021x))
		phase2_str = g_ascii_strup (nm_setting_802_1x_get_phase2_auth (s_8021x), -1);
	else if (nm_setting_802_1x_get_phase2_autheap (s_8021x))
		phase2_str = g_ascii_strup (nm_setting_802_1x_get_phase2_autheap (s_8021x), -1);

	if (phase2_str) {
		g_string_append (str, ", ");
		g_string_append (str, phase2_str);
		g_free (phase2_str);
	}
	
out:
	return g_string_free (str, FALSE);
}
static const char *
get_security_type (NMEditorWirelessSecurityMethodBinding *binding)
{
	const char *key_mgmt, *auth_alg;

	if (!binding->s_wsec_in_use)
		return "none";

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (binding->s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (binding->s_wsec);

	/* No IEEE 802.1x */
	if (!strcmp (key_mgmt, "none")) {
		NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (binding->s_wsec);

		if (wep_type == NM_WEP_KEY_TYPE_KEY)
			return "wep-key";
		else
			return "wep-passphrase";
	}

	if (!strcmp (key_mgmt, "ieee8021x")) {
		if (auth_alg && !strcmp (auth_alg, "leap"))
			return "leap";
		return "dynamic-wep";
	}

	if (   !strcmp (key_mgmt, "wpa-none")
	    || !strcmp (key_mgmt, "wpa-psk"))
		return "wpa-personal";

	if (!strcmp (key_mgmt, "wpa-eap"))
		return "wpa-enterprise";

	return NULL;
}
NMAccessPoint *
nm_ap_new_fake_from_connection (NMConnection *connection)
{
	NMAccessPoint *ap;
	NMSettingWireless *s_wireless;
	NMSettingWirelessSecurity *s_wireless_sec;
	const GByteArray *ssid;
	const char *mode, *band, *key_mgmt;
	guint32 channel, flags;
	gboolean psk = FALSE, eap = FALSE;

	g_return_val_if_fail (connection != NULL, NULL);

	s_wireless = NM_SETTING_WIRELESS (nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS));
	g_return_val_if_fail (s_wireless != NULL, NULL);

	ssid = nm_setting_wireless_get_ssid (s_wireless);
	g_return_val_if_fail (ssid != NULL, NULL);
	g_return_val_if_fail (ssid->len > 0, NULL);

	ap = nm_ap_new ();
	nm_ap_set_fake (ap, TRUE);
	nm_ap_set_ssid (ap, ssid);

	// FIXME: bssid too?

	mode = nm_setting_wireless_get_mode (s_wireless);
	if (mode) {
		if (!strcmp (mode, "infrastructure"))
			nm_ap_set_mode (ap, NM_802_11_MODE_INFRA);
		else if (!strcmp (mode, "adhoc"))
			nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC);
		else
			goto error;
	} else {
		nm_ap_set_mode (ap, NM_802_11_MODE_INFRA);
	}

	band = nm_setting_wireless_get_band (s_wireless);
	channel = nm_setting_wireless_get_channel (s_wireless);

	if (band && channel) {
		guint32 freq = channel_to_freq (channel, band);

		if (freq == 0)
			goto error;

		nm_ap_set_freq (ap, freq);
	}

	s_wireless_sec = (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
	/* Assume presence of a security setting means the AP is encrypted */
	if (!s_wireless_sec)
		goto done;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);

	/* Everything below here uses encryption */
	nm_ap_set_flags (ap, nm_ap_get_flags (ap) | NM_802_11_AP_FLAGS_PRIVACY);

	/* Static & Dynamic WEP */
	if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x"))
		goto done;

	psk = !strcmp (key_mgmt, "wpa-psk");
	eap = !strcmp (key_mgmt, "wpa-eap");
	if (psk || eap) {
		if (has_proto (s_wireless_sec, PROTO_WPA)) {
			flags = nm_ap_get_wpa_flags (ap);
			flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK;
			nm_ap_set_wpa_flags (ap, flags);
		}
		if (has_proto (s_wireless_sec, PROTO_RSN)) {
			flags = nm_ap_get_rsn_flags (ap);
			flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK;
			nm_ap_set_rsn_flags (ap, flags);
		}

		add_pair_ciphers (ap, s_wireless_sec);
		add_group_ciphers (ap, s_wireless_sec);
	} else if (!strcmp (key_mgmt, "wpa-none")) {
		guint32 i;

		/* Ad-Hoc has special requirements: proto=WPA, pairwise=(none), and
		 * group=TKIP/CCMP (but not both).
		 */

		flags = nm_ap_get_wpa_flags (ap);
		flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK;

		/* Clear ciphers; pairwise must be unset anyway, and group gets set below */
		flags &= ~(  NM_802_11_AP_SEC_PAIR_WEP40
		           | NM_802_11_AP_SEC_PAIR_WEP104
		           | NM_802_11_AP_SEC_PAIR_TKIP
		           | NM_802_11_AP_SEC_PAIR_CCMP
		           | NM_802_11_AP_SEC_GROUP_WEP40
		           | NM_802_11_AP_SEC_GROUP_WEP104
		           | NM_802_11_AP_SEC_GROUP_TKIP
		           | NM_802_11_AP_SEC_GROUP_CCMP);

		for (i = 0; i < nm_setting_wireless_security_get_num_groups (s_wireless_sec); i++) {
			if (!strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, i), "ccmp")) {
				flags |= NM_802_11_AP_SEC_GROUP_CCMP;
				break;
			}
		}

		/* Default to TKIP since not all WPA-capable cards can do CCMP */
		if (!(flags & NM_802_11_AP_SEC_GROUP_CCMP))
			flags |= NM_802_11_AP_SEC_GROUP_TKIP;

		nm_ap_set_wpa_flags (ap, flags);

		/* Don't use Ad-Hoc RSN yet */
		nm_ap_set_rsn_flags (ap, NM_802_11_AP_SEC_NONE);
	}

done:
	return ap;

error:
	g_object_unref (ap);
	return NULL;
}
static void
connection_secrets_response_cb (NMAWirelessDialog *dialog,
                                gint response,
                                gpointer user_data)
{
    SecretsRequestInfo *info = user_data;
    NMConnection *connection;
    GHashTable *settings = NULL;
    NMSetting *s_wireless_sec;
    const char *key_mgmt;
    GError *error = NULL;

    gtk_widget_hide (GTK_WIDGET (dialog));

    connection = nma_wireless_dialog_get_connection (dialog);

    if (response != GTK_RESPONSE_OK) {
        error = g_error_new (NM_SETTINGS_INTERFACE_ERROR,
                             NM_SETTINGS_INTERFACE_ERROR_SECRETS_REQUEST_CANCELED,
                             "%s.%d (%s): canceled",
                             __FILE__, __LINE__, __func__);

        goto done;
    }

    /* Returned secrets are a{sa{sv}}; this is the outer a{s...} hash that
     * will contain all the individual settings hashes.
     */
    settings = g_hash_table_new_full (g_str_hash, g_str_equal,
                                      g_free, (GDestroyNotify) g_hash_table_destroy);

    /* If the user chose an 802.1x-based auth method, return 802.1x secrets,
     * not wireless secrets.  Can happen with Dynamic WEP, because NM doesn't
     * know the capabilities of the AP (since Dynamic WEP APs don't broadcast
     * beacons), and therefore defaults to requesting WEP secrets from the
     * wireless-security setting, not the 802.1x setting.
     */

    s_wireless_sec = nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY);
    key_mgmt = nm_setting_wireless_security_get_key_mgmt (NM_SETTING_WIRELESS_SECURITY (s_wireless_sec));
    if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
        const char *auth_alg;

        /* LEAP secrets aren't in the 802.1x setting */
        auth_alg = nm_setting_wireless_security_get_auth_alg (NM_SETTING_WIRELESS_SECURITY (s_wireless_sec));
        if (!auth_alg || strcmp (auth_alg, "leap")) {
            NMSetting *s_8021x;

            s_8021x = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X);
            if (!s_8021x) {
                error = g_error_new (NM_SETTINGS_INTERFACE_ERROR,
                                     NM_SETTINGS_INTERFACE_ERROR_INVALID_CONNECTION,
                                     "%s.%d (%s): requested setting '802-1x' didn't"
                                     " exist in the connection.",
                                     __FILE__, __LINE__, __func__);
                goto done;
            }

            /* Add the 802.1x setting */
            g_hash_table_insert (settings,
                                 g_strdup (nm_setting_get_name (s_8021x)),
                                 nm_setting_to_hash (s_8021x));
        }
    }

    /* Add the 802-11-wireless-security setting no matter what */
    g_hash_table_insert (settings,
                         g_strdup (nm_setting_get_name (s_wireless_sec)),
                         nm_setting_to_hash (s_wireless_sec));

    info->callback ((NMSettingsConnectionInterface *) connection, settings, NULL, info->callback_data);

    /* Save the connection back to GConf _after_ hashing it, because
     * saving to GConf might trigger the GConf change notifiers, resulting
     * in the connection being read back in from GConf which clears secrets.
     */
    if (NM_IS_GCONF_CONNECTION (connection)) {
        nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (connection),
                update_cb,
                NULL);
    }

done:
    if (settings)
        g_hash_table_destroy (settings);

    if (error) {
        g_warning ("%s", error->message);
        info->callback (NM_SETTINGS_CONNECTION_INTERFACE (connection), NULL, error, info->callback_data);
        g_error_free (error);
    }

    g_free (info);

    if (connection)
        nm_connection_clear_secrets (connection);

    gtk_widget_destroy (GTK_WIDGET (dialog));
}
gboolean
nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self,
                                                    NMSettingWirelessSecurity *setting,
                                                    NMSetting8021x *setting_8021x,
                                                    const char *con_uuid,
                                                    guint32 mtu,
                                                    GError **error)
{
	const char *key_mgmt, *auth_alg;
	const char *psk;

	g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
	g_return_val_if_fail (setting != NULL, FALSE);
	g_return_val_if_fail (con_uuid != NULL, FALSE);
	g_return_val_if_fail (!error || !*error, FALSE);

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting);
	if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE, error))
		return FALSE;

	auth_alg = nm_setting_wireless_security_get_auth_alg (setting);
	if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE, error))
		return FALSE;

	psk = nm_setting_wireless_security_get_psk (setting);
	if (psk) {
		size_t psk_len = strlen (psk);

		if (psk_len == 64) {
			gs_unref_bytes GBytes *bytes = NULL;

			/* Hex PSK */
			bytes = nm_utils_hexstr2bin (psk);
			if (!bytes) {
				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
				             "Cannot add psk to supplicant config due to invalid hex");
				return FALSE;
			}

			if (!nm_supplicant_config_add_option (self,
			                                      "psk",
			                                      g_bytes_get_data (bytes, NULL),
			                                      g_bytes_get_size (bytes),
			                                      TRUE,
			                                      error))
				return FALSE;
		} else if (psk_len >= 8 && psk_len <= 63) {
			/* Use TYPE_STRING here so that it gets pushed to the
			 * supplicant as a string, and therefore gets quoted,
			 * and therefore the supplicant will interpret it as a
			 * passphrase and not a hex key.
			 */
			if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE, error))
				return FALSE;
		} else {
			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
			             "Cannot add psk to supplicant config due to invalid PSK length %u (not between 8 and 63 characters)",
			             (guint) psk_len);
			return FALSE;
		}
	}

	/* Only WPA-specific things when using WPA */
	if (   !strcmp (key_mgmt, "wpa-none")
	    || !strcmp (key_mgmt, "wpa-psk")
	    || !strcmp (key_mgmt, "wpa-eap")) {
		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, FALSE, error))
			return FALSE;
		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, FALSE, error))
			return FALSE;
		if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, group, groups, "group", ' ', TRUE, FALSE, error))
			return FALSE;
	}

	/* WEP keys if required */
	if (!strcmp (key_mgmt, "none")) {
		NMWepKeyType wep_type = nm_setting_wireless_security_get_wep_key_type (setting);
		const char *wep0 = nm_setting_wireless_security_get_wep_key (setting, 0);
		const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1);
		const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2);
		const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3);

		if (!add_wep_key (self, wep0, "wep_key0", wep_type, error))
			return FALSE;
		if (!add_wep_key (self, wep1, "wep_key1", wep_type, error))
			return FALSE;
		if (!add_wep_key (self, wep2, "wep_key2", wep_type, error))
			return FALSE;
		if (!add_wep_key (self, wep3, "wep_key3", wep_type, error))
			return FALSE;

		if (wep0 || wep1 || wep2 || wep3) {
			gs_free char *value = NULL;

			value = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (setting));
			if (!nm_supplicant_config_add_option (self, "wep_tx_keyidx", value, -1, FALSE, error))
				return FALSE;
		}
	}

	if (auth_alg && !strcmp (auth_alg, "leap")) {
		/* LEAP */
		if (!strcmp (key_mgmt, "ieee8021x")) {
			const char *tmp;

			tmp = nm_setting_wireless_security_get_leap_username (setting);
			if (!add_string_val (self, tmp, "identity", FALSE, FALSE, error))
				return FALSE;

			tmp = nm_setting_wireless_security_get_leap_password (setting);
			if (!add_string_val (self, tmp, "password", FALSE, TRUE, error))
				return FALSE;

			if (!add_string_val (self, "leap", "eap", TRUE, FALSE, error))
				return FALSE;
		} else {
			g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
			             "Invalid key-mgmt \"%s\" for leap", key_mgmt);
			return FALSE;
		}
	} else {
		/* 802.1x for Dynamic WEP and WPA-Enterprise */
		if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) {
			if (!setting_8021x) {
				g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
				             "Cannot set key-mgmt %s with missing 8021x setting", key_mgmt);
				return FALSE;
			}
			if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE, error))
				return FALSE;
		}

		if (!strcmp (key_mgmt, "wpa-eap")) {
			/* If using WPA Enterprise, enable optimized background scanning
			 * to ensure roaming within an ESS works well.
			 */
			if (!nm_supplicant_config_add_option (self, "bgscan", "simple:30:-65:300", -1, FALSE, error))
				return FALSE;

			/* When using WPA-Enterprise, we want to use Proactive Key Caching (also
			 * called Opportunistic Key Caching) to avoid full EAP exchanges when
			 * roaming between access points in the same mobility group.
			 */
			if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE, error))
				return FALSE;
		}
	}

	return TRUE;
}
/**
 * nm_setting_wireless_ap_security_compatible:
 * @s_wireless: a #NMSettingWireless
 * @s_wireless_sec: a #NMSettingWirelessSecurity or %NULL
 * @ap_flags: the %NM80211ApFlags of the given access point
 * @ap_wpa: the %NM80211ApSecurityFlags of the given access point's WPA
 * capabilities
 * @ap_rsn: the %NM80211ApSecurityFlags of the given access point's WPA2/RSN
 * capabilities
 * @ap_mode: the 802.11 mode of the AP, either Ad-Hoc or Infrastructure
 *
 * Given a #NMSettingWireless and an optional #NMSettingWirelessSecurity,
 * determine if the configuration given by the settings is compatible with
 * the security of an access point using that access point's capability flags
 * and mode.  Useful for clients that wish to filter a set of connections
 * against a set of access points and determine which connections are
 * compatible with which access points.
 *
 * Returns: %TRUE if the given settings are compatible with the access point's
 * security flags and mode, %FALSE if they are not.
 */
gboolean
nm_setting_wireless_ap_security_compatible (NMSettingWireless *s_wireless,
                                            NMSettingWirelessSecurity *s_wireless_sec,
                                            NM80211ApFlags ap_flags,
                                            NM80211ApSecurityFlags ap_wpa,
                                            NM80211ApSecurityFlags ap_rsn,
                                            NM80211Mode ap_mode)
{
	const char *key_mgmt = NULL, *cipher;
	guint32 num, i;
	gboolean found = FALSE;

	g_return_val_if_fail (NM_IS_SETTING_WIRELESS (s_wireless), FALSE);

	if (!s_wireless_sec) {
		if (   (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
		    || (ap_wpa != NM_802_11_AP_SEC_NONE)
		    || (ap_rsn != NM_802_11_AP_SEC_NONE))
			return FALSE;
		return TRUE;
	}

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
	if (!key_mgmt)
		return FALSE;

	/* Static WEP */
	if (!strcmp (key_mgmt, "none")) {
		if (   !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
		    || (ap_wpa != NM_802_11_AP_SEC_NONE)
		    || (ap_rsn != NM_802_11_AP_SEC_NONE))
			return FALSE;
		return TRUE;
	}

	/* Adhoc WPA */
	if (!strcmp (key_mgmt, "wpa-none")) {
		if (ap_mode != NM_802_11_MODE_ADHOC)
			return FALSE;
		/* FIXME: validate ciphers if they're in the beacon */
		return TRUE;
	}

	/* Adhoc WPA2 (ie, RSN IBSS) */
	if (ap_mode == NM_802_11_MODE_ADHOC) {
		if (strcmp (key_mgmt, "wpa-psk"))
			return FALSE;

		/* Ensure the AP has RSN PSK capability */
		if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK))
			return FALSE;

		/* Fall through and check ciphers in generic WPA-PSK code */
	}

	/* Dynamic WEP or LEAP */
	if (!strcmp (key_mgmt, "ieee8021x")) {
		if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
			return FALSE;

		/* If the AP is advertising a WPA IE, make sure it supports WEP ciphers */
		if (ap_wpa != NM_802_11_AP_SEC_NONE) {
			if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
				return FALSE;

			/* quick check; can't use AP if it doesn't support at least one
			 * WEP cipher in both pairwise and group suites.
			 */
			if (   !(ap_wpa & (NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104))
			    || !(ap_wpa & (NM_802_11_AP_SEC_GROUP_WEP40 | NM_802_11_AP_SEC_GROUP_WEP104)))
				return FALSE;

			/* Match at least one pairwise cipher with AP's capability if the
			 * wireless-security setting explicitly lists pairwise ciphers
			 */
			num = nm_setting_wireless_security_get_num_pairwise (s_wireless_sec);
			for (i = 0, found = FALSE; i < num; i++) {
				cipher = nm_setting_wireless_security_get_pairwise (s_wireless_sec, i);
				if ((found = match_cipher (cipher, "wep40", ap_wpa, ap_wpa, NM_802_11_AP_SEC_PAIR_WEP40)))
					break;
				if ((found = match_cipher (cipher, "wep104", ap_wpa, ap_wpa, NM_802_11_AP_SEC_PAIR_WEP104)))
					break;
			}
			if (!found && num)
				return FALSE;

			/* Match at least one group cipher with AP's capability if the
			 * wireless-security setting explicitly lists group ciphers
			 */
			num = nm_setting_wireless_security_get_num_groups (s_wireless_sec);
			for (i = 0, found = FALSE; i < num; i++) {
				cipher = nm_setting_wireless_security_get_group (s_wireless_sec, i);
				if ((found = match_cipher (cipher, "wep40", ap_wpa, ap_wpa, NM_802_11_AP_SEC_GROUP_WEP40)))
					break;
				if ((found = match_cipher (cipher, "wep104", ap_wpa, ap_wpa, NM_802_11_AP_SEC_GROUP_WEP104)))
					break;
			}
			if (!found && num)
				return FALSE;
		}
		return TRUE;
	}

	/* WPA[2]-PSK and WPA[2] Enterprise */
	if (   !strcmp (key_mgmt, "wpa-psk")
	    || !strcmp (key_mgmt, "wpa-eap")) {

		if (!strcmp (key_mgmt, "wpa-psk")) {
			if (   !(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK)
			    && !(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK))
				return FALSE;
		} else if (!strcmp (key_mgmt, "wpa-eap")) {
			if (   !(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
			    && !(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
				return FALSE;
		}

		// FIXME: should handle WPA and RSN separately here to ensure that
		// if the Connection only uses WPA we don't match a cipher against
		// the AP's RSN IE instead

		/* Match at least one pairwise cipher with AP's capability if the
		 * wireless-security setting explicitly lists pairwise ciphers
		 */
		num = nm_setting_wireless_security_get_num_pairwise (s_wireless_sec);
		for (i = 0, found = FALSE; i < num; i++) {
			cipher = nm_setting_wireless_security_get_pairwise (s_wireless_sec, i);
			if ((found = match_cipher (cipher, "tkip", ap_wpa, ap_rsn, NM_802_11_AP_SEC_PAIR_TKIP)))
				break;
			if ((found = match_cipher (cipher, "ccmp", ap_wpa, ap_rsn, NM_802_11_AP_SEC_PAIR_CCMP)))
				break;
		}
		if (!found && num)
			return FALSE;

		/* Match at least one group cipher with AP's capability if the
		 * wireless-security setting explicitly lists group ciphers
		 */
		num = nm_setting_wireless_security_get_num_groups (s_wireless_sec);
		for (i = 0, found = FALSE; i < num; i++) {
			cipher = nm_setting_wireless_security_get_group (s_wireless_sec, i);

			if ((found = match_cipher (cipher, "wep40", ap_wpa, ap_rsn, NM_802_11_AP_SEC_GROUP_WEP40)))
				break;
			if ((found = match_cipher (cipher, "wep104", ap_wpa, ap_rsn, NM_802_11_AP_SEC_GROUP_WEP104)))
				break;
			if ((found = match_cipher (cipher, "tkip", ap_wpa, ap_rsn, NM_802_11_AP_SEC_GROUP_TKIP)))
				break;
			if ((found = match_cipher (cipher, "ccmp", ap_wpa, ap_rsn, NM_802_11_AP_SEC_GROUP_CCMP)))
				break;
		}
		if (!found && num)
			return FALSE;

		return TRUE;
	}

	return FALSE;
}
static gboolean
verify_dynamic_wep (NMSettingWirelessSecurity *s_wsec,
                    NMSetting8021x *s_8021x,
                    gboolean adhoc,
                    GError **error)
{
	const char *key_mgmt, *auth_alg, *leap_username;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
	leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);

	g_return_val_if_fail (leap_username == NULL, TRUE);

	if (key_mgmt) {
		if (!strcmp (key_mgmt, "ieee8021x")) {
			if (!s_8021x) {
				/* 802.1x key management requires an 802.1x setting */
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "Dynamic WEP requires an 802.1x setting");
				return FALSE;
			}

			if (auth_alg && strcmp (auth_alg, "open")) {
				/* 802.1x key management must use "open" authentication */
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "Dynamic WEP requires 'open' authentication");
				return FALSE;
			}

			/* Dynamic WEP incompatible with anything static WEP related */
			if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
				return FALSE;
		} else if (!strcmp (key_mgmt, "none")) {
			if (s_8021x) {
				/* 802.1x setting requires 802.1x key management */
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "Dynamic WEP requires 'ieee8021x' key management");
				return FALSE;
			}
		}
	} else if (s_8021x) {
		/* 802.1x setting incompatible with anything but 'open' auth */
		if (auth_alg && strcmp (auth_alg, "open")) {
			/* 802.1x key management must use "open" authentication */
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "Dynamic WEP requires 'open' authentication");
			return FALSE;
		}

		/* Dynamic WEP incompatible with anything static WEP related */
		if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
			return FALSE;
	}

	return TRUE;
}
Example #13
0
static gboolean
connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
{
	NMSettingConnection *s_con;
	NMSettingWireless *s_wifi;
	NMSettingWirelessSecurity *s_wsec;
	const char *ctype;
	const char *hwaddr, *setting_hwaddr;
	NMDeviceWifiCapabilities wifi_caps;
	const char *key_mgmt;

	s_con = nm_connection_get_setting_connection (connection);
	g_assert (s_con);

	ctype = nm_setting_connection_get_connection_type (s_con);
	if (strcmp (ctype, NM_SETTING_WIRELESS_SETTING_NAME) != 0) {
		g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_NOT_WIFI_CONNECTION,
		             "The connection was not a Wi-Fi connection.");
		return FALSE;
	}

	s_wifi = nm_connection_get_setting_wireless (connection);
	if (!s_wifi) {
		g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_INVALID_WIFI_CONNECTION,
		             "The connection was not a valid Wi-Fi connection.");
		return FALSE;
	}

	/* Check MAC address */
	hwaddr = nm_device_wifi_get_permanent_hw_address (NM_DEVICE_WIFI (device));
	if (hwaddr) {
		if (!nm_utils_hwaddr_valid (hwaddr, ETH_ALEN)) {
			g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_INVALID_DEVICE_MAC,
			             "Invalid device MAC address.");
			return FALSE;
		}
		setting_hwaddr = nm_setting_wireless_get_mac_address (s_wifi);
		if (setting_hwaddr && !nm_utils_hwaddr_matches (setting_hwaddr, -1, hwaddr, -1)) {
			g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MAC_MISMATCH,
			             "The MACs of the device and the connection didn't match.");
			return FALSE;
		}
	}

	/* Check device capabilities; we assume all devices can do WEP at least */
	wifi_caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));

	s_wsec = nm_connection_get_setting_wireless_security (connection);
	if (s_wsec) {
		/* Connection has security, verify it against the device's capabilities */
		key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
		if (   !g_strcmp0 (key_mgmt, "wpa-none")
		    || !g_strcmp0 (key_mgmt, "wpa-psk")
		    || !g_strcmp0 (key_mgmt, "wpa-eap")) {

			/* Is device only WEP capable? */
			if (!(wifi_caps & WPA_CAPS)) {
				g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MISSING_DEVICE_WPA_CAPS,
				             "The device missed WPA capabilities required by the connection.");
				return FALSE;
			}

			/* Make sure WPA2/RSN-only connections don't get chosen for WPA-only cards */
			if (has_proto (s_wsec, "rsn") && !has_proto (s_wsec, "wpa") && !(wifi_caps & RSN_CAPS)) {
				g_set_error (error, NM_DEVICE_WIFI_ERROR, NM_DEVICE_WIFI_ERROR_MISSING_DEVICE_RSN_CAPS,
				             "The device missed WPA2/RSN capabilities required by the connection.");
				return FALSE;
			}
		}
	}

	return NM_DEVICE_CLASS (nm_device_wifi_parent_class)->connection_compatible (device, connection, error);
}
static gboolean
verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
               const char *tag,
               GError **error)
{
	const char *key_mgmt;
	int n, i;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	if (key_mgmt && !strncmp (key_mgmt, "wpa", 3)) {
		g_set_error (error,
		             NM_SETTING_WIRELESS_SECURITY_ERROR,
		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		             "%s incompatible with any WPA key management", tag);
		return FALSE;
	}

	if (nm_setting_wireless_security_get_num_protos (s_wsec)) {
		g_set_error (error,
		             NM_SETTING_WIRELESS_SECURITY_ERROR,
		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		             "%s incompatible with any 'proto' setting", tag);
		return FALSE;
	}

	n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
	for (i = 0; i < n; i++) {
		const char *pw;

		pw = nm_setting_wireless_security_get_pairwise (s_wsec, i);
		if (strcmp (pw, "wep40") && strcmp (pw, "wep104")) {
			g_set_error (error,
			             NM_SETTING_WIRELESS_SECURITY_ERROR,
			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			             "%s is incompatible with WPA pairwise ciphers", tag);
			return FALSE;
		}
	}

	n = nm_setting_wireless_security_get_num_groups (s_wsec);
	for (i = 0; i < n; i++) {
		const char *gr;

		gr = nm_setting_wireless_security_get_group (s_wsec, i);
		if (strcmp (gr, "wep40") && strcmp (gr, "wep104")) {
			g_set_error (error,
			             NM_SETTING_WIRELESS_SECURITY_ERROR,
			             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			             "%s is incompatible with WPA group ciphers", tag);
			return FALSE;
		}
	}

	if (nm_setting_wireless_security_get_psk (s_wsec)) {
		g_set_error (error,
		             NM_SETTING_WIRELESS_SECURITY_ERROR,
		             NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		             "%s is incompatible with a WPA Pre-Shared Key", tag);
		return FALSE;
	}

	return TRUE;
}
gboolean
nm_ap_utils_complete_connection (const GByteArray *ap_ssid,
                                 const guint8 ap_bssid[ETH_ALEN],
                                 NM80211Mode ap_mode,
                                 guint32 ap_flags,
                                 guint32 ap_wpa_flags,
                                 guint32 ap_rsn_flags,
                                 NMConnection *connection,
                                 gboolean lock_bssid,
                                 GError **error)
{
	NMSettingWireless *s_wifi;
	NMSettingWirelessSecurity *s_wsec;
	NMSetting8021x *s_8021x;
	const GByteArray *ssid;
	const char *mode, *key_mgmt, *auth_alg, *leap_username;
	gboolean adhoc = FALSE;

	s_wifi = nm_connection_get_setting_wireless (connection);
	g_assert (s_wifi);
	s_wsec = nm_connection_get_setting_wireless_security (connection);
	s_8021x = nm_connection_get_setting_802_1x (connection);

	/* Fill in missing SSID */
	ssid = nm_setting_wireless_get_ssid (s_wifi);
	if (!ssid)
		g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL);
	else if (   ssid->len != ap_ssid->len
	         || memcmp (ssid->data, ap_ssid->data, ssid->len)) {
		g_set_error_literal (error,
		                     NM_SETTING_WIRELESS_ERROR,
		                     NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
		                     "Setting SSID did not match AP SSID");
		return FALSE;
	}

	if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) {
		GByteArray *bssid;

		bssid = g_byte_array_sized_new (ETH_ALEN);
		g_byte_array_append (bssid, ap_bssid, ETH_ALEN);
		g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL);
		g_byte_array_free (bssid, TRUE);
	}

	/* And mode */
	mode = nm_setting_wireless_get_mode (s_wifi);
	if (mode) {
		gboolean valid = FALSE;

		/* Make sure the supplied mode matches the AP's */
		if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)) {
			if (ap_mode == NM_802_11_MODE_INFRA)
				valid = TRUE;
		} else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
			if (ap_mode == NM_802_11_MODE_ADHOC)
				valid = TRUE;
			adhoc = TRUE;
		}

		if (valid == FALSE) {
			g_set_error (error,
			             NM_SETTING_WIRELESS_ERROR,
			             NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
			             NM_SETTING_WIRELESS_MODE);
			return FALSE;
		}
	} else {
		mode = NM_SETTING_WIRELESS_MODE_INFRA;
		if (ap_mode == NM_802_11_MODE_ADHOC) {
			mode = NM_SETTING_WIRELESS_MODE_ADHOC;
			adhoc = TRUE;
		}
		g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL);
	}

	/* Security */

	/* Open */
	if (   !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
	    && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
	    && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
		/* Make sure the connection doesn't specify security */
		if (nm_setting_wireless_get_security (s_wifi) || s_wsec || s_8021x) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "AP is unencrypted but setting specifies security");
			return FALSE;
		}
		return TRUE;
	}

	/* Everything else requires security */
	g_object_set (G_OBJECT (s_wifi),
	              NM_SETTING_WIRELESS_SEC, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
	              NULL);
	if (!s_wsec) {
		s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
		nm_connection_add_setting (connection, NM_SETTING (s_wsec));
	}

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
	leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);

	/* Ad-Hoc checks */
	if (!verify_adhoc (s_wsec, s_8021x, adhoc, error))
		return FALSE;

	/* Static WEP, Dynamic WEP, or LEAP */
	if (   (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
	    && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
	    && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
		const char *tag = "WEP";
		gboolean is_dynamic_wep = FALSE;

		if (!verify_leap (s_wsec, s_8021x, adhoc, error))
			return FALSE;

		if (leap_username) {
			tag = "LEAP";
		} else {
			/* Static or Dynamic WEP */
			if (!verify_dynamic_wep (s_wsec, s_8021x, adhoc, error))
				return FALSE;

			if (s_8021x || (key_mgmt && !strcmp (key_mgmt, "ieee8021x"))) {
				is_dynamic_wep = TRUE;
				tag = "Dynamic WEP";
			}
		}

		/* Nothing WPA-related can be set */
		if (!verify_no_wpa (s_wsec, tag, error))
			return FALSE;

		if (leap_username) {
			/* LEAP */
			g_object_set (s_wsec,
			              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
			              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
			              NULL);
		} else if (is_dynamic_wep) {
			/* Dynamic WEP */
			g_object_set (s_wsec,
			              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
			              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
			              NULL);
			nm_setting_wireless_security_add_pairwise (s_wsec, "wep40");
			nm_setting_wireless_security_add_pairwise (s_wsec, "wep104");
			nm_setting_wireless_security_add_group (s_wsec, "wep40");
			nm_setting_wireless_security_add_group (s_wsec, "wep104");

			if (s_8021x) {
				/* Dynamic WEP requires a valid 802.1x setting since we can't
				 * autocomplete 802.1x.
				 */
				if (!nm_setting_verify (NM_SETTING (s_8021x), NULL, error))
					return FALSE;
			}
		} else {
			/* Static WEP */
			g_object_set (s_wsec,
			              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
			              NULL);
		}

		return TRUE;
	}

	/* WPA/RSN */
	g_assert (ap_wpa_flags || ap_rsn_flags);

	/* Ensure key management is valid for WPA */
	if ((key_mgmt && !strcmp (key_mgmt, "ieee8021x")) || leap_username) {
		g_set_error_literal (error,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		                     "WPA incompatible with non-EAP (original) LEAP or Dynamic WEP");
		return FALSE;
	}

	/* 'shared' auth incompatible with any type of WPA */
	if (auth_alg && strcmp (auth_alg, "open")) {
		g_set_error_literal (error,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		                     "WPA incompatible with Shared Key authentication");
		return FALSE;
	}

	if (!verify_no_wep (s_wsec, "WPA", error))
		return FALSE;

	if (!verify_wpa_psk (s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error))
		return FALSE;

	if (!adhoc && !verify_wpa_eap (s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error))
		return FALSE;

	if (adhoc) {
		g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
		/* Ad-Hoc does not support RSN/WPA2 */
		nm_setting_wireless_security_add_proto (s_wsec, "wpa");
		nm_setting_wireless_security_add_pairwise (s_wsec, "none");
		nm_setting_wireless_security_add_group (s_wsec, "tkip");
	} else if (s_8021x) {
		g_object_set (s_wsec,
		              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
		              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
		              NULL);
		/* Leave proto/pairwise/group as client set them; if they are unset the
		 * supplicant will figure out the best combination at connect time.
		 */

		/* 802.1x also requires the client to completely fill in the 8021x
		 * setting.  Since there's so much configuration required for it, there's
		 * no way it can be automatically completed.
		 */
	} else if (   (key_mgmt && !strcmp (key_mgmt, "wpa-psk"))
	           || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
	           || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
		g_object_set (s_wsec,
		              NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
		              NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
		              NULL);
		/* Leave proto/pairwise/group as client set them; if they are unset the
		 * supplicant will figure out the best combination at connect time.
		 */
	} else {
		g_set_error_literal (error,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR,
		                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
		                     "Failed to determine AP security information");
		return FALSE;
	}

	return TRUE;
}
static gboolean
verify_leap (NMSettingWirelessSecurity *s_wsec,
             NMSetting8021x *s_8021x,
             gboolean adhoc,
             GError **error)
{
	const char *key_mgmt, *auth_alg, *leap_username;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
	leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);

	/* One (or both) of two things indicates we want LEAP:
	 * 1) auth_alg == 'leap'
	 * 2) valid leap_username
     *
     * LEAP always requires a LEAP username.
	 */

	if (auth_alg) {
		if (!strcmp (auth_alg, "leap")) {
			/* LEAP authentication requires at least a LEAP username */
			if (!leap_username) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
				                     "LEAP requires a LEAP username");
				return FALSE;
			}
		} else if (leap_username) {
			/* Leap username requires 'leap' auth */
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "LEAP requires 'leap' authentication");
			return FALSE;
		}
	}

	if (leap_username) {
		if (key_mgmt && strcmp (key_mgmt, "ieee8021x")) {
			/* LEAP requires ieee8021x key management */
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X,
			                     "LEAP requires IEEE 802.1x key management");
			return FALSE;
		}
	}

	/* At this point if auth_alg is set it must be 'leap', and if key_mgmt
	 * is set it must be 'ieee8021x'.
	 */
	if (leap_username) {
		if (auth_alg)
			g_assert (strcmp (auth_alg, "leap") == 0);
		if (key_mgmt)
			g_assert (strcmp (key_mgmt, "ieee8021x") == 0);

		if (adhoc) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
			                     "LEAP incompatible with Ad-Hoc mode");
			return FALSE;
		}

		if (!verify_no_wep (s_wsec, "LEAP", error))
			return FALSE;

		if (s_8021x) {
			g_set_error_literal (error,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR,
			                     NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
			                     "LEAP incompatible with 802.1x setting");
			return FALSE;
		}
	}

	return TRUE;
}
static gboolean
verify_wpa_psk (NMSettingWirelessSecurity *s_wsec,
                NMSetting8021x *s_8021x,
                gboolean adhoc,
                guint32 wpa_flags,
                guint32 rsn_flags,
                GError **error)
{
	const char *key_mgmt, *auth_alg, *tmp;
	int n;

	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
	auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);

	if (key_mgmt) {
		if (!strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-none")) {
			if (s_8021x) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA-PSK incompatible with 802.1x");
				return FALSE;
			}

			if (auth_alg && strcmp (auth_alg, "open")) {
				/* WPA must use "open" authentication */
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA-PSK requires 'open' authentication");
				return FALSE;
			}
		}

		if (!strcmp (key_mgmt, "wpa-none")) {
			if (!adhoc) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA Ad-Hoc requires an Ad-Hoc mode AP");
				return FALSE;
			}

			/* Ad-Hoc WPA requires 'wpa' proto, 'none' pairwise, and 'tkip' group */
			n = nm_setting_wireless_security_get_num_protos (s_wsec);
			tmp = (n > 0) ? nm_setting_wireless_security_get_proto (s_wsec, 0) : NULL;
			if (n > 1 || strcmp (tmp, "wpa")) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA Ad-Hoc requires 'wpa' proto");
				return FALSE;
			}

			n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
			tmp = (n > 0) ? nm_setting_wireless_security_get_pairwise (s_wsec, 0) : NULL;
			if (n > 1 || strcmp (tmp, "none")) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA Ad-Hoc requires 'none' pairwise cipher");
				return FALSE;
			}

			n = nm_setting_wireless_security_get_num_groups (s_wsec);
			tmp = (n > 0) ? nm_setting_wireless_security_get_group (s_wsec, 0) : NULL;
			if (n > 1 || strcmp (tmp, "tkip")) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "WPA Ad-Hoc requires 'tkip' group cipher");
				return FALSE;
			}
		}

		if (!strcmp (key_mgmt, "wpa-psk")) {
			/* Make sure the AP's capabilities support WPA-PSK */
			if (   !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
			    && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
				g_set_error_literal (error,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR,
				                     NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
				                     "AP does not support PSK but setting requires it");
				return FALSE;
			}
		}
	}

	return TRUE;
}