xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/eap_user_db.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
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