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]) { 86252190Srpaulo os_free(user->password); 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]); 92252190Srpaulo } 93252190Srpaulo } 94252190Srpaulo 95252190Srpaulo return 0; 96252190Srpaulo} 97252190Srpaulo 98252190Srpaulo 99252190Srpaulostatic int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[]) 100252190Srpaulo{ 101252190Srpaulo struct hostapd_eap_user *user = ctx; 102252190Srpaulo int i, id = -1, methods = -1; 103252190Srpaulo size_t len; 104252190Srpaulo 105252190Srpaulo for (i = 0; i < argc; i++) { 106252190Srpaulo if (os_strcmp(col[i], "identity") == 0 && argv[i]) 107252190Srpaulo id = i; 108252190Srpaulo else if (os_strcmp(col[i], "methods") == 0 && argv[i]) 109252190Srpaulo methods = i; 110252190Srpaulo } 111252190Srpaulo 112252190Srpaulo if (id < 0 || methods < 0) 113252190Srpaulo return 0; 114252190Srpaulo 115252190Srpaulo len = os_strlen(argv[id]); 116252190Srpaulo if (len <= user->identity_len && 117252190Srpaulo os_memcmp(argv[id], user->identity, len) == 0 && 118252190Srpaulo (user->password == NULL || len > user->password_len)) { 119252190Srpaulo os_free(user->password); 120252190Srpaulo user->password_len = os_strlen(argv[id]); 121252190Srpaulo user->password = (u8 *) os_strdup(argv[id]); 122252190Srpaulo user->next = (void *) 1; 123252190Srpaulo set_user_methods(user, argv[methods]); 124252190Srpaulo } 125252190Srpaulo 126252190Srpaulo return 0; 127252190Srpaulo} 128252190Srpaulo 129252190Srpaulo 130252190Srpaulostatic const struct hostapd_eap_user * 131252190Srpauloeap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, 132252190Srpaulo size_t identity_len, int phase2) 133252190Srpaulo{ 134252190Srpaulo sqlite3 *db; 135252190Srpaulo struct hostapd_eap_user *user = NULL; 136252190Srpaulo char id_str[256], cmd[300]; 137252190Srpaulo size_t i; 138252190Srpaulo 139252190Srpaulo if (identity_len >= sizeof(id_str)) 140252190Srpaulo return NULL; 141252190Srpaulo os_memcpy(id_str, identity, identity_len); 142252190Srpaulo id_str[identity_len] = '\0'; 143252190Srpaulo for (i = 0; i < identity_len; i++) { 144252190Srpaulo if (id_str[i] >= 'a' && id_str[i] <= 'z') 145252190Srpaulo continue; 146252190Srpaulo if (id_str[i] >= 'A' && id_str[i] <= 'Z') 147252190Srpaulo continue; 148252190Srpaulo if (id_str[i] >= '0' && id_str[i] <= '9') 149252190Srpaulo continue; 150252190Srpaulo if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' || 151252190Srpaulo id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' || 152252190Srpaulo id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' || 153252190Srpaulo id_str[i] == '=' || id_str[i] == ' ') 154252190Srpaulo continue; 155252190Srpaulo wpa_printf(MSG_INFO, "DB: Unsupported character in identity"); 156252190Srpaulo return NULL; 157252190Srpaulo } 158252190Srpaulo 159252190Srpaulo os_free(hapd->tmp_eap_user.identity); 160252190Srpaulo os_free(hapd->tmp_eap_user.password); 161252190Srpaulo os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user)); 162252190Srpaulo hapd->tmp_eap_user.phase2 = phase2; 163252190Srpaulo hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1); 164252190Srpaulo if (hapd->tmp_eap_user.identity == NULL) 165252190Srpaulo return NULL; 166252190Srpaulo os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len); 167252190Srpaulo 168252190Srpaulo if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) { 169252190Srpaulo wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s", 170252190Srpaulo hapd->conf->eap_user_sqlite, sqlite3_errmsg(db)); 171252190Srpaulo sqlite3_close(db); 172252190Srpaulo return NULL; 173252190Srpaulo } 174252190Srpaulo 175252190Srpaulo os_snprintf(cmd, sizeof(cmd), 176252190Srpaulo "SELECT password,methods FROM users WHERE " 177252190Srpaulo "identity='%s' AND phase2=%d;", id_str, phase2); 178252190Srpaulo wpa_printf(MSG_DEBUG, "DB: %s", cmd); 179252190Srpaulo if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) != 180252190Srpaulo SQLITE_OK) { 181252190Srpaulo wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation"); 182252190Srpaulo } else if (hapd->tmp_eap_user.next) 183252190Srpaulo user = &hapd->tmp_eap_user; 184252190Srpaulo 185252190Srpaulo if (user == NULL && !phase2) { 186252190Srpaulo os_snprintf(cmd, sizeof(cmd), 187252190Srpaulo "SELECT identity,methods FROM wildcards;"); 188252190Srpaulo wpa_printf(MSG_DEBUG, "DB: %s", cmd); 189252190Srpaulo if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user, 190252190Srpaulo NULL) != SQLITE_OK) { 191252190Srpaulo wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL " 192252190Srpaulo "operation"); 193252190Srpaulo } else if (hapd->tmp_eap_user.next) { 194252190Srpaulo user = &hapd->tmp_eap_user; 195252190Srpaulo os_free(user->identity); 196252190Srpaulo user->identity = user->password; 197252190Srpaulo user->identity_len = user->password_len; 198252190Srpaulo user->password = NULL; 199252190Srpaulo user->password_len = 0; 200252190Srpaulo } 201252190Srpaulo } 202252190Srpaulo 203252190Srpaulo sqlite3_close(db); 204252190Srpaulo 205252190Srpaulo return user; 206252190Srpaulo} 207252190Srpaulo 208252190Srpaulo#endif /* CONFIG_SQLITE */ 209252190Srpaulo 210252190Srpaulo 211252190Srpauloconst struct hostapd_eap_user * 212252190Srpaulohostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity, 213252190Srpaulo size_t identity_len, int phase2) 214252190Srpaulo{ 215252190Srpaulo const struct hostapd_bss_config *conf = hapd->conf; 216252190Srpaulo struct hostapd_eap_user *user = conf->eap_user; 217252190Srpaulo 218252190Srpaulo#ifdef CONFIG_WPS 219252190Srpaulo if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN && 220252190Srpaulo os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) { 221252190Srpaulo static struct hostapd_eap_user wsc_enrollee; 222252190Srpaulo os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee)); 223252190Srpaulo wsc_enrollee.methods[0].method = eap_server_get_type( 224252190Srpaulo "WSC", &wsc_enrollee.methods[0].vendor); 225252190Srpaulo return &wsc_enrollee; 226252190Srpaulo } 227252190Srpaulo 228252190Srpaulo if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN && 229252190Srpaulo os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) { 230252190Srpaulo static struct hostapd_eap_user wsc_registrar; 231252190Srpaulo os_memset(&wsc_registrar, 0, sizeof(wsc_registrar)); 232252190Srpaulo wsc_registrar.methods[0].method = eap_server_get_type( 233252190Srpaulo "WSC", &wsc_registrar.methods[0].vendor); 234252190Srpaulo wsc_registrar.password = (u8 *) conf->ap_pin; 235252190Srpaulo wsc_registrar.password_len = conf->ap_pin ? 236252190Srpaulo os_strlen(conf->ap_pin) : 0; 237252190Srpaulo return &wsc_registrar; 238252190Srpaulo } 239252190Srpaulo#endif /* CONFIG_WPS */ 240252190Srpaulo 241252190Srpaulo while (user) { 242252190Srpaulo if (!phase2 && user->identity == NULL) { 243252190Srpaulo /* Wildcard match */ 244252190Srpaulo break; 245252190Srpaulo } 246252190Srpaulo 247252190Srpaulo if (user->phase2 == !!phase2 && user->wildcard_prefix && 248252190Srpaulo identity_len >= user->identity_len && 249252190Srpaulo os_memcmp(user->identity, identity, user->identity_len) == 250252190Srpaulo 0) { 251252190Srpaulo /* Wildcard prefix match */ 252252190Srpaulo break; 253252190Srpaulo } 254252190Srpaulo 255252190Srpaulo if (user->phase2 == !!phase2 && 256252190Srpaulo user->identity_len == identity_len && 257252190Srpaulo os_memcmp(user->identity, identity, identity_len) == 0) 258252190Srpaulo break; 259252190Srpaulo user = user->next; 260252190Srpaulo } 261252190Srpaulo 262252190Srpaulo#ifdef CONFIG_SQLITE 263252190Srpaulo if (user == NULL && conf->eap_user_sqlite) { 264252190Srpaulo return eap_user_sqlite_get(hapd, identity, identity_len, 265252190Srpaulo phase2); 266252190Srpaulo } 267252190Srpaulo#endif /* CONFIG_SQLITE */ 268252190Srpaulo 269252190Srpaulo return user; 270252190Srpaulo} 271