]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add preliminary support for using SQLite for eap_user database
authorJouni Malinen <j@w1.fi>
Tue, 20 Nov 2012 22:47:47 +0000 (00:47 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 20 Nov 2012 22:47:47 +0000 (00:47 +0200)
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>

12 files changed:
hostapd/Makefile
hostapd/config_file.c
hostapd/defconfig
hostapd/hostapd.conf
hostapd/hostapd.eap_user_sqlite [new file with mode: 0644]
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/authsrv.c
src/ap/eap_user_db.c [new file with mode: 0644]
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_1x.c

index 6fe282c08c2cc8a311f725a46087ffad222449c7..4cc38059b7510b5ff200c2d032b72b4519713505 100644 (file)
@@ -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
index f9b398431130600d74c6a2c6a018264997ae1136..7c9f941c2d2307dc8f812ea4f6d002c8cf7da370 100644 (file)
@@ -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);
index 204aa768301f5d0e7cb4d6863c589226c106160a..b5ddca34c09d019a68cfcaf6f112343b5825e5f2 100644 (file)
@@ -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
index edbd77234cb7ebb495eda32d070e52b59071badb..5f0eb96661de8477c3d2ca4882f4d58eaf4d7c99 100644 (file)
@@ -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 (file)
index 0000000..f688327
--- /dev/null
@@ -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');
index 31e1c19cc0f5bc4a62d0c2ea96c61b363ae8ed3e..3c699f71ec71fb58d953d8e0233e8292ea45a254 100644 (file)
@@ -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;
-}
index f5e4a6a59df78ddbac22e19365f6d09736ff6180..0a83856d0391f1ad907f630d2289636ee70c2987 100644 (file)
@@ -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);
 
index 5c03f45c482b30c5d5777059ed9b45c3a6d2dad1..d66d97e4a0db4852ae109b9dbadab8e8ef63855b 100644 (file)
@@ -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 (file)
index 0000000..79d50e5
--- /dev/null
@@ -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;
+}
index 1c968a7a777395dbd53581488c8f799a722f8f08..cef9dafc52e05d5fdbd6c12ecdfea013213af091 100644 (file)
@@ -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 */
 }
 
 
index 71f476c0ee98275cdee3fc46ffefeb669047c05b..f1e7d9ff7ec5a73baf0364a53343ac19249bf0b6 100644 (file)
@@ -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 */
index e87431ef1dcba5255bcd1ea254067a80cfaac639..7ac1d3e63f14c0eadb93a2711e07dd45f81ee0a7 100644 (file)
@@ -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;