Home | History | Annotate | Line # | Download | only in wpa_supplicant
      1 /*
      2  * WPA Supplicant / Configuration backend: Windows registry
      3  * Copyright (c) 2003-2019, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  *
      8  * This file implements a configuration backend for Windows registry. All the
      9  * configuration information is stored in the registry and the format for
     10  * network configuration fields is same as described in the sample
     11  * configuration file, wpa_supplicant.conf.
     12  *
     13  * Configuration data is in
     14  * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
     15  * key. Each configuration profile has its own key under this. In terms of text
     16  * files, each profile would map to a separate text file with possibly multiple
     17  * networks. Under each profile, there is a networks key that lists all
     18  * networks as a subkey. Each network has set of values in the same way as
     19  * network block in the configuration file. In addition, blobs subkey has
     20  * possible blobs as values.
     21  *
     22  * Example network configuration block:
     23  * \verbatim
     24 HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
     25    ssid="example"
     26    key_mgmt=WPA-PSK
     27 \endverbatim
     28  */
     29 
     30 #include "includes.h"
     31 
     32 #include "common.h"
     33 #include "uuid.h"
     34 #include "config.h"
     35 
     36 #ifndef WPA_KEY_ROOT
     37 #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
     38 #endif
     39 #ifndef WPA_KEY_PREFIX
     40 #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
     41 #endif
     42 
     43 #ifdef UNICODE
     44 #define TSTR "%S"
     45 #else /* UNICODE */
     46 #define TSTR "%s"
     47 #endif /* UNICODE */
     48 
     49 
     50 static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
     51 {
     52 	struct wpa_config_blob *blob;
     53 	int errors = 0;
     54 	HKEY bhk;
     55 	LONG ret;
     56 	DWORD i;
     57 
     58 	ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
     59 	if (ret != ERROR_SUCCESS) {
     60 		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
     61 			   "blobs key");
     62 		return 0; /* assume no blobs */
     63 	}
     64 
     65 	for (i = 0; ; i++) {
     66 #define TNAMELEN 255
     67 		TCHAR name[TNAMELEN];
     68 		char data[4096];
     69 		DWORD namelen, datalen, type;
     70 
     71 		namelen = TNAMELEN;
     72 		datalen = sizeof(data);
     73 		ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
     74 				   (LPBYTE) data, &datalen);
     75 
     76 		if (ret == ERROR_NO_MORE_ITEMS)
     77 			break;
     78 
     79 		if (ret != ERROR_SUCCESS) {
     80 			wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
     81 				   (unsigned int) ret);
     82 			break;
     83 		}
     84 
     85 		if (namelen >= TNAMELEN)
     86 			namelen = TNAMELEN - 1;
     87 		name[namelen] = TEXT('\0');
     88 		wpa_unicode2ascii_inplace(name);
     89 
     90 		if (datalen >= sizeof(data))
     91 			datalen = sizeof(data) - 1;
     92 
     93 		wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
     94 			   (int) i, name, (int) datalen);
     95 
     96 		blob = os_zalloc(sizeof(*blob));
     97 		if (blob == NULL) {
     98 			errors++;
     99 			break;
    100 		}
    101 		blob->name = os_strdup((char *) name);
    102 		blob->data = os_memdup(data, datalen);
    103 		if (blob->name == NULL || blob->data == NULL) {
    104 			wpa_config_free_blob(blob);
    105 			errors++;
    106 			break;
    107 		}
    108 		blob->len = datalen;
    109 
    110 		wpa_config_set_blob(config, blob);
    111 	}
    112 
    113 	RegCloseKey(bhk);
    114 
    115 	return errors ? -1 : 0;
    116 }
    117 
    118 
    119 static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
    120 {
    121 	DWORD val, buflen;
    122 	LONG ret;
    123 
    124 	buflen = sizeof(val);
    125 	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
    126 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    127 		wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
    128 		*_val = val;
    129 		return 0;
    130 	}
    131 
    132 	return -1;
    133 }
    134 
    135 
    136 static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
    137 {
    138 	DWORD buflen;
    139 	LONG ret;
    140 	TCHAR *val;
    141 
    142 	buflen = 0;
    143 	ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
    144 	if (ret != ERROR_SUCCESS)
    145 		return NULL;
    146 	val = os_malloc(buflen);
    147 	if (val == NULL)
    148 		return NULL;
    149 
    150 	ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
    151 	if (ret != ERROR_SUCCESS) {
    152 		os_free(val);
    153 		return NULL;
    154 	}
    155 
    156 	wpa_unicode2ascii_inplace(val);
    157 	wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
    158 	return (char *) val;
    159 }
    160 
    161 
    162 #ifdef CONFIG_WPS
    163 static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
    164 {
    165 	char *str;
    166 	int ret = 0;
    167 
    168 	str = wpa_config_read_reg_string(hk, TEXT("uuid"));
    169 	if (str == NULL)
    170 		return 0;
    171 
    172 	if (uuid_str2bin(str, config->uuid))
    173 		ret = -1;
    174 
    175 	os_free(str);
    176 
    177 	return ret;
    178 }
    179 
    180 
    181 static int wpa_config_read_global_os_version(struct wpa_config *config,
    182 					     HKEY hk)
    183 {
    184 	char *str;
    185 	int ret = 0;
    186 
    187 	str = wpa_config_read_reg_string(hk, TEXT("os_version"));
    188 	if (str == NULL)
    189 		return 0;
    190 
    191 	if (hexstr2bin(str, config->os_version, 4))
    192 		ret = -1;
    193 
    194 	os_free(str);
    195 
    196 	return ret;
    197 }
    198 #endif /* CONFIG_WPS */
    199 
    200 
    201 static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
    202 {
    203 	int errors = 0;
    204 	int val;
    205 
    206 	wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
    207 	wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
    208 				  &config->fast_reauth);
    209 	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
    210 				  (int *) &config->dot11RSNAConfigPMKLifetime);
    211 	wpa_config_read_reg_dword(hk,
    212 				  TEXT("dot11RSNAConfigPMKReauthThreshold"),
    213 				  (int *)
    214 				  &config->dot11RSNAConfigPMKReauthThreshold);
    215 	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
    216 				  (int *) &config->dot11RSNAConfigSATimeout);
    217 	wpa_config_read_reg_dword(hk, TEXT("update_config"),
    218 				  &config->update_config);
    219 
    220 	if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
    221 				      &config->eapol_version) == 0) {
    222 		if (config->eapol_version < 1 ||
    223 		    config->eapol_version > 2) {
    224 			wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
    225 				   config->eapol_version);
    226 			errors++;
    227 		}
    228 	}
    229 
    230 	config->ctrl_interface = wpa_config_read_reg_string(
    231 		hk, TEXT("ctrl_interface"));
    232 
    233 #ifdef CONFIG_WPS
    234 	if (wpa_config_read_global_uuid(config, hk))
    235 		errors++;
    236 	wpa_config_read_reg_dword(hk, TEXT("auto_uuid"), &config->auto_uuid);
    237 	config->device_name = wpa_config_read_reg_string(
    238 		hk, TEXT("device_name"));
    239 	config->manufacturer = wpa_config_read_reg_string(
    240 		hk, TEXT("manufacturer"));
    241 	config->model_name = wpa_config_read_reg_string(
    242 		hk, TEXT("model_name"));
    243 	config->serial_number = wpa_config_read_reg_string(
    244 		hk, TEXT("serial_number"));
    245 	{
    246 		char *t = wpa_config_read_reg_string(
    247 			hk, TEXT("device_type"));
    248 		if (t && wps_dev_type_str2bin(t, config->device_type))
    249 			errors++;
    250 		os_free(t);
    251 	}
    252 	config->config_methods = wpa_config_read_reg_string(
    253 		hk, TEXT("config_methods"));
    254 	if (wpa_config_read_global_os_version(config, hk))
    255 		errors++;
    256 	wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
    257 				  &config->wps_cred_processing);
    258 	wpa_config_read_reg_dword(hk, TEXT("wps_cred_add_sae"),
    259 				  &config->wps_cred_add_sae);
    260 #endif /* CONFIG_WPS */
    261 #ifdef CONFIG_P2P
    262 	config->p2p_ssid_postfix = wpa_config_read_reg_string(
    263 		hk, TEXT("p2p_ssid_postfix"));
    264 	wpa_config_read_reg_dword(hk, TEXT("p2p_group_idle"),
    265 				  (int *) &config->p2p_group_idle);
    266 #endif /* CONFIG_P2P */
    267 
    268 	wpa_config_read_reg_dword(hk, TEXT("bss_max_count"),
    269 				  (int *) &config->bss_max_count);
    270 	wpa_config_read_reg_dword(hk, TEXT("filter_ssids"),
    271 				  &config->filter_ssids);
    272 	wpa_config_read_reg_dword(hk, TEXT("max_num_sta"),
    273 				  (int *) &config->max_num_sta);
    274 	wpa_config_read_reg_dword(hk, TEXT("disassoc_low_ack"),
    275 				  (int *) &config->disassoc_low_ack);
    276 
    277 	wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc);
    278 	wpa_config_read_reg_dword(hk, TEXT("pmf"), &val);
    279 	config->pmf = val;
    280 	if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"),
    281 				      &val) == 0) {
    282 		if (val < 0 || val > 1) {
    283 			wpa_printf(MSG_ERROR,
    284 				   "Invalid Extended Key ID setting (%d)", val);
    285 			errors++;
    286 		}
    287 		config->extended_key_id = val;
    288 	}
    289 
    290 	return errors ? -1 : 0;
    291 }
    292 
    293 
    294 static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
    295 						 int id)
    296 {
    297 	HKEY nhk;
    298 	LONG ret;
    299 	DWORD i;
    300 	struct wpa_ssid *ssid;
    301 	int errors = 0;
    302 
    303 	ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
    304 	if (ret != ERROR_SUCCESS) {
    305 		wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
    306 			   "network '" TSTR "'", netw);
    307 		return NULL;
    308 	}
    309 
    310 	wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
    311 	ssid = os_zalloc(sizeof(*ssid));
    312 	if (ssid == NULL) {
    313 		RegCloseKey(nhk);
    314 		return NULL;
    315 	}
    316 	dl_list_init(&ssid->psk_list);
    317 	ssid->id = id;
    318 
    319 	wpa_config_set_network_defaults(ssid);
    320 
    321 	for (i = 0; ; i++) {
    322 		TCHAR name[255], data[1024];
    323 		DWORD namelen, datalen, type;
    324 
    325 		namelen = 255;
    326 		datalen = sizeof(data);
    327 		ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
    328 				   (LPBYTE) data, &datalen);
    329 
    330 		if (ret == ERROR_NO_MORE_ITEMS)
    331 			break;
    332 
    333 		if (ret != ERROR_SUCCESS) {
    334 			wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
    335 				   (unsigned int) ret);
    336 			break;
    337 		}
    338 
    339 		if (namelen >= 255)
    340 			namelen = 255 - 1;
    341 		name[namelen] = TEXT('\0');
    342 
    343 		if (datalen >= 1024)
    344 			datalen = 1024 - 1;
    345 		data[datalen] = TEXT('\0');
    346 
    347 		wpa_unicode2ascii_inplace(name);
    348 		wpa_unicode2ascii_inplace(data);
    349 		if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
    350 			errors++;
    351 	}
    352 
    353 	RegCloseKey(nhk);
    354 
    355 	if (ssid->passphrase) {
    356 		if (ssid->psk_set) {
    357 			wpa_printf(MSG_ERROR, "Both PSK and passphrase "
    358 				   "configured for network '" TSTR "'.", netw);
    359 			errors++;
    360 		}
    361 		wpa_config_update_psk(ssid);
    362 	}
    363 
    364 	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
    365 	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
    366 	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
    367 		/* Group cipher cannot be stronger than the pairwise cipher. */
    368 		wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
    369 			   "list since it was not allowed for pairwise "
    370 			   "cipher for network '" TSTR "'.", netw);
    371 		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
    372 	}
    373 
    374 	if (errors) {
    375 		wpa_config_free_ssid(ssid);
    376 		ssid = NULL;
    377 	}
    378 
    379 	return ssid;
    380 }
    381 
    382 
    383 static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
    384 {
    385 	HKEY nhk;
    386 	struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
    387 	int errors = 0;
    388 	LONG ret;
    389 	DWORD i;
    390 
    391 	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
    392 			   &nhk);
    393 	if (ret != ERROR_SUCCESS) {
    394 		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
    395 			   "registry key");
    396 		return -1;
    397 	}
    398 
    399 	for (i = 0; ; i++) {
    400 		TCHAR name[255];
    401 		DWORD namelen;
    402 
    403 		namelen = 255;
    404 		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
    405 				   NULL);
    406 
    407 		if (ret == ERROR_NO_MORE_ITEMS)
    408 			break;
    409 
    410 		if (ret != ERROR_SUCCESS) {
    411 			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
    412 				   (unsigned int) ret);
    413 			break;
    414 		}
    415 
    416 		if (namelen >= 255)
    417 			namelen = 255 - 1;
    418 		name[namelen] = '\0';
    419 
    420 		ssid = wpa_config_read_network(nhk, name, i);
    421 		if (ssid == NULL) {
    422 			wpa_printf(MSG_ERROR, "Failed to parse network "
    423 				   "profile '%s'.", name);
    424 			errors++;
    425 			continue;
    426 		}
    427 		if (head == NULL) {
    428 			head = tail = ssid;
    429 		} else {
    430 			tail->next = ssid;
    431 			tail = ssid;
    432 		}
    433 		if (wpa_config_add_prio_network(config, ssid)) {
    434 			wpa_printf(MSG_ERROR, "Failed to add network profile "
    435 				   "'%s' to priority list.", name);
    436 			errors++;
    437 			continue;
    438 		}
    439 	}
    440 
    441 	RegCloseKey(nhk);
    442 
    443 	config->ssid = head;
    444 
    445 	return errors ? -1 : 0;
    446 }
    447 
    448 
    449 struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp,
    450 				    bool ro)
    451 {
    452 	TCHAR buf[256];
    453 	int errors = 0;
    454 	struct wpa_config *config;
    455 	HKEY hk;
    456 	LONG ret;
    457 
    458 	if (name == NULL)
    459 		return NULL;
    460 	if (cfgp)
    461 		config = cfgp;
    462 	else
    463 		config = wpa_config_alloc_empty(NULL, NULL);
    464 	if (config == NULL)
    465 		return NULL;
    466 	wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
    467 
    468 #ifdef UNICODE
    469 	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
    470 #else /* UNICODE */
    471 	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
    472 #endif /* UNICODE */
    473 
    474 	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
    475 	if (ret != ERROR_SUCCESS) {
    476 		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
    477 			   "configuration registry HKLM\\" TSTR, buf);
    478 		os_free(config);
    479 		return NULL;
    480 	}
    481 
    482 	if (wpa_config_read_global(config, hk))
    483 		errors++;
    484 
    485 	if (wpa_config_read_networks(config, hk))
    486 		errors++;
    487 
    488 	if (wpa_config_read_blobs(config, hk))
    489 		errors++;
    490 
    491 	wpa_config_debug_dump_networks(config);
    492 
    493 	RegCloseKey(hk);
    494 
    495 	if (errors) {
    496 		wpa_config_free(config);
    497 		config = NULL;
    498 	}
    499 
    500 	return config;
    501 }
    502 
    503 
    504 static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
    505 				      int def)
    506 {
    507 	LONG ret;
    508 	DWORD _val = val;
    509 
    510 	if (val == def) {
    511 		RegDeleteValue(hk, name);
    512 		return 0;
    513 	}
    514 
    515 	ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
    516 			    sizeof(_val));
    517 	if (ret != ERROR_SUCCESS) {
    518 		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
    519 			   name, val, (int) GetLastError());
    520 		return -1;
    521 	}
    522 
    523 	return 0;
    524 }
    525 
    526 
    527 static int wpa_config_write_reg_string(HKEY hk, const char *name,
    528 				       const char *val)
    529 {
    530 	LONG ret;
    531 	TCHAR *_name, *_val;
    532 
    533 	_name = wpa_strdup_tchar(name);
    534 	if (_name == NULL)
    535 		return -1;
    536 
    537 	if (val == NULL) {
    538 		RegDeleteValue(hk, _name);
    539 		os_free(_name);
    540 		return 0;
    541 	}
    542 
    543 	_val = wpa_strdup_tchar(val);
    544 	if (_val == NULL) {
    545 		os_free(_name);
    546 		return -1;
    547 	}
    548 	ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
    549 			    (os_strlen(val) + 1) * sizeof(TCHAR));
    550 	if (ret != ERROR_SUCCESS) {
    551 		wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
    552 			   "error %d", name, val, (int) GetLastError());
    553 		os_free(_name);
    554 		os_free(_val);
    555 		return -1;
    556 	}
    557 
    558 	os_free(_name);
    559 	os_free(_val);
    560 	return 0;
    561 }
    562 
    563 
    564 static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
    565 {
    566 #ifdef CONFIG_CTRL_IFACE
    567 	wpa_config_write_reg_string(hk, "ctrl_interface",
    568 				    config->ctrl_interface);
    569 #endif /* CONFIG_CTRL_IFACE */
    570 
    571 	wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
    572 				   config->eapol_version,
    573 				   DEFAULT_EAPOL_VERSION);
    574 	wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
    575 				   DEFAULT_AP_SCAN);
    576 	wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
    577 				   config->fast_reauth, DEFAULT_FAST_REAUTH);
    578 	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
    579 				   config->dot11RSNAConfigPMKLifetime, 0);
    580 	wpa_config_write_reg_dword(hk,
    581 				   TEXT("dot11RSNAConfigPMKReauthThreshold"),
    582 				   config->dot11RSNAConfigPMKReauthThreshold,
    583 				   0);
    584 	wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
    585 				   config->dot11RSNAConfigSATimeout, 0);
    586 	wpa_config_write_reg_dword(hk, TEXT("update_config"),
    587 				   config->update_config,
    588 				   0);
    589 #ifdef CONFIG_WPS
    590 	if (!is_nil_uuid(config->uuid)) {
    591 		char buf[40];
    592 		uuid_bin2str(config->uuid, buf, sizeof(buf));
    593 		wpa_config_write_reg_string(hk, "uuid", buf);
    594 	}
    595 	wpa_config_write_reg_dword(hk, TEXT("auto_uuid"), config->auto_uuid,
    596 				   0);
    597 	wpa_config_write_reg_string(hk, "device_name", config->device_name);
    598 	wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
    599 	wpa_config_write_reg_string(hk, "model_name", config->model_name);
    600 	wpa_config_write_reg_string(hk, "model_number", config->model_number);
    601 	wpa_config_write_reg_string(hk, "serial_number",
    602 				    config->serial_number);
    603 	{
    604 		char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
    605 		buf = wps_dev_type_bin2str(config->device_type,
    606 					   _buf, sizeof(_buf));
    607 		wpa_config_write_reg_string(hk, "device_type", buf);
    608 	}
    609 	wpa_config_write_reg_string(hk, "config_methods",
    610 				    config->config_methods);
    611 	if (WPA_GET_BE32(config->os_version)) {
    612 		char vbuf[10];
    613 		os_snprintf(vbuf, sizeof(vbuf), "%08x",
    614 			    WPA_GET_BE32(config->os_version));
    615 		wpa_config_write_reg_string(hk, "os_version", vbuf);
    616 	}
    617 	wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
    618 				   config->wps_cred_processing, 0);
    619 	wpa_config_write_reg_dword(hk, TEXT("wps_cred_add_sae"),
    620 				   config->wps_cred_add_sae, 0);
    621 #endif /* CONFIG_WPS */
    622 #ifdef CONFIG_P2P
    623 	wpa_config_write_reg_string(hk, "p2p_ssid_postfix",
    624 				    config->p2p_ssid_postfix);
    625 	wpa_config_write_reg_dword(hk, TEXT("p2p_group_idle"),
    626 				   config->p2p_group_idle, 0);
    627 #endif /* CONFIG_P2P */
    628 
    629 	wpa_config_write_reg_dword(hk, TEXT("bss_max_count"),
    630 				   config->bss_max_count,
    631 				   DEFAULT_BSS_MAX_COUNT);
    632 	wpa_config_write_reg_dword(hk, TEXT("filter_ssids"),
    633 				   config->filter_ssids, 0);
    634 	wpa_config_write_reg_dword(hk, TEXT("max_num_sta"),
    635 				   config->max_num_sta, DEFAULT_MAX_NUM_STA);
    636 	wpa_config_write_reg_dword(hk, TEXT("ap_isolate"),
    637 				   config->ap_isolate, DEFAULT_AP_ISOLATE);
    638 	wpa_config_write_reg_dword(hk, TEXT("disassoc_low_ack"),
    639 				   config->disassoc_low_ack, 0);
    640 
    641 	wpa_config_write_reg_dword(hk, TEXT("okc"), config->okc, 0);
    642 	wpa_config_write_reg_dword(hk, TEXT("pmf"), config->pmf, 0);
    643 
    644 	wpa_config_write_reg_dword(hk, TEXT("external_sim"),
    645 				   config->external_sim, 0);
    646 
    647 	return 0;
    648 }
    649 
    650 
    651 static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
    652 {
    653 	HKEY nhk;
    654 	int i, errors = 0;
    655 	LONG ret;
    656 
    657 	ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
    658 	if (ret != ERROR_SUCCESS) {
    659 		wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
    660 			   "' for subkey deletion: error 0x%x (%d)", key,
    661 			   (unsigned int) ret, (int) GetLastError());
    662 		return 0;
    663 	}
    664 
    665 	for (i = 0; ; i++) {
    666 		TCHAR name[255];
    667 		DWORD namelen;
    668 
    669 		namelen = 255;
    670 		ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
    671 				   NULL);
    672 
    673 		if (ret == ERROR_NO_MORE_ITEMS)
    674 			break;
    675 
    676 		if (ret != ERROR_SUCCESS) {
    677 			wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
    678 				   (unsigned int) ret, (int) GetLastError());
    679 			break;
    680 		}
    681 
    682 		if (namelen >= 255)
    683 			namelen = 255 - 1;
    684 		name[namelen] = TEXT('\0');
    685 
    686 		ret = RegDeleteKey(nhk, name);
    687 		if (ret != ERROR_SUCCESS) {
    688 			wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
    689 				   (unsigned int) ret, (int) GetLastError());
    690 			errors++;
    691 		}
    692 	}
    693 
    694 	RegCloseKey(nhk);
    695 
    696 	return errors ? -1 : 0;
    697 }
    698 
    699 
    700 static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
    701 {
    702 	char *value = wpa_config_get(ssid, field);
    703 	if (value == NULL)
    704 		return;
    705 	wpa_config_write_reg_string(hk, field, value);
    706 	os_free(value);
    707 }
    708 
    709 
    710 static void write_int(HKEY hk, const char *field, int value, int def)
    711 {
    712 	char val[20];
    713 	if (value == def)
    714 		return;
    715 	os_snprintf(val, sizeof(val), "%d", value);
    716 	wpa_config_write_reg_string(hk, field, val);
    717 }
    718 
    719 
    720 static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
    721 {
    722 	char *value = wpa_config_get(ssid, "bssid");
    723 	if (value == NULL)
    724 		return;
    725 	wpa_config_write_reg_string(hk, "bssid", value);
    726 	os_free(value);
    727 }
    728 
    729 
    730 static void write_psk(HKEY hk, struct wpa_ssid *ssid)
    731 {
    732 	char *value = wpa_config_get(ssid, "psk");
    733 	if (value == NULL)
    734 		return;
    735 	wpa_config_write_reg_string(hk, "psk", value);
    736 	os_free(value);
    737 }
    738 
    739 
    740 static void write_proto(HKEY hk, struct wpa_ssid *ssid)
    741 {
    742 	char *value;
    743 
    744 	if (ssid->proto == DEFAULT_PROTO)
    745 		return;
    746 
    747 	value = wpa_config_get(ssid, "proto");
    748 	if (value == NULL)
    749 		return;
    750 	if (value[0])
    751 		wpa_config_write_reg_string(hk, "proto", value);
    752 	os_free(value);
    753 }
    754 
    755 
    756 static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
    757 {
    758 	char *value;
    759 
    760 	if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
    761 		return;
    762 
    763 	value = wpa_config_get(ssid, "key_mgmt");
    764 	if (value == NULL)
    765 		return;
    766 	if (value[0])
    767 		wpa_config_write_reg_string(hk, "key_mgmt", value);
    768 	os_free(value);
    769 }
    770 
    771 
    772 static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
    773 {
    774 	char *value;
    775 
    776 	if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
    777 		return;
    778 
    779 	value = wpa_config_get(ssid, "pairwise");
    780 	if (value == NULL)
    781 		return;
    782 	if (value[0])
    783 		wpa_config_write_reg_string(hk, "pairwise", value);
    784 	os_free(value);
    785 }
    786 
    787 
    788 static void write_group(HKEY hk, struct wpa_ssid *ssid)
    789 {
    790 	char *value;
    791 
    792 	if (ssid->group_cipher == DEFAULT_GROUP)
    793 		return;
    794 
    795 	value = wpa_config_get(ssid, "group");
    796 	if (value == NULL)
    797 		return;
    798 	if (value[0])
    799 		wpa_config_write_reg_string(hk, "group", value);
    800 	os_free(value);
    801 }
    802 
    803 
    804 static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
    805 {
    806 	char *value;
    807 
    808 	if (ssid->auth_alg == 0)
    809 		return;
    810 
    811 	value = wpa_config_get(ssid, "auth_alg");
    812 	if (value == NULL)
    813 		return;
    814 	if (value[0])
    815 		wpa_config_write_reg_string(hk, "auth_alg", value);
    816 	os_free(value);
    817 }
    818 
    819 
    820 #ifdef IEEE8021X_EAPOL
    821 static void write_eap(HKEY hk, struct wpa_ssid *ssid)
    822 {
    823 	char *value;
    824 
    825 	value = wpa_config_get(ssid, "eap");
    826 	if (value == NULL)
    827 		return;
    828 
    829 	if (value[0])
    830 		wpa_config_write_reg_string(hk, "eap", value);
    831 	os_free(value);
    832 }
    833 #endif /* IEEE8021X_EAPOL */
    834 
    835 
    836 #ifdef CONFIG_WEP
    837 static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
    838 {
    839 	char field[20], *value;
    840 
    841 	os_snprintf(field, sizeof(field), "wep_key%d", idx);
    842 	value = wpa_config_get(ssid, field);
    843 	if (value) {
    844 		wpa_config_write_reg_string(hk, field, value);
    845 		os_free(value);
    846 	}
    847 }
    848 #endif /* CONFIG_WEP */
    849 
    850 
    851 static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
    852 {
    853 	int errors = 0;
    854 	HKEY nhk, netw;
    855 	LONG ret;
    856 	TCHAR name[5];
    857 
    858 	ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
    859 	if (ret != ERROR_SUCCESS) {
    860 		wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
    861 			   "for subkey addition: error 0x%x (%d)",
    862 			   (unsigned int) ret, (int) GetLastError());
    863 		return 0;
    864 	}
    865 
    866 #ifdef UNICODE
    867 	wsprintf(name, L"%04d", id);
    868 #else /* UNICODE */
    869 	os_snprintf(name, sizeof(name), "%04d", id);
    870 #endif /* UNICODE */
    871 	ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
    872 			     NULL);
    873 	RegCloseKey(nhk);
    874 	if (ret != ERROR_SUCCESS) {
    875 		wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
    876 			   " error 0x%x (%d)",
    877 			   name, (unsigned int) ret, (int) GetLastError());
    878 		return -1;
    879 	}
    880 
    881 #define STR(t) write_str(netw, #t, ssid)
    882 #define INT(t) write_int(netw, #t, ssid->t, 0)
    883 #define INTe(t, m) write_int(netw, #t, ssid->eap.m, 0)
    884 #define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
    885 #define INT_DEFe(t, m, def) write_int(netw, #t, ssid->eap.m, def)
    886 
    887 	STR(ssid);
    888 	INT(scan_ssid);
    889 	write_bssid(netw, ssid);
    890 	write_psk(netw, ssid);
    891 	STR(sae_password);
    892 	STR(sae_password_id);
    893 	write_proto(netw, ssid);
    894 	write_key_mgmt(netw, ssid);
    895 	write_pairwise(netw, ssid);
    896 	write_group(netw, ssid);
    897 	write_auth_alg(netw, ssid);
    898 #ifdef IEEE8021X_EAPOL
    899 	write_eap(netw, ssid);
    900 	STR(identity);
    901 	STR(anonymous_identity);
    902 	STR(imsi_identity);
    903 	STR(password);
    904 	STR(ca_cert);
    905 	STR(ca_path);
    906 	STR(client_cert);
    907 	STR(private_key);
    908 	STR(private_key_passwd);
    909 	STR(subject_match);
    910 	STR(check_cert_subject);
    911 	STR(altsubject_match);
    912 	STR(ca_cert2);
    913 	STR(ca_path2);
    914 	STR(client_cert2);
    915 	STR(private_key2);
    916 	STR(private_key2_passwd);
    917 	STR(subject_match2);
    918 	STR(check_cert_subject2);
    919 	STR(altsubject_match2);
    920 	STR(phase1);
    921 	STR(phase2);
    922 	STR(pcsc);
    923 	STR(pin);
    924 	STR(engine_id);
    925 	STR(key_id);
    926 	STR(cert_id);
    927 	STR(ca_cert_id);
    928 	STR(key2_id);
    929 	STR(pin2);
    930 	STR(engine2_id);
    931 	STR(cert2_id);
    932 	STR(ca_cert2_id);
    933 	INTe(engine, cert.engine);
    934 	INTe(engine2, phase2_cert.engine);
    935 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
    936 #endif /* IEEE8021X_EAPOL */
    937 #ifdef CONFIG_WEP
    938 	{
    939 		int i;
    940 
    941 		for (i = 0; i < 4; i++)
    942 			write_wep_key(netw, i, ssid);
    943 		INT(wep_tx_keyidx);
    944 	}
    945 #endif /* CONFIG_WEP */
    946 	INT(priority);
    947 #ifdef IEEE8021X_EAPOL
    948 	INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
    949 	STR(pac_file);
    950 	INT_DEFe(fragment_size, fragment_size, DEFAULT_FRAGMENT_SIZE);
    951 #endif /* IEEE8021X_EAPOL */
    952 	INT(mode);
    953 	write_int(netw, "proactive_key_caching", ssid->proactive_key_caching,
    954 		  -1);
    955 	INT(disabled);
    956 	write_int(netw, "ieee80211w", ssid->ieee80211w,
    957 		  MGMT_FRAME_PROTECTION_DEFAULT);
    958 	STR(id_str);
    959 #ifdef CONFIG_HS20
    960 	INT(update_identifier);
    961 #endif /* CONFIG_HS20 */
    962 	INT(group_rekey);
    963 	INT(ft_eap_pmksa_caching);
    964 
    965 #undef STR
    966 #undef INT
    967 #undef INT_DEF
    968 
    969 	RegCloseKey(netw);
    970 
    971 	return errors ? -1 : 0;
    972 }
    973 
    974 
    975 static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
    976 {
    977 	HKEY bhk;
    978 	LONG ret;
    979 	TCHAR *name;
    980 
    981 	ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
    982 			     &bhk, NULL);
    983 	if (ret != ERROR_SUCCESS) {
    984 		wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
    985 			   "error 0x%x (%d)",
    986 			   (unsigned int) ret, (int) GetLastError());
    987 		return -1;
    988 	}
    989 
    990 	name = wpa_strdup_tchar(blob->name);
    991 	ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
    992 			    blob->len);
    993 	if (ret != ERROR_SUCCESS) {
    994 		wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
    995 			   "error 0x%x (%d)", blob->name, (unsigned int) ret,
    996 			   (int) GetLastError());
    997 		RegCloseKey(bhk);
    998 		os_free(name);
    999 		return -1;
   1000 	}
   1001 	os_free(name);
   1002 
   1003 	RegCloseKey(bhk);
   1004 
   1005 	return 0;
   1006 }
   1007 
   1008 
   1009 int wpa_config_write(const char *name, struct wpa_config *config)
   1010 {
   1011 	TCHAR buf[256];
   1012 	HKEY hk;
   1013 	LONG ret;
   1014 	int errors = 0;
   1015 	struct wpa_ssid *ssid;
   1016 	struct wpa_config_blob *blob;
   1017 	int id;
   1018 
   1019 	wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
   1020 
   1021 #ifdef UNICODE
   1022 	_snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
   1023 #else /* UNICODE */
   1024 	os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
   1025 #endif /* UNICODE */
   1026 
   1027 	ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
   1028 	if (ret != ERROR_SUCCESS) {
   1029 		wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
   1030 			   "configuration registry %s: error %d", buf,
   1031 			   (int) GetLastError());
   1032 		return -1;
   1033 	}
   1034 
   1035 	if (wpa_config_write_global(config, hk)) {
   1036 		wpa_printf(MSG_ERROR, "Failed to write global configuration "
   1037 			   "data");
   1038 		errors++;
   1039 	}
   1040 
   1041 	wpa_config_delete_subkeys(hk, TEXT("networks"));
   1042 	for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
   1043 		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
   1044 			continue; /* do not save temporary WPS networks */
   1045 		if (wpa_config_write_network(hk, ssid, id))
   1046 			errors++;
   1047 	}
   1048 
   1049 	RegDeleteKey(hk, TEXT("blobs"));
   1050 	for (blob = config->blobs; blob; blob = blob->next) {
   1051 		if (wpa_config_write_blob(hk, blob))
   1052 			errors++;
   1053 	}
   1054 
   1055 	RegCloseKey(hk);
   1056 
   1057 	wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
   1058 		   name, errors ? "un" : "");
   1059 	return errors ? -1 : 0;
   1060 }
   1061