13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / EAP user database
33ff40c12SJohn Marino * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino #ifdef CONFIG_SQLITE
113ff40c12SJohn Marino #include <sqlite3.h>
123ff40c12SJohn Marino #endif /* CONFIG_SQLITE */
133ff40c12SJohn Marino
143ff40c12SJohn Marino #include "common.h"
153ff40c12SJohn Marino #include "eap_common/eap_wsc_common.h"
163ff40c12SJohn Marino #include "eap_server/eap_methods.h"
173ff40c12SJohn Marino #include "eap_server/eap.h"
183ff40c12SJohn Marino #include "ap_config.h"
193ff40c12SJohn Marino #include "hostapd.h"
203ff40c12SJohn Marino
213ff40c12SJohn Marino #ifdef CONFIG_SQLITE
223ff40c12SJohn Marino
set_user_methods(struct hostapd_eap_user * user,const char * methods)233ff40c12SJohn Marino static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
243ff40c12SJohn Marino {
253ff40c12SJohn Marino char *buf, *start;
263ff40c12SJohn Marino int num_methods;
273ff40c12SJohn Marino
283ff40c12SJohn Marino buf = os_strdup(methods);
293ff40c12SJohn Marino if (buf == NULL)
303ff40c12SJohn Marino return;
313ff40c12SJohn Marino
323ff40c12SJohn Marino os_memset(&user->methods, 0, sizeof(user->methods));
333ff40c12SJohn Marino num_methods = 0;
343ff40c12SJohn Marino start = buf;
353ff40c12SJohn Marino while (*start) {
363ff40c12SJohn Marino char *pos3 = os_strchr(start, ',');
373ff40c12SJohn Marino if (pos3)
383ff40c12SJohn Marino *pos3++ = '\0';
393ff40c12SJohn Marino user->methods[num_methods].method =
403ff40c12SJohn Marino eap_server_get_type(start,
413ff40c12SJohn Marino &user->methods[num_methods].vendor);
423ff40c12SJohn Marino if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
433ff40c12SJohn Marino user->methods[num_methods].method == EAP_TYPE_NONE) {
443ff40c12SJohn Marino if (os_strcmp(start, "TTLS-PAP") == 0) {
453ff40c12SJohn Marino user->ttls_auth |= EAP_TTLS_AUTH_PAP;
463ff40c12SJohn Marino goto skip_eap;
473ff40c12SJohn Marino }
483ff40c12SJohn Marino if (os_strcmp(start, "TTLS-CHAP") == 0) {
493ff40c12SJohn Marino user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
503ff40c12SJohn Marino goto skip_eap;
513ff40c12SJohn Marino }
523ff40c12SJohn Marino if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
533ff40c12SJohn Marino user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
543ff40c12SJohn Marino goto skip_eap;
553ff40c12SJohn Marino }
563ff40c12SJohn Marino if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
573ff40c12SJohn Marino user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
583ff40c12SJohn Marino goto skip_eap;
593ff40c12SJohn Marino }
603ff40c12SJohn Marino wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
613ff40c12SJohn Marino start);
623ff40c12SJohn Marino os_free(buf);
633ff40c12SJohn Marino return;
643ff40c12SJohn Marino }
653ff40c12SJohn Marino
663ff40c12SJohn Marino num_methods++;
673ff40c12SJohn Marino if (num_methods >= EAP_MAX_METHODS)
683ff40c12SJohn Marino break;
693ff40c12SJohn Marino skip_eap:
703ff40c12SJohn Marino if (pos3 == NULL)
713ff40c12SJohn Marino break;
723ff40c12SJohn Marino start = pos3;
733ff40c12SJohn Marino }
743ff40c12SJohn Marino
753ff40c12SJohn Marino os_free(buf);
763ff40c12SJohn Marino }
773ff40c12SJohn Marino
783ff40c12SJohn Marino
get_user_cb(void * ctx,int argc,char * argv[],char * col[])793ff40c12SJohn Marino static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
803ff40c12SJohn Marino {
813ff40c12SJohn Marino struct hostapd_eap_user *user = ctx;
823ff40c12SJohn Marino int i;
833ff40c12SJohn Marino
843ff40c12SJohn Marino for (i = 0; i < argc; i++) {
853ff40c12SJohn Marino if (os_strcmp(col[i], "password") == 0 && argv[i]) {
86*a1157835SDaniel Fojt bin_clear_free(user->password, user->password_len);
873ff40c12SJohn Marino user->password_len = os_strlen(argv[i]);
883ff40c12SJohn Marino user->password = (u8 *) os_strdup(argv[i]);
893ff40c12SJohn Marino user->next = (void *) 1;
903ff40c12SJohn Marino } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
913ff40c12SJohn Marino set_user_methods(user, argv[i]);
92*a1157835SDaniel Fojt } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
93*a1157835SDaniel Fojt user->remediation = strlen(argv[i]) > 0;
94*a1157835SDaniel Fojt } else if (os_strcmp(col[i], "t_c_timestamp") == 0 && argv[i]) {
95*a1157835SDaniel Fojt user->t_c_timestamp = strtol(argv[i], NULL, 10);
963ff40c12SJohn Marino }
973ff40c12SJohn Marino }
983ff40c12SJohn Marino
993ff40c12SJohn Marino return 0;
1003ff40c12SJohn Marino }
1013ff40c12SJohn Marino
1023ff40c12SJohn Marino
get_wildcard_cb(void * ctx,int argc,char * argv[],char * col[])1033ff40c12SJohn Marino static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
1043ff40c12SJohn Marino {
1053ff40c12SJohn Marino struct hostapd_eap_user *user = ctx;
1063ff40c12SJohn Marino int i, id = -1, methods = -1;
1073ff40c12SJohn Marino size_t len;
1083ff40c12SJohn Marino
1093ff40c12SJohn Marino for (i = 0; i < argc; i++) {
1103ff40c12SJohn Marino if (os_strcmp(col[i], "identity") == 0 && argv[i])
1113ff40c12SJohn Marino id = i;
1123ff40c12SJohn Marino else if (os_strcmp(col[i], "methods") == 0 && argv[i])
1133ff40c12SJohn Marino methods = i;
1143ff40c12SJohn Marino }
1153ff40c12SJohn Marino
1163ff40c12SJohn Marino if (id < 0 || methods < 0)
1173ff40c12SJohn Marino return 0;
1183ff40c12SJohn Marino
1193ff40c12SJohn Marino len = os_strlen(argv[id]);
1203ff40c12SJohn Marino if (len <= user->identity_len &&
1213ff40c12SJohn Marino os_memcmp(argv[id], user->identity, len) == 0 &&
1223ff40c12SJohn Marino (user->password == NULL || len > user->password_len)) {
123*a1157835SDaniel Fojt bin_clear_free(user->password, user->password_len);
1243ff40c12SJohn Marino user->password_len = os_strlen(argv[id]);
1253ff40c12SJohn Marino user->password = (u8 *) os_strdup(argv[id]);
1263ff40c12SJohn Marino user->next = (void *) 1;
1273ff40c12SJohn Marino set_user_methods(user, argv[methods]);
1283ff40c12SJohn Marino }
1293ff40c12SJohn Marino
1303ff40c12SJohn Marino return 0;
1313ff40c12SJohn Marino }
1323ff40c12SJohn Marino
1333ff40c12SJohn Marino
1343ff40c12SJohn Marino static const struct hostapd_eap_user *
eap_user_sqlite_get(struct hostapd_data * hapd,const u8 * identity,size_t identity_len,int phase2)1353ff40c12SJohn Marino eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
1363ff40c12SJohn Marino size_t identity_len, int phase2)
1373ff40c12SJohn Marino {
1383ff40c12SJohn Marino sqlite3 *db;
1393ff40c12SJohn Marino struct hostapd_eap_user *user = NULL;
1403ff40c12SJohn Marino char id_str[256], cmd[300];
1413ff40c12SJohn Marino size_t i;
142*a1157835SDaniel Fojt int res;
1433ff40c12SJohn Marino
144*a1157835SDaniel Fojt if (identity_len >= sizeof(id_str)) {
145*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
146*a1157835SDaniel Fojt __func__, (int) identity_len,
147*a1157835SDaniel Fojt (int) (sizeof(id_str)));
1483ff40c12SJohn Marino return NULL;
149*a1157835SDaniel Fojt }
1503ff40c12SJohn Marino os_memcpy(id_str, identity, identity_len);
1513ff40c12SJohn Marino id_str[identity_len] = '\0';
1523ff40c12SJohn Marino for (i = 0; i < identity_len; i++) {
1533ff40c12SJohn Marino if (id_str[i] >= 'a' && id_str[i] <= 'z')
1543ff40c12SJohn Marino continue;
1553ff40c12SJohn Marino if (id_str[i] >= 'A' && id_str[i] <= 'Z')
1563ff40c12SJohn Marino continue;
1573ff40c12SJohn Marino if (id_str[i] >= '0' && id_str[i] <= '9')
1583ff40c12SJohn Marino continue;
1593ff40c12SJohn Marino if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
1603ff40c12SJohn Marino id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
1613ff40c12SJohn Marino id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
1623ff40c12SJohn Marino id_str[i] == '=' || id_str[i] == ' ')
1633ff40c12SJohn Marino continue;
1643ff40c12SJohn Marino wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
1653ff40c12SJohn Marino return NULL;
1663ff40c12SJohn Marino }
1673ff40c12SJohn Marino
168*a1157835SDaniel Fojt bin_clear_free(hapd->tmp_eap_user.identity,
169*a1157835SDaniel Fojt hapd->tmp_eap_user.identity_len);
170*a1157835SDaniel Fojt bin_clear_free(hapd->tmp_eap_user.password,
171*a1157835SDaniel Fojt hapd->tmp_eap_user.password_len);
1723ff40c12SJohn Marino os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
1733ff40c12SJohn Marino hapd->tmp_eap_user.phase2 = phase2;
1743ff40c12SJohn Marino hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
1753ff40c12SJohn Marino if (hapd->tmp_eap_user.identity == NULL)
1763ff40c12SJohn Marino return NULL;
1773ff40c12SJohn Marino os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
178*a1157835SDaniel Fojt hapd->tmp_eap_user.identity_len = identity_len;
1793ff40c12SJohn Marino
1803ff40c12SJohn Marino if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
1813ff40c12SJohn Marino wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
1823ff40c12SJohn Marino hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
1833ff40c12SJohn Marino sqlite3_close(db);
1843ff40c12SJohn Marino return NULL;
1853ff40c12SJohn Marino }
1863ff40c12SJohn Marino
187*a1157835SDaniel Fojt res = os_snprintf(cmd, sizeof(cmd),
188*a1157835SDaniel Fojt "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
189*a1157835SDaniel Fojt id_str, phase2);
190*a1157835SDaniel Fojt if (os_snprintf_error(sizeof(cmd), res))
191*a1157835SDaniel Fojt goto fail;
192*a1157835SDaniel Fojt
1933ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DB: %s", cmd);
1943ff40c12SJohn Marino if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
1953ff40c12SJohn Marino SQLITE_OK) {
196*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
197*a1157835SDaniel Fojt "DB: Failed to complete SQL operation: %s db: %s",
198*a1157835SDaniel Fojt sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
1993ff40c12SJohn Marino } else if (hapd->tmp_eap_user.next)
2003ff40c12SJohn Marino user = &hapd->tmp_eap_user;
2013ff40c12SJohn Marino
2023ff40c12SJohn Marino if (user == NULL && !phase2) {
2033ff40c12SJohn Marino os_snprintf(cmd, sizeof(cmd),
2043ff40c12SJohn Marino "SELECT identity,methods FROM wildcards;");
2053ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "DB: %s", cmd);
2063ff40c12SJohn Marino if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
2073ff40c12SJohn Marino NULL) != SQLITE_OK) {
208*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
209*a1157835SDaniel Fojt "DB: Failed to complete SQL operation: %s db: %s",
210*a1157835SDaniel Fojt sqlite3_errmsg(db),
211*a1157835SDaniel Fojt hapd->conf->eap_user_sqlite);
2123ff40c12SJohn Marino } else if (hapd->tmp_eap_user.next) {
2133ff40c12SJohn Marino user = &hapd->tmp_eap_user;
2143ff40c12SJohn Marino os_free(user->identity);
2153ff40c12SJohn Marino user->identity = user->password;
2163ff40c12SJohn Marino user->identity_len = user->password_len;
2173ff40c12SJohn Marino user->password = NULL;
2183ff40c12SJohn Marino user->password_len = 0;
2193ff40c12SJohn Marino }
2203ff40c12SJohn Marino }
2213ff40c12SJohn Marino
222*a1157835SDaniel Fojt fail:
2233ff40c12SJohn Marino sqlite3_close(db);
2243ff40c12SJohn Marino
2253ff40c12SJohn Marino return user;
2263ff40c12SJohn Marino }
2273ff40c12SJohn Marino
2283ff40c12SJohn Marino #endif /* CONFIG_SQLITE */
2293ff40c12SJohn Marino
2303ff40c12SJohn Marino
2313ff40c12SJohn Marino const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data * hapd,const u8 * identity,size_t identity_len,int phase2)2323ff40c12SJohn Marino hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
2333ff40c12SJohn Marino size_t identity_len, int phase2)
2343ff40c12SJohn Marino {
2353ff40c12SJohn Marino const struct hostapd_bss_config *conf = hapd->conf;
2363ff40c12SJohn Marino struct hostapd_eap_user *user = conf->eap_user;
2373ff40c12SJohn Marino
2383ff40c12SJohn Marino #ifdef CONFIG_WPS
2393ff40c12SJohn Marino if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
2403ff40c12SJohn Marino os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
2413ff40c12SJohn Marino static struct hostapd_eap_user wsc_enrollee;
2423ff40c12SJohn Marino os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
2433ff40c12SJohn Marino wsc_enrollee.methods[0].method = eap_server_get_type(
2443ff40c12SJohn Marino "WSC", &wsc_enrollee.methods[0].vendor);
2453ff40c12SJohn Marino return &wsc_enrollee;
2463ff40c12SJohn Marino }
2473ff40c12SJohn Marino
2483ff40c12SJohn Marino if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
2493ff40c12SJohn Marino os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
2503ff40c12SJohn Marino static struct hostapd_eap_user wsc_registrar;
2513ff40c12SJohn Marino os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
2523ff40c12SJohn Marino wsc_registrar.methods[0].method = eap_server_get_type(
2533ff40c12SJohn Marino "WSC", &wsc_registrar.methods[0].vendor);
2543ff40c12SJohn Marino wsc_registrar.password = (u8 *) conf->ap_pin;
2553ff40c12SJohn Marino wsc_registrar.password_len = conf->ap_pin ?
2563ff40c12SJohn Marino os_strlen(conf->ap_pin) : 0;
2573ff40c12SJohn Marino return &wsc_registrar;
2583ff40c12SJohn Marino }
2593ff40c12SJohn Marino #endif /* CONFIG_WPS */
2603ff40c12SJohn Marino
2613ff40c12SJohn Marino while (user) {
2623ff40c12SJohn Marino if (!phase2 && user->identity == NULL) {
2633ff40c12SJohn Marino /* Wildcard match */
2643ff40c12SJohn Marino break;
2653ff40c12SJohn Marino }
2663ff40c12SJohn Marino
2673ff40c12SJohn Marino if (user->phase2 == !!phase2 && user->wildcard_prefix &&
2683ff40c12SJohn Marino identity_len >= user->identity_len &&
2693ff40c12SJohn Marino os_memcmp(user->identity, identity, user->identity_len) ==
2703ff40c12SJohn Marino 0) {
2713ff40c12SJohn Marino /* Wildcard prefix match */
2723ff40c12SJohn Marino break;
2733ff40c12SJohn Marino }
2743ff40c12SJohn Marino
2753ff40c12SJohn Marino if (user->phase2 == !!phase2 &&
2763ff40c12SJohn Marino user->identity_len == identity_len &&
2773ff40c12SJohn Marino os_memcmp(user->identity, identity, identity_len) == 0)
2783ff40c12SJohn Marino break;
2793ff40c12SJohn Marino user = user->next;
2803ff40c12SJohn Marino }
2813ff40c12SJohn Marino
2823ff40c12SJohn Marino #ifdef CONFIG_SQLITE
2833ff40c12SJohn Marino if (user == NULL && conf->eap_user_sqlite) {
2843ff40c12SJohn Marino return eap_user_sqlite_get(hapd, identity, identity_len,
2853ff40c12SJohn Marino phase2);
2863ff40c12SJohn Marino }
2873ff40c12SJohn Marino #endif /* CONFIG_SQLITE */
2883ff40c12SJohn Marino
2893ff40c12SJohn Marino return user;
2903ff40c12SJohn Marino }
291