/**
 * wpas_dbus_iface_add_network - Add a new configured network
 * @message: Pointer to incoming dbus message
 * @wpa_s: wpa_supplicant structure for a network interface
 * Returns: A dbus message containing the object path of the new network
 *
 * Handler function for "addNetwork" method call of a network interface.
 */
DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
					  struct wpa_supplicant *wpa_s)
{
	DBusMessage *reply = NULL;
	struct wpa_ssid *ssid;
	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL) {
		reply = dbus_message_new_error(message,
					       WPAS_ERROR_ADD_NETWORK_ERROR,
					       "wpa_supplicant could not add "
					       "a network on this interface.");
		goto out;
	}
	wpas_notify_network_added(wpa_s, ssid);
	ssid->disabled = 1;
	wpa_config_set_network_defaults(ssid);

	/* Construct the object path for this network. */
	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
		    "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
		    wpa_s->dbus_path, ssid->id);

	reply = dbus_message_new_method_return(message);
	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
				 &path, DBUS_TYPE_INVALID);

out:
	return reply;
}
Example #2
0
static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
{
	struct wpa_ssid *ssid;
	int errors = 0, end = 0;
	char buf[2000], *pos, *pos2;

	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
		   *line);
	ssid = os_zalloc(sizeof(*ssid));
	if (ssid == NULL)
		return NULL;
	dl_list_init(&ssid->psk_list);
	ssid->id = id;

	wpa_config_set_network_defaults(ssid);

	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
		if (os_strcmp(pos, "}") == 0) {
			end = 1;
			break;
		}

		pos2 = os_strchr(pos, '=');
		if (pos2 == NULL) {
			wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
				   "'%s'.", *line, pos);
			errors++;
			continue;
		}

		*pos2++ = '\0';
		if (*pos2 == '"') {
			if (os_strchr(pos2 + 1, '"') == NULL) {
				wpa_printf(MSG_ERROR, "Line %d: invalid "
					   "quotation '%s'.", *line, pos2);
				errors++;
				continue;
			}
		}

		if (wpa_config_set(ssid, pos, pos2, *line) < 0)
			errors++;
	}

	if (!end) {
		wpa_printf(MSG_ERROR, "Line %d: network block was not "
			   "terminated properly.", *line);
		errors++;
	}

	errors += wpa_config_validate_network(ssid, *line);

	if (errors) {
		wpa_config_free_ssid(ssid);
		ssid = NULL;
	}

	return ssid;
}
Example #3
0
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
					      int registrar, const u8 *bssid)
{
	struct wpa_ssid *ssid;

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL)
		return NULL;
	wpas_notify_network_added(wpa_s, ssid);
	wpa_config_set_network_defaults(ssid);
	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
	    wpa_config_set(ssid, "identity", registrar ?
			   "\"" WSC_ID_REGISTRAR "\"" :
			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
		wpas_notify_network_removed(wpa_s, ssid);
		wpa_config_remove_network(wpa_s->conf, ssid->id);
		return NULL;
	}

	if (bssid) {
		struct wpa_bss *bss;
		int count = 0;

		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
		ssid->bssid_set = 1;

		dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
			if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
				continue;

			os_free(ssid->ssid);
			ssid->ssid = os_malloc(bss->ssid_len);
			if (ssid->ssid == NULL)
				break;
			os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
			ssid->ssid_len = bss->ssid_len;
			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
					  "scan results",
					  ssid->ssid, ssid->ssid_len);
			count++;
		}

		if (count > 1) {
			wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
				   "for the AP; use wildcard");
			os_free(ssid->ssid);
			ssid->ssid = NULL;
			ssid->ssid_len = 0;
		}
	}

	return ssid;
}
Example #4
0
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
					      int registrar, const u8 *bssid)
{
	struct wpa_ssid *ssid;

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL)
		return NULL;
	wpa_config_set_network_defaults(ssid);
	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
	    wpa_config_set(ssid, "identity", registrar ?
			   "\"" WSC_ID_REGISTRAR "\"" :
			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
		wpa_config_remove_network(wpa_s->conf, ssid->id);
		return NULL;
	}

	if (bssid) {
		size_t i;
		struct wpa_scan_res *res;

		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
		ssid->bssid_set = 1;

		/* Try to get SSID from scan results */
		if (wpa_s->scan_res == NULL &&
		    wpa_supplicant_get_scan_results(wpa_s) < 0)
			return ssid; /* Could not find any scan results */

		for (i = 0; i < wpa_s->scan_res->num; i++) {
			const u8 *ie;

			res = wpa_s->scan_res->res[i];
			if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0)
				continue;

			ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
			if (ie == NULL)
				break;
			os_free(ssid->ssid);
			ssid->ssid = os_malloc(ie[1]);
			if (ssid->ssid == NULL)
				break;
			os_memcpy(ssid->ssid, ie + 2, ie[1]);
			ssid->ssid_len = ie[1];
			break;
		}
	}

	return ssid;
}
Example #5
0
static int wpa_supplicant_ctrl_iface_add_network(
	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
{
	struct wpa_ssid *ssid;
	int ret;

	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL)
		return -1;
	ssid->disabled = 1;
	wpa_config_set_network_defaults(ssid);

	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
	if (ret < 0 || (size_t) ret >= buflen)
		return -1;
	return ret;
}
/**
 * wpas_dbus_iface_add_network - Add a new configured network
 * @message: Pointer to incoming dbus message
 * @wpa_s: wpa_supplicant structure for a network interface
 * Returns: A dbus message containing the object path of the new network
 *
 * Handler function for "addNetwork" method call of a network interface.
 */
DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
					  struct wpa_supplicant *wpa_s)
{
	DBusMessage *reply = NULL;
	struct wpa_ssid *ssid;
	char *path = NULL;

	path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
	if (path == NULL) {
		perror("wpas_dbus_iface_scan_results[dbus]: out of "
		       "memory.");
		wpa_printf(MSG_ERROR, "dbus control interface: not "
			   "enough memory to send scan results "
			   "signal.");
		goto out;
	}

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL) {
		reply = dbus_message_new_error(message,
					       WPAS_ERROR_ADD_NETWORK_ERROR,
					       "wpa_supplicant could not add "
					       "a network on this interface.");
		goto out;
	}
	ssid->disabled = 1;
	wpa_config_set_network_defaults(ssid);

	/* Construct the object path for this network. */
	snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
		 "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
		 wpa_supplicant_get_dbus_path(wpa_s),
		 ssid->id);

	reply = dbus_message_new_method_return(message);
	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
				 &path, DBUS_TYPE_INVALID);

