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