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