out:
	free(path);
	return reply;
}
Example #7
0
static int wpa_supplicant_wps_cred(void *ctx,
				   const struct wps_credential *cred)
{
	struct wpa_supplicant *wpa_s = ctx;
	struct wpa_ssid *ssid = wpa_s->current_ssid;
	u8 key_idx = 0;
	u16 auth_type;

	if ((wpa_s->conf->wps_cred_processing == 1 ||
	     wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
		size_t blen = cred->cred_attr_len * 2 + 1;
		char *buf = os_malloc(blen);
		if (buf) {
			wpa_snprintf_hex(buf, blen,
					 cred->cred_attr, cred->cred_attr_len);
			wpa_msg(wpa_s, MSG_INFO, "%s%s",
				WPS_EVENT_CRED_RECEIVED, buf);
			os_free(buf);
		}

		wpas_notify_wps_credential(wpa_s, cred);
	} else
		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);

	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
			cred->cred_attr, cred->cred_attr_len);

	if (wpa_s->conf->wps_cred_processing == 1)
		return 0;

	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
		   cred->auth_type);
	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
			cred->key, cred->key_len);
	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
		   MAC2STR(cred->mac_addr));

	auth_type = cred->auth_type;
	if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
		wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
			   "auth_type into WPA2PSK");
		auth_type = WPS_AUTH_WPA2PSK;
	}

	if (auth_type != WPS_AUTH_OPEN &&
	    auth_type != WPS_AUTH_SHARED &&
	    auth_type != WPS_AUTH_WPAPSK &&
	    auth_type != WPS_AUTH_WPA2PSK) {
		wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
			   "unsupported authentication type 0x%x",
			   auth_type);
		return 0;
	}

	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
			   "on the received credential");
		os_free(ssid->eap.identity);
		ssid->eap.identity = NULL;
		ssid->eap.identity_len = 0;
		os_free(ssid->eap.phase1);
		ssid->eap.phase1 = NULL;
		os_free(ssid->eap.eap_methods);
		ssid->eap.eap_methods = NULL;
	} else {
		wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
			   "received credential");
		ssid = wpa_config_add_network(wpa_s->conf);
		if (ssid == NULL)
			return -1;
		wpas_notify_network_added(wpa_s, ssid);
	}

	wpa_config_set_network_defaults(ssid);

	os_free(ssid->ssid);
	ssid->ssid = os_malloc(cred->ssid_len);
	if (ssid->ssid) {
		os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
		ssid->ssid_len = cred->ssid_len;
	}

	switch (cred->encr_type) {
	case WPS_ENCR_NONE:
		break;
	case WPS_ENCR_WEP:
		if (cred->key_len <= 0)
			break;
		if (cred->key_len != 5 && cred->key_len != 13 &&
		    cred->key_len != 10 && cred->key_len != 26) {
			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
				   "%lu", (unsigned long) cred->key_len);
			return -1;
		}
		if (cred->key_idx > NUM_WEP_KEYS) {
			wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
				   cred->key_idx);
			return -1;
		}
		if (cred->key_idx)
			key_idx = cred->key_idx - 1;
		if (cred->key_len == 10 || cred->key_len == 26) {
			if (hexstr2bin((char *) cred->key,
				       ssid->wep_key[key_idx],
				       cred->key_len / 2) < 0) {
				wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
					   "%d", key_idx);
				return -1;
			}
			ssid->wep_key_len[key_idx] = cred->key_len / 2;
		} else {
			os_memcpy(ssid->wep_key[key_idx], cred->key,
				  cred->key_len);
			ssid->wep_key_len[key_idx] = cred->key_len;
		}
		ssid->wep_tx_keyidx = key_idx;
		break;
	case WPS_ENCR_TKIP:
		ssid->pairwise_cipher = WPA_CIPHER_TKIP;
		break;
	case WPS_ENCR_AES:
		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
		break;
	}

	switch (auth_type) {
	case WPS_AUTH_OPEN:
		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
		ssid->proto = 0;
		break;
	case WPS_AUTH_SHARED:
		ssid->auth_alg = WPA_AUTH_ALG_SHARED;
		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
		ssid->proto = 0;
		break;
	case WPS_AUTH_WPAPSK:
		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
		ssid->proto = WPA_PROTO_WPA;
		break;
	case WPS_AUTH_WPA:
		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
		ssid->proto = WPA_PROTO_WPA;
		break;
	case WPS_AUTH_WPA2:
		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
		ssid->proto = WPA_PROTO_RSN;
		break;
	case WPS_AUTH_WPA2PSK:
		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
		ssid->proto = WPA_PROTO_RSN;
		break;
	}

	if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
		if (cred->key_len == 2 * PMK_LEN) {
			if (hexstr2bin((const char *) cred->key, ssid->psk,
				       PMK_LEN)) {
				wpa_printf(MSG_ERROR, "WPS: Invalid Network "
					   "Key");
				return -1;
			}
			ssid->psk_set = 1;
		} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
			os_free(ssid->passphrase);
			ssid->passphrase = os_malloc(cred->key_len + 1);
			if (ssid->passphrase == NULL)
				return -1;
			os_memcpy(ssid->passphrase, cred->key, cred->key_len);
			ssid->passphrase[cred->key_len] = '\0';
			wpa_config_update_psk(ssid);
		} else {
			wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
				   "length %lu",
				   (unsigned long) cred->key_len);
			return -1;
		}
	}

	wpas_wps_security_workaround(wpa_s, ssid, cred);

#ifndef CONFIG_NO_CONFIG_WRITE
	if (wpa_s->conf->update_config &&
	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
		wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
		return -1;
	}
