1252190Srpaulo/* 2252190Srpaulo * hostapd / EAP user database 3252190Srpaulo * Copyright (c) 2012, Jouni Malinen <j@w1.fi> 4252190Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7252190Srpaulo */ 8252190Srpaulo 9252190Srpaulo#include "includes.h" 10252190Srpaulo#ifdef CONFIG_SQLITE 11252190Srpaulo#include <sqlite3.h> 12252190Srpaulo#endif /* CONFIG_SQLITE */ 13252190Srpaulo 14252190Srpaulo#include "common.h" 15252190Srpaulo#include "eap_common/eap_wsc_common.h" 16252190Srpaulo#include "eap_server/eap_methods.h" 17252190Srpaulo#include "eap_server/eap.h" 18252190Srpaulo#include "ap_config.h" 19252190Srpaulo#include "hostapd.h" 20252190Srpaulo 21252190Srpaulo#ifdef CONFIG_SQLITE 22252190Srpaulo 23252190Srpaulostatic void set_user_methods(struct hostapd_eap_user *user, const char *methods) 24252190Srpaulo{ 25252190Srpaulo char *buf, *start; 26252190Srpaulo int num_methods; 27252190Srpaulo 28252190Srpaulo buf = os_strdup(methods); 29252190Srpaulo if (buf == NULL) 30252190Srpaulo return; 31252190Srpaulo 32252190Srpaulo os_memset(&user->methods, 0, sizeof(user->methods)); 33252190Srpaulo num_methods = 0; 34252190Srpaulo start = buf; 35252190Srpaulo while (*start) { 36252190Srpaulo char *pos3 = os_strchr(start, ','); 37252190Srpaulo if (pos3) 38252190Srpaulo *pos3++ = '\0'; 39252190Srpaulo user->methods[num_methods].method = 40252190Srpaulo eap_server_get_type(start, 41252190Srpaulo &user->methods[num_methods].vendor); 42252190Srpaulo if (user->methods[num_methods].vendor == EAP_VENDOR_IETF && 43252190Srpaulo user->methods[num_methods].method == EAP_TYPE_NONE) { 44252190Srpaulo if (os_strcmp(start, "TTLS-PAP") == 0) { 45252190Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_PAP; 46252190Srpaulo goto skip_eap; 47252190Srpaulo } 48252190Srpaulo if (os_strcmp(start, "TTLS-CHAP") == 0) { 49252190Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_CHAP; 50252190Srpaulo goto skip_eap; 51252190Srpaulo } 52252190Srpaulo if (os_strcmp(start, "TTLS-MSCHAP") == 0) { 53252190Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP; 54252190Srpaulo goto skip_eap; 55252190Srpaulo } 56252190Srpaulo if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) { 57252190Srpaulo user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2; 58252190Srpaulo goto skip_eap; 59252190Srpaulo } 60252190Srpaulo wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'", 61252190Srpaulo start); 62252190Srpaulo os_free(buf); 63252190Srpaulo return; 64252190Srpaulo } 65252190Srpaulo 66252190Srpaulo num_methods++; 67252190Srpaulo if (num_methods >= EAP_MAX_METHODS) 68252190Srpaulo break; 69252190Srpaulo skip_eap: 70252190Srpaulo if (pos3 == NULL) 71252190Srpaulo break; 72252190Srpaulo start = pos3; 73252190Srpaulo } 74252190Srpaulo 75252190Srpaulo os_free(buf); 76252190Srpaulo} 77252190Srpaulo 78252190Srpaulo 79252190Srpaulostatic int get_user_cb(void *ctx, int argc, char *argv[], char *col[]) 80252190Srpaulo{ 81252190Srpaulo struct hostapd_eap_user *user = ctx; 82252190Srpaulo int i; 83252190Srpaulo 84252190Srpaulo for (i = 0; i < argc; i++) { 85252190Srpaulo if (os_strcmp(col[i], "password") == 0 && argv[i]) { 86281806Srpaulo bin_clear_free(user->password, user->password_len); 87252190Srpaulo user->password_len = os_strlen(argv[i]); 88252190Srpaulo user->password = (u8 *) os_strdup(argv[i]); 89252190Srpaulo user->next = (void *) 1; 90252190Srpaulo } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) { 91252190Srpaulo set_user_methods(user, argv[i]); 92281806Srpaulo } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) { 93281806Srpaulo user->remediation = strlen(argv[i]) > 0; 94252190Srpaulo } 95252190Srpaulo } 96252190Srpaulo 97252190Srpaulo return 0; 98252190Srpaulo} 99252190Srpaulo 100252190Srpaulo 101252190Srpaulostatic int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[]) 102252190Srpaulo{ 103252190Srpaulo struct hostapd_eap_user *user = ctx; 104252190Srpaulo int i, id = -1, methods = -1; 105252190Srpaulo size_t len; 106252190Srpaulo 107252190Srpaulo for (i = 0; i < argc; i++) { 108252190Srpaulo if (os_strcmp(col[i], "identity") == 0 && argv[i]) 109252190Srpaulo id = i; 110252190Srpaulo else if (os_strcmp(col[i], "methods") == 0 && argv[i]) 111252190Srpaulo methods = i; 112252190Srpaulo } 113252190Srpaulo 114252190Srpaulo if (id < 0 || methods < 0) 115252190Srpaulo return 0; 116252190Srpaulo 117252190Srpaulo len = os_strlen(argv[id]); 118252190Srpaulo if (len <= user->identity_len && 119252190Srpaulo os_memcmp(argv[id], user->identity, len) == 0 && 120252190Srpaulo (user->password == NULL || len > user->password_len)) { 121281806Srpaulo bin_clear_free(user->password, user->password_len); 122252190Srpaulo user->password_len = os_strlen(argv[id]); 123252190Srpaulo user->password = (u8 *) os_strdup(argv[id]); 124252190Srpaulo user->next = (void *) 1; 125252190Srpaulo set_user_methods(user, argv[methods]); 126252190Srpaulo } 127252190Srpaulo 128252190Srpaulo return 0; 129252190Srpaulo} 130252190Srpaulo 131252190Srpaulo 132252190Srpaulostatic const struct hostapd_eap_user * 133252190Srpauloeap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, 134252190Srpaulo size_t identity_len, int phase2) 135252190Srpaulo{ 136252190Srpaulo sqlite3 *db; 137252190Srpaulo struct hostapd_eap_user *user = NULL; 138252190Srpaulo char id_str[256], cmd[300]; 139252190Srpaulo size_t i; 140252190Srpaulo 141289549Srpaulo if (identity_len >= sizeof(id_str)) { 142289549Srpaulo wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d", 143289549Srpaulo __func__, (int) identity_len, 144289549Srpaulo (int) (sizeof(id_str))); 145252190Srpaulo return NULL; 146289549Srpaulo } 147252190Srpaulo os_memcpy(id_str, identity, identity_len); 148252190Srpaulo id_str[identity_len] = '\0'; 149252190Srpaulo for (i = 0; i < identity_len; i++) { 150252190Srpaulo if (id_str[i] >= 'a' && id_str[i] <= 'z') 151252190Srpaulo continue; 152252190Srpaulo if (id_str[i] >= 'A' && id_str[i] <= 'Z') 153252190Srpaulo continue; 154252190Srpaulo if (id_str[i] >= '0' && id_str[i] <= '9') 155252190Srpaulo continue; 156252190Srpaulo if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' || 157252190Srpaulo id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' || 158252190Srpaulo id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' || 159252190Srpaulo id_str[i] == '=' || id_str[i] == ' ') 160252190Srpaulo continue; 161252190Srpaulo wpa_printf(MSG_INFO, "DB: Unsupported character in identity"); 162252190Srpaulo return NULL; 163252190Srpaulo } 164252190Srpaulo 165281806Srpaulo bin_clear_free(hapd->tmp_eap_user.identity, 166281806Srpaulo hapd->tmp_eap_user.identity_len); 167281806Srpaulo bin_clear_free(hapd->tmp_eap_user.password, 168281806Srpaulo hapd->tmp_eap_user.password_len); 169252190Srpaulo os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user)); 170252190Srpaulo hapd->tmp_eap_user.phase2 = phase2; 171252190Srpaulo hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1); 172252190Srpaulo if (hapd->tmp_eap_user.identity == NULL) 173252190Srpaulo return NULL; 174252190Srpaulo os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len); 175252190Srpaulo 176252190Srpaulo if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) { 177252190Srpaulo wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s", 178252190Srpaulo hapd->conf->eap_user_sqlite, sqlite3_errmsg(db)); 179252190Srpaulo sqlite3_close(db); 180252190Srpaulo return NULL; 181252190Srpaulo } 182252190Srpaulo 183252190Srpaulo os_snprintf(cmd, sizeof(cmd), 184281806Srpaulo "SELECT * FROM users WHERE identity='%s' AND phase2=%d;", 185281806Srpaulo id_str, phase2); 186252190Srpaulo wpa_printf(MSG_DEBUG, "DB: %s", cmd); 187252190Srpaulo if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) != 188252190Srpaulo SQLITE_OK) { 189289549Srpaulo wpa_printf(MSG_DEBUG, 190289549Srpaulo "DB: Failed to complete SQL operation: %s db: %s", 191289549Srpaulo sqlite3_errmsg(db), hapd->conf->eap_user_sqlite); 192252190Srpaulo } else if (hapd->tmp_eap_user.next) 193252190Srpaulo user = &hapd->tmp_eap_user; 194252190Srpaulo 195252190Srpaulo if (user == NULL && !phase2) { 196252190Srpaulo os_snprintf(cmd, sizeof(cmd), 197252190Srpaulo "SELECT identity,methods FROM wildcards;"); 198252190Srpaulo wpa_printf(MSG_DEBUG, "DB: %s", cmd); 199252190Srpaulo if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user, 200252190Srpaulo NULL) != SQLITE_OK) { 201289549Srpaulo wpa_printf(MSG_DEBUG, 202289549Srpaulo "DB: Failed to complete SQL operation: %s db: %s", 203289549Srpaulo sqlite3_errmsg(db), 204289549Srpaulo hapd->conf->eap_user_sqlite); 205252190Srpaulo } else if (hapd->tmp_eap_user.next) { 206252190Srpaulo user = &hapd->tmp_eap_user; 207252190Srpaulo os_free(user->identity); 208252190Srpaulo user->identity = user->password; 209252190Srpaulo user->identity_len = user->password_len; 210252190Srpaulo user->password = NULL; 211252190Srpaulo user->password_len = 0; 212252190Srpaulo } 213252190Srpaulo } 214252190Srpaulo 215252190Srpaulo sqlite3_close(db); 216252190Srpaulo 217252190Srpaulo return user; 218252190Srpaulo} 219252190Srpaulo 220252190Srpaulo#endif /* CONFIG_SQLITE */ 221252190Srpaulo 222252190Srpaulo 223252190Srpauloconst struct hostapd_eap_user * 224252190Srpaulohostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, 225252190Srpaulo size_t identity_len, int phase2) 226252190Srpaulo{ 227252190Srpaulo const struct hostapd_bss_config *conf = hapd->conf; 228252190Srpaulo struct hostapd_eap_user *user = conf->eap_user; 229252190Srpaulo 230252190Srpaulo#ifdef CONFIG_WPS 231252190Srpaulo if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN && 232252190Srpaulo os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) { 233252190Srpaulo static struct hostapd_eap_user wsc_enrollee; 234252190Srpaulo os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee)); 235252190Srpaulo wsc_enrollee.methods[0].method = eap_server_get_type( 236252190Srpaulo "WSC", &wsc_enrollee.methods[0].vendor); 237252190Srpaulo return &wsc_enrollee; 238252190Srpaulo } 239252190Srpaulo 240252190Srpaulo if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN && 241252190Srpaulo os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) { 242252190Srpaulo static struct hostapd_eap_user wsc_registrar; 243252190Srpaulo os_memset(&wsc_registrar, 0, sizeof(wsc_registrar)); 244252190Srpaulo wsc_registrar.methods[0].method = eap_server_get_type( 245252190Srpaulo "WSC", &wsc_registrar.methods[0].vendor); 246252190Srpaulo wsc_registrar.password = (u8 *) conf->ap_pin; 247252190Srpaulo wsc_registrar.password_len = conf->ap_pin ? 248252190Srpaulo os_strlen(conf->ap_pin) : 0; 249252190Srpaulo return &wsc_registrar; 250252190Srpaulo } 251252190Srpaulo#endif /* CONFIG_WPS */ 252252190Srpaulo 253252190Srpaulo while (user) { 254252190Srpaulo if (!phase2 && user->identity == NULL) { 255252190Srpaulo /* Wildcard match */ 256252190Srpaulo break; 257252190Srpaulo } 258252190Srpaulo 259252190Srpaulo if (user->phase2 == !!phase2 && user->wildcard_prefix && 260252190Srpaulo identity_len >= user->identity_len && 261252190Srpaulo os_memcmp(user->identity, identity, user->identity_len) == 262252190Srpaulo 0) { 263252190Srpaulo /* Wildcard prefix match */ 264252190Srpaulo break; 265252190Srpaulo } 266252190Srpaulo 267252190Srpaulo if (user->phase2 == !!phase2 && 268252190Srpaulo user->identity_len == identity_len && 269252190Srpaulo os_memcmp(user->identity, identity, identity_len) == 0) 270252190Srpaulo break; 271252190Srpaulo user = user->next; 272252190Srpaulo } 273252190Srpaulo 274252190Srpaulo#ifdef CONFIG_SQLITE 275252190Srpaulo if (user == NULL && conf->eap_user_sqlite) { 276252190Srpaulo return eap_user_sqlite_get(hapd, identity, identity_len, 277252190Srpaulo phase2); 278252190Srpaulo } 279252190Srpaulo#endif /* CONFIG_SQLITE */ 280252190Srpaulo 281252190Srpaulo return user; 282252190Srpaulo} 283