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