#endif /* CONFIG_NO_CONFIG_WRITE */

	return 0;
}
Example #8
0
static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
						 int id)
{
	HKEY nhk;
	LONG ret;
	DWORD i;
	struct wpa_ssid *ssid;
	int errors = 0;

	ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
	if (ret != ERROR_SUCCESS) {
		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
			   "network '" TSTR "'", netw);
		return NULL;
	}

	wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
	ssid = os_zalloc(sizeof(*ssid));
	if (ssid == NULL) {
		RegCloseKey(nhk);
		return NULL;
	}
	dl_list_init(&ssid->psk_list);
	ssid->id = id;

	wpa_config_set_network_defaults(ssid);

	for (i = 0; ; i++) {
		TCHAR name[255], data[1024];
		DWORD namelen, datalen, type;

		namelen = 255;
		datalen = sizeof(data);
		ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
				   (LPBYTE) data, &datalen);

		if (ret == ERROR_NO_MORE_ITEMS)
			break;

		if (ret != ERROR_SUCCESS) {
			wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
				   (unsigned int) ret);
			break;
		}

		if (namelen >= 255)
			namelen = 255 - 1;
		name[namelen] = TEXT('\0');

		if (datalen >= 1024)
			datalen = 1024 - 1;
		data[datalen] = TEXT('\0');

		wpa_unicode2ascii_inplace(name);
		wpa_unicode2ascii_inplace(data);
		if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
			errors++;
	}

	RegCloseKey(nhk);

	if (ssid->passphrase) {
		if (ssid->psk_set) {
			wpa_printf(MSG_ERROR, "Both PSK and passphrase "
				   "configured for network '" TSTR "'.", netw);
			errors++;
		}
		wpa_config_update_psk(ssid);
	}

	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
		/* Group cipher cannot be stronger than the pairwise cipher. */
		wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
			   "list since it was not allowed for pairwise "
			   "cipher for network '" TSTR "'.", netw);
		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
	}

	if (errors) {
		wpa_config_free_ssid(ssid);
		ssid = NULL;
	}

	return ssid;
}
Example #9
0
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
	struct wpa_ssid *ssid;
	struct nai_realm *realm;
	struct nai_realm_eap *eap = NULL;
	u16 count, i;
	char buf[100];
	const u8 *ie;

	if (bss == NULL)
		return -1;
	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
	if (ie == NULL || ie[1] == 0) {
		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
			   MACSTR, MAC2STR(bss->bssid));
		return -1;
	}

	realm = nai_realm_parse(bss->anqp_nai_realm, &count);
	if (realm == NULL) {
		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
		count = 0;
	}

	for (i = 0; i < count; i++) {
		if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
			continue;
		eap = nai_realm_find_eap(wpa_s, &realm[i]);
		if (eap)
			break;
	}

	if (!eap) {
		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
			if (realm)
				nai_realm_free(realm, count);
			return 0;
		}

		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
			   "and EAP method found for " MACSTR,
			   MAC2STR(bss->bssid));
		nai_realm_free(realm, count);
		return -1;
	}

	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
		   MAC2STR(bss->bssid));

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL) {
		nai_realm_free(realm, count);
		return -1;
	}
	wpas_notify_network_added(wpa_s, ssid);
	wpa_config_set_network_defaults(ssid);
	ssid->temporary = 1;
	ssid->ssid = os_zalloc(ie[1] + 1);
	if (ssid->ssid == NULL)
		goto fail;
	os_memcpy(ssid->ssid, ie + 2, ie[1]);
	ssid->ssid_len = ie[1];

	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
						     eap->method), 0) < 0)
		goto fail;

	if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
	    wpa_config_set_quoted(ssid, "identity",
				  wpa_s->conf->home_username) < 0)
		goto fail;

	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
	    < 0)
		goto fail;

	switch (eap->method) {
	case EAP_TYPE_TTLS:
		if (eap->inner_method) {
			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
				    eap_get_name(EAP_VENDOR_IETF,
						 eap->inner_method));
			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
				goto fail;
			break;
		}
		switch (eap->inner_non_eap) {
		case NAI_REALM_INNER_NON_EAP_PAP:
			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
			    0)
				goto fail;
			break;
		case NAI_REALM_INNER_NON_EAP_CHAP:
			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
			    < 0)
				goto fail;
			break;
		case NAI_REALM_INNER_NON_EAP_MSCHAP:
			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
					   0) < 0)
				goto fail;
			break;
		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
					   0) < 0)
				goto fail;
			break;
		}
		break;
	case EAP_TYPE_PEAP:
		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
			    eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
			goto fail;
		break;
	}

	if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
	    wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
	    0)
		goto fail;

	nai_realm_free(realm, count);

	wpa_supplicant_select_network(wpa_s, ssid);

	return 0;

fail:
	wpas_notify_network_removed(wpa_s, ssid);
	wpa_config_remove_network(wpa_s->conf, ssid->id);
	nai_realm_free(realm, count);
	return -1;
}
Example #10
0
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
				     struct wpa_bss *bss)
{
#ifdef INTERWORKING_3GPP
	struct wpa_ssid *ssid;
	const u8 *ie;

	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
	if (ie == NULL)
		return -1;
	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
		   MAC2STR(bss->bssid));

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL)
		return -1;

	wpas_notify_network_added(wpa_s, ssid);
	wpa_config_set_network_defaults(ssid);
	ssid->temporary = 1;
	ssid->ssid = os_zalloc(ie[1] + 1);
	if (ssid->ssid == NULL)
		goto fail;
	os_memcpy(ssid->ssid, ie + 2, ie[1]);
	ssid->ssid_len = ie[1];

	/* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
	if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
		wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
		goto fail;
	}
	if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
		goto fail;
	}

	if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
		if (wpa_config_set_quoted(ssid, "password",
					  wpa_s->conf->home_milenage) < 0)
			goto fail;
	} else {
		/* TODO: PIN */
		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
			goto fail;
	}

	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
	    < 0)
		goto fail;

	wpa_supplicant_select_network(wpa_s, ssid);

	return 0;

fail:
	wpas_notify_network_removed(wpa_s, ssid);
	wpa_config_remove_network(wpa_s->conf, ssid->id);
#endif /* INTERWORKING_3GPP */
	return -1;
}
Example #11
0
static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
{
	struct wpa_ssid *ssid;
	int errors = 0, end = 0;
	char buf[256], *pos, *pos2;

	wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
		   *line);
	ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
	if (ssid == NULL)
		return NULL;
	memset(ssid, 0, sizeof(*ssid));
	ssid->id = id;

	wpa_config_set_network_defaults(ssid);

	while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
		if (strcmp(pos, "}") == 0) {
			end = 1;
			break;
		}

		pos2 = strchr(pos, '=');
		if (pos2 == NULL) {
			wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
				   "'%s'.", *line, pos);
			errors++;
			continue;
		}

		*pos2++ = '\0';
		if (*pos2 == '"') {
			if (strchr(pos2 + 1, '"') == NULL) {
				wpa_printf(MSG_ERROR, "Line %d: invalid "
					   "quotation '%s'.", *line, pos2);
				errors++;
				continue;
			}
		}

		if (wpa_config_set(ssid, pos, pos2, *line) < 0)
			errors++;
	}

	if (!end) {
		wpa_printf(MSG_ERROR, "Line %d: network block was not "
			   "terminated properly.", *line);
		errors++;
	}

	if (ssid->passphrase) {
		if (ssid->psk_set) {
			wpa_printf(MSG_ERROR, "Line %d: both PSK and "
				   "passphrase configured.", *line);
			errors++;
		}
		wpa_config_update_psk(ssid);
	}

	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
		wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
			   "management, but no PSK configured.", *line);
		errors++;
	}

	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
		/* Group cipher cannot be stronger than the pairwise cipher. */
		wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
			   " list since it was not allowed for pairwise "
			   "cipher", *line);
		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
	}

	if (errors) {
		free(ssid);
		ssid = NULL;
	}

	return ssid;
}
Example #12
0
struct wpa_scan_result *wps_select_ssid(struct wpa_supplicant *wpa_s,
		struct wpa_scan_result *results,
		int num, struct wpa_ssid **ssid)
{
	struct wpa_scan_result *bss;
	struct wpa_scan_result *selected = 0;
	int num_good;
	struct wpa_scan_result *maybe = 0;
        int num_maybe;
	struct wpa_ssid *tmp;
	int ret = -1;
	char *var, *value;
	struct wps_data *data = 0;
	char bssid_str[18+1];
	char ssid_str[32+3];
    u8 uuidSel[SIZE_UUID];
    u8 uuidBss[SIZE_UUID];
    size_t length;
	struct wps_config *wps;
	int i;
        int is_push_button;

	do {
		if (!wpa_s || !wpa_s->conf || !results || !num || !ssid)
			break;

		wps = wpa_s->conf->wps;
                is_push_button = (wps->dev_pwd_len == 8 && 
                        memcmp(wps->dev_pwd, "00000000", 8) == 0);

		if (wps->nwid_trying_wps != -1) {
			(void)wpa_config_remove_network(wpa_s->conf, wps->nwid_trying_wps);
			wps->nwid_trying_wps = -1;
		}

		*ssid = 0;

		num_good = 0;
		num_maybe = 0;
		for (i = 0; i < num; i++) {
			bss = &results[i];
            if (wps->filter_bssid_flag && memcmp(
                        wps->filter_bssid, bss->bssid, 6) != 0) {
                continue;
            }
            if (wps->filter_ssid_length > 0 && memcmp(
                        wps->filter_ssid, bss->ssid, 
                        wps->filter_ssid_length) != 0) {
                continue;
            }
			if (bss->wps_ie_len) {
				u16 dev_pwd_id;

				do {
					if (wps_create_wps_data(&data))
						break;

					if (wps_parse_wps_ie(bss->wps_ie, bss->wps_ie_len, data))
						break;

		            length = sizeof(uuidBss);
                    /* selected bss UUID-E */
		            if (wps_get_value(data, WPS_TYPE_UUID_E, uuidBss, &length))
			            break;

					if (wps_get_value(data, WPS_TYPE_DEVICE_PWD_ID, &dev_pwd_id, 0))
						break;

                    if (is_push_button) {
                        if (WPS_DEVICEPWDID_PUSH_BTN != dev_pwd_id) 
                            break;
                    } else {        /* PIN mode */
                        if (WPS_DEVICEPWDID_DEFAULT != dev_pwd_id) {
                            break;
                        }
                    }
                    
                    /* In the case of a dual-band AP and a dual-band station,
                     * the station may discover more than one Registrar in PBC mode.
                     * If the dual-band station does discover more than one Registrar
                     * in PBC mode, one each RF band, and the UUID in the Beacon and
                     * Probe-Response are the same for all RF bands, then the station 
                     * shall not consider this to be a session overlap.
                     */
					if (num_good) {
					    /* check dual-band concurrent AP case */
					    if (((selected->freq >= 4000) && (bss->freq <= 3000)) ||
					        ((selected->freq <= 3000) && (bss->freq >= 4000)))
					    {
                    		/* one is 2.4GHz and another is 5GHz */
                    		if (memcmp(uuidSel, uuidBss, length) == 0)
                    		{
                    		    /* UUID-E of them are totally the same */
                    		    /* Select the 5GHz one */
                    		    if (bss->freq >= 4000)
					                selected = bss;
                    		    break;
                    		}
					    }
					}
				    selected = bss;
            		memcpy(&uuidSel, &uuidBss, length);
					num_good++;
				} while (0);

				(void)wps_destroy_wps_data(&data);

                /* If we have WPS at all then it's a maybe
                 * for PIN
                 */
                if (!is_push_button) {
                    num_maybe++;
					if ((!maybe) || (bss->qual > maybe->qual)) {
						maybe = bss;
					}
                }
			} else {
                /* No WPS IE */
                /* If in open mode, it may support WPS...
                 * (some microsoft products)
                 * take it as a maybe
                 */
                if ((bss->caps & IEEE80211_CAP_PRIVACY) == 0) {
                    num_maybe++;
                    if ((!maybe) || (bss->qual > maybe->qual)) {
                        maybe = bss;
                    }
                }
            }
		}

        /* Push button mode must have exact explicit match.
         * For PIN mode, due to greater security, we are willing
         * to be more lenient; and due to the ambiguity of the WPS
         * standard, it is not actually required that the AP
         * advertise it's PIN mode (as versus PB mode
         * which requires such advertisement).
         * But we want either one good match, or if no good match,
         * then just one maybe... otherwise the user should have
         * done pre-filtering.... 
         * for best results, the user should do pre-filtering!
         */
        if (is_push_button) {
		    if (num_good > 1) {
		        wpa_msg(wpa_s, MSG_INFO, 
                        "Must be only one AP enabled WPS-PBC");
                break;
            } else if (num_good == 1) {
                /* good */
            } else if (num_good == 0) {
		        wpa_msg(wpa_s, MSG_INFO, 
                        "There are no APs which are enabled WPS-PBC");
                break;
            }
		} else { /* PIN mode */
		    if (num_good > 1) {
			    wpa_msg(wpa_s, MSG_INFO, 
                        "Must be only one AP enabled WPS-PIN");
                break;
            } else if (num_good == 1) {
                /* good */
            } else if (num_maybe > 1) {
			    wpa_msg(wpa_s, MSG_INFO, 
                        "There are no APs which are enabled WPS-PIN"
                        " but attaching WPS IE, concern some microsoft products,"
                        " try to connect strongest RSSI one");
				selected = maybe;
            } else if (num_maybe == 1) {
                /* select this one */
                selected = maybe;
            } else {
			    wpa_msg(wpa_s, MSG_INFO, 
                        "There are no APs available for WPS");
                break;
            }
        }

		if (!selected)
			break;

		*ssid = wpa_config_add_network(wpa_s->conf);
		if (!*ssid)
			break;
		wpa_config_set_network_defaults(*ssid);
		(*ssid)->disabled = 1;

		/* bssid */
		var = "bssid";
		os_snprintf(bssid_str, sizeof(bssid_str), "%02X:%02X:%02X:%02X:%02X:%02X",
					selected->bssid[0], selected->bssid[1],
					selected->bssid[2], selected->bssid[3],
					selected->bssid[4], selected->bssid[5]);
		bssid_str[18] = 0;
		if (wpa_config_set(*ssid, var, bssid_str, 0))
			break;

		/* ssid */
		var = "ssid";
		ssid_str[0] = '"';
		os_memcpy(ssid_str + 1, selected->ssid, selected->ssid_len);
		ssid_str[selected->ssid_len + 1] = '"';
		ssid_str[selected->ssid_len + 2] = 0;
		if (wpa_config_set(*ssid, var, ssid_str, 0))
			break;

		/* auth_alg */
		var = "auth_alg";
		value = "OPEN";
		if (wpa_config_set(*ssid, var, value, 0))
			break;

		/* key_mgmt */
		var = "key_mgmt";
		value = "IEEE8021X";
		if (wpa_config_set(*ssid, var, value, 0))
			break;

		/* eap */
		var = "eap";
		value = "WPS";
		if (wpa_config_set(*ssid, var, value, 0))
			break;

		/* identity */
		var = "identity";
		free((*ssid)->identity);
		switch (wps->reg_mode) {
		case WPS_SUPPLICANT_REGMODE_NONE:
			value = WPS_IDENTITY_ENROLLEE;
			break;
		default:
			value = WPS_IDENTITY_REGISTRAR;
			break;
		}
		(*ssid)->identity = (u8 *)os_strdup(value);
		(*ssid)->identity_len = os_strlen(value);

		ret = 0;
	} while (0);

	if (ret) {
		if (*ssid)
			(void)wpa_config_remove_network(wpa_s->conf, (*ssid)->id);
		selected = 0;
	} else {
		wpa_msg(wpa_s, MSG_INFO, "Found AP for WPS [%*s]", (*ssid)->ssid_len,(*ssid)->ssid);

		switch (wps->reg_mode) {
		case WPS_SUPPLICANT_REGMODE_NONE:
			if (wps->config) {
				free(wps->config);
				wps->config = 0;
				wps->config_len = 0;
			}
			break;
		case WPS_SUPPLICANT_REGMODE_CONFIGURE_AP:
			break;
		case WPS_SUPPLICANT_REGMODE_REGISTER_AP:
		case WPS_SUPPLICANT_REGMODE_REGISTER_STA:
			if (wps->config) {
				free(wps->config);
				wps->config = 0;
				wps->config_len = 0;
			}

			(void)wps_get_supplicant_ssid_configuration(wpa_s, (*ssid)->id, &wps->config, &wps->config_len);
			break;
		default:
			break;
		}

		if (wpa_s->current_ssid)
			wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);

		tmp = wpa_s->conf->ssid;
		while (tmp) {
                        #if 0   /* original from Sony */
			tmp->disabled = (*ssid)->id != tmp->id;
                        #else
                        /* Set bit 1 of disabled as "temporary WPS bit" */
			tmp->disabled = ((*ssid)->id != tmp->id) << 1;
                        #endif
			tmp = tmp->next;
		}

		wps->nwid_trying_wps = (*ssid)->id;

		wpa_s->reassociate = 1;
		wpa_supplicant_req_scan(wpa_s, 0, 0);
	}

	return selected;
}
Example #13
0
/*
 * This installs received WPS configuration into a new network configuration.
 * It is optional that the new network configuration be saved to the
 * original configuration file.
 */
int wps_set_supplicant_ssid_configuration(void *ctx, u8 *buf, size_t len)
{
	int ret = -1;
	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)ctx;
	struct wpa_ssid *ssid = 0;
	struct wps_data *wps = 0;
	u8 str_ssid[33];
	size_t ssid_length;
	u16 auth, encr;
	u8 nwKeyIdx;
	u8 *nwKey = 0;
	size_t nwKey_length;
	u8 macAddr[6];
	char *eapType = 0;
	char *eapIdentity = 0;
	Boolean keyProvideAuto;
	Boolean enabled8021X;
	Boolean passphrase = 0;
	size_t length;
	char *var, *value;

	do {
		if (!wpa_s)
			break;

                /* Optionally share new configuration with other software,
                 * e.g. with hostapd.
                 */
                wps_new_configuration_share(wpa_s, buf, len);

		ssid = wpa_config_add_network(wpa_s->conf);
		if (!ssid)
			break;
		wpa_config_set_network_defaults(ssid);

		if (wps_create_wps_data(&wps))
			break;

		if(wps_parse_wps_data(buf, len, wps))
			break;

		/* SSID */
		ssid_length = sizeof(str_ssid);
		if(wps_get_value(wps, WPS_TYPE_SSID, str_ssid, &ssid_length))
			break;
		str_ssid[ssid_length] = 0;

		/* Authentication Type */
		if (wps_get_value(wps, WPS_TYPE_AUTH_TYPE, &auth, NULL))
			break;

		/* Encryption Type */
		if (wps_get_value(wps, WPS_TYPE_ENCR_TYPE, &encr, NULL))
			break;

		/* Network Key Index (Option) */
		if(wps_get_value(wps, WPS_TYPE_NW_KEY_INDEX, &nwKeyIdx, NULL))
			nwKeyIdx = 1;
		if ((1 > nwKeyIdx) || (4 < nwKeyIdx)) { /* warning */
			wpa_printf(MSG_WARNING, "Network Key Index is fixed. %d -> 1\n", nwKeyIdx);
			nwKeyIdx = 1;
		}

		/* Network Key */
		nwKey_length = 0;
		(void)wps_get_value(wps, WPS_TYPE_NW_KEY, NULL, &nwKey_length);
		if (nwKey_length) {
			nwKey = (u8 *)calloc(1, nwKey_length + 1);
			if (!nwKey)
				break;
			if (wps_get_value(wps, WPS_TYPE_NW_KEY, nwKey, &nwKey_length)) {
				break;
			}
			nwKey[nwKey_length] = 0;
		}

		/* MAC Address */
		length = sizeof(macAddr);
		if(wps_get_value(wps, WPS_TYPE_MAC_ADDR, macAddr, &length))
			break;

		/* EAP Type (Option) */
		length = 0;
		(void)wps_get_value(wps, WPS_TYPE_EAP_TYPE, NULL, &length);
		if (length) {
			eapType = (char *)calloc(1, length + 1);
			if (!eapType)
				break;
			if (wps_get_value(wps, WPS_TYPE_EAP_TYPE, eapType, &length)) {
				break;
			}
			eapType[length] = 0;
		}

		/* EAP Identity (Option) */
		length = 0;
		(void)wps_get_value(wps, WPS_TYPE_EAP_IDENTITY, NULL, &length);
		if (length) {
			eapIdentity = (char *)calloc(1, length + 1);
			if (!eapIdentity)
				break;
			if (wps_get_value(wps, WPS_TYPE_EAP_IDENTITY, eapIdentity, &length)) {
				break;
			}
			eapIdentity[length] = 0;
		}

		/* Key Provided Automaticaly (Option) */
		if(wps_get_value(wps, WPS_TYPE_KEY_PROVIDED_AUTO, &keyProvideAuto, NULL))
			keyProvideAuto = 0;

		/* 802.1X Enabled (Option) */
		if(wps_get_value(wps, WPS_TYPE_8021X_ENABLED, &enabled8021X, NULL))
			enabled8021X = 0;

		/* Set Configuration */
                /* %%%%%% Sony set disabled to 1... why? */
		ssid->disabled = 0;
		/* ssid */
		var = "ssid";
		value = (char *)os_malloc(os_strlen((char *)str_ssid) + 3);
		if (!value)
			break;
		os_snprintf(value, os_strlen((char *)str_ssid) + 3, "\"%s\"", str_ssid);
		if (wpa_config_set(ssid, var, value, 0))
			break;
		free(value);

		/* auth_alg */
		var = "auth_alg";
		if (WPS_AUTHTYPE_SHARED == auth)
			value = "SHARED";
		else
			value = "OPEN";
		if (wpa_config_set(ssid, var, value, 0))
			break;

		/* key_mgmt */
		var = "key_mgmt";
		switch (auth) {
		case WPS_AUTHTYPE_OPEN:
		case WPS_AUTHTYPE_SHARED:
			if (enabled8021X)
				value = "IEEE8021X";
			else
				value = "NONE";
			break;
		case WPS_AUTHTYPE_WPAPSK:
		case WPS_AUTHTYPE_WPA2PSK:
			if (enabled8021X)
				value = "WPA-PSK IEEE8021X";
			else
				value = "WPA-PSK";
			break;
		case WPS_AUTHTYPE_WPA:
		case WPS_AUTHTYPE_WPA2:
			if (enabled8021X)
				value = "WPA-EAP IEEE8021X";
			else
				value = "WPA-EAP";
			break;
		default:
			value = 0;
			break;
		}
		if (!value | wpa_config_set(ssid, var, value, 0))
			break;

		/* proto */
		var = "proto";
		switch (auth) {
		case WPS_AUTHTYPE_WPA:
		case WPS_AUTHTYPE_WPAPSK:
			value = "WPA";
			break;
		case WPS_AUTHTYPE_WPA2:
		case WPS_AUTHTYPE_WPA2PSK:
			value = "RSN";
			break;
		default:
			ssid->proto = 0;
			value = 0;
			break;
		}
		if (value && wpa_config_set(ssid, var, value, 0))
			break;

		/* pariwise */
		var = "pairwise";
		switch (encr) {
		case WPS_ENCRTYPE_NONE:
			ssid->pairwise_cipher = WPA_CIPHER_NONE;
			value = 0;
			break;
		case WPS_ENCRTYPE_TKIP:
			value = "TKIP";
			break;
		case WPS_ENCRTYPE_AES:
			value = "CCMP";
			break;
		default:
			value = 0;
			break;
		}
		if (value && wpa_config_set(ssid, var, value, 0))
			break;

		/* group */
		var = "group";
		switch (encr) {
		case WPS_ENCRTYPE_NONE:
			ssid->group_cipher = WPA_CIPHER_NONE;
			value = 0;
			break;
		case WPS_ENCRTYPE_WEP:
			value = "WEP104 WEP40";
			break;
		case WPS_ENCRTYPE_TKIP:
			value = "TKIP";
			break;
		case WPS_ENCRTYPE_AES:
                        #if 0   /* original */
			value = "CCMP";
                        #else   /* HACK! */
                        /* It is not uncommon for group cipher to be
                         * TKIP whereas the pairwise is CCMP, but 
                         * WPS makes no distinction.
                         * Workaround by configuring both in this case.
                         */
			value = "TKIP CCMP";
                        #endif
			break;
		default:
			value = 0;
			break;
		}
		if (value && wpa_config_set(ssid, var, value, 0))
			break;

		/* wep_tx_keyidx */
		var = "wep_tx_keyidx";
		switch (encr) {
		case WPS_ENCRTYPE_WEP:
			value = (char *)os_malloc(2);
			if (!value)
				break;
			os_snprintf(value, 2, "%d", nwKeyIdx - 1);
			break;
		default:
			value = 0;
			break;
		}
		if (value && wpa_config_set(ssid, var, value, 0)) {
			free(value);
			break;
		} else if (value)
			free(value);
		if (!value && (WPS_ENCRTYPE_WEP == encr))
			break;

		/* wep_keyn */
		switch (encr) {
		case WPS_ENCRTYPE_WEP:
			var = (char *)os_malloc(9);
			if (!var)
				break;
			os_snprintf(var, 9, "wep_key%d", nwKeyIdx - 1);
			if (is_hex(nwKey, nwKey_length)) {
				value = (char *)os_malloc(nwKey_length * 2 + 1);
				if (!value)
					break;
				wpa_snprintf_hex_uppercase(value, nwKey_length * 2 + 1,
										   nwKey, nwKey_length);
				value[nwKey_length * 2] = 0;
			} else if ((5 == nwKey_length) || (13 == nwKey_length)) {
				value = (char *)os_malloc(nwKey_length + 3);
				if (!value)
					break;
				os_snprintf(value, nwKey_length + 3, "\"%s\"", nwKey);
			} else if ((nwKey_length) || (13 == nwKey_length)) {
				value = (char *)os_malloc(nwKey_length + 1);
				if (!value)
					break;
				os_memcpy(value, nwKey, nwKey_length);
				value[nwKey_length] = 0;
			}
			break;
		default:
			var = 0;
			value = 0;
			break;
		}
		if (var && value && wpa_config_set(ssid, var, value, 0))
			break;
		if (var)
			free(var);
		if (value)
			free(value);
		if ((!var || !value) && (WPS_ENCRTYPE_WEP == encr))
			break;

		/* psk */
		var = "psk";
		switch (auth) {
		case WPS_AUTHTYPE_WPA:
		case WPS_AUTHTYPE_WPA2:
		case WPS_AUTHTYPE_WPAPSK:
		case WPS_AUTHTYPE_WPA2PSK:
			if (nwKey_length) {
				value = (char *)os_malloc(nwKey_length + 3);
				if (!value)
					break;
				if (64 > nwKey_length) {
					os_snprintf(value, nwKey_length + 3, "\"%s\"", nwKey);
					passphrase = 1;
				} else if (64 == nwKey_length) {
					os_memcpy(value, nwKey, nwKey_length);
					value[nwKey_length] = 0;
				} else {
					free(value);
					value = 0;
					break;
				}
			} else
				value = 0;
			break;
		default:
			value = 0;
			break;
		}
		if (value && wpa_config_set(ssid, var, value, 0)) {
			free(value);
			break;
		} else if (value)
			free(value);
		if (nwKey_length && !value &&
			((WPS_AUTHTYPE_WPA == auth) ||
			 (WPS_AUTHTYPE_WPA2 == auth) ||
			 (WPS_AUTHTYPE_WPAPSK == auth) ||
			 (WPS_AUTHTYPE_WPA2PSK == auth)))
			break;
		
		/* eap */
		if (eapType && os_strlen(eapType)) {
			var = "eap";
			value = (char *)eapType;
			if (wpa_config_set(ssid, var, value, 0))
				break;
		}

		/* identity */
		if (eapIdentity && os_strlen(eapIdentity)) {
			var = "identity";
			value = (char *)eapIdentity;
			if (wpa_config_set(ssid, var, value, 0))
				break;
		}

		ret = 0;
	} while (0);

	(void)wps_destroy_wps_data(&wps);

	if (ret) {
		if (ssid)
			(void)wpa_config_remove_network(wpa_s->conf, ssid->id);
	} else {
		if (passphrase)
			wpa_config_update_psk(ssid);
	}

	if (nwKey)
		free(nwKey);
	if (eapType)
		free(eapType);
	if (eapIdentity)
		free(eapIdentity);

	return ret?ret:ssid->id;
}
status_t
WPASupplicantApp::_JoinNetwork(BMessage *message)
{
	const char *interfaceName = NULL;
	status_t status = message->FindString("device", &interfaceName);
	if (status != B_OK)
		return status;

	// Check if we already registered this interface.
	wpa_supplicant *interface = wpa_supplicant_get_iface(fWPAGlobal,
		interfaceName);
	if (interface == NULL) {
		wpa_interface interfaceOptions;
		memset(&interfaceOptions, 0, sizeof(wpa_interface));

		interfaceOptions.ifname = interfaceName;

		interface = wpa_supplicant_add_iface(fWPAGlobal, &interfaceOptions);
		if (interface == NULL)
			return B_NO_MEMORY;
	} else {
		// Disable everything
		wpa_supplicant_disable_network(interface, NULL);

		// Try to remove any existing network
		while (true) {
			wpa_ssid *network = wpa_config_get_network(interface->conf, 0);
			if (network == NULL)
				break;

			wpas_notify_network_removed(interface, network);
			wpa_config_remove_network(interface->conf, network->id);
		}
	}

	const char *networkName = NULL;
	status = message->FindString("name", &networkName);
	if (status != B_OK)
		return status;

	uint32 authMode = B_NETWORK_AUTHENTICATION_NONE;
	status = message->FindUInt32("authentication", &authMode);
	if (status != B_OK)
		return status;

	uint32 encapMode = B_NETWORK_EAP_ENCAPSULATION_NONE;
	if (authMode == B_NETWORK_AUTHENTICATION_EAP)
		message->FindUInt32("encapsulation", &encapMode);

	const char *username = NULL;
	if (encapMode > B_NETWORK_EAP_ENCAPSULATION_NONE) {
		status = message->FindString("username", &username);
		if (status != B_OK)
			return status;
	}

	const char *password = NULL;
	if (authMode > B_NETWORK_AUTHENTICATION_NONE) {
		status = message->FindString("password", &password);
		if (status != B_OK)
			return status;
	}

	wpa_ssid *network = wpa_config_add_network(interface->conf);
	if (network == NULL)
		return B_NO_MEMORY;

	wpas_notify_network_added(interface, network);

	network->disabled = 1;
	wpa_config_set_network_defaults(network);

	// Fill in the info from the join request

	// The format includes the quotes
	BString value;
	value = "\"";
	value += networkName;
	value += "\"";
	int result = wpa_config_set(network, "ssid", value.String(), 0);

	if (result == 0)
		result = wpa_config_set(network, "scan_ssid", "1", 1);

	if (authMode >= B_NETWORK_AUTHENTICATION_WPA) {
		if (result == 0)
			result = wpa_config_set(network, "proto", "WPA RSN", 2);
		if (result == 0) {
			switch (authMode) {
				case B_NETWORK_AUTHENTICATION_WPA:
				case B_NETWORK_AUTHENTICATION_WPA2:
				default:
					result = wpa_config_set(network, "key_mgmt", "WPA-PSK", 3);
					break;
				case B_NETWORK_AUTHENTICATION_EAP:
					result = wpa_config_set(network, "key_mgmt", "WPA-EAP", 3);
					break;
			}
		}
		if (result == 0)
			result = wpa_config_set(network, "pairwise", "CCMP TKIP NONE", 4);
		if (result == 0) {
			result = wpa_config_set(network, "group",
				"CCMP TKIP WEP104 WEP40", 5);
		}
		if (result == 0) {
			if (encapMode > B_NETWORK_EAP_ENCAPSULATION_NONE) {
				switch (encapMode) {
					case B_NETWORK_EAP_ENCAPSULATION_PEAP:
						result = wpa_config_set(network, "eap", "PEAP", 6);
						break;
					case B_NETWORK_EAP_ENCAPSULATION_TLS:
						result = wpa_config_set(network, "eap", "TLS", 6);
						break;
				}
			}
		}
	} else {
		// Open or WEP.
		if (result == 0)
			result = wpa_config_set(network, "key_mgmt", "NONE", 6);
	}

	if (result == 0) {
		if (authMode == B_NETWORK_AUTHENTICATION_WEP) {
			if (strncmp("0x", password, 2) == 0) {
				// interpret as hex key
				// TODO: make this non-ambiguous
				result = wpa_config_set(network, "wep_key0", password + 2, 7);
			} else {
				value = "\"";
				value += password;
				value += "\"";
				result = wpa_config_set(network, "wep_key0", value.String(), 8);
			}

			if (result == 0)
				result = wpa_config_set(network, "wep_tx_keyidx", "0", 9);
		} else if (authMode == B_NETWORK_AUTHENTICATION_EAP) {
			// EAP
			value = "\"";
			value += password;
			value += "\"";
			result = wpa_config_set(network, "password", value.String(), 10);
			if (encapMode > B_NETWORK_EAP_ENCAPSULATION_NONE) {
				value = "\"";
				value += username;
				value += "\"";
				result = wpa_config_set(network, "identity",
					value.String(), 11);
			}
			// TODO: Does EAP need the same thing?
			#if 0
			if (result == 0) {
				// We need to actually "apply" the PSK
				wpa_config_update_psk(network);
			}
			#endif
		} else if (authMode >= B_NETWORK_AUTHENTICATION_WPA) {
			// WPA/WPA2
			value = "\"";
			value += password;
			value += "\"";
			result = wpa_config_set(network, "psk", value.String(), 10);

			if (result == 0) {
				// We need to actually "apply" the PSK
				wpa_config_update_psk(network);
			}
		}

		if (result != 0) {
			// The key format is invalid, we need to ask for another password.
			BMessage newJoinRequest = *message;
			newJoinRequest.RemoveName("password");
			newJoinRequest.AddString("error", "Password format invalid");
			newJoinRequest.AddBool("forceDialog", true);
			PostMessage(&newJoinRequest);
		}
	}

	if (result != 0) {
		wpas_notify_network_removed(interface, network);
		wpa_config_remove_network(interface->conf, network->id);
		return B_ERROR;
	}

	// Set up watching for the completion event
	_StartWatchingInterfaceChanges(interface, _InterfaceStateChangeCallback,
		message);

	// Now attempt to connect
	wpa_supplicant_select_network(interface, network);

	// Use a message runner to return a timeout and stop watching after a while
	BMessage timeout(kMsgJoinTimeout);
	timeout.AddPointer("interface", interface);

	BMessageRunner::StartSending(be_app_messenger, &timeout,
		15 * 1000 * 1000, 1);
		// Note that we don't need to cancel this. If joining works before the
		// timeout happens, it will take the StateChangeWatchingEntry with it
		// and the timeout message won't match anything and be discarded.

	return B_OK;
}
Example #15
0
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
					      int registrar, const u8 *bssid)
{
	struct wpa_ssid *ssid;

	ssid = wpa_config_add_network(wpa_s->conf);
	if (ssid == NULL)
		return NULL;
	wpas_notify_network_added(wpa_s, ssid);
	wpa_config_set_network_defaults(ssid);
	ssid->temporary = 1;
	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
	    wpa_config_set(ssid, "identity", registrar ?
			   "\"" WSC_ID_REGISTRAR "\"" :
			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
		wpas_notify_network_removed(wpa_s, ssid);
		wpa_config_remove_network(wpa_s->conf, ssid->id);
		return NULL;
	}

	if (bssid) {
#ifndef CONFIG_P2P
		struct wpa_bss *bss;
		int count = 0;
#endif /* CONFIG_P2P */

		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
		ssid->bssid_set = 1;

		/*
		 * Note: With P2P, the SSID may change at the time the WPS
		 * provisioning is started, so better not filter the AP based
		 * on the current SSID in the scan results.
		 */
#ifndef CONFIG_P2P
		dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
			if (os_memcmp(bssid, bss->bssid, ETH_ALEN) != 0)
				continue;

			os_free(ssid->ssid);
			ssid->ssid = os_malloc(bss->ssid_len);
			if (ssid->ssid == NULL)
				break;
			os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
			ssid->ssid_len = bss->ssid_len;
			wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
					  "scan results",
					  ssid->ssid, ssid->ssid_len);
			count++;
		}

		if (count > 1) {
			wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
				   "for the AP; use wildcard");
			os_free(ssid->ssid);
			ssid->ssid = NULL;
			ssid->ssid_len = 0;
		}
#endif /* CONFIG_P2P */
	}

	return ssid;
}