aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2012-11-20 22:47:47 (GMT)
committerJouni Malinen <j@w1.fi>2012-11-20 22:47:47 (GMT)
commitee431d77a51b361b4697f2b737bcf46a1860a6fe (patch)
tree915508b851e41762840dcdbc50b7d821f90fd61c
parent6201b052c87b043a240324976c58b71aa6cbdfca (diff)
downloadhostap-ee431d77a51b361b4697f2b737bcf46a1860a6fe.zip
hostap-ee431d77a51b361b4697f2b737bcf46a1860a6fe.tar.gz
hostap-ee431d77a51b361b4697f2b737bcf46a1860a6fe.tar.bz2
Add preliminary support for using SQLite for eap_user database
CONFIG_SQLITE=y option can now be used to allow the eap_user_file text file to be replaced with a SQLite database (eap_user_file=sqlite:/path/to/sqlite.db). hostapd.eap_user_sqlite shows an example of how the database tables can be created for this purpose. This commit does not yet include full functionality of the text file format, but at least basic EAP-TTLS/MSCHAPv2 style authentication mechanisms with plaintext passwords can be used for tests. Signed-hostap: Jouni Malinen <j@w1.fi>
-rw-r--r--hostapd/Makefile1
-rw-r--r--hostapd/config_file.c6
-rw-r--r--hostapd/defconfig2
-rw-r--r--hostapd/hostapd.conf2
-rw-r--r--hostapd/hostapd.eap_user_sqlite17
-rw-r--r--src/ap/ap_config.c55
-rw-r--r--src/ap/ap_config.h4
-rw-r--r--src/ap/authsrv.c2
-rw-r--r--src/ap/eap_user_db.c270
-rw-r--r--src/ap/hostapd.c5
-rw-r--r--src/ap/hostapd.h9
-rw-r--r--src/ap/ieee802_1x.c3
12 files changed, 315 insertions, 61 deletions
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 6fe282c..4cc3805 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -43,6 +43,7 @@ OBJS += ../src/ap/utils.o
OBJS += ../src/ap/authsrv.o
OBJS += ../src/ap/ieee802_1x.o
OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
OBJS += ../src/ap/ieee802_11_auth.o
OBJS += ../src/ap/sta_info.o
OBJS += ../src/ap/wpa_auth.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index f9b3984..7c9f941 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -200,6 +200,12 @@ static int hostapd_config_read_eap_user(const char *fname,
if (!fname)
return 0;
+ if (os_strncmp(fname, "sqlite:", 7) == 0) {
+ os_free(conf->eap_user_sqlite);
+ conf->eap_user_sqlite = os_strdup(fname + 7);
+ return 0;
+ }
+
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 204aa76..b5ddca3 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -265,5 +265,5 @@ CONFIG_IPV6=y
# Hotspot 2.0
#CONFIG_HS20=y
-# Enable SQLite database support in hlr_auc_gw
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index edbd772..5f0eb96 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -629,6 +629,8 @@ eapol_key_index_workaround=0
eap_server=0
# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
#eap_user_file=/etc/hostapd.eap_user
# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
new file mode 100644
index 0000000..f688327
--- /dev/null
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+ identity TEXT PRIMARY KEY,
+ methods TEXT,
+ password TEXT,
+ phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+ identity TEXT PRIMARY KEY,
+ methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 31e1c19..3c699f7 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -408,6 +408,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
user = user->next;
hostapd_config_free_eap_user(prev_user);
}
+ os_free(conf->eap_user_sqlite);
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
@@ -619,57 +620,3 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
return NULL;
}
-
-
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2)
-{
- struct hostapd_eap_user *user = conf->eap_user;
-
-#ifdef CONFIG_WPS
- if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
- os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
- static struct hostapd_eap_user wsc_enrollee;
- os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
- wsc_enrollee.methods[0].method = eap_server_get_type(
- "WSC", &wsc_enrollee.methods[0].vendor);
- return &wsc_enrollee;
- }
-
- if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
- os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
- static struct hostapd_eap_user wsc_registrar;
- os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
- wsc_registrar.methods[0].method = eap_server_get_type(
- "WSC", &wsc_registrar.methods[0].vendor);
- wsc_registrar.password = (u8 *) conf->ap_pin;
- wsc_registrar.password_len = conf->ap_pin ?
- os_strlen(conf->ap_pin) : 0;
- return &wsc_registrar;
- }
-#endif /* CONFIG_WPS */
-
- while (user) {
- if (!phase2 && user->identity == NULL) {
- /* Wildcard match */
- break;
- }
-
- if (user->phase2 == !!phase2 && user->wildcard_prefix &&
- identity_len >= user->identity_len &&
- os_memcmp(user->identity, identity, user->identity_len) ==
- 0) {
- /* Wildcard prefix match */
- break;
- }
-
- if (user->phase2 == !!phase2 &&
- user->identity_len == identity_len &&
- os_memcmp(user->identity, identity, identity_len) == 0)
- break;
- user = user->next;
- }
-
- return user;
-}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f5e4a6a..0a83856 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -192,6 +192,7 @@ struct hostapd_bss_config {
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
+ char *eap_user_sqlite;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
@@ -523,9 +524,6 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
-const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
- size_t identity_len, int phase2);
struct hostapd_radius_attr *
hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 5c03f45..d66d97e 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -92,7 +92,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
- srv.conf_ctx = conf;
+ srv.conf_ctx = hapd;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
new file mode 100644
index 0000000..79d50e5
--- /dev/null
+++ b/src/ap/eap_user_db.c
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+ char *buf, *start;
+ int num_methods;
+
+ buf = os_strdup(methods);
+ if (buf == NULL)
+ return;
+
+ os_memset(&user->methods, 0, sizeof(user->methods));
+ num_methods = 0;
+ start = buf;
+ while (*start) {
+ char *pos3 = os_strchr(start, ',');
+ if (pos3)
+ *pos3++ = '\0';
+ user->methods[num_methods].method =
+ eap_server_get_type(start,
+ &user->methods[num_methods].vendor);
+ if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE) {
+ if (os_strcmp(start, "TTLS-PAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-CHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+ goto skip_eap;
+ }
+ if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+ user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+ goto skip_eap;
+ }
+ wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+ start);
+ os_free(buf);
+ return;
+ }
+
+ num_methods++;
+ if (num_methods >= EAP_MAX_METHODS)
+ break;
+ skip_eap:
+ if (pos3 == NULL)
+ break;
+ start = pos3;
+ }
+
+ os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[i]);
+ user->password = (u8 *) os_strdup(argv[i]);
+ user->next = (void *) 1;
+ } else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+ set_user_methods(user, argv[i]);
+ }
+ }
+
+ return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct hostapd_eap_user *user = ctx;
+ int i, id = -1, methods = -1;
+ size_t len;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "identity") == 0 && argv[i])
+ id = i;
+ else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+ methods = i;
+ }
+
+ if (id < 0 || methods < 0)
+ return 0;
+
+ len = os_strlen(argv[id]);
+ if (len <= user->identity_len &&
+ os_memcmp(argv[id], user->identity, len) == 0 &&
+ (user->password == NULL || len > user->password_len)) {
+ os_free(user->password);
+ user->password_len = os_strlen(argv[id]);
+ user->password = (u8 *) os_strdup(argv[id]);
+ user->next = (void *) 1;
+ set_user_methods(user, argv[methods]);
+ }
+
+ return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ sqlite3 *db;
+ struct hostapd_eap_user *user = NULL;
+ char id_str[256], cmd[300];
+ size_t i;
+
+ if (identity_len >= sizeof(id_str))
+ return NULL;
+ os_memcpy(id_str, identity, identity_len);
+ id_str[identity_len] = '\0';
+ for (i = 0; i < identity_len; i++) {
+ if (id_str[i] >= 'a' && id_str[i] <= 'z')
+ continue;
+ if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+ continue;
+ if (id_str[i] >= '0' && id_str[i] <= '9')
+ continue;
+ if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+ id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+ id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+ id_str[i] == '=' || id_str[i] == ' ')
+ continue;
+ wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+ return NULL;
+ }
+
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+ os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+ hapd->tmp_eap_user.phase2 = phase2;
+ hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+ if (hapd->tmp_eap_user.identity == NULL)
+ return NULL;
+ os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+ if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+ wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+ hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT password,methods FROM users WHERE "
+ "identity='%s' AND phase2=%d;", id_str, phase2);
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+ SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+ } else if (hapd->tmp_eap_user.next)
+ user = &hapd->tmp_eap_user;
+
+ if (user == NULL && !phase2) {
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT identity,methods FROM wildcards;");
+ wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+ if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+ NULL) != SQLITE_OK) {
+ wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+ "operation");
+ } else if (hapd->tmp_eap_user.next) {
+ user = &hapd->tmp_eap_user;
+ os_free(user->identity);
+ user->identity = user->password;
+ user->identity_len = user->password_len;
+ user->password = NULL;
+ user->password_len = 0;
+ }
+ }
+
+ sqlite3_close(db);
+
+ return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2)
+{
+ const struct hostapd_bss_config *conf = hapd->conf;
+ struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+ static struct hostapd_eap_user wsc_enrollee;
+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+ wsc_enrollee.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_enrollee.methods[0].vendor);
+ return &wsc_enrollee;
+ }
+
+ if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+ static struct hostapd_eap_user wsc_registrar;
+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+ wsc_registrar.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_registrar.methods[0].vendor);
+ wsc_registrar.password = (u8 *) conf->ap_pin;
+ wsc_registrar.password_len = conf->ap_pin ?
+ os_strlen(conf->ap_pin) : 0;
+ return &wsc_registrar;
+ }
+#endif /* CONFIG_WPS */
+
+ while (user) {
+ if (!phase2 && user->identity == NULL) {
+ /* Wildcard match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ os_memcmp(user->identity, identity, user->identity_len) ==
+ 0) {
+ /* Wildcard prefix match */
+ break;
+ }
+
+ if (user->phase2 == !!phase2 &&
+ user->identity_len == identity_len &&
+ os_memcmp(user->identity, identity, identity_len) == 0)
+ break;
+ user = user->next;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (user == NULL && conf->eap_user_sqlite) {
+ return eap_user_sqlite_get(hapd, identity, identity_len,
+ phase2);
+ }
+#endif /* CONFIG_SQLITE */
+
+ return user;
+}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 1c968a7..cef9daf 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -273,6 +273,11 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_INTERWORKING
gas_serv_deinit(hapd);
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ os_free(hapd->tmp_eap_user.identity);
+ os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 71f476c..f1e7d9f 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -10,6 +10,7 @@
#define HOSTAPD_H
#include "common/defs.h"
+#include "ap_config.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
@@ -187,6 +188,10 @@ struct hostapd_data {
#ifdef CONFIG_INTERWORKING
size_t gas_frag_limit;
#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+ struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
};
@@ -297,4 +302,8 @@ int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset);
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+ size_t identity_len, int phase2);
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index e87431e..7ac1d3e 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1686,8 +1686,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
const struct hostapd_eap_user *eap_user;
int i;
- eap_user = hostapd_get_eap_user(hapd->conf, identity,
- identity_len, phase2);
+ eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;