Use shared string parser for global configuration fields
[wpasupplicant] / wpa_supplicant / config_file.c
1 /*
2  * WPA Supplicant / Configuration backend: text file
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 text files. All the
15  * configuration information is stored in a text file that uses a format
16  * described in the sample configuration file, wpa_supplicant.conf.
17  */
18
19 #include "includes.h"
20
21 #include "common.h"
22 #include "config.h"
23 #include "base64.h"
24 #include "uuid.h"
25 #include "eap_peer/eap_methods.h"
26
27
28 /**
29  * wpa_config_get_line - Read the next configuration file line
30  * @s: Buffer for the line
31  * @size: The buffer length
32  * @stream: File stream to read from
33  * @line: Pointer to a variable storing the file line number
34  * @_pos: Buffer for the pointer to the beginning of data on the text line or
35  * %NULL if not needed (returned value used instead)
36  * Returns: Pointer to the beginning of data on the text line or %NULL if no
37  * more text lines are available.
38  *
39  * This function reads the next non-empty line from the configuration file and
40  * removes comments. The returned string is guaranteed to be null-terminated.
41  */
42 static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
43                                   char **_pos)
44 {
45         char *pos, *end, *sstart;
46
47         while (fgets(s, size, stream)) {
48                 (*line)++;
49                 s[size - 1] = '\0';
50                 pos = s;
51
52                 /* Skip white space from the beginning of line. */
53                 while (*pos == ' ' || *pos == '\t' || *pos == '\r')
54                         pos++;
55
56                 /* Skip comment lines and empty lines */
57                 if (*pos == '#' || *pos == '\n' || *pos == '\0')
58                         continue;
59
60                 /*
61                  * Remove # comments unless they are within a double quoted
62                  * string.
63                  */
64                 sstart = os_strchr(pos, '"');
65                 if (sstart)
66                         sstart = os_strrchr(sstart + 1, '"');
67                 if (!sstart)
68                         sstart = pos;
69                 end = os_strchr(sstart, '#');
70                 if (end)
71                         *end-- = '\0';
72                 else
73                         end = pos + os_strlen(pos) - 1;
74
75                 /* Remove trailing white space. */
76                 while (end > pos &&
77                        (*end == '\n' || *end == ' ' || *end == '\t' ||
78                         *end == '\r'))
79                         *end-- = '\0';
80
81                 if (*pos == '\0')
82                         continue;
83
84                 if (_pos)
85                         *_pos = pos;
86                 return pos;
87         }
88
89         if (_pos)
90                 *_pos = NULL;
91         return NULL;
92 }
93
94
95 static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
96 {
97         int errors = 0;
98
99         if (ssid->passphrase) {
100                 if (ssid->psk_set) {
101                         wpa_printf(MSG_ERROR, "Line %d: both PSK and "
102                                    "passphrase configured.", line);
103                         errors++;
104                 }
105                 wpa_config_update_psk(ssid);
106         }
107
108         if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
109                                WPA_KEY_MGMT_PSK_SHA256)) &&
110             !ssid->psk_set) {
111                 wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
112                            "management, but no PSK configured.", line);
113                 errors++;
114         }
115
116         if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
117             !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
118             !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
119                 /* Group cipher cannot be stronger than the pairwise cipher. */
120                 wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
121                            " list since it was not allowed for pairwise "
122                            "cipher", line);
123                 ssid->group_cipher &= ~WPA_CIPHER_CCMP;
124         }
125
126         return errors;
127 }
128
129
130 static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
131 {
132         struct wpa_ssid *ssid;
133         int errors = 0, end = 0;
134         char buf[256], *pos, *pos2;
135
136         wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
137                    *line);
138         ssid = os_zalloc(sizeof(*ssid));
139         if (ssid == NULL)
140                 return NULL;
141         ssid->id = id;
142
143         wpa_config_set_network_defaults(ssid);
144
145         while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
146                 if (os_strcmp(pos, "}") == 0) {
147                         end = 1;
148                         break;
149                 }
150
151                 pos2 = os_strchr(pos, '=');
152                 if (pos2 == NULL) {
153                         wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
154                                    "'%s'.", *line, pos);
155                         errors++;
156                         continue;
157                 }
158
159                 *pos2++ = '\0';
160                 if (*pos2 == '"') {
161                         if (os_strchr(pos2 + 1, '"') == NULL) {
162                                 wpa_printf(MSG_ERROR, "Line %d: invalid "
163                                            "quotation '%s'.", *line, pos2);
164                                 errors++;
165                                 continue;
166                         }
167                 }
168
169                 if (wpa_config_set(ssid, pos, pos2, *line) < 0)
170                         errors++;
171         }
172
173         if (!end) {
174                 wpa_printf(MSG_ERROR, "Line %d: network block was not "
175                            "terminated properly.", *line);
176                 errors++;
177         }
178
179         errors += wpa_config_validate_network(ssid, *line);
180
181         if (errors) {
182                 wpa_config_free_ssid(ssid);
183                 ssid = NULL;
184         }
185
186         return ssid;
187 }
188
189
190 #ifndef CONFIG_NO_CONFIG_BLOBS
191 static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
192                                                      const char *name)
193 {
194         struct wpa_config_blob *blob;
195         char buf[256], *pos;
196         unsigned char *encoded = NULL, *nencoded;
197         int end = 0;
198         size_t encoded_len = 0, len;
199
200         wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
201                    *line, name);
202
203         while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
204                 if (os_strcmp(pos, "}") == 0) {
205                         end = 1;
206                         break;
207                 }
208
209                 len = os_strlen(pos);
210                 nencoded = os_realloc(encoded, encoded_len + len);
211                 if (nencoded == NULL) {
212                         wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
213                                    "blob", *line);
214                         os_free(encoded);
215                         return NULL;
216                 }
217                 encoded = nencoded;
218                 os_memcpy(encoded + encoded_len, pos, len);
219                 encoded_len += len;
220         }
221
222         if (!end) {
223                 wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
224                            "properly", *line);
225                 os_free(encoded);
226                 return NULL;
227         }
228
229         blob = os_zalloc(sizeof(*blob));
230         if (blob == NULL) {
231                 os_free(encoded);
232                 return NULL;
233         }
234         blob->name = os_strdup(name);
235         blob->data = base64_decode(encoded, encoded_len, &blob->len);
236         os_free(encoded);
237
238         if (blob->name == NULL || blob->data == NULL) {
239                 wpa_config_free_blob(blob);
240                 return NULL;
241         }
242
243         return blob;
244 }
245
246
247 static int wpa_config_process_blob(struct wpa_config *config, FILE *f,
248                                    int *line, char *bname)
249 {
250         char *name_end;
251         struct wpa_config_blob *blob;
252
253         name_end = os_strchr(bname, '=');
254         if (name_end == NULL) {
255                 wpa_printf(MSG_ERROR, "Line %d: no blob name terminator",
256                            *line);
257                 return -1;
258         }
259         *name_end = '\0';
260
261         blob = wpa_config_read_blob(f, line, bname);
262         if (blob == NULL) {
263                 wpa_printf(MSG_ERROR, "Line %d: failed to read blob %s",
264                            *line, bname);
265                 return -1;
266         }
267         wpa_config_set_blob(config, blob);
268         return 0;
269 }
270 #endif /* CONFIG_NO_CONFIG_BLOBS */
271
272
273 struct global_parse_data {
274         char *name;
275         int (*parser)(const struct global_parse_data *data,
276                       struct wpa_config *config, int line, const char *value);
277         void *param1, *param2, *param3;
278 };
279
280
281 static int wpa_config_parse_int(const struct global_parse_data *data,
282                                 struct wpa_config *config, int line,
283                                 const char *pos)
284 {
285         int *dst;
286         dst = (int *) (((u8 *) config) + (long) data->param1);
287         *dst = atoi(pos);
288         wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
289         return 0;
290 }
291
292
293 static int wpa_config_parse_str(const struct global_parse_data *data,
294                                 struct wpa_config *config, int line,
295                                 const char *pos)
296 {
297         size_t len;
298         char **dst, *tmp;
299
300         len = os_strlen(pos);
301         if (data->param2 && len < (size_t) data->param2) {
302                 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
303                            "min_len=%ld)", line, data->name,
304                            (unsigned long) len, (long) data->param2);
305                 return -1;
306         }
307
308         if (data->param3 && len > (size_t) data->param3) {
309                 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
310                            "max_len=%ld)", line, data->name,
311                            (unsigned long) len, (long) data->param3);
312                 return -1;
313         }
314
315         tmp = os_strdup(pos);
316         if (tmp == NULL)
317                 return -1;
318
319         dst = (char **) (((u8 *) config) + (long) data->param1);
320         os_free(*dst);
321         *dst = tmp;
322         wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
323
324         return 0;
325 }
326
327
328 static int wpa_config_process_country(const struct global_parse_data *data,
329                                       struct wpa_config *config, int line,
330                                       const char *pos)
331 {
332         if (!pos[0] || !pos[1]) {
333                 wpa_printf(MSG_DEBUG, "Invalid country set");
334                 return -1;
335         }
336         config->country[0] = pos[0];
337         config->country[1] = pos[1];
338         wpa_printf(MSG_DEBUG, "country='%c%c'",
339                    config->country[0], config->country[1]);
340         return 0;
341 }
342
343
344 static int wpa_config_process_eapol_version(
345         const struct global_parse_data *data, struct wpa_config *config,
346         int line, const char *pos)
347 {
348         config->eapol_version = atoi(pos);
349         if (config->eapol_version < 1 || config->eapol_version > 2) {
350                 wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL version (%d): "
351                            "'%s'.", line, config->eapol_version, pos);
352                 return -1;
353         }
354         wpa_printf(MSG_DEBUG, "eapol_version=%d", config->eapol_version);
355         return 0;
356 }
357
358
359 static int wpa_config_process_load_dynamic_eap(
360         const struct global_parse_data *data, struct wpa_config *config,
361         int line, const char *so)
362 {
363         int ret;
364         wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
365         ret = eap_peer_method_load(so);
366         if (ret == -2) {
367                 wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
368                            "reloading.");
369         } else if (ret) {
370                 wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
371                            "method '%s'.", line, so);
372                 return -1;
373         }
374
375         return 0;
376 }
377
378
379 #ifdef CONFIG_WPS
380
381 static int wpa_config_process_uuid(const struct global_parse_data *data,
382                                    struct wpa_config *config, int line,
383                                    const char *pos)
384 {
385         char buf[40];
386         if (uuid_str2bin(pos, config->uuid)) {
387                 wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
388                 return -1;
389         }
390         uuid_bin2str(config->uuid, buf, sizeof(buf));
391         wpa_printf(MSG_DEBUG, "uuid=%s", buf);
392         return 0;
393 }
394
395
396 static int wpa_config_process_os_version(const struct global_parse_data *data,
397                                          struct wpa_config *config, int line,
398                                          const char *pos)
399 {
400         if (hexstr2bin(pos, config->os_version, 4)) {
401                 wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
402                 return -1;
403         }
404         wpa_printf(MSG_DEBUG, "os_version=%08x",
405                    WPA_GET_BE32(config->os_version));
406         return 0;
407 }
408
409 #endif /* CONFIG_WPS */
410
411
412 #ifdef OFFSET
413 #undef OFFSET
414 #endif /* OFFSET */
415 /* OFFSET: Get offset of a variable within the wpa_config structure */
416 #define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
417
418 #define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
419 #define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
420 #define INT(f) #f, wpa_config_parse_int, OFFSET(f), NULL, NULL
421 #define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
422 #define STR(f) _STR(f), NULL, NULL
423 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
424
425 static const struct global_parse_data global_fields[] = {
426 #ifdef CONFIG_CTRL_IFACE
427         { STR(ctrl_interface) },
428         { STR(ctrl_interface_group) } /* deprecated */,
429 #endif /* CONFIG_CTRL_IFACE */
430         { FUNC(eapol_version) },
431         { INT(ap_scan) },
432         { INT(fast_reauth) },
433 #ifdef EAP_TLS_OPENSSL
434         { STR(opensc_engine_path) },
435         { STR(pkcs11_engine_path) },
436         { STR(pkcs11_module_path) },
437 #endif /* EAP_TLS_OPENSSL */
438         { STR(driver_param) },
439         { INT(dot11RSNAConfigPMKLifetime) },
440         { INT(dot11RSNAConfigPMKReauthThreshold) },
441         { INT(dot11RSNAConfigSATimeout) },
442 #ifndef CONFIG_NO_CONFIG_WRITE
443         { INT(update_config) },
444 #endif /* CONFIG_NO_CONFIG_WRITE */
445         { FUNC_NO_VAR(load_dynamic_eap) },
446 #ifdef CONFIG_WPS
447         { FUNC(uuid) },
448         { STR_RANGE(device_name, 0, 32) },
449         { STR_RANGE(manufacturer, 0, 64) },
450         { STR_RANGE(model_name, 0, 32) },
451         { STR_RANGE(model_number, 0, 32) },
452         { STR_RANGE(serial_number, 0, 32) },
453         { STR(device_type) },
454         { FUNC(os_version) },
455 #endif /* CONFIG_WPS */
456         { FUNC(country) }
457 };
458
459 #undef FUNC
460 #undef INT
461 #undef _STR
462 #undef STR
463 #undef STR_RANGE
464 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
465
466
467 static int wpa_config_process_global(struct wpa_config *config, char *pos,
468                                      int line)
469 {
470         size_t i;
471         int ret = 0;
472
473         for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
474                 const struct global_parse_data *field = &global_fields[i];
475                 size_t flen = os_strlen(field->name);
476                 if (os_strncmp(pos, field->name, flen) != 0 ||
477                     pos[flen] != '=')
478                         continue;
479
480                 if (field->parser(field, config, line, pos + flen + 1)) {
481                         wpa_printf(MSG_ERROR, "Line %d: failed to "
482                                    "parse '%s'.", line, pos);
483                         ret = -1;
484                 }
485                 break;
486         }
487         if (i == NUM_GLOBAL_FIELDS) {
488                 wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
489                            line, pos);
490                 ret = -1;
491         }
492
493         return ret;
494 }
495
496
497 struct wpa_config * wpa_config_read(const char *name)
498 {
499         FILE *f;
500         char buf[256], *pos;
501         int errors = 0, line = 0;
502         struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
503         struct wpa_config *config;
504         int id = 0;
505
506         config = wpa_config_alloc_empty(NULL, NULL);
507         if (config == NULL)
508                 return NULL;
509         wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
510         f = fopen(name, "r");
511         if (f == NULL) {
512                 os_free(config);
513                 return NULL;
514         }
515
516         while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
517                 if (os_strcmp(pos, "network={") == 0) {
518                         ssid = wpa_config_read_network(f, &line, id++);
519                         if (ssid == NULL) {
520                                 wpa_printf(MSG_ERROR, "Line %d: failed to "
521                                            "parse network block.", line);
522                                 errors++;
523                                 continue;
524                         }
525                         if (head == NULL) {
526                                 head = tail = ssid;
527                         } else {
528                                 tail->next = ssid;
529                                 tail = ssid;
530                         }
531                         if (wpa_config_add_prio_network(config, ssid)) {
532                                 wpa_printf(MSG_ERROR, "Line %d: failed to add "
533                                            "network block to priority list.",
534                                            line);
535                                 errors++;
536                                 continue;
537                         }
538 #ifndef CONFIG_NO_CONFIG_BLOBS
539                 } else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
540                         if (wpa_config_process_blob(config, f, &line, pos + 12)
541                             < 0) {
542                                 errors++;
543                                 continue;
544                         }
545 #endif /* CONFIG_NO_CONFIG_BLOBS */
546                 } else if (wpa_config_process_global(config, pos, line) < 0) {
547                         wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
548                                    "line '%s'.", line, pos);
549                         errors++;
550                         continue;
551                 }
552         }
553
554         fclose(f);
555
556         config->ssid = head;
557         wpa_config_debug_dump_networks(config);
558
559         if (errors) {
560                 wpa_config_free(config);
561                 config = NULL;
562                 head = NULL;
563         }
564
565         return config;
566 }
567
568
569 #ifndef CONFIG_NO_CONFIG_WRITE
570
571 static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
572 {
573         char *value = wpa_config_get(ssid, field);
574         if (value == NULL)
575                 return;
576         fprintf(f, "\t%s=%s\n", field, value);
577         os_free(value);
578 }
579
580
581 static void write_int(FILE *f, const char *field, int value, int def)
582 {
583         if (value == def)
584                 return;
585         fprintf(f, "\t%s=%d\n", field, value);
586 }
587
588
589 static void write_bssid(FILE *f, struct wpa_ssid *ssid)
590 {
591         char *value = wpa_config_get(ssid, "bssid");
592         if (value == NULL)
593                 return;
594         fprintf(f, "\tbssid=%s\n", value);
595         os_free(value);
596 }
597
598
599 static void write_psk(FILE *f, struct wpa_ssid *ssid)
600 {
601         char *value = wpa_config_get(ssid, "psk");
602         if (value == NULL)
603                 return;
604         fprintf(f, "\tpsk=%s\n", value);
605         os_free(value);
606 }
607
608
609 static void write_proto(FILE *f, struct wpa_ssid *ssid)
610 {
611         char *value;
612
613         if (ssid->proto == DEFAULT_PROTO)
614                 return;
615
616         value = wpa_config_get(ssid, "proto");
617         if (value == NULL)
618                 return;
619         if (value[0])
620                 fprintf(f, "\tproto=%s\n", value);
621         os_free(value);
622 }
623
624
625 static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
626 {
627         char *value;
628
629         if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
630                 return;
631
632         value = wpa_config_get(ssid, "key_mgmt");
633         if (value == NULL)
634                 return;
635         if (value[0])
636                 fprintf(f, "\tkey_mgmt=%s\n", value);
637         os_free(value);
638 }
639
640
641 static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
642 {
643         char *value;
644
645         if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
646                 return;
647
648         value = wpa_config_get(ssid, "pairwise");
649         if (value == NULL)
650                 return;
651         if (value[0])
652                 fprintf(f, "\tpairwise=%s\n", value);
653         os_free(value);
654 }
655
656
657 static void write_group(FILE *f, struct wpa_ssid *ssid)
658 {
659         char *value;
660
661         if (ssid->group_cipher == DEFAULT_GROUP)
662                 return;
663
664         value = wpa_config_get(ssid, "group");
665         if (value == NULL)
666                 return;
667         if (value[0])
668                 fprintf(f, "\tgroup=%s\n", value);
669         os_free(value);
670 }
671
672
673 static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
674 {
675         char *value;
676
677         if (ssid->auth_alg == 0)
678                 return;
679
680         value = wpa_config_get(ssid, "auth_alg");
681         if (value == NULL)
682                 return;
683         if (value[0])
684                 fprintf(f, "\tauth_alg=%s\n", value);
685         os_free(value);
686 }
687
688
689 #ifdef IEEE8021X_EAPOL
690 static void write_eap(FILE *f, struct wpa_ssid *ssid)
691 {
692         char *value;
693
694         value = wpa_config_get(ssid, "eap");
695         if (value == NULL)
696                 return;
697
698         if (value[0])
699                 fprintf(f, "\teap=%s\n", value);
700         os_free(value);
701 }
702 #endif /* IEEE8021X_EAPOL */
703
704
705 static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
706 {
707         char field[20], *value;
708         int res;
709
710         res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
711         if (res < 0 || (size_t) res >= sizeof(field))
712                 return;
713         value = wpa_config_get(ssid, field);
714         if (value) {
715                 fprintf(f, "\t%s=%s\n", field, value);
716                 os_free(value);
717         }
718 }
719
720
721 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
722 {
723         int i;
724
725 #define STR(t) write_str(f, #t, ssid)
726 #define INT(t) write_int(f, #t, ssid->t, 0)
727 #define INTe(t) write_int(f, #t, ssid->eap.t, 0)
728 #define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
729 #define INT_DEFe(t, def) write_int(f, #t, ssid->eap.t, def)
730
731         STR(ssid);
732         INT(scan_ssid);
733         write_bssid(f, ssid);
734         write_psk(f, ssid);
735         write_proto(f, ssid);
736         write_key_mgmt(f, ssid);
737         write_pairwise(f, ssid);
738         write_group(f, ssid);
739         write_auth_alg(f, ssid);
740 #ifdef IEEE8021X_EAPOL
741         write_eap(f, ssid);
742         STR(identity);
743         STR(anonymous_identity);
744         STR(password);
745         STR(ca_cert);
746         STR(ca_path);
747         STR(client_cert);
748         STR(private_key);
749         STR(private_key_passwd);
750         STR(dh_file);
751         STR(subject_match);
752         STR(altsubject_match);
753         STR(ca_cert2);
754         STR(ca_path2);
755         STR(client_cert2);
756         STR(private_key2);
757         STR(private_key2_passwd);
758         STR(dh_file2);
759         STR(subject_match2);
760         STR(altsubject_match2);
761         STR(phase1);
762         STR(phase2);
763         STR(pcsc);
764         STR(pin);
765         STR(engine_id);
766         STR(key_id);
767         STR(cert_id);
768         STR(ca_cert_id);
769         STR(key2_id);
770         STR(pin2);
771         STR(engine2_id);
772         STR(cert2_id);
773         STR(ca_cert2_id);
774         INTe(engine);
775         INTe(engine2);
776         INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
777 #endif /* IEEE8021X_EAPOL */
778         for (i = 0; i < 4; i++)
779                 write_wep_key(f, i, ssid);
780         INT(wep_tx_keyidx);
781         INT(priority);
782 #ifdef IEEE8021X_EAPOL
783         INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
784         STR(pac_file);
785         INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
786 #endif /* IEEE8021X_EAPOL */
787         INT(mode);
788         INT(proactive_key_caching);
789         INT(disabled);
790         INT(peerkey);
791 #ifdef CONFIG_IEEE80211W
792         INT(ieee80211w);
793 #endif /* CONFIG_IEEE80211W */
794         STR(id_str);
795
796 #undef STR
797 #undef INT
798 #undef INT_DEF
799 }
800
801
802 #ifndef CONFIG_NO_CONFIG_BLOBS
803 static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
804 {
805         unsigned char *encoded;
806
807         encoded = base64_encode(blob->data, blob->len, NULL);
808         if (encoded == NULL)
809                 return -1;
810
811         fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
812         os_free(encoded);
813         return 0;
814 }
815 #endif /* CONFIG_NO_CONFIG_BLOBS */
816
817
818 static void wpa_config_write_global(FILE *f, struct wpa_config *config)
819 {
820 #ifdef CONFIG_CTRL_IFACE
821         if (config->ctrl_interface)
822                 fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
823         if (config->ctrl_interface_group)
824                 fprintf(f, "ctrl_interface_group=%s\n",
825                         config->ctrl_interface_group);
826 #endif /* CONFIG_CTRL_IFACE */
827         if (config->eapol_version != DEFAULT_EAPOL_VERSION)
828                 fprintf(f, "eapol_version=%d\n", config->eapol_version);
829         if (config->ap_scan != DEFAULT_AP_SCAN)
830                 fprintf(f, "ap_scan=%d\n", config->ap_scan);
831         if (config->fast_reauth != DEFAULT_FAST_REAUTH)
832                 fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
833 #ifdef EAP_TLS_OPENSSL
834         if (config->opensc_engine_path)
835                 fprintf(f, "opensc_engine_path=%s\n",
836                         config->opensc_engine_path);
837         if (config->pkcs11_engine_path)
838                 fprintf(f, "pkcs11_engine_path=%s\n",
839                         config->pkcs11_engine_path);
840         if (config->pkcs11_module_path)
841                 fprintf(f, "pkcs11_module_path=%s\n",
842                         config->pkcs11_module_path);
843 #endif /* EAP_TLS_OPENSSL */
844         if (config->driver_param)
845                 fprintf(f, "driver_param=%s\n", config->driver_param);
846         if (config->dot11RSNAConfigPMKLifetime)
847                 fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
848                         config->dot11RSNAConfigPMKLifetime);
849         if (config->dot11RSNAConfigPMKReauthThreshold)
850                 fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
851                         config->dot11RSNAConfigPMKReauthThreshold);
852         if (config->dot11RSNAConfigSATimeout)
853                 fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
854                         config->dot11RSNAConfigSATimeout);
855         if (config->update_config)
856                 fprintf(f, "update_config=%d\n", config->update_config);
857 #ifdef CONFIG_WPS
858         if (is_nil_uuid(config->uuid)) {
859                 char buf[40];
860                 uuid_bin2str(config->uuid, buf, sizeof(buf));
861                 fprintf(f, "uuid=%s\n", buf);
862         }
863         if (config->device_name)
864                 fprintf(f, "device_name=%s\n", config->device_name);
865         if (config->manufacturer)
866                 fprintf(f, "manufacturer=%s\n", config->manufacturer);
867         if (config->model_name)
868                 fprintf(f, "model_name=%s\n", config->model_name);
869         if (config->model_number)
870                 fprintf(f, "model_number=%s\n", config->model_number);
871         if (config->serial_number)
872                 fprintf(f, "serial_number=%s\n", config->serial_number);
873         if (config->device_type)
874                 fprintf(f, "device_type=%s\n", config->device_type);
875         if (config->os_version)
876                 fprintf(f, "os_version=%08x\n",
877                         WPA_GET_BE32(config->os_version));
878 #endif /* CONFIG_WPS */
879         if (config->country[0] && config->country[1]) {
880                 fprintf(f, "country=%c%c\n",
881                         config->country[0], config->country[1]);
882         }
883 }
884
885 #endif /* CONFIG_NO_CONFIG_WRITE */
886
887
888 int wpa_config_write(const char *name, struct wpa_config *config)
889 {
890 #ifndef CONFIG_NO_CONFIG_WRITE
891         FILE *f;
892         struct wpa_ssid *ssid;
893 #ifndef CONFIG_NO_CONFIG_BLOBS
894         struct wpa_config_blob *blob;
895 #endif /* CONFIG_NO_CONFIG_BLOBS */
896         int ret = 0;
897
898         wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
899
900         f = fopen(name, "w");
901         if (f == NULL) {
902                 wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
903                 return -1;
904         }
905
906         wpa_config_write_global(f, config);
907
908         for (ssid = config->ssid; ssid; ssid = ssid->next) {
909                 if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
910                         continue; /* do not save temporary WPS networks */
911                 fprintf(f, "\nnetwork={\n");
912                 wpa_config_write_network(f, ssid);
913                 fprintf(f, "}\n");
914         }
915
916 #ifndef CONFIG_NO_CONFIG_BLOBS
917         for (blob = config->blobs; blob; blob = blob->next) {
918                 ret = wpa_config_write_blob(f, blob);
919                 if (ret)
920                         break;
921         }
922 #endif /* CONFIG_NO_CONFIG_BLOBS */
923
924         fclose(f);
925
926         wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
927                    name, ret ? "un" : "");
928         return ret;
929 #else /* CONFIG_NO_CONFIG_WRITE */
930         return -1;
931 #endif /* CONFIG_NO_CONFIG_WRITE */
932 }