OSDN Git Service

am be5cce4a: Check if interface is valid in wpa_ctrl_close()
[android-x86/external-wpa_supplicant.git] / config_file.c
1 /*
2  * WPA Supplicant / Configuration backend: text file
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 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 "eap_methods.h"
25
26 #include <sys/stat.h>
27
28
29 /**
30  * wpa_config_get_line - Read the next configuration file line
31  * @s: Buffer for the line
32  * @size: The buffer length
33  * @stream: File stream to read from
34  * @line: Pointer to a variable storing the file line number
35  * @_pos: Buffer for the pointer to the beginning of data on the text line or
36  * %NULL if not needed (returned value used instead)
37  * Returns: Pointer to the beginning of data on the text line or %NULL if no
38  * more text lines are available.
39  *
40  * This function reads the next non-empty line from the configuration file and
41  * removes comments. The returned string is guaranteed to be null-terminated.
42  */
43 static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
44                                   char **_pos)
45 {
46         char *pos, *end, *sstart;
47
48         while (fgets(s, size, stream)) {
49                 (*line)++;
50                 s[size - 1] = '\0';
51                 pos = s;
52
53                 /* Skip white space from the beginning of line. */
54                 while (*pos == ' ' || *pos == '\t' || *pos == '\r')
55                         pos++;
56
57                 /* Skip comment lines and empty lines */
58                 if (*pos == '#' || *pos == '\n' || *pos == '\0')
59                         continue;
60
61                 /*
62                  * Remove # comments unless they are within a double quoted
63                  * string.
64                  */
65                 sstart = os_strchr(pos, '"');
66                 if (sstart)
67                         sstart = os_strrchr(sstart + 1, '"');
68                 if (!sstart)
69                         sstart = pos;
70                 end = os_strchr(sstart, '#');
71                 if (end)
72                         *end-- = '\0';
73                 else
74                         end = pos + os_strlen(pos) - 1;
75
76                 /* Remove trailing white space. */
77                 while (end > pos &&
78                        (*end == '\n' || *end == ' ' || *end == '\t' ||
79                         *end == '\r'))
80                         *end-- = '\0';
81
82                 if (*pos == '\0')
83                         continue;
84
85                 if (_pos)
86                         *_pos = pos;
87                 return pos;
88         }
89
90         if (_pos)
91                 *_pos = NULL;
92         return NULL;
93 }
94
95
96 static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
97 {
98         int errors = 0;
99
100         if (ssid->passphrase) {
101                 if (ssid->psk_set) {
102                         wpa_printf(MSG_ERROR, "Line %d: both PSK and "
103                                    "passphrase configured.", line);
104                         errors++;
105                 }
106                 wpa_config_update_psk(ssid);
107         }
108
109         if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
110                 wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
111                            "management, but no PSK configured.", line);
112                 errors++;
113         }
114
115         if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
116             !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
117             !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
118                 /* Group cipher cannot be stronger than the pairwise cipher. */
119                 wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
120                            " list since it was not allowed for pairwise "
121                            "cipher", line);
122                 ssid->group_cipher &= ~WPA_CIPHER_CCMP;
123         }
124
125         return errors;
126 }
127
128
129 static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
130 {
131         struct wpa_ssid *ssid;
132         int errors = 0, end = 0;
133         char buf[256], *pos, *pos2;
134
135         wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
136                    *line);
137         ssid = os_zalloc(sizeof(*ssid));
138         if (ssid == NULL)
139                 return NULL;
140         ssid->id = id;
141
142         wpa_config_set_network_defaults(ssid);
143
144         while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
145                 if (os_strcmp(pos, "}") == 0) {
146                         end = 1;
147                         break;
148                 }
149
150                 pos2 = os_strchr(pos, '=');
151                 if (pos2 == NULL) {
152                         wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
153                                    "'%s'.", *line, pos);
154                         errors++;
155                         continue;
156                 }
157
158                 *pos2++ = '\0';
159                 if (*pos2 == '"') {
160                         if (os_strchr(pos2 + 1, '"') == NULL) {
161                                 wpa_printf(MSG_ERROR, "Line %d: invalid "
162                                            "quotation '%s'.", *line, pos2);
163                                 errors++;
164                                 continue;
165                         }
166                 }
167
168                 if (wpa_config_set(ssid, pos, pos2, *line) < 0)
169                         errors++;
170         }
171
172         if (!end) {
173                 wpa_printf(MSG_ERROR, "Line %d: network block was not "
174                            "terminated properly.", *line);
175                 errors++;
176         }
177
178         errors += wpa_config_validate_network(ssid, *line);
179
180         if (errors) {
181                 wpa_config_free_ssid(ssid);
182                 ssid = NULL;
183         }
184
185         return ssid;
186 }
187
188
189 static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
190                                                      const char *name)
191 {
192         struct wpa_config_blob *blob;
193         char buf[256], *pos;
194         unsigned char *encoded = NULL, *nencoded;
195         int end = 0;
196         size_t encoded_len = 0, len;
197
198         wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
199                    *line, name);
200
201         while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
202                 if (os_strcmp(pos, "}") == 0) {
203                         end = 1;
204                         break;
205                 }
206
207                 len = os_strlen(pos);
208                 nencoded = os_realloc(encoded, encoded_len + len);
209                 if (nencoded == NULL) {
210                         wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
211                                    "blob", *line);
212                         os_free(encoded);
213                         return NULL;
214                 }
215                 encoded = nencoded;
216                 os_memcpy(encoded + encoded_len, pos, len);
217                 encoded_len += len;
218         }
219
220         if (!end) {
221                 wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
222                            "properly", *line);
223                 os_free(encoded);
224                 return NULL;
225         }
226
227         blob = os_zalloc(sizeof(*blob));
228         if (blob == NULL) {
229                 os_free(encoded);
230                 return NULL;
231         }
232         blob->name = os_strdup(name);
233         blob->data = base64_decode(encoded, encoded_len, &blob->len);
234         os_free(encoded);
235
236         if (blob->name == NULL || blob->data == NULL) {
237                 wpa_config_free_blob(blob);
238                 return NULL;
239         }
240
241         return blob;
242 }
243
244
245 struct wpa_config * wpa_config_read(const char *name)
246 {
247         FILE *f;
248         char buf[256], *pos;
249         int errors = 0, line = 0;
250         struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
251         struct wpa_config *config;
252         int id = 0;
253
254         config = wpa_config_alloc_empty(NULL, NULL);
255         if (config == NULL)
256                 return NULL;
257         wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
258         f = fopen(name, "r");
259         if (f == NULL) {
260                 os_free(config);
261                 return NULL;
262         }
263         /* When creating the config file, give group read/write access
264          * to allow backup and restoring the file.
265          */
266         chmod(name, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
267
268         while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
269                 if (os_strcmp(pos, "network={") == 0) {
270                         ssid = wpa_config_read_network(f, &line, id++);
271                         if (ssid == NULL) {
272                                 wpa_printf(MSG_ERROR, "Line %d: failed to "
273                                            "parse network block.", line);
274 #ifndef WPA_IGNORE_CONFIG_ERRORS
275                                 errors++;
276 #endif
277                                 continue;
278                         }
279                         if (head == NULL) {
280                                 head = tail = ssid;
281                         } else {
282                                 tail->next = ssid;
283                                 tail = ssid;
284                         }
285                         if (wpa_config_add_prio_network(config, ssid)) {
286                                 wpa_printf(MSG_ERROR, "Line %d: failed to add "
287                                            "network block to priority list.",
288                                            line);
289                                 errors++;
290                                 continue;
291                         }
292                 } else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
293                         char *bname = pos + 12, *name_end;
294                         struct wpa_config_blob *blob;
295
296                         name_end = os_strchr(bname, '=');
297                         if (name_end == NULL) {
298                                 wpa_printf(MSG_ERROR, "Line %d: no blob name "
299                                            "terminator", line);
300                                 errors++;
301                                 continue;
302                         }
303                         *name_end = '\0';
304
305                         blob = wpa_config_read_blob(f, &line, bname);
306                         if (blob == NULL) {
307                                 wpa_printf(MSG_ERROR, "Line %d: failed to read"
308                                            " blob %s", line, bname);
309                                 errors++;
310                                 continue;
311                         }
312                         wpa_config_set_blob(config, blob);
313 #ifdef CONFIG_CTRL_IFACE
314                 } else if (os_strncmp(pos, "ctrl_interface=", 15) == 0) {
315                         os_free(config->ctrl_interface);
316                         config->ctrl_interface = os_strdup(pos + 15);
317                         wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
318                                    config->ctrl_interface);
319                 } else if (os_strncmp(pos, "ctrl_interface_group=", 21) == 0) {
320                         os_free(config->ctrl_interface_group);
321                         config->ctrl_interface_group = os_strdup(pos + 21);
322                         wpa_printf(MSG_DEBUG, "ctrl_interface_group='%s' "
323                                    "(DEPRECATED)",
324                                    config->ctrl_interface_group);
325 #endif /* CONFIG_CTRL_IFACE */
326                 } else if (os_strncmp(pos, "eapol_version=", 14) == 0) {
327                         config->eapol_version = atoi(pos + 14);
328                         if (config->eapol_version < 1 ||
329                             config->eapol_version > 2) {
330                                 wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
331                                            "version (%d): '%s'.",
332                                            line, config->eapol_version, pos);
333                                 errors++;
334                                 continue;
335                         }
336                         wpa_printf(MSG_DEBUG, "eapol_version=%d",
337                                    config->eapol_version);
338                 } else if (os_strncmp(pos, "ap_scan=", 8) == 0) {
339                         config->ap_scan = atoi(pos + 8);
340                         wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
341                 } else if (os_strncmp(pos, "fast_reauth=", 12) == 0) {
342                         config->fast_reauth = atoi(pos + 12);
343                         wpa_printf(MSG_DEBUG, "fast_reauth=%d",
344                                    config->fast_reauth);
345                 } else if (os_strncmp(pos, "opensc_engine_path=", 19) == 0) {
346                         os_free(config->opensc_engine_path);
347                         config->opensc_engine_path = os_strdup(pos + 19);
348                         wpa_printf(MSG_DEBUG, "opensc_engine_path='%s'",
349                                    config->opensc_engine_path);
350                 } else if (os_strncmp(pos, "pkcs11_engine_path=", 19) == 0) {
351                         os_free(config->pkcs11_engine_path);
352                         config->pkcs11_engine_path = os_strdup(pos + 19);
353                         wpa_printf(MSG_DEBUG, "pkcs11_engine_path='%s'",
354                                    config->pkcs11_engine_path);
355                 } else if (os_strncmp(pos, "pkcs11_module_path=", 19) == 0) {
356                         os_free(config->pkcs11_module_path);
357                         config->pkcs11_module_path = os_strdup(pos + 19);
358                         wpa_printf(MSG_DEBUG, "pkcs11_module_path='%s'",
359                                    config->pkcs11_module_path);
360                 } else if (os_strncmp(pos, "driver_param=", 13) == 0) {
361                         os_free(config->driver_param);
362                         config->driver_param = os_strdup(pos + 13);
363                         wpa_printf(MSG_DEBUG, "driver_param='%s'",
364                                    config->driver_param);
365                 } else if (os_strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27)
366                            == 0) {
367                         config->dot11RSNAConfigPMKLifetime = atoi(pos + 27);
368                         wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKLifetime=%d",
369                                    config->dot11RSNAConfigPMKLifetime);
370                 } else if (os_strncmp(pos,
371                                       "dot11RSNAConfigPMKReauthThreshold=", 34)
372                            == 0) {
373                         config->dot11RSNAConfigPMKReauthThreshold =
374                                 atoi(pos + 34);
375                         wpa_printf(MSG_DEBUG,
376                                    "dot11RSNAConfigPMKReauthThreshold=%d",
377                                    config->dot11RSNAConfigPMKReauthThreshold);
378                 } else if (os_strncmp(pos, "dot11RSNAConfigSATimeout=", 25) ==
379                            0) {
380                         config->dot11RSNAConfigSATimeout = atoi(pos + 25);
381                         wpa_printf(MSG_DEBUG, "dot11RSNAConfigSATimeout=%d",
382                                    config->dot11RSNAConfigSATimeout);
383                 } else if (os_strncmp(pos, "update_config=", 14) == 0) {
384                         config->update_config = atoi(pos + 14);
385                         wpa_printf(MSG_DEBUG, "update_config=%d",
386                                    config->update_config);
387                 } else if (os_strncmp(pos, "load_dynamic_eap=", 17) == 0) {
388                         char *so = pos + 17;
389                         int ret;
390                         wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
391                         ret = eap_peer_method_load(so);
392                         if (ret == -2) {
393                                 wpa_printf(MSG_DEBUG, "This EAP type was "
394                                            "already loaded - not reloading.");
395                         } else if (ret) {
396                                 wpa_printf(MSG_ERROR, "Line %d: Failed to "
397                                            "load dynamic EAP method '%s'.",
398                                            line, so);
399                                 errors++;
400                         }
401                 } else {
402                         wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
403                                    "line '%s'.", line, pos);
404                         errors++;
405                         continue;
406                 }
407         }
408
409         fclose(f);
410
411         config->ssid = head;
412         wpa_config_debug_dump_networks(config);
413
414 #ifndef WPA_IGNORE_CONFIG_ERRORS
415         if (errors) {
416                 wpa_config_free(config);
417                 config = NULL;
418                 head = NULL;
419         }
420 #endif
421         return config;
422 }
423
424
425 static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
426 {
427         char *value = wpa_config_get(ssid, field);
428         if (value == NULL)
429                 return;
430         fprintf(f, "\t%s=%s\n", field, value);
431         os_free(value);
432 }
433
434
435 static void write_int(FILE *f, const char *field, int value, int def)
436 {
437         if (value == def)
438                 return;
439         fprintf(f, "\t%s=%d\n", field, value);
440 }
441
442
443 static void write_bssid(FILE *f, struct wpa_ssid *ssid)
444 {
445         char *value = wpa_config_get(ssid, "bssid");
446         if (value == NULL)
447                 return;
448         fprintf(f, "\tbssid=%s\n", value);
449         os_free(value);
450 }
451
452
453 static void write_psk(FILE *f, struct wpa_ssid *ssid)
454 {
455         char *value = wpa_config_get(ssid, "psk");
456         if (value == NULL)
457                 return;
458         fprintf(f, "\tpsk=%s\n", value);
459         os_free(value);
460 }
461
462
463 static void write_proto(FILE *f, struct wpa_ssid *ssid)
464 {
465         char *value;
466
467         if (ssid->proto == DEFAULT_PROTO)
468                 return;
469
470         value = wpa_config_get(ssid, "proto");
471         if (value == NULL)
472                 return;
473         if (value[0])
474                 fprintf(f, "\tproto=%s\n", value);
475         os_free(value);
476 }
477
478
479 static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
480 {
481         char *value;
482
483         if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
484                 return;
485
486         value = wpa_config_get(ssid, "key_mgmt");
487         if (value == NULL)
488                 return;
489         if (value[0])
490                 fprintf(f, "\tkey_mgmt=%s\n", value);
491         os_free(value);
492 }
493
494
495 static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
496 {
497         char *value;
498
499         if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
500                 return;
501
502         value = wpa_config_get(ssid, "pairwise");
503         if (value == NULL)
504                 return;
505         if (value[0])
506                 fprintf(f, "\tpairwise=%s\n", value);
507         os_free(value);
508 }
509
510
511 static void write_group(FILE *f, struct wpa_ssid *ssid)
512 {
513         char *value;
514
515         if (ssid->group_cipher == DEFAULT_GROUP)
516                 return;
517
518         value = wpa_config_get(ssid, "group");
519         if (value == NULL)
520                 return;
521         if (value[0])
522                 fprintf(f, "\tgroup=%s\n", value);
523         os_free(value);
524 }
525
526
527 static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
528 {
529         char *value;
530
531         if (ssid->auth_alg == 0)
532                 return;
533
534         value = wpa_config_get(ssid, "auth_alg");
535         if (value == NULL)
536                 return;
537         if (value[0])
538                 fprintf(f, "\tauth_alg=%s\n", value);
539         os_free(value);
540 }
541
542
543 #ifdef IEEE8021X_EAPOL
544 static void write_eap(FILE *f, struct wpa_ssid *ssid)
545 {
546         char *value;
547
548         value = wpa_config_get(ssid, "eap");
549         if (value == NULL)
550                 return;
551
552         if (value[0])
553                 fprintf(f, "\teap=%s\n", value);
554         os_free(value);
555 }
556 #endif /* IEEE8021X_EAPOL */
557
558
559 static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
560 {
561         char field[20], *value;
562
563         os_snprintf(field, sizeof(field), "wep_key%d", idx);
564         value = wpa_config_get(ssid, field);
565         if (value) {
566                 fprintf(f, "\t%s=%s\n", field, value);
567                 os_free(value);
568         }
569 }
570
571
572 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
573 {
574         int i;
575
576 #define STR(t) write_str(f, #t, ssid)
577 #define INT(t) write_int(f, #t, ssid->t, 0)
578 #define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
579
580         STR(ssid);
581         INT(scan_ssid);
582         write_bssid(f, ssid);
583         write_psk(f, ssid);
584         write_proto(f, ssid);
585         write_key_mgmt(f, ssid);
586         write_pairwise(f, ssid);
587         write_group(f, ssid);
588         write_auth_alg(f, ssid);
589 #ifdef IEEE8021X_EAPOL
590         write_eap(f, ssid);
591         STR(identity);
592         STR(anonymous_identity);
593         STR(eappsk);
594         STR(nai);
595         STR(password);
596         STR(ca_cert);
597         STR(ca_path);
598         STR(client_cert);
599         STR(private_key);
600         STR(private_key_passwd);
601         STR(dh_file);
602         STR(subject_match);
603         STR(altsubject_match);
604         STR(ca_cert2);
605         STR(ca_path2);
606         STR(client_cert2);
607         STR(private_key2);
608         STR(private_key2_passwd);
609         STR(dh_file2);
610         STR(subject_match2);
611         STR(altsubject_match2);
612         STR(phase1);
613         STR(phase2);
614         STR(pcsc);
615         STR(pin);
616         STR(engine_id);
617         STR(key_id);
618         INT(engine);
619         INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
620 #endif /* IEEE8021X_EAPOL */
621         for (i = 0; i < 4; i++)
622                 write_wep_key(f, i, ssid);
623         INT(wep_tx_keyidx);
624         INT(priority);
625 #ifdef IEEE8021X_EAPOL
626         INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
627         STR(pac_file);
628         INT_DEF(fragment_size, DEFAULT_FRAGMENT_SIZE);
629 #endif /* IEEE8021X_EAPOL */
630         INT(mode);
631         INT(proactive_key_caching);
632         INT(disabled);
633         INT(peerkey);
634 #ifdef CONFIG_IEEE80211W
635         INT(ieee80211w);
636 #endif /* CONFIG_IEEE80211W */
637         STR(id_str);
638
639 #undef STR
640 #undef INT
641 #undef INT_DEF
642 }
643
644
645 static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
646 {
647         unsigned char *encoded;
648
649         encoded = base64_encode(blob->data, blob->len, NULL);
650         if (encoded == NULL)
651                 return -1;
652
653         fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
654         os_free(encoded);
655         return 0;
656 }
657
658
659 static void wpa_config_write_global(FILE *f, struct wpa_config *config)
660 {
661 #ifdef CONFIG_CTRL_IFACE
662         if (config->ctrl_interface)
663                 fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
664         if (config->ctrl_interface_group)
665                 fprintf(f, "ctrl_interface_group=%s\n",
666                         config->ctrl_interface_group);
667 #endif /* CONFIG_CTRL_IFACE */
668         if (config->eapol_version != DEFAULT_EAPOL_VERSION)
669                 fprintf(f, "eapol_version=%d\n", config->eapol_version);
670         if (config->ap_scan != DEFAULT_AP_SCAN)
671                 fprintf(f, "ap_scan=%d\n", config->ap_scan);
672         if (config->fast_reauth != DEFAULT_FAST_REAUTH)
673                 fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
674         if (config->opensc_engine_path)
675                 fprintf(f, "opensc_engine_path=%s\n",
676                         config->opensc_engine_path);
677         if (config->pkcs11_engine_path)
678                 fprintf(f, "pkcs11_engine_path=%s\n",
679                         config->pkcs11_engine_path);
680         if (config->pkcs11_module_path)
681                 fprintf(f, "pkcs11_module_path=%s\n",
682                         config->pkcs11_module_path);
683         if (config->driver_param)
684                 fprintf(f, "driver_param=%s\n", config->driver_param);
685         if (config->dot11RSNAConfigPMKLifetime)
686                 fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
687                         config->dot11RSNAConfigPMKLifetime);
688         if (config->dot11RSNAConfigPMKReauthThreshold)
689                 fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
690                         config->dot11RSNAConfigPMKReauthThreshold);
691         if (config->dot11RSNAConfigSATimeout)
692                 fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
693                         config->dot11RSNAConfigSATimeout);
694         if (config->update_config)
695                 fprintf(f, "update_config=%d\n", config->update_config);
696 }
697
698
699 int wpa_config_write(const char *name, struct wpa_config *config)
700 {
701         FILE *f;
702         struct wpa_ssid *ssid;
703         struct wpa_config_blob *blob;
704         int ret = 0;
705
706         wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
707
708         f = fopen(name, "w");
709         if (f == NULL) {
710                 wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
711                 return -1;
712         }
713
714         wpa_config_write_global(f, config);
715
716         for (ssid = config->ssid; ssid; ssid = ssid->next) {
717                 fprintf(f, "\nnetwork={\n");
718                 wpa_config_write_network(f, ssid);
719                 fprintf(f, "}\n");
720         }
721
722         for (blob = config->blobs; blob; blob = blob->next) {
723                 ret = wpa_config_write_blob(f, blob);
724                 if (ret)
725                         break;
726         }
727
728         fclose(f);
729
730         wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
731                    name, ret ? "un" : "");
732         return ret;
733 }