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