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