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