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