1189251Ssam/* 2189251Ssam * WPA Supplicant / Configuration parser and common functions 3189251Ssam * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5189251Ssam * This program is free software; you can redistribute it and/or modify 6189251Ssam * it under the terms of the GNU General Public License version 2 as 7189251Ssam * published by the Free Software Foundation. 8189251Ssam * 9189251Ssam * Alternatively, this software may be distributed under the terms of BSD 10189251Ssam * license. 11189251Ssam * 12189251Ssam * See README and COPYING for more details. 13189251Ssam */ 14189251Ssam 15189251Ssam#include "includes.h" 16189251Ssam 17189251Ssam#include "common.h" 18214734Srpaulo#include "crypto/sha1.h" 19214734Srpaulo#include "rsn_supp/wpa.h" 20189251Ssam#include "eap_peer/eap.h" 21189251Ssam#include "config.h" 22189251Ssam 23189251Ssam 24189251Ssam#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE) 25189251Ssam#define NO_CONFIG_WRITE 26189251Ssam#endif 27189251Ssam 28189251Ssam/* 29189251Ssam * Structure for network configuration parsing. This data is used to implement 30189251Ssam * a generic parser for each network block variable. The table of configuration 31189251Ssam * variables is defined below in this file (ssid_fields[]). 32189251Ssam */ 33189251Ssamstruct parse_data { 34189251Ssam /* Configuration variable name */ 35189251Ssam char *name; 36189251Ssam 37189251Ssam /* Parser function for this variable */ 38189251Ssam int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid, 39189251Ssam int line, const char *value); 40189251Ssam 41189251Ssam#ifndef NO_CONFIG_WRITE 42189251Ssam /* Writer function (i.e., to get the variable in text format from 43189251Ssam * internal presentation). */ 44189251Ssam char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid); 45189251Ssam#endif /* NO_CONFIG_WRITE */ 46189251Ssam 47189251Ssam /* Variable specific parameters for the parser. */ 48189251Ssam void *param1, *param2, *param3, *param4; 49189251Ssam 50189251Ssam /* 0 = this variable can be included in debug output and ctrl_iface 51189251Ssam * 1 = this variable contains key/private data and it must not be 52189251Ssam * included in debug output unless explicitly requested. In 53189251Ssam * addition, this variable will not be readable through the 54189251Ssam * ctrl_iface. 55189251Ssam */ 56189251Ssam int key_data; 57189251Ssam}; 58189251Ssam 59189251Ssam 60189251Ssamstatic char * wpa_config_parse_string(const char *value, size_t *len) 61189251Ssam{ 62189251Ssam if (*value == '"') { 63189251Ssam const char *pos; 64189251Ssam char *str; 65189251Ssam value++; 66189251Ssam pos = os_strrchr(value, '"'); 67189251Ssam if (pos == NULL || pos[1] != '\0') 68189251Ssam return NULL; 69189251Ssam *len = pos - value; 70189251Ssam str = os_malloc(*len + 1); 71189251Ssam if (str == NULL) 72189251Ssam return NULL; 73189251Ssam os_memcpy(str, value, *len); 74189251Ssam str[*len] = '\0'; 75189251Ssam return str; 76189251Ssam } else { 77189251Ssam u8 *str; 78189251Ssam size_t tlen, hlen = os_strlen(value); 79189251Ssam if (hlen & 1) 80189251Ssam return NULL; 81189251Ssam tlen = hlen / 2; 82189251Ssam str = os_malloc(tlen + 1); 83189251Ssam if (str == NULL) 84189251Ssam return NULL; 85189251Ssam if (hexstr2bin(value, str, tlen)) { 86189251Ssam os_free(str); 87189251Ssam return NULL; 88189251Ssam } 89189251Ssam str[tlen] = '\0'; 90189251Ssam *len = tlen; 91189251Ssam return (char *) str; 92189251Ssam } 93189251Ssam} 94189251Ssam 95189251Ssam 96189251Ssamstatic int wpa_config_parse_str(const struct parse_data *data, 97189251Ssam struct wpa_ssid *ssid, 98189251Ssam int line, const char *value) 99189251Ssam{ 100189251Ssam size_t res_len, *dst_len; 101189251Ssam char **dst, *tmp; 102189251Ssam 103189251Ssam if (os_strcmp(value, "NULL") == 0) { 104189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string '%s'", 105189251Ssam data->name); 106189251Ssam tmp = NULL; 107189251Ssam res_len = 0; 108189251Ssam goto set; 109189251Ssam } 110189251Ssam 111189251Ssam tmp = wpa_config_parse_string(value, &res_len); 112189251Ssam if (tmp == NULL) { 113189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.", 114189251Ssam line, data->name, 115189251Ssam data->key_data ? "[KEY DATA REMOVED]" : value); 116189251Ssam return -1; 117189251Ssam } 118189251Ssam 119189251Ssam if (data->key_data) { 120189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 121189251Ssam (u8 *) tmp, res_len); 122189251Ssam } else { 123189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, data->name, 124189251Ssam (u8 *) tmp, res_len); 125189251Ssam } 126189251Ssam 127189251Ssam if (data->param3 && res_len < (size_t) data->param3) { 128189251Ssam wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu " 129189251Ssam "min_len=%ld)", line, data->name, 130189251Ssam (unsigned long) res_len, (long) data->param3); 131189251Ssam os_free(tmp); 132189251Ssam return -1; 133189251Ssam } 134189251Ssam 135189251Ssam if (data->param4 && res_len > (size_t) data->param4) { 136189251Ssam wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu " 137189251Ssam "max_len=%ld)", line, data->name, 138189251Ssam (unsigned long) res_len, (long) data->param4); 139189251Ssam os_free(tmp); 140189251Ssam return -1; 141189251Ssam } 142189251Ssam 143189251Ssamset: 144189251Ssam dst = (char **) (((u8 *) ssid) + (long) data->param1); 145189251Ssam dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2); 146189251Ssam os_free(*dst); 147189251Ssam *dst = tmp; 148189251Ssam if (data->param2) 149189251Ssam *dst_len = res_len; 150189251Ssam 151189251Ssam return 0; 152189251Ssam} 153189251Ssam 154189251Ssam 155189251Ssam#ifndef NO_CONFIG_WRITE 156189251Ssamstatic int is_hex(const u8 *data, size_t len) 157189251Ssam{ 158189251Ssam size_t i; 159189251Ssam 160189251Ssam for (i = 0; i < len; i++) { 161189251Ssam if (data[i] < 32 || data[i] >= 127) 162189251Ssam return 1; 163189251Ssam } 164189251Ssam return 0; 165189251Ssam} 166189251Ssam 167189251Ssam 168189251Ssamstatic char * wpa_config_write_string_ascii(const u8 *value, size_t len) 169189251Ssam{ 170189251Ssam char *buf; 171189251Ssam 172189251Ssam buf = os_malloc(len + 3); 173189251Ssam if (buf == NULL) 174189251Ssam return NULL; 175189251Ssam buf[0] = '"'; 176189251Ssam os_memcpy(buf + 1, value, len); 177189251Ssam buf[len + 1] = '"'; 178189251Ssam buf[len + 2] = '\0'; 179189251Ssam 180189251Ssam return buf; 181189251Ssam} 182189251Ssam 183189251Ssam 184189251Ssamstatic char * wpa_config_write_string_hex(const u8 *value, size_t len) 185189251Ssam{ 186189251Ssam char *buf; 187189251Ssam 188189251Ssam buf = os_zalloc(2 * len + 1); 189189251Ssam if (buf == NULL) 190189251Ssam return NULL; 191189251Ssam wpa_snprintf_hex(buf, 2 * len + 1, value, len); 192189251Ssam 193189251Ssam return buf; 194189251Ssam} 195189251Ssam 196189251Ssam 197189251Ssamstatic char * wpa_config_write_string(const u8 *value, size_t len) 198189251Ssam{ 199189251Ssam if (value == NULL) 200189251Ssam return NULL; 201189251Ssam 202189251Ssam if (is_hex(value, len)) 203189251Ssam return wpa_config_write_string_hex(value, len); 204189251Ssam else 205189251Ssam return wpa_config_write_string_ascii(value, len); 206189251Ssam} 207189251Ssam 208189251Ssam 209189251Ssamstatic char * wpa_config_write_str(const struct parse_data *data, 210189251Ssam struct wpa_ssid *ssid) 211189251Ssam{ 212189251Ssam size_t len; 213189251Ssam char **src; 214189251Ssam 215189251Ssam src = (char **) (((u8 *) ssid) + (long) data->param1); 216189251Ssam if (*src == NULL) 217189251Ssam return NULL; 218189251Ssam 219189251Ssam if (data->param2) 220189251Ssam len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); 221189251Ssam else 222189251Ssam len = os_strlen(*src); 223189251Ssam 224189251Ssam return wpa_config_write_string((const u8 *) *src, len); 225189251Ssam} 226189251Ssam#endif /* NO_CONFIG_WRITE */ 227189251Ssam 228189251Ssam 229189251Ssamstatic int wpa_config_parse_int(const struct parse_data *data, 230189251Ssam struct wpa_ssid *ssid, 231189251Ssam int line, const char *value) 232189251Ssam{ 233189251Ssam int *dst; 234189251Ssam 235189251Ssam dst = (int *) (((u8 *) ssid) + (long) data->param1); 236189251Ssam *dst = atoi(value); 237189251Ssam wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst); 238189251Ssam 239189251Ssam if (data->param3 && *dst < (long) data->param3) { 240189251Ssam wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d " 241189251Ssam "min_value=%ld)", line, data->name, *dst, 242189251Ssam (long) data->param3); 243189251Ssam *dst = (long) data->param3; 244189251Ssam return -1; 245189251Ssam } 246189251Ssam 247189251Ssam if (data->param4 && *dst > (long) data->param4) { 248189251Ssam wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d " 249189251Ssam "max_value=%ld)", line, data->name, *dst, 250189251Ssam (long) data->param4); 251189251Ssam *dst = (long) data->param4; 252189251Ssam return -1; 253189251Ssam } 254189251Ssam 255189251Ssam return 0; 256189251Ssam} 257189251Ssam 258189251Ssam 259189251Ssam#ifndef NO_CONFIG_WRITE 260189251Ssamstatic char * wpa_config_write_int(const struct parse_data *data, 261189251Ssam struct wpa_ssid *ssid) 262189251Ssam{ 263189251Ssam int *src, res; 264189251Ssam char *value; 265189251Ssam 266189251Ssam src = (int *) (((u8 *) ssid) + (long) data->param1); 267189251Ssam 268189251Ssam value = os_malloc(20); 269189251Ssam if (value == NULL) 270189251Ssam return NULL; 271189251Ssam res = os_snprintf(value, 20, "%d", *src); 272189251Ssam if (res < 0 || res >= 20) { 273189251Ssam os_free(value); 274189251Ssam return NULL; 275189251Ssam } 276189251Ssam value[20 - 1] = '\0'; 277189251Ssam return value; 278189251Ssam} 279189251Ssam#endif /* NO_CONFIG_WRITE */ 280189251Ssam 281189251Ssam 282189251Ssamstatic int wpa_config_parse_bssid(const struct parse_data *data, 283189251Ssam struct wpa_ssid *ssid, int line, 284189251Ssam const char *value) 285189251Ssam{ 286189251Ssam if (hwaddr_aton(value, ssid->bssid)) { 287189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.", 288189251Ssam line, value); 289189251Ssam return -1; 290189251Ssam } 291189251Ssam ssid->bssid_set = 1; 292189251Ssam wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN); 293189251Ssam return 0; 294189251Ssam} 295189251Ssam 296189251Ssam 297189251Ssam#ifndef NO_CONFIG_WRITE 298189251Ssamstatic char * wpa_config_write_bssid(const struct parse_data *data, 299189251Ssam struct wpa_ssid *ssid) 300189251Ssam{ 301189251Ssam char *value; 302189251Ssam int res; 303189251Ssam 304189251Ssam if (!ssid->bssid_set) 305189251Ssam return NULL; 306189251Ssam 307189251Ssam value = os_malloc(20); 308189251Ssam if (value == NULL) 309189251Ssam return NULL; 310189251Ssam res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid)); 311189251Ssam if (res < 0 || res >= 20) { 312189251Ssam os_free(value); 313189251Ssam return NULL; 314189251Ssam } 315189251Ssam value[20 - 1] = '\0'; 316189251Ssam return value; 317189251Ssam} 318189251Ssam#endif /* NO_CONFIG_WRITE */ 319189251Ssam 320189251Ssam 321189251Ssamstatic int wpa_config_parse_psk(const struct parse_data *data, 322189251Ssam struct wpa_ssid *ssid, int line, 323189251Ssam const char *value) 324189251Ssam{ 325189251Ssam if (*value == '"') { 326189251Ssam#ifndef CONFIG_NO_PBKDF2 327189251Ssam const char *pos; 328189251Ssam size_t len; 329189251Ssam 330189251Ssam value++; 331189251Ssam pos = os_strrchr(value, '"'); 332189251Ssam if (pos) 333189251Ssam len = pos - value; 334189251Ssam else 335189251Ssam len = os_strlen(value); 336189251Ssam if (len < 8 || len > 63) { 337189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase " 338189251Ssam "length %lu (expected: 8..63) '%s'.", 339189251Ssam line, (unsigned long) len, value); 340189251Ssam return -1; 341189251Ssam } 342189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)", 343189251Ssam (u8 *) value, len); 344189251Ssam if (ssid->passphrase && os_strlen(ssid->passphrase) == len && 345189251Ssam os_memcmp(ssid->passphrase, value, len) == 0) 346189251Ssam return 0; 347189251Ssam ssid->psk_set = 0; 348189251Ssam os_free(ssid->passphrase); 349189251Ssam ssid->passphrase = os_malloc(len + 1); 350189251Ssam if (ssid->passphrase == NULL) 351189251Ssam return -1; 352189251Ssam os_memcpy(ssid->passphrase, value, len); 353189251Ssam ssid->passphrase[len] = '\0'; 354189251Ssam return 0; 355189251Ssam#else /* CONFIG_NO_PBKDF2 */ 356189251Ssam wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not " 357189251Ssam "supported.", line); 358189251Ssam return -1; 359189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 360189251Ssam } 361189251Ssam 362189251Ssam if (hexstr2bin(value, ssid->psk, PMK_LEN) || 363189251Ssam value[PMK_LEN * 2] != '\0') { 364189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.", 365189251Ssam line, value); 366189251Ssam return -1; 367189251Ssam } 368189251Ssam 369189251Ssam os_free(ssid->passphrase); 370189251Ssam ssid->passphrase = NULL; 371189251Ssam 372189251Ssam ssid->psk_set = 1; 373189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN); 374189251Ssam return 0; 375189251Ssam} 376189251Ssam 377189251Ssam 378189251Ssam#ifndef NO_CONFIG_WRITE 379189251Ssamstatic char * wpa_config_write_psk(const struct parse_data *data, 380189251Ssam struct wpa_ssid *ssid) 381189251Ssam{ 382189251Ssam if (ssid->passphrase) 383189251Ssam return wpa_config_write_string_ascii( 384189251Ssam (const u8 *) ssid->passphrase, 385189251Ssam os_strlen(ssid->passphrase)); 386189251Ssam 387189251Ssam if (ssid->psk_set) 388189251Ssam return wpa_config_write_string_hex(ssid->psk, PMK_LEN); 389189251Ssam 390189251Ssam return NULL; 391189251Ssam} 392189251Ssam#endif /* NO_CONFIG_WRITE */ 393189251Ssam 394189251Ssam 395189251Ssamstatic int wpa_config_parse_proto(const struct parse_data *data, 396189251Ssam struct wpa_ssid *ssid, int line, 397189251Ssam const char *value) 398189251Ssam{ 399189251Ssam int val = 0, last, errors = 0; 400189251Ssam char *start, *end, *buf; 401189251Ssam 402189251Ssam buf = os_strdup(value); 403189251Ssam if (buf == NULL) 404189251Ssam return -1; 405189251Ssam start = buf; 406189251Ssam 407189251Ssam while (*start != '\0') { 408189251Ssam while (*start == ' ' || *start == '\t') 409189251Ssam start++; 410189251Ssam if (*start == '\0') 411189251Ssam break; 412189251Ssam end = start; 413189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 414189251Ssam end++; 415189251Ssam last = *end == '\0'; 416189251Ssam *end = '\0'; 417189251Ssam if (os_strcmp(start, "WPA") == 0) 418189251Ssam val |= WPA_PROTO_WPA; 419189251Ssam else if (os_strcmp(start, "RSN") == 0 || 420189251Ssam os_strcmp(start, "WPA2") == 0) 421189251Ssam val |= WPA_PROTO_RSN; 422189251Ssam else { 423189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'", 424189251Ssam line, start); 425189251Ssam errors++; 426189251Ssam } 427189251Ssam 428189251Ssam if (last) 429189251Ssam break; 430189251Ssam start = end + 1; 431189251Ssam } 432189251Ssam os_free(buf); 433189251Ssam 434189251Ssam if (val == 0) { 435189251Ssam wpa_printf(MSG_ERROR, 436189251Ssam "Line %d: no proto values configured.", line); 437189251Ssam errors++; 438189251Ssam } 439189251Ssam 440189251Ssam wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val); 441189251Ssam ssid->proto = val; 442189251Ssam return errors ? -1 : 0; 443189251Ssam} 444189251Ssam 445189251Ssam 446189251Ssam#ifndef NO_CONFIG_WRITE 447189251Ssamstatic char * wpa_config_write_proto(const struct parse_data *data, 448189251Ssam struct wpa_ssid *ssid) 449189251Ssam{ 450189251Ssam int first = 1, ret; 451189251Ssam char *buf, *pos, *end; 452189251Ssam 453189251Ssam pos = buf = os_zalloc(10); 454189251Ssam if (buf == NULL) 455189251Ssam return NULL; 456189251Ssam end = buf + 10; 457189251Ssam 458189251Ssam if (ssid->proto & WPA_PROTO_WPA) { 459189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " "); 460189251Ssam if (ret < 0 || ret >= end - pos) 461189251Ssam return buf; 462189251Ssam pos += ret; 463189251Ssam first = 0; 464189251Ssam } 465189251Ssam 466189251Ssam if (ssid->proto & WPA_PROTO_RSN) { 467189251Ssam ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " "); 468189251Ssam if (ret < 0 || ret >= end - pos) 469189251Ssam return buf; 470189251Ssam pos += ret; 471189251Ssam first = 0; 472189251Ssam } 473189251Ssam 474189251Ssam return buf; 475189251Ssam} 476189251Ssam#endif /* NO_CONFIG_WRITE */ 477189251Ssam 478189251Ssam 479189251Ssamstatic int wpa_config_parse_key_mgmt(const struct parse_data *data, 480189251Ssam struct wpa_ssid *ssid, int line, 481189251Ssam const char *value) 482189251Ssam{ 483189251Ssam int val = 0, last, errors = 0; 484189251Ssam char *start, *end, *buf; 485189251Ssam 486189251Ssam buf = os_strdup(value); 487189251Ssam if (buf == NULL) 488189251Ssam return -1; 489189251Ssam start = buf; 490189251Ssam 491189251Ssam while (*start != '\0') { 492189251Ssam while (*start == ' ' || *start == '\t') 493189251Ssam start++; 494189251Ssam if (*start == '\0') 495189251Ssam break; 496189251Ssam end = start; 497189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 498189251Ssam end++; 499189251Ssam last = *end == '\0'; 500189251Ssam *end = '\0'; 501189251Ssam if (os_strcmp(start, "WPA-PSK") == 0) 502189251Ssam val |= WPA_KEY_MGMT_PSK; 503189251Ssam else if (os_strcmp(start, "WPA-EAP") == 0) 504189251Ssam val |= WPA_KEY_MGMT_IEEE8021X; 505189251Ssam else if (os_strcmp(start, "IEEE8021X") == 0) 506189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA; 507189251Ssam else if (os_strcmp(start, "NONE") == 0) 508189251Ssam val |= WPA_KEY_MGMT_NONE; 509189251Ssam else if (os_strcmp(start, "WPA-NONE") == 0) 510189251Ssam val |= WPA_KEY_MGMT_WPA_NONE; 511189251Ssam#ifdef CONFIG_IEEE80211R 512189251Ssam else if (os_strcmp(start, "FT-PSK") == 0) 513189251Ssam val |= WPA_KEY_MGMT_FT_PSK; 514189251Ssam else if (os_strcmp(start, "FT-EAP") == 0) 515189251Ssam val |= WPA_KEY_MGMT_FT_IEEE8021X; 516189251Ssam#endif /* CONFIG_IEEE80211R */ 517189251Ssam#ifdef CONFIG_IEEE80211W 518189251Ssam else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) 519189251Ssam val |= WPA_KEY_MGMT_PSK_SHA256; 520189251Ssam else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) 521189251Ssam val |= WPA_KEY_MGMT_IEEE8021X_SHA256; 522189251Ssam#endif /* CONFIG_IEEE80211W */ 523189251Ssam#ifdef CONFIG_WPS 524189251Ssam else if (os_strcmp(start, "WPS") == 0) 525189251Ssam val |= WPA_KEY_MGMT_WPS; 526189251Ssam#endif /* CONFIG_WPS */ 527189251Ssam else { 528189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", 529189251Ssam line, start); 530189251Ssam errors++; 531189251Ssam } 532189251Ssam 533189251Ssam if (last) 534189251Ssam break; 535189251Ssam start = end + 1; 536189251Ssam } 537189251Ssam os_free(buf); 538189251Ssam 539189251Ssam if (val == 0) { 540189251Ssam wpa_printf(MSG_ERROR, 541189251Ssam "Line %d: no key_mgmt values configured.", line); 542189251Ssam errors++; 543189251Ssam } 544189251Ssam 545189251Ssam wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val); 546189251Ssam ssid->key_mgmt = val; 547189251Ssam return errors ? -1 : 0; 548189251Ssam} 549189251Ssam 550189251Ssam 551189251Ssam#ifndef NO_CONFIG_WRITE 552189251Ssamstatic char * wpa_config_write_key_mgmt(const struct parse_data *data, 553189251Ssam struct wpa_ssid *ssid) 554189251Ssam{ 555189251Ssam char *buf, *pos, *end; 556189251Ssam int ret; 557189251Ssam 558189251Ssam pos = buf = os_zalloc(50); 559189251Ssam if (buf == NULL) 560189251Ssam return NULL; 561189251Ssam end = buf + 50; 562189251Ssam 563189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { 564189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-PSK", 565189251Ssam pos == buf ? "" : " "); 566189251Ssam if (ret < 0 || ret >= end - pos) { 567189251Ssam end[-1] = '\0'; 568189251Ssam return buf; 569189251Ssam } 570189251Ssam pos += ret; 571189251Ssam } 572189251Ssam 573189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) { 574189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-EAP", 575189251Ssam pos == buf ? "" : " "); 576189251Ssam if (ret < 0 || ret >= end - pos) { 577189251Ssam end[-1] = '\0'; 578189251Ssam return buf; 579189251Ssam } 580189251Ssam pos += ret; 581189251Ssam } 582189251Ssam 583189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 584189251Ssam ret = os_snprintf(pos, end - pos, "%sIEEE8021X", 585189251Ssam pos == buf ? "" : " "); 586189251Ssam if (ret < 0 || ret >= end - pos) { 587189251Ssam end[-1] = '\0'; 588189251Ssam return buf; 589189251Ssam } 590189251Ssam pos += ret; 591189251Ssam } 592189251Ssam 593189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) { 594189251Ssam ret = os_snprintf(pos, end - pos, "%sNONE", 595189251Ssam pos == buf ? "" : " "); 596189251Ssam if (ret < 0 || ret >= end - pos) { 597189251Ssam end[-1] = '\0'; 598189251Ssam return buf; 599189251Ssam } 600189251Ssam pos += ret; 601189251Ssam } 602189251Ssam 603189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) { 604189251Ssam ret = os_snprintf(pos, end - pos, "%sWPA-NONE", 605189251Ssam pos == buf ? "" : " "); 606189251Ssam if (ret < 0 || ret >= end - pos) { 607189251Ssam end[-1] = '\0'; 608189251Ssam return buf; 609189251Ssam } 610189251Ssam pos += ret; 611189251Ssam } 612189251Ssam 613189251Ssam#ifdef CONFIG_IEEE80211R 614189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) 615189251Ssam pos += os_snprintf(pos, end - pos, "%sFT-PSK", 616189251Ssam pos == buf ? "" : " "); 617189251Ssam 618189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) 619189251Ssam pos += os_snprintf(pos, end - pos, "%sFT-EAP", 620189251Ssam pos == buf ? "" : " "); 621189251Ssam#endif /* CONFIG_IEEE80211R */ 622189251Ssam 623189251Ssam#ifdef CONFIG_IEEE80211W 624189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) 625189251Ssam pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256", 626189251Ssam pos == buf ? "" : " "); 627189251Ssam 628189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) 629189251Ssam pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256", 630189251Ssam pos == buf ? "" : " "); 631189251Ssam#endif /* CONFIG_IEEE80211W */ 632189251Ssam 633189251Ssam#ifdef CONFIG_WPS 634189251Ssam if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) 635189251Ssam pos += os_snprintf(pos, end - pos, "%sWPS", 636189251Ssam pos == buf ? "" : " "); 637189251Ssam#endif /* CONFIG_WPS */ 638189251Ssam 639189251Ssam return buf; 640189251Ssam} 641189251Ssam#endif /* NO_CONFIG_WRITE */ 642189251Ssam 643189251Ssam 644189251Ssamstatic int wpa_config_parse_cipher(int line, const char *value) 645189251Ssam{ 646189251Ssam int val = 0, last; 647189251Ssam char *start, *end, *buf; 648189251Ssam 649189251Ssam buf = os_strdup(value); 650189251Ssam if (buf == NULL) 651189251Ssam return -1; 652189251Ssam start = buf; 653189251Ssam 654189251Ssam while (*start != '\0') { 655189251Ssam while (*start == ' ' || *start == '\t') 656189251Ssam start++; 657189251Ssam if (*start == '\0') 658189251Ssam break; 659189251Ssam end = start; 660189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 661189251Ssam end++; 662189251Ssam last = *end == '\0'; 663189251Ssam *end = '\0'; 664189251Ssam if (os_strcmp(start, "CCMP") == 0) 665189251Ssam val |= WPA_CIPHER_CCMP; 666189251Ssam else if (os_strcmp(start, "TKIP") == 0) 667189251Ssam val |= WPA_CIPHER_TKIP; 668189251Ssam else if (os_strcmp(start, "WEP104") == 0) 669189251Ssam val |= WPA_CIPHER_WEP104; 670189251Ssam else if (os_strcmp(start, "WEP40") == 0) 671189251Ssam val |= WPA_CIPHER_WEP40; 672189251Ssam else if (os_strcmp(start, "NONE") == 0) 673189251Ssam val |= WPA_CIPHER_NONE; 674189251Ssam else { 675189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.", 676189251Ssam line, start); 677189251Ssam os_free(buf); 678189251Ssam return -1; 679189251Ssam } 680189251Ssam 681189251Ssam if (last) 682189251Ssam break; 683189251Ssam start = end + 1; 684189251Ssam } 685189251Ssam os_free(buf); 686189251Ssam 687189251Ssam if (val == 0) { 688189251Ssam wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.", 689189251Ssam line); 690189251Ssam return -1; 691189251Ssam } 692189251Ssam return val; 693189251Ssam} 694189251Ssam 695189251Ssam 696189251Ssam#ifndef NO_CONFIG_WRITE 697189251Ssamstatic char * wpa_config_write_cipher(int cipher) 698189251Ssam{ 699189251Ssam char *buf, *pos, *end; 700189251Ssam int ret; 701189251Ssam 702189251Ssam pos = buf = os_zalloc(50); 703189251Ssam if (buf == NULL) 704189251Ssam return NULL; 705189251Ssam end = buf + 50; 706189251Ssam 707189251Ssam if (cipher & WPA_CIPHER_CCMP) { 708189251Ssam ret = os_snprintf(pos, end - pos, "%sCCMP", 709189251Ssam pos == buf ? "" : " "); 710189251Ssam if (ret < 0 || ret >= end - pos) { 711189251Ssam end[-1] = '\0'; 712189251Ssam return buf; 713189251Ssam } 714189251Ssam pos += ret; 715189251Ssam } 716189251Ssam 717189251Ssam if (cipher & WPA_CIPHER_TKIP) { 718189251Ssam ret = os_snprintf(pos, end - pos, "%sTKIP", 719189251Ssam pos == buf ? "" : " "); 720189251Ssam if (ret < 0 || ret >= end - pos) { 721189251Ssam end[-1] = '\0'; 722189251Ssam return buf; 723189251Ssam } 724189251Ssam pos += ret; 725189251Ssam } 726189251Ssam 727189251Ssam if (cipher & WPA_CIPHER_WEP104) { 728189251Ssam ret = os_snprintf(pos, end - pos, "%sWEP104", 729189251Ssam pos == buf ? "" : " "); 730189251Ssam if (ret < 0 || ret >= end - pos) { 731189251Ssam end[-1] = '\0'; 732189251Ssam return buf; 733189251Ssam } 734189251Ssam pos += ret; 735189251Ssam } 736189251Ssam 737189251Ssam if (cipher & WPA_CIPHER_WEP40) { 738189251Ssam ret = os_snprintf(pos, end - pos, "%sWEP40", 739189251Ssam pos == buf ? "" : " "); 740189251Ssam if (ret < 0 || ret >= end - pos) { 741189251Ssam end[-1] = '\0'; 742189251Ssam return buf; 743189251Ssam } 744189251Ssam pos += ret; 745189251Ssam } 746189251Ssam 747189251Ssam if (cipher & WPA_CIPHER_NONE) { 748189251Ssam ret = os_snprintf(pos, end - pos, "%sNONE", 749189251Ssam pos == buf ? "" : " "); 750189251Ssam if (ret < 0 || ret >= end - pos) { 751189251Ssam end[-1] = '\0'; 752189251Ssam return buf; 753189251Ssam } 754189251Ssam pos += ret; 755189251Ssam } 756189251Ssam 757189251Ssam return buf; 758189251Ssam} 759189251Ssam#endif /* NO_CONFIG_WRITE */ 760189251Ssam 761189251Ssam 762189251Ssamstatic int wpa_config_parse_pairwise(const struct parse_data *data, 763189251Ssam struct wpa_ssid *ssid, int line, 764189251Ssam const char *value) 765189251Ssam{ 766189251Ssam int val; 767189251Ssam val = wpa_config_parse_cipher(line, value); 768189251Ssam if (val == -1) 769189251Ssam return -1; 770189251Ssam if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) { 771189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " 772189251Ssam "(0x%x).", line, val); 773189251Ssam return -1; 774189251Ssam } 775189251Ssam 776189251Ssam wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val); 777189251Ssam ssid->pairwise_cipher = val; 778189251Ssam return 0; 779189251Ssam} 780189251Ssam 781189251Ssam 782189251Ssam#ifndef NO_CONFIG_WRITE 783189251Ssamstatic char * wpa_config_write_pairwise(const struct parse_data *data, 784189251Ssam struct wpa_ssid *ssid) 785189251Ssam{ 786189251Ssam return wpa_config_write_cipher(ssid->pairwise_cipher); 787189251Ssam} 788189251Ssam#endif /* NO_CONFIG_WRITE */ 789189251Ssam 790189251Ssam 791189251Ssamstatic int wpa_config_parse_group(const struct parse_data *data, 792189251Ssam struct wpa_ssid *ssid, int line, 793189251Ssam const char *value) 794189251Ssam{ 795189251Ssam int val; 796189251Ssam val = wpa_config_parse_cipher(line, value); 797189251Ssam if (val == -1) 798189251Ssam return -1; 799189251Ssam if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | 800189251Ssam WPA_CIPHER_WEP40)) { 801189251Ssam wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " 802189251Ssam "(0x%x).", line, val); 803189251Ssam return -1; 804189251Ssam } 805189251Ssam 806189251Ssam wpa_printf(MSG_MSGDUMP, "group: 0x%x", val); 807189251Ssam ssid->group_cipher = val; 808189251Ssam return 0; 809189251Ssam} 810189251Ssam 811189251Ssam 812189251Ssam#ifndef NO_CONFIG_WRITE 813189251Ssamstatic char * wpa_config_write_group(const struct parse_data *data, 814189251Ssam struct wpa_ssid *ssid) 815189251Ssam{ 816189251Ssam return wpa_config_write_cipher(ssid->group_cipher); 817189251Ssam} 818189251Ssam#endif /* NO_CONFIG_WRITE */ 819189251Ssam 820189251Ssam 821189251Ssamstatic int wpa_config_parse_auth_alg(const struct parse_data *data, 822189251Ssam struct wpa_ssid *ssid, int line, 823189251Ssam const char *value) 824189251Ssam{ 825189251Ssam int val = 0, last, errors = 0; 826189251Ssam char *start, *end, *buf; 827189251Ssam 828189251Ssam buf = os_strdup(value); 829189251Ssam if (buf == NULL) 830189251Ssam return -1; 831189251Ssam start = buf; 832189251Ssam 833189251Ssam while (*start != '\0') { 834189251Ssam while (*start == ' ' || *start == '\t') 835189251Ssam start++; 836189251Ssam if (*start == '\0') 837189251Ssam break; 838189251Ssam end = start; 839189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 840189251Ssam end++; 841189251Ssam last = *end == '\0'; 842189251Ssam *end = '\0'; 843189251Ssam if (os_strcmp(start, "OPEN") == 0) 844189251Ssam val |= WPA_AUTH_ALG_OPEN; 845189251Ssam else if (os_strcmp(start, "SHARED") == 0) 846189251Ssam val |= WPA_AUTH_ALG_SHARED; 847189251Ssam else if (os_strcmp(start, "LEAP") == 0) 848189251Ssam val |= WPA_AUTH_ALG_LEAP; 849189251Ssam else { 850189251Ssam wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'", 851189251Ssam line, start); 852189251Ssam errors++; 853189251Ssam } 854189251Ssam 855189251Ssam if (last) 856189251Ssam break; 857189251Ssam start = end + 1; 858189251Ssam } 859189251Ssam os_free(buf); 860189251Ssam 861189251Ssam if (val == 0) { 862189251Ssam wpa_printf(MSG_ERROR, 863189251Ssam "Line %d: no auth_alg values configured.", line); 864189251Ssam errors++; 865189251Ssam } 866189251Ssam 867189251Ssam wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val); 868189251Ssam ssid->auth_alg = val; 869189251Ssam return errors ? -1 : 0; 870189251Ssam} 871189251Ssam 872189251Ssam 873189251Ssam#ifndef NO_CONFIG_WRITE 874189251Ssamstatic char * wpa_config_write_auth_alg(const struct parse_data *data, 875189251Ssam struct wpa_ssid *ssid) 876189251Ssam{ 877189251Ssam char *buf, *pos, *end; 878189251Ssam int ret; 879189251Ssam 880189251Ssam pos = buf = os_zalloc(30); 881189251Ssam if (buf == NULL) 882189251Ssam return NULL; 883189251Ssam end = buf + 30; 884189251Ssam 885189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) { 886189251Ssam ret = os_snprintf(pos, end - pos, "%sOPEN", 887189251Ssam pos == buf ? "" : " "); 888189251Ssam if (ret < 0 || ret >= end - pos) { 889189251Ssam end[-1] = '\0'; 890189251Ssam return buf; 891189251Ssam } 892189251Ssam pos += ret; 893189251Ssam } 894189251Ssam 895189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) { 896189251Ssam ret = os_snprintf(pos, end - pos, "%sSHARED", 897189251Ssam pos == buf ? "" : " "); 898189251Ssam if (ret < 0 || ret >= end - pos) { 899189251Ssam end[-1] = '\0'; 900189251Ssam return buf; 901189251Ssam } 902189251Ssam pos += ret; 903189251Ssam } 904189251Ssam 905189251Ssam if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) { 906189251Ssam ret = os_snprintf(pos, end - pos, "%sLEAP", 907189251Ssam pos == buf ? "" : " "); 908189251Ssam if (ret < 0 || ret >= end - pos) { 909189251Ssam end[-1] = '\0'; 910189251Ssam return buf; 911189251Ssam } 912189251Ssam pos += ret; 913189251Ssam } 914189251Ssam 915189251Ssam return buf; 916189251Ssam} 917189251Ssam#endif /* NO_CONFIG_WRITE */ 918189251Ssam 919189251Ssam 920214734Srpaulostatic int * wpa_config_parse_freqs(const struct parse_data *data, 921214734Srpaulo struct wpa_ssid *ssid, int line, 922214734Srpaulo const char *value) 923214734Srpaulo{ 924214734Srpaulo int *freqs; 925214734Srpaulo size_t used, len; 926214734Srpaulo const char *pos; 927214734Srpaulo 928214734Srpaulo used = 0; 929214734Srpaulo len = 10; 930214734Srpaulo freqs = os_zalloc((len + 1) * sizeof(int)); 931214734Srpaulo if (freqs == NULL) 932214734Srpaulo return NULL; 933214734Srpaulo 934214734Srpaulo pos = value; 935214734Srpaulo while (pos) { 936214734Srpaulo while (*pos == ' ') 937214734Srpaulo pos++; 938214734Srpaulo if (used == len) { 939214734Srpaulo int *n; 940214734Srpaulo size_t i; 941214734Srpaulo n = os_realloc(freqs, (len * 2 + 1) * sizeof(int)); 942214734Srpaulo if (n == NULL) { 943214734Srpaulo os_free(freqs); 944214734Srpaulo return NULL; 945214734Srpaulo } 946214734Srpaulo for (i = len; i <= len * 2; i++) 947214734Srpaulo n[i] = 0; 948214734Srpaulo freqs = n; 949214734Srpaulo len *= 2; 950214734Srpaulo } 951214734Srpaulo 952214734Srpaulo freqs[used] = atoi(pos); 953214734Srpaulo if (freqs[used] == 0) 954214734Srpaulo break; 955214734Srpaulo used++; 956214734Srpaulo pos = os_strchr(pos + 1, ' '); 957214734Srpaulo } 958214734Srpaulo 959214734Srpaulo return freqs; 960214734Srpaulo} 961214734Srpaulo 962214734Srpaulo 963214734Srpaulostatic int wpa_config_parse_scan_freq(const struct parse_data *data, 964214734Srpaulo struct wpa_ssid *ssid, int line, 965214734Srpaulo const char *value) 966214734Srpaulo{ 967214734Srpaulo int *freqs; 968214734Srpaulo 969214734Srpaulo freqs = wpa_config_parse_freqs(data, ssid, line, value); 970214734Srpaulo if (freqs == NULL) 971214734Srpaulo return -1; 972214734Srpaulo os_free(ssid->scan_freq); 973214734Srpaulo ssid->scan_freq = freqs; 974214734Srpaulo 975214734Srpaulo return 0; 976214734Srpaulo} 977214734Srpaulo 978214734Srpaulo 979214734Srpaulostatic int wpa_config_parse_freq_list(const struct parse_data *data, 980214734Srpaulo struct wpa_ssid *ssid, int line, 981214734Srpaulo const char *value) 982214734Srpaulo{ 983214734Srpaulo int *freqs; 984214734Srpaulo 985214734Srpaulo freqs = wpa_config_parse_freqs(data, ssid, line, value); 986214734Srpaulo if (freqs == NULL) 987214734Srpaulo return -1; 988214734Srpaulo os_free(ssid->freq_list); 989214734Srpaulo ssid->freq_list = freqs; 990214734Srpaulo 991214734Srpaulo return 0; 992214734Srpaulo} 993214734Srpaulo 994214734Srpaulo 995214734Srpaulo#ifndef NO_CONFIG_WRITE 996214734Srpaulostatic char * wpa_config_write_freqs(const struct parse_data *data, 997214734Srpaulo const int *freqs) 998214734Srpaulo{ 999214734Srpaulo char *buf, *pos, *end; 1000214734Srpaulo int i, ret; 1001214734Srpaulo size_t count; 1002214734Srpaulo 1003214734Srpaulo if (freqs == NULL) 1004214734Srpaulo return NULL; 1005214734Srpaulo 1006214734Srpaulo count = 0; 1007214734Srpaulo for (i = 0; freqs[i]; i++) 1008214734Srpaulo count++; 1009214734Srpaulo 1010214734Srpaulo pos = buf = os_zalloc(10 * count + 1); 1011214734Srpaulo if (buf == NULL) 1012214734Srpaulo return NULL; 1013214734Srpaulo end = buf + 10 * count + 1; 1014214734Srpaulo 1015214734Srpaulo for (i = 0; freqs[i]; i++) { 1016214734Srpaulo ret = os_snprintf(pos, end - pos, "%s%u", 1017214734Srpaulo i == 0 ? "" : " ", freqs[i]); 1018214734Srpaulo if (ret < 0 || ret >= end - pos) { 1019214734Srpaulo end[-1] = '\0'; 1020214734Srpaulo return buf; 1021214734Srpaulo } 1022214734Srpaulo pos += ret; 1023214734Srpaulo } 1024214734Srpaulo 1025214734Srpaulo return buf; 1026214734Srpaulo} 1027214734Srpaulo 1028214734Srpaulo 1029214734Srpaulostatic char * wpa_config_write_scan_freq(const struct parse_data *data, 1030214734Srpaulo struct wpa_ssid *ssid) 1031214734Srpaulo{ 1032214734Srpaulo return wpa_config_write_freqs(data, ssid->scan_freq); 1033214734Srpaulo} 1034214734Srpaulo 1035214734Srpaulo 1036214734Srpaulostatic char * wpa_config_write_freq_list(const struct parse_data *data, 1037214734Srpaulo struct wpa_ssid *ssid) 1038214734Srpaulo{ 1039214734Srpaulo return wpa_config_write_freqs(data, ssid->freq_list); 1040214734Srpaulo} 1041214734Srpaulo#endif /* NO_CONFIG_WRITE */ 1042214734Srpaulo 1043214734Srpaulo 1044189251Ssam#ifdef IEEE8021X_EAPOL 1045189251Ssamstatic int wpa_config_parse_eap(const struct parse_data *data, 1046189251Ssam struct wpa_ssid *ssid, int line, 1047189251Ssam const char *value) 1048189251Ssam{ 1049189251Ssam int last, errors = 0; 1050189251Ssam char *start, *end, *buf; 1051189251Ssam struct eap_method_type *methods = NULL, *tmp; 1052189251Ssam size_t num_methods = 0; 1053189251Ssam 1054189251Ssam buf = os_strdup(value); 1055189251Ssam if (buf == NULL) 1056189251Ssam return -1; 1057189251Ssam start = buf; 1058189251Ssam 1059189251Ssam while (*start != '\0') { 1060189251Ssam while (*start == ' ' || *start == '\t') 1061189251Ssam start++; 1062189251Ssam if (*start == '\0') 1063189251Ssam break; 1064189251Ssam end = start; 1065189251Ssam while (*end != ' ' && *end != '\t' && *end != '\0') 1066189251Ssam end++; 1067189251Ssam last = *end == '\0'; 1068189251Ssam *end = '\0'; 1069189251Ssam tmp = methods; 1070189251Ssam methods = os_realloc(methods, 1071189251Ssam (num_methods + 1) * sizeof(*methods)); 1072189251Ssam if (methods == NULL) { 1073189251Ssam os_free(tmp); 1074189251Ssam os_free(buf); 1075189251Ssam return -1; 1076189251Ssam } 1077189251Ssam methods[num_methods].method = eap_peer_get_type( 1078189251Ssam start, &methods[num_methods].vendor); 1079189251Ssam if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1080189251Ssam methods[num_methods].method == EAP_TYPE_NONE) { 1081189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown EAP method " 1082189251Ssam "'%s'", line, start); 1083189251Ssam wpa_printf(MSG_ERROR, "You may need to add support for" 1084189251Ssam " this EAP method during wpa_supplicant\n" 1085189251Ssam "build time configuration.\n" 1086189251Ssam "See README for more information."); 1087189251Ssam errors++; 1088189251Ssam } else if (methods[num_methods].vendor == EAP_VENDOR_IETF && 1089189251Ssam methods[num_methods].method == EAP_TYPE_LEAP) 1090189251Ssam ssid->leap++; 1091189251Ssam else 1092189251Ssam ssid->non_leap++; 1093189251Ssam num_methods++; 1094189251Ssam if (last) 1095189251Ssam break; 1096189251Ssam start = end + 1; 1097189251Ssam } 1098189251Ssam os_free(buf); 1099189251Ssam 1100189251Ssam tmp = methods; 1101189251Ssam methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); 1102189251Ssam if (methods == NULL) { 1103189251Ssam os_free(tmp); 1104189251Ssam return -1; 1105189251Ssam } 1106189251Ssam methods[num_methods].vendor = EAP_VENDOR_IETF; 1107189251Ssam methods[num_methods].method = EAP_TYPE_NONE; 1108189251Ssam num_methods++; 1109189251Ssam 1110189251Ssam wpa_hexdump(MSG_MSGDUMP, "eap methods", 1111189251Ssam (u8 *) methods, num_methods * sizeof(*methods)); 1112189251Ssam ssid->eap.eap_methods = methods; 1113189251Ssam return errors ? -1 : 0; 1114189251Ssam} 1115189251Ssam 1116189251Ssam 1117189251Ssamstatic char * wpa_config_write_eap(const struct parse_data *data, 1118189251Ssam struct wpa_ssid *ssid) 1119189251Ssam{ 1120189251Ssam int i, ret; 1121189251Ssam char *buf, *pos, *end; 1122189251Ssam const struct eap_method_type *eap_methods = ssid->eap.eap_methods; 1123189251Ssam const char *name; 1124189251Ssam 1125189251Ssam if (eap_methods == NULL) 1126189251Ssam return NULL; 1127189251Ssam 1128189251Ssam pos = buf = os_zalloc(100); 1129189251Ssam if (buf == NULL) 1130189251Ssam return NULL; 1131189251Ssam end = buf + 100; 1132189251Ssam 1133189251Ssam for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF || 1134189251Ssam eap_methods[i].method != EAP_TYPE_NONE; i++) { 1135189251Ssam name = eap_get_name(eap_methods[i].vendor, 1136189251Ssam eap_methods[i].method); 1137189251Ssam if (name) { 1138189251Ssam ret = os_snprintf(pos, end - pos, "%s%s", 1139189251Ssam pos == buf ? "" : " ", name); 1140189251Ssam if (ret < 0 || ret >= end - pos) 1141189251Ssam break; 1142189251Ssam pos += ret; 1143189251Ssam } 1144189251Ssam } 1145189251Ssam 1146189251Ssam end[-1] = '\0'; 1147189251Ssam 1148189251Ssam return buf; 1149189251Ssam} 1150189251Ssam 1151189251Ssam 1152189251Ssamstatic int wpa_config_parse_password(const struct parse_data *data, 1153189251Ssam struct wpa_ssid *ssid, int line, 1154189251Ssam const char *value) 1155189251Ssam{ 1156189251Ssam u8 *hash; 1157189251Ssam 1158189251Ssam if (os_strcmp(value, "NULL") == 0) { 1159189251Ssam wpa_printf(MSG_DEBUG, "Unset configuration string 'password'"); 1160189251Ssam os_free(ssid->eap.password); 1161189251Ssam ssid->eap.password = NULL; 1162189251Ssam ssid->eap.password_len = 0; 1163189251Ssam return 0; 1164189251Ssam } 1165189251Ssam 1166189251Ssam if (os_strncmp(value, "hash:", 5) != 0) { 1167189251Ssam char *tmp; 1168189251Ssam size_t res_len; 1169189251Ssam 1170189251Ssam tmp = wpa_config_parse_string(value, &res_len); 1171189251Ssam if (tmp == NULL) { 1172189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to parse " 1173189251Ssam "password.", line); 1174189251Ssam return -1; 1175189251Ssam } 1176189251Ssam wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name, 1177189251Ssam (u8 *) tmp, res_len); 1178189251Ssam 1179189251Ssam os_free(ssid->eap.password); 1180189251Ssam ssid->eap.password = (u8 *) tmp; 1181189251Ssam ssid->eap.password_len = res_len; 1182189251Ssam ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1183189251Ssam 1184189251Ssam return 0; 1185189251Ssam } 1186189251Ssam 1187189251Ssam 1188189251Ssam /* NtPasswordHash: hash:<32 hex digits> */ 1189189251Ssam if (os_strlen(value + 5) != 2 * 16) { 1190189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length " 1191189251Ssam "(expected 32 hex digits)", line); 1192189251Ssam return -1; 1193189251Ssam } 1194189251Ssam 1195189251Ssam hash = os_malloc(16); 1196189251Ssam if (hash == NULL) 1197189251Ssam return -1; 1198189251Ssam 1199189251Ssam if (hexstr2bin(value + 5, hash, 16)) { 1200189251Ssam os_free(hash); 1201189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line); 1202189251Ssam return -1; 1203189251Ssam } 1204189251Ssam 1205189251Ssam wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16); 1206189251Ssam 1207189251Ssam os_free(ssid->eap.password); 1208189251Ssam ssid->eap.password = hash; 1209189251Ssam ssid->eap.password_len = 16; 1210189251Ssam ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; 1211189251Ssam 1212189251Ssam return 0; 1213189251Ssam} 1214189251Ssam 1215189251Ssam 1216189251Ssamstatic char * wpa_config_write_password(const struct parse_data *data, 1217189251Ssam struct wpa_ssid *ssid) 1218189251Ssam{ 1219189251Ssam char *buf; 1220189251Ssam 1221189251Ssam if (ssid->eap.password == NULL) 1222189251Ssam return NULL; 1223189251Ssam 1224189251Ssam if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { 1225189251Ssam return wpa_config_write_string( 1226189251Ssam ssid->eap.password, ssid->eap.password_len); 1227189251Ssam } 1228189251Ssam 1229189251Ssam buf = os_malloc(5 + 32 + 1); 1230189251Ssam if (buf == NULL) 1231189251Ssam return NULL; 1232189251Ssam 1233189251Ssam os_memcpy(buf, "hash:", 5); 1234189251Ssam wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16); 1235189251Ssam 1236189251Ssam return buf; 1237189251Ssam} 1238189251Ssam#endif /* IEEE8021X_EAPOL */ 1239189251Ssam 1240189251Ssam 1241189251Ssamstatic int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, 1242189251Ssam const char *value, int idx) 1243189251Ssam{ 1244189251Ssam char *buf, title[20]; 1245189251Ssam int res; 1246189251Ssam 1247189251Ssam buf = wpa_config_parse_string(value, len); 1248189251Ssam if (buf == NULL) { 1249189251Ssam wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.", 1250189251Ssam line, idx, value); 1251189251Ssam return -1; 1252189251Ssam } 1253189251Ssam if (*len > MAX_WEP_KEY_LEN) { 1254189251Ssam wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.", 1255189251Ssam line, idx, value); 1256189251Ssam os_free(buf); 1257189251Ssam return -1; 1258189251Ssam } 1259189251Ssam os_memcpy(key, buf, *len); 1260189251Ssam os_free(buf); 1261189251Ssam res = os_snprintf(title, sizeof(title), "wep_key%d", idx); 1262189251Ssam if (res >= 0 && (size_t) res < sizeof(title)) 1263189251Ssam wpa_hexdump_key(MSG_MSGDUMP, title, key, *len); 1264189251Ssam return 0; 1265189251Ssam} 1266189251Ssam 1267189251Ssam 1268189251Ssamstatic int wpa_config_parse_wep_key0(const struct parse_data *data, 1269189251Ssam struct wpa_ssid *ssid, int line, 1270189251Ssam const char *value) 1271189251Ssam{ 1272189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[0], 1273189251Ssam &ssid->wep_key_len[0], line, 1274189251Ssam value, 0); 1275189251Ssam} 1276189251Ssam 1277189251Ssam 1278189251Ssamstatic int wpa_config_parse_wep_key1(const struct parse_data *data, 1279189251Ssam struct wpa_ssid *ssid, int line, 1280189251Ssam const char *value) 1281189251Ssam{ 1282189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[1], 1283189251Ssam &ssid->wep_key_len[1], line, 1284189251Ssam value, 1); 1285189251Ssam} 1286189251Ssam 1287189251Ssam 1288189251Ssamstatic int wpa_config_parse_wep_key2(const struct parse_data *data, 1289189251Ssam struct wpa_ssid *ssid, int line, 1290189251Ssam const char *value) 1291189251Ssam{ 1292189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[2], 1293189251Ssam &ssid->wep_key_len[2], line, 1294189251Ssam value, 2); 1295189251Ssam} 1296189251Ssam 1297189251Ssam 1298189251Ssamstatic int wpa_config_parse_wep_key3(const struct parse_data *data, 1299189251Ssam struct wpa_ssid *ssid, int line, 1300189251Ssam const char *value) 1301189251Ssam{ 1302189251Ssam return wpa_config_parse_wep_key(ssid->wep_key[3], 1303189251Ssam &ssid->wep_key_len[3], line, 1304189251Ssam value, 3); 1305189251Ssam} 1306189251Ssam 1307189251Ssam 1308189251Ssam#ifndef NO_CONFIG_WRITE 1309189251Ssamstatic char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx) 1310189251Ssam{ 1311189251Ssam if (ssid->wep_key_len[idx] == 0) 1312189251Ssam return NULL; 1313189251Ssam return wpa_config_write_string(ssid->wep_key[idx], 1314189251Ssam ssid->wep_key_len[idx]); 1315189251Ssam} 1316189251Ssam 1317189251Ssam 1318189251Ssamstatic char * wpa_config_write_wep_key0(const struct parse_data *data, 1319189251Ssam struct wpa_ssid *ssid) 1320189251Ssam{ 1321189251Ssam return wpa_config_write_wep_key(ssid, 0); 1322189251Ssam} 1323189251Ssam 1324189251Ssam 1325189251Ssamstatic char * wpa_config_write_wep_key1(const struct parse_data *data, 1326189251Ssam struct wpa_ssid *ssid) 1327189251Ssam{ 1328189251Ssam return wpa_config_write_wep_key(ssid, 1); 1329189251Ssam} 1330189251Ssam 1331189251Ssam 1332189251Ssamstatic char * wpa_config_write_wep_key2(const struct parse_data *data, 1333189251Ssam struct wpa_ssid *ssid) 1334189251Ssam{ 1335189251Ssam return wpa_config_write_wep_key(ssid, 2); 1336189251Ssam} 1337189251Ssam 1338189251Ssam 1339189251Ssamstatic char * wpa_config_write_wep_key3(const struct parse_data *data, 1340189251Ssam struct wpa_ssid *ssid) 1341189251Ssam{ 1342189251Ssam return wpa_config_write_wep_key(ssid, 3); 1343189251Ssam} 1344189251Ssam#endif /* NO_CONFIG_WRITE */ 1345189251Ssam 1346189251Ssam 1347189251Ssam/* Helper macros for network block parser */ 1348189251Ssam 1349189251Ssam#ifdef OFFSET 1350189251Ssam#undef OFFSET 1351189251Ssam#endif /* OFFSET */ 1352189251Ssam/* OFFSET: Get offset of a variable within the wpa_ssid structure */ 1353189251Ssam#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v) 1354189251Ssam 1355189251Ssam/* STR: Define a string variable for an ASCII string; f = field name */ 1356189251Ssam#ifdef NO_CONFIG_WRITE 1357189251Ssam#define _STR(f) #f, wpa_config_parse_str, OFFSET(f) 1358189251Ssam#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f) 1359189251Ssam#else /* NO_CONFIG_WRITE */ 1360189251Ssam#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f) 1361189251Ssam#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f) 1362189251Ssam#endif /* NO_CONFIG_WRITE */ 1363189251Ssam#define STR(f) _STR(f), NULL, NULL, NULL, 0 1364189251Ssam#define STRe(f) _STRe(f), NULL, NULL, NULL, 0 1365189251Ssam#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1 1366189251Ssam#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1 1367189251Ssam 1368189251Ssam/* STR_LEN: Define a string variable with a separate variable for storing the 1369189251Ssam * data length. Unlike STR(), this can be used to store arbitrary binary data 1370189251Ssam * (i.e., even nul termination character). */ 1371189251Ssam#define _STR_LEN(f) _STR(f), OFFSET(f ## _len) 1372189251Ssam#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len) 1373189251Ssam#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0 1374189251Ssam#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0 1375189251Ssam#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1 1376189251Ssam 1377189251Ssam/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length 1378189251Ssam * explicitly specified. */ 1379189251Ssam#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max) 1380189251Ssam#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0 1381189251Ssam#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1 1382189251Ssam 1383189251Ssam#ifdef NO_CONFIG_WRITE 1384189251Ssam#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0 1385189251Ssam#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0 1386189251Ssam#else /* NO_CONFIG_WRITE */ 1387189251Ssam#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1388189251Ssam OFFSET(f), (void *) 0 1389189251Ssam#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ 1390189251Ssam OFFSET(eap.f), (void *) 0 1391189251Ssam#endif /* NO_CONFIG_WRITE */ 1392189251Ssam 1393189251Ssam/* INT: Define an integer variable */ 1394189251Ssam#define INT(f) _INT(f), NULL, NULL, 0 1395189251Ssam#define INTe(f) _INTe(f), NULL, NULL, 0 1396189251Ssam 1397189251Ssam/* INT_RANGE: Define an integer variable with allowed value range */ 1398189251Ssam#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0 1399189251Ssam 1400189251Ssam/* FUNC: Define a configuration variable that uses a custom function for 1401189251Ssam * parsing and writing the value. */ 1402189251Ssam#ifdef NO_CONFIG_WRITE 1403189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL 1404189251Ssam#else /* NO_CONFIG_WRITE */ 1405189251Ssam#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \ 1406189251Ssam NULL, NULL, NULL, NULL 1407189251Ssam#endif /* NO_CONFIG_WRITE */ 1408189251Ssam#define FUNC(f) _FUNC(f), 0 1409189251Ssam#define FUNC_KEY(f) _FUNC(f), 1 1410189251Ssam 1411189251Ssam/* 1412189251Ssam * Table of network configuration variables. This table is used to parse each 1413189251Ssam * network configuration variable, e.g., each line in wpa_supplicant.conf file 1414189251Ssam * that is inside a network block. 1415189251Ssam * 1416189251Ssam * This table is generated using the helper macros defined above and with 1417189251Ssam * generous help from the C pre-processor. The field name is stored as a string 1418189251Ssam * into .name and for STR and INT types, the offset of the target buffer within 1419189251Ssam * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar 1420189251Ssam * offset to the field containing the length of the configuration variable. 1421189251Ssam * .param3 and .param4 can be used to mark the allowed range (length for STR 1422189251Ssam * and value for INT). 1423189251Ssam * 1424189251Ssam * For each configuration line in wpa_supplicant.conf, the parser goes through 1425189251Ssam * this table and select the entry that matches with the field name. The parser 1426189251Ssam * function (.parser) is then called to parse the actual value of the field. 1427189251Ssam * 1428189251Ssam * This kind of mechanism makes it easy to add new configuration parameters, 1429189251Ssam * since only one line needs to be added into this table and into the 1430189251Ssam * struct wpa_ssid definition if the new variable is either a string or 1431189251Ssam * integer. More complex types will need to use their own parser and writer 1432189251Ssam * functions. 1433189251Ssam */ 1434189251Ssamstatic const struct parse_data ssid_fields[] = { 1435189251Ssam { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, 1436189251Ssam { INT_RANGE(scan_ssid, 0, 1) }, 1437189251Ssam { FUNC(bssid) }, 1438189251Ssam { FUNC_KEY(psk) }, 1439189251Ssam { FUNC(proto) }, 1440189251Ssam { FUNC(key_mgmt) }, 1441189251Ssam { FUNC(pairwise) }, 1442189251Ssam { FUNC(group) }, 1443189251Ssam { FUNC(auth_alg) }, 1444214734Srpaulo { FUNC(scan_freq) }, 1445214734Srpaulo { FUNC(freq_list) }, 1446189251Ssam#ifdef IEEE8021X_EAPOL 1447189251Ssam { FUNC(eap) }, 1448189251Ssam { STR_LENe(identity) }, 1449189251Ssam { STR_LENe(anonymous_identity) }, 1450189251Ssam { FUNC_KEY(password) }, 1451189251Ssam { STRe(ca_cert) }, 1452189251Ssam { STRe(ca_path) }, 1453189251Ssam { STRe(client_cert) }, 1454189251Ssam { STRe(private_key) }, 1455189251Ssam { STR_KEYe(private_key_passwd) }, 1456189251Ssam { STRe(dh_file) }, 1457189251Ssam { STRe(subject_match) }, 1458189251Ssam { STRe(altsubject_match) }, 1459189251Ssam { STRe(ca_cert2) }, 1460189251Ssam { STRe(ca_path2) }, 1461189251Ssam { STRe(client_cert2) }, 1462189251Ssam { STRe(private_key2) }, 1463189251Ssam { STR_KEYe(private_key2_passwd) }, 1464189251Ssam { STRe(dh_file2) }, 1465189251Ssam { STRe(subject_match2) }, 1466189251Ssam { STRe(altsubject_match2) }, 1467189251Ssam { STRe(phase1) }, 1468189251Ssam { STRe(phase2) }, 1469189251Ssam { STRe(pcsc) }, 1470189251Ssam { STR_KEYe(pin) }, 1471189251Ssam { STRe(engine_id) }, 1472189251Ssam { STRe(key_id) }, 1473189251Ssam { STRe(cert_id) }, 1474189251Ssam { STRe(ca_cert_id) }, 1475189251Ssam { STR_KEYe(pin2) }, 1476189251Ssam { STRe(engine2_id) }, 1477189251Ssam { STRe(key2_id) }, 1478189251Ssam { STRe(cert2_id) }, 1479189251Ssam { STRe(ca_cert2_id) }, 1480189251Ssam { INTe(engine) }, 1481189251Ssam { INTe(engine2) }, 1482189251Ssam { INT(eapol_flags) }, 1483189251Ssam#endif /* IEEE8021X_EAPOL */ 1484189251Ssam { FUNC_KEY(wep_key0) }, 1485189251Ssam { FUNC_KEY(wep_key1) }, 1486189251Ssam { FUNC_KEY(wep_key2) }, 1487189251Ssam { FUNC_KEY(wep_key3) }, 1488189251Ssam { INT(wep_tx_keyidx) }, 1489189251Ssam { INT(priority) }, 1490189251Ssam#ifdef IEEE8021X_EAPOL 1491189251Ssam { INT(eap_workaround) }, 1492189251Ssam { STRe(pac_file) }, 1493189251Ssam { INTe(fragment_size) }, 1494189251Ssam#endif /* IEEE8021X_EAPOL */ 1495214734Srpaulo { INT_RANGE(mode, 0, 2) }, 1496189251Ssam { INT_RANGE(proactive_key_caching, 0, 1) }, 1497189251Ssam { INT_RANGE(disabled, 0, 1) }, 1498189251Ssam { STR(id_str) }, 1499189251Ssam#ifdef CONFIG_IEEE80211W 1500189251Ssam { INT_RANGE(ieee80211w, 0, 2) }, 1501189251Ssam#endif /* CONFIG_IEEE80211W */ 1502189251Ssam { INT_RANGE(peerkey, 0, 1) }, 1503189251Ssam { INT_RANGE(mixed_cell, 0, 1) }, 1504189251Ssam { INT_RANGE(frequency, 0, 10000) }, 1505214734Srpaulo { INT(wpa_ptk_rekey) }, 1506214734Srpaulo { STR(bgscan) }, 1507189251Ssam}; 1508189251Ssam 1509189251Ssam#undef OFFSET 1510189251Ssam#undef _STR 1511189251Ssam#undef STR 1512189251Ssam#undef STR_KEY 1513189251Ssam#undef _STR_LEN 1514189251Ssam#undef STR_LEN 1515189251Ssam#undef STR_LEN_KEY 1516189251Ssam#undef _STR_RANGE 1517189251Ssam#undef STR_RANGE 1518189251Ssam#undef STR_RANGE_KEY 1519189251Ssam#undef _INT 1520189251Ssam#undef INT 1521189251Ssam#undef INT_RANGE 1522189251Ssam#undef _FUNC 1523189251Ssam#undef FUNC 1524189251Ssam#undef FUNC_KEY 1525189251Ssam#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0])) 1526189251Ssam 1527189251Ssam 1528189251Ssam/** 1529189251Ssam * wpa_config_add_prio_network - Add a network to priority lists 1530189251Ssam * @config: Configuration data from wpa_config_read() 1531189251Ssam * @ssid: Pointer to the network configuration to be added to the list 1532189251Ssam * Returns: 0 on success, -1 on failure 1533189251Ssam * 1534189251Ssam * This function is used to add a network block to the priority list of 1535189251Ssam * networks. This must be called for each network when reading in the full 1536189251Ssam * configuration. In addition, this can be used indirectly when updating 1537189251Ssam * priorities by calling wpa_config_update_prio_list(). 1538189251Ssam */ 1539189251Ssamint wpa_config_add_prio_network(struct wpa_config *config, 1540189251Ssam struct wpa_ssid *ssid) 1541189251Ssam{ 1542189251Ssam int prio; 1543189251Ssam struct wpa_ssid *prev, **nlist; 1544189251Ssam 1545189251Ssam /* 1546189251Ssam * Add to an existing priority list if one is available for the 1547189251Ssam * configured priority level for this network. 1548189251Ssam */ 1549189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 1550189251Ssam prev = config->pssid[prio]; 1551189251Ssam if (prev->priority == ssid->priority) { 1552189251Ssam while (prev->pnext) 1553189251Ssam prev = prev->pnext; 1554189251Ssam prev->pnext = ssid; 1555189251Ssam return 0; 1556189251Ssam } 1557189251Ssam } 1558189251Ssam 1559189251Ssam /* First network for this priority - add a new priority list */ 1560189251Ssam nlist = os_realloc(config->pssid, 1561189251Ssam (config->num_prio + 1) * sizeof(struct wpa_ssid *)); 1562189251Ssam if (nlist == NULL) 1563189251Ssam return -1; 1564189251Ssam 1565189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 1566189251Ssam if (nlist[prio]->priority < ssid->priority) 1567189251Ssam break; 1568189251Ssam } 1569189251Ssam 1570189251Ssam os_memmove(&nlist[prio + 1], &nlist[prio], 1571189251Ssam (config->num_prio - prio) * sizeof(struct wpa_ssid *)); 1572189251Ssam 1573189251Ssam nlist[prio] = ssid; 1574189251Ssam config->num_prio++; 1575189251Ssam config->pssid = nlist; 1576189251Ssam 1577189251Ssam return 0; 1578189251Ssam} 1579189251Ssam 1580189251Ssam 1581189251Ssam/** 1582189251Ssam * wpa_config_update_prio_list - Update network priority list 1583189251Ssam * @config: Configuration data from wpa_config_read() 1584189251Ssam * Returns: 0 on success, -1 on failure 1585189251Ssam * 1586189251Ssam * This function is called to update the priority list of networks in the 1587189251Ssam * configuration when a network is being added or removed. This is also called 1588189251Ssam * if a priority for a network is changed. 1589189251Ssam */ 1590214734Srpauloint wpa_config_update_prio_list(struct wpa_config *config) 1591189251Ssam{ 1592189251Ssam struct wpa_ssid *ssid; 1593189251Ssam int ret = 0; 1594189251Ssam 1595189251Ssam os_free(config->pssid); 1596189251Ssam config->pssid = NULL; 1597189251Ssam config->num_prio = 0; 1598189251Ssam 1599189251Ssam ssid = config->ssid; 1600189251Ssam while (ssid) { 1601189251Ssam ssid->pnext = NULL; 1602189251Ssam if (wpa_config_add_prio_network(config, ssid) < 0) 1603189251Ssam ret = -1; 1604189251Ssam ssid = ssid->next; 1605189251Ssam } 1606189251Ssam 1607189251Ssam return ret; 1608189251Ssam} 1609189251Ssam 1610189251Ssam 1611189251Ssam#ifdef IEEE8021X_EAPOL 1612189251Ssamstatic void eap_peer_config_free(struct eap_peer_config *eap) 1613189251Ssam{ 1614189251Ssam os_free(eap->eap_methods); 1615189251Ssam os_free(eap->identity); 1616189251Ssam os_free(eap->anonymous_identity); 1617189251Ssam os_free(eap->password); 1618189251Ssam os_free(eap->ca_cert); 1619189251Ssam os_free(eap->ca_path); 1620189251Ssam os_free(eap->client_cert); 1621189251Ssam os_free(eap->private_key); 1622189251Ssam os_free(eap->private_key_passwd); 1623189251Ssam os_free(eap->dh_file); 1624189251Ssam os_free(eap->subject_match); 1625189251Ssam os_free(eap->altsubject_match); 1626189251Ssam os_free(eap->ca_cert2); 1627189251Ssam os_free(eap->ca_path2); 1628189251Ssam os_free(eap->client_cert2); 1629189251Ssam os_free(eap->private_key2); 1630189251Ssam os_free(eap->private_key2_passwd); 1631189251Ssam os_free(eap->dh_file2); 1632189251Ssam os_free(eap->subject_match2); 1633189251Ssam os_free(eap->altsubject_match2); 1634189251Ssam os_free(eap->phase1); 1635189251Ssam os_free(eap->phase2); 1636189251Ssam os_free(eap->pcsc); 1637189251Ssam os_free(eap->pin); 1638189251Ssam os_free(eap->engine_id); 1639189251Ssam os_free(eap->key_id); 1640189251Ssam os_free(eap->cert_id); 1641189251Ssam os_free(eap->ca_cert_id); 1642189251Ssam os_free(eap->key2_id); 1643189251Ssam os_free(eap->cert2_id); 1644189251Ssam os_free(eap->ca_cert2_id); 1645189251Ssam os_free(eap->pin2); 1646189251Ssam os_free(eap->engine2_id); 1647189251Ssam os_free(eap->otp); 1648189251Ssam os_free(eap->pending_req_otp); 1649189251Ssam os_free(eap->pac_file); 1650189251Ssam os_free(eap->new_password); 1651189251Ssam} 1652189251Ssam#endif /* IEEE8021X_EAPOL */ 1653189251Ssam 1654189251Ssam 1655189251Ssam/** 1656189251Ssam * wpa_config_free_ssid - Free network/ssid configuration data 1657189251Ssam * @ssid: Configuration data for the network 1658189251Ssam * 1659189251Ssam * This function frees all resources allocated for the network configuration 1660189251Ssam * data. 1661189251Ssam */ 1662189251Ssamvoid wpa_config_free_ssid(struct wpa_ssid *ssid) 1663189251Ssam{ 1664189251Ssam os_free(ssid->ssid); 1665189251Ssam os_free(ssid->passphrase); 1666189251Ssam#ifdef IEEE8021X_EAPOL 1667189251Ssam eap_peer_config_free(&ssid->eap); 1668189251Ssam#endif /* IEEE8021X_EAPOL */ 1669189251Ssam os_free(ssid->id_str); 1670214734Srpaulo os_free(ssid->scan_freq); 1671214734Srpaulo os_free(ssid->freq_list); 1672214734Srpaulo os_free(ssid->bgscan); 1673189251Ssam os_free(ssid); 1674189251Ssam} 1675189251Ssam 1676189251Ssam 1677189251Ssam/** 1678189251Ssam * wpa_config_free - Free configuration data 1679189251Ssam * @config: Configuration data from wpa_config_read() 1680189251Ssam * 1681189251Ssam * This function frees all resources allocated for the configuration data by 1682189251Ssam * wpa_config_read(). 1683189251Ssam */ 1684189251Ssamvoid wpa_config_free(struct wpa_config *config) 1685189251Ssam{ 1686189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 1687189251Ssam struct wpa_config_blob *blob, *prevblob; 1688189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 1689189251Ssam struct wpa_ssid *ssid, *prev = NULL; 1690189251Ssam ssid = config->ssid; 1691189251Ssam while (ssid) { 1692189251Ssam prev = ssid; 1693189251Ssam ssid = ssid->next; 1694189251Ssam wpa_config_free_ssid(prev); 1695189251Ssam } 1696189251Ssam 1697189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 1698189251Ssam blob = config->blobs; 1699189251Ssam prevblob = NULL; 1700189251Ssam while (blob) { 1701189251Ssam prevblob = blob; 1702189251Ssam blob = blob->next; 1703189251Ssam wpa_config_free_blob(prevblob); 1704189251Ssam } 1705189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 1706189251Ssam 1707189251Ssam os_free(config->ctrl_interface); 1708189251Ssam os_free(config->ctrl_interface_group); 1709189251Ssam os_free(config->opensc_engine_path); 1710189251Ssam os_free(config->pkcs11_engine_path); 1711189251Ssam os_free(config->pkcs11_module_path); 1712189251Ssam os_free(config->driver_param); 1713189251Ssam os_free(config->device_name); 1714189251Ssam os_free(config->manufacturer); 1715189251Ssam os_free(config->model_name); 1716189251Ssam os_free(config->model_number); 1717189251Ssam os_free(config->serial_number); 1718189251Ssam os_free(config->device_type); 1719214734Srpaulo os_free(config->config_methods); 1720189251Ssam os_free(config->pssid); 1721189251Ssam os_free(config); 1722189251Ssam} 1723189251Ssam 1724189251Ssam 1725189251Ssam/** 1726189251Ssam * wpa_config_get_network - Get configured network based on id 1727189251Ssam * @config: Configuration data from wpa_config_read() 1728189251Ssam * @id: Unique network id to search for 1729189251Ssam * Returns: Network configuration or %NULL if not found 1730189251Ssam */ 1731189251Ssamstruct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id) 1732189251Ssam{ 1733189251Ssam struct wpa_ssid *ssid; 1734189251Ssam 1735189251Ssam ssid = config->ssid; 1736189251Ssam while (ssid) { 1737189251Ssam if (id == ssid->id) 1738189251Ssam break; 1739189251Ssam ssid = ssid->next; 1740189251Ssam } 1741189251Ssam 1742189251Ssam return ssid; 1743189251Ssam} 1744189251Ssam 1745189251Ssam 1746189251Ssam/** 1747189251Ssam * wpa_config_add_network - Add a new network with empty configuration 1748189251Ssam * @config: Configuration data from wpa_config_read() 1749189251Ssam * Returns: The new network configuration or %NULL if operation failed 1750189251Ssam */ 1751189251Ssamstruct wpa_ssid * wpa_config_add_network(struct wpa_config *config) 1752189251Ssam{ 1753189251Ssam int id; 1754189251Ssam struct wpa_ssid *ssid, *last = NULL; 1755189251Ssam 1756189251Ssam id = -1; 1757189251Ssam ssid = config->ssid; 1758189251Ssam while (ssid) { 1759189251Ssam if (ssid->id > id) 1760189251Ssam id = ssid->id; 1761189251Ssam last = ssid; 1762189251Ssam ssid = ssid->next; 1763189251Ssam } 1764189251Ssam id++; 1765189251Ssam 1766189251Ssam ssid = os_zalloc(sizeof(*ssid)); 1767189251Ssam if (ssid == NULL) 1768189251Ssam return NULL; 1769189251Ssam ssid->id = id; 1770189251Ssam if (last) 1771189251Ssam last->next = ssid; 1772189251Ssam else 1773189251Ssam config->ssid = ssid; 1774189251Ssam 1775189251Ssam wpa_config_update_prio_list(config); 1776189251Ssam 1777189251Ssam return ssid; 1778189251Ssam} 1779189251Ssam 1780189251Ssam 1781189251Ssam/** 1782189251Ssam * wpa_config_remove_network - Remove a configured network based on id 1783189251Ssam * @config: Configuration data from wpa_config_read() 1784189251Ssam * @id: Unique network id to search for 1785189251Ssam * Returns: 0 on success, or -1 if the network was not found 1786189251Ssam */ 1787189251Ssamint wpa_config_remove_network(struct wpa_config *config, int id) 1788189251Ssam{ 1789189251Ssam struct wpa_ssid *ssid, *prev = NULL; 1790189251Ssam 1791189251Ssam ssid = config->ssid; 1792189251Ssam while (ssid) { 1793189251Ssam if (id == ssid->id) 1794189251Ssam break; 1795189251Ssam prev = ssid; 1796189251Ssam ssid = ssid->next; 1797189251Ssam } 1798189251Ssam 1799189251Ssam if (ssid == NULL) 1800189251Ssam return -1; 1801189251Ssam 1802189251Ssam if (prev) 1803189251Ssam prev->next = ssid->next; 1804189251Ssam else 1805189251Ssam config->ssid = ssid->next; 1806189251Ssam 1807189251Ssam wpa_config_update_prio_list(config); 1808189251Ssam wpa_config_free_ssid(ssid); 1809189251Ssam return 0; 1810189251Ssam} 1811189251Ssam 1812189251Ssam 1813189251Ssam/** 1814189251Ssam * wpa_config_set_network_defaults - Set network default values 1815189251Ssam * @ssid: Pointer to network configuration data 1816189251Ssam */ 1817189251Ssamvoid wpa_config_set_network_defaults(struct wpa_ssid *ssid) 1818189251Ssam{ 1819189251Ssam ssid->proto = DEFAULT_PROTO; 1820189251Ssam ssid->pairwise_cipher = DEFAULT_PAIRWISE; 1821189251Ssam ssid->group_cipher = DEFAULT_GROUP; 1822189251Ssam ssid->key_mgmt = DEFAULT_KEY_MGMT; 1823189251Ssam#ifdef IEEE8021X_EAPOL 1824189251Ssam ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; 1825189251Ssam ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; 1826189251Ssam ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; 1827189251Ssam#endif /* IEEE8021X_EAPOL */ 1828189251Ssam} 1829189251Ssam 1830189251Ssam 1831189251Ssam/** 1832189251Ssam * wpa_config_set - Set a variable in network configuration 1833189251Ssam * @ssid: Pointer to network configuration data 1834189251Ssam * @var: Variable name, e.g., "ssid" 1835189251Ssam * @value: Variable value 1836189251Ssam * @line: Line number in configuration file or 0 if not used 1837189251Ssam * Returns: 0 on success, -1 on failure 1838189251Ssam * 1839189251Ssam * This function can be used to set network configuration variables based on 1840189251Ssam * both the configuration file and management interface input. The value 1841189251Ssam * parameter must be in the same format as the text-based configuration file is 1842189251Ssam * using. For example, strings are using double quotation marks. 1843189251Ssam */ 1844189251Ssamint wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value, 1845189251Ssam int line) 1846189251Ssam{ 1847189251Ssam size_t i; 1848189251Ssam int ret = 0; 1849189251Ssam 1850189251Ssam if (ssid == NULL || var == NULL || value == NULL) 1851189251Ssam return -1; 1852189251Ssam 1853189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 1854189251Ssam const struct parse_data *field = &ssid_fields[i]; 1855189251Ssam if (os_strcmp(var, field->name) != 0) 1856189251Ssam continue; 1857189251Ssam 1858189251Ssam if (field->parser(field, ssid, line, value)) { 1859189251Ssam if (line) { 1860189251Ssam wpa_printf(MSG_ERROR, "Line %d: failed to " 1861189251Ssam "parse %s '%s'.", line, var, value); 1862189251Ssam } 1863189251Ssam ret = -1; 1864189251Ssam } 1865189251Ssam break; 1866189251Ssam } 1867189251Ssam if (i == NUM_SSID_FIELDS) { 1868189251Ssam if (line) { 1869189251Ssam wpa_printf(MSG_ERROR, "Line %d: unknown network field " 1870189251Ssam "'%s'.", line, var); 1871189251Ssam } 1872189251Ssam ret = -1; 1873189251Ssam } 1874189251Ssam 1875189251Ssam return ret; 1876189251Ssam} 1877189251Ssam 1878189251Ssam 1879214734Srpaulo/** 1880214734Srpaulo * wpa_config_get_all - Get all options from network configuration 1881214734Srpaulo * @ssid: Pointer to network configuration data 1882214734Srpaulo * @get_keys: Determines if keys/passwords will be included in returned list 1883214734Srpaulo * Returns: %NULL terminated list of all set keys and their values in the form 1884214734Srpaulo * of [key1, val1, key2, val2, ... , NULL] 1885214734Srpaulo * 1886214734Srpaulo * This function can be used to get list of all configured network properties. 1887214734Srpaulo * The caller is responsible for freeing the returned list and all its 1888214734Srpaulo * elements. 1889214734Srpaulo */ 1890214734Srpaulochar ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) 1891214734Srpaulo{ 1892214734Srpaulo const struct parse_data *field; 1893214734Srpaulo char *key, *value; 1894214734Srpaulo size_t i; 1895214734Srpaulo char **props; 1896214734Srpaulo int fields_num; 1897214734Srpaulo 1898214734Srpaulo props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1)); 1899214734Srpaulo if (!props) 1900214734Srpaulo return NULL; 1901214734Srpaulo 1902214734Srpaulo fields_num = 0; 1903214734Srpaulo for (i = 0; i < NUM_SSID_FIELDS; i++) { 1904214734Srpaulo field = &ssid_fields[i]; 1905214734Srpaulo if (field->key_data && !get_keys) 1906214734Srpaulo continue; 1907214734Srpaulo value = field->writer(field, ssid); 1908214734Srpaulo if (value == NULL) 1909214734Srpaulo continue; 1910214734Srpaulo if (os_strlen(value) == 0) { 1911214734Srpaulo os_free(value); 1912214734Srpaulo continue; 1913214734Srpaulo } 1914214734Srpaulo 1915214734Srpaulo key = os_strdup(field->name); 1916214734Srpaulo if (key == NULL) { 1917214734Srpaulo os_free(value); 1918214734Srpaulo goto err; 1919214734Srpaulo } 1920214734Srpaulo 1921214734Srpaulo props[fields_num * 2] = key; 1922214734Srpaulo props[fields_num * 2 + 1] = value; 1923214734Srpaulo 1924214734Srpaulo fields_num++; 1925214734Srpaulo } 1926214734Srpaulo 1927214734Srpaulo return props; 1928214734Srpaulo 1929214734Srpauloerr: 1930214734Srpaulo value = *props; 1931214734Srpaulo while (value) 1932214734Srpaulo os_free(value++); 1933214734Srpaulo os_free(props); 1934214734Srpaulo return NULL; 1935214734Srpaulo} 1936214734Srpaulo 1937214734Srpaulo 1938189251Ssam#ifndef NO_CONFIG_WRITE 1939189251Ssam/** 1940189251Ssam * wpa_config_get - Get a variable in network configuration 1941189251Ssam * @ssid: Pointer to network configuration data 1942189251Ssam * @var: Variable name, e.g., "ssid" 1943189251Ssam * Returns: Value of the variable or %NULL on failure 1944189251Ssam * 1945189251Ssam * This function can be used to get network configuration variables. The 1946189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 1947189251Ssam * the same format that the text-based configuration file and wpa_config_set() 1948189251Ssam * are using for the value. The caller is responsible for freeing the returned 1949189251Ssam * value. 1950189251Ssam */ 1951189251Ssamchar * wpa_config_get(struct wpa_ssid *ssid, const char *var) 1952189251Ssam{ 1953189251Ssam size_t i; 1954189251Ssam 1955189251Ssam if (ssid == NULL || var == NULL) 1956189251Ssam return NULL; 1957189251Ssam 1958189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 1959189251Ssam const struct parse_data *field = &ssid_fields[i]; 1960189251Ssam if (os_strcmp(var, field->name) == 0) 1961189251Ssam return field->writer(field, ssid); 1962189251Ssam } 1963189251Ssam 1964189251Ssam return NULL; 1965189251Ssam} 1966189251Ssam 1967189251Ssam 1968189251Ssam/** 1969189251Ssam * wpa_config_get_no_key - Get a variable in network configuration (no keys) 1970189251Ssam * @ssid: Pointer to network configuration data 1971189251Ssam * @var: Variable name, e.g., "ssid" 1972189251Ssam * Returns: Value of the variable or %NULL on failure 1973189251Ssam * 1974189251Ssam * This function can be used to get network configuration variable like 1975189251Ssam * wpa_config_get(). The only difference is that this functions does not expose 1976189251Ssam * key/password material from the configuration. In case a key/password field 1977189251Ssam * is requested, the returned value is an empty string or %NULL if the variable 1978189251Ssam * is not set or "*" if the variable is set (regardless of its value). The 1979189251Ssam * returned value is a copy of the configuration variable in text format, i.e,. 1980189251Ssam * the same format that the text-based configuration file and wpa_config_set() 1981189251Ssam * are using for the value. The caller is responsible for freeing the returned 1982189251Ssam * value. 1983189251Ssam */ 1984189251Ssamchar * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) 1985189251Ssam{ 1986189251Ssam size_t i; 1987189251Ssam 1988189251Ssam if (ssid == NULL || var == NULL) 1989189251Ssam return NULL; 1990189251Ssam 1991189251Ssam for (i = 0; i < NUM_SSID_FIELDS; i++) { 1992189251Ssam const struct parse_data *field = &ssid_fields[i]; 1993189251Ssam if (os_strcmp(var, field->name) == 0) { 1994189251Ssam char *res = field->writer(field, ssid); 1995189251Ssam if (field->key_data) { 1996189251Ssam if (res && res[0]) { 1997189251Ssam wpa_printf(MSG_DEBUG, "Do not allow " 1998189251Ssam "key_data field to be " 1999189251Ssam "exposed"); 2000189251Ssam os_free(res); 2001189251Ssam return os_strdup("*"); 2002189251Ssam } 2003189251Ssam 2004189251Ssam os_free(res); 2005189251Ssam return NULL; 2006189251Ssam } 2007189251Ssam return res; 2008189251Ssam } 2009189251Ssam } 2010189251Ssam 2011189251Ssam return NULL; 2012189251Ssam} 2013189251Ssam#endif /* NO_CONFIG_WRITE */ 2014189251Ssam 2015189251Ssam 2016189251Ssam/** 2017189251Ssam * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID 2018189251Ssam * @ssid: Pointer to network configuration data 2019189251Ssam * 2020189251Ssam * This function must be called to update WPA PSK when either SSID or the 2021189251Ssam * passphrase has changed for the network configuration. 2022189251Ssam */ 2023189251Ssamvoid wpa_config_update_psk(struct wpa_ssid *ssid) 2024189251Ssam{ 2025189251Ssam#ifndef CONFIG_NO_PBKDF2 2026189251Ssam pbkdf2_sha1(ssid->passphrase, 2027189251Ssam (char *) ssid->ssid, ssid->ssid_len, 4096, 2028189251Ssam ssid->psk, PMK_LEN); 2029189251Ssam wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", 2030189251Ssam ssid->psk, PMK_LEN); 2031189251Ssam ssid->psk_set = 1; 2032189251Ssam#endif /* CONFIG_NO_PBKDF2 */ 2033189251Ssam} 2034189251Ssam 2035189251Ssam 2036189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 2037189251Ssam/** 2038189251Ssam * wpa_config_get_blob - Get a named configuration blob 2039189251Ssam * @config: Configuration data from wpa_config_read() 2040189251Ssam * @name: Name of the blob 2041189251Ssam * Returns: Pointer to blob data or %NULL if not found 2042189251Ssam */ 2043189251Ssamconst struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config, 2044189251Ssam const char *name) 2045189251Ssam{ 2046189251Ssam struct wpa_config_blob *blob = config->blobs; 2047189251Ssam 2048189251Ssam while (blob) { 2049189251Ssam if (os_strcmp(blob->name, name) == 0) 2050189251Ssam return blob; 2051189251Ssam blob = blob->next; 2052189251Ssam } 2053189251Ssam return NULL; 2054189251Ssam} 2055189251Ssam 2056189251Ssam 2057189251Ssam/** 2058189251Ssam * wpa_config_set_blob - Set or add a named configuration blob 2059189251Ssam * @config: Configuration data from wpa_config_read() 2060189251Ssam * @blob: New value for the blob 2061189251Ssam * 2062189251Ssam * Adds a new configuration blob or replaces the current value of an existing 2063189251Ssam * blob. 2064189251Ssam */ 2065189251Ssamvoid wpa_config_set_blob(struct wpa_config *config, 2066189251Ssam struct wpa_config_blob *blob) 2067189251Ssam{ 2068189251Ssam wpa_config_remove_blob(config, blob->name); 2069189251Ssam blob->next = config->blobs; 2070189251Ssam config->blobs = blob; 2071189251Ssam} 2072189251Ssam 2073189251Ssam 2074189251Ssam/** 2075189251Ssam * wpa_config_free_blob - Free blob data 2076189251Ssam * @blob: Pointer to blob to be freed 2077189251Ssam */ 2078189251Ssamvoid wpa_config_free_blob(struct wpa_config_blob *blob) 2079189251Ssam{ 2080189251Ssam if (blob) { 2081189251Ssam os_free(blob->name); 2082189251Ssam os_free(blob->data); 2083189251Ssam os_free(blob); 2084189251Ssam } 2085189251Ssam} 2086189251Ssam 2087189251Ssam 2088189251Ssam/** 2089189251Ssam * wpa_config_remove_blob - Remove a named configuration blob 2090189251Ssam * @config: Configuration data from wpa_config_read() 2091189251Ssam * @name: Name of the blob to remove 2092189251Ssam * Returns: 0 if blob was removed or -1 if blob was not found 2093189251Ssam */ 2094189251Ssamint wpa_config_remove_blob(struct wpa_config *config, const char *name) 2095189251Ssam{ 2096189251Ssam struct wpa_config_blob *pos = config->blobs, *prev = NULL; 2097189251Ssam 2098189251Ssam while (pos) { 2099189251Ssam if (os_strcmp(pos->name, name) == 0) { 2100189251Ssam if (prev) 2101189251Ssam prev->next = pos->next; 2102189251Ssam else 2103189251Ssam config->blobs = pos->next; 2104189251Ssam wpa_config_free_blob(pos); 2105189251Ssam return 0; 2106189251Ssam } 2107189251Ssam prev = pos; 2108189251Ssam pos = pos->next; 2109189251Ssam } 2110189251Ssam 2111189251Ssam return -1; 2112189251Ssam} 2113189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 2114189251Ssam 2115189251Ssam 2116189251Ssam/** 2117189251Ssam * wpa_config_alloc_empty - Allocate an empty configuration 2118189251Ssam * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain 2119189251Ssam * socket 2120189251Ssam * @driver_param: Driver parameters 2121189251Ssam * Returns: Pointer to allocated configuration data or %NULL on failure 2122189251Ssam */ 2123189251Ssamstruct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, 2124189251Ssam const char *driver_param) 2125189251Ssam{ 2126189251Ssam struct wpa_config *config; 2127189251Ssam 2128189251Ssam config = os_zalloc(sizeof(*config)); 2129189251Ssam if (config == NULL) 2130189251Ssam return NULL; 2131189251Ssam config->eapol_version = DEFAULT_EAPOL_VERSION; 2132189251Ssam config->ap_scan = DEFAULT_AP_SCAN; 2133189251Ssam config->fast_reauth = DEFAULT_FAST_REAUTH; 2134214734Srpaulo config->bss_max_count = DEFAULT_BSS_MAX_COUNT; 2135189251Ssam 2136189251Ssam if (ctrl_interface) 2137189251Ssam config->ctrl_interface = os_strdup(ctrl_interface); 2138189251Ssam if (driver_param) 2139189251Ssam config->driver_param = os_strdup(driver_param); 2140189251Ssam 2141189251Ssam return config; 2142189251Ssam} 2143189251Ssam 2144189251Ssam 2145189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG 2146189251Ssam/** 2147189251Ssam * wpa_config_debug_dump_networks - Debug dump of configured networks 2148189251Ssam * @config: Configuration data from wpa_config_read() 2149189251Ssam */ 2150189251Ssamvoid wpa_config_debug_dump_networks(struct wpa_config *config) 2151189251Ssam{ 2152189251Ssam int prio; 2153189251Ssam struct wpa_ssid *ssid; 2154189251Ssam 2155189251Ssam for (prio = 0; prio < config->num_prio; prio++) { 2156189251Ssam ssid = config->pssid[prio]; 2157189251Ssam wpa_printf(MSG_DEBUG, "Priority group %d", 2158189251Ssam ssid->priority); 2159189251Ssam while (ssid) { 2160189251Ssam wpa_printf(MSG_DEBUG, " id=%d ssid='%s'", 2161189251Ssam ssid->id, 2162189251Ssam wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); 2163189251Ssam ssid = ssid->pnext; 2164189251Ssam } 2165189251Ssam } 2166189251Ssam} 2167189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */ 2168