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