EAP-SIM DB: Optional use of SQLite database for pseudonyms
This allows hostapd to use an SQLite database for storing EAP-SIM/AKA pseudonyms over process restarts. CONFIG_SQLITE=y build option adds support for this and the SQLite database file is specified in eap_sib_db configuration parameter. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
c3550295fb
commit
66979bb833
3 changed files with 229 additions and 6 deletions
|
@ -825,6 +825,12 @@ ifdef CONFIG_DEBUG_FILE
|
|||
CFLAGS += -DCONFIG_DEBUG_FILE
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SQLITE
|
||||
CFLAGS += -DCONFIG_SQLITE
|
||||
LIBS += -lsqlite3
|
||||
LIBS_h += -lsqlite3
|
||||
endif
|
||||
|
||||
ALL=hostapd hostapd_cli
|
||||
|
||||
all: verify_config $(ALL)
|
||||
|
@ -892,11 +898,6 @@ ifdef TLS_FUNCS
|
|||
LIBS_n += -lcrypto
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SQLITE
|
||||
CFLAGS += -DCONFIG_SQLITE
|
||||
LIBS_h += -lsqlite3
|
||||
endif
|
||||
|
||||
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
|
||||
HOBJS += ../src/crypto/aes-encblock.o
|
||||
ifdef CONFIG_INTERNAL_AES
|
||||
|
|
|
@ -681,8 +681,10 @@ eap_server=0
|
|||
# This is a text string in implementation specific format. The example
|
||||
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
|
||||
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
|
||||
# prefix.
|
||||
# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
|
||||
# database file can be described with an optional db=<path> parameter.
|
||||
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
|
||||
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
|
||||
|
||||
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
|
||||
# random value. It is configured as a 16-octet value in hex format. It can be
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
#include "includes.h"
|
||||
#include <sys/un.h>
|
||||
#ifdef CONFIG_SQLITE
|
||||
#include <sqlite3.h>
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto/random.h"
|
||||
|
@ -66,9 +69,190 @@ struct eap_sim_db_data {
|
|||
struct eap_sim_pseudonym *pseudonyms;
|
||||
struct eap_sim_reauth *reauths;
|
||||
struct eap_sim_db_pending *pending;
|
||||
#ifdef CONFIG_SQLITE
|
||||
sqlite3 *sqlite_db;
|
||||
u8 db_tmp_identity[100];
|
||||
char db_tmp_pseudonym_str[100];
|
||||
struct eap_sim_pseudonym db_tmp_pseudonym;
|
||||
#endif /* CONFIG_SQLITE */
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
|
||||
static int db_table_exists(sqlite3 *db, const char *name)
|
||||
{
|
||||
char cmd[128];
|
||||
os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
|
||||
return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
static int db_table_create_pseudonym(sqlite3 *db)
|
||||
{
|
||||
char *err = NULL;
|
||||
const char *sql =
|
||||
"CREATE TABLE pseudonyms("
|
||||
" imsi INTEGER PRIMARY KEY NOT NULL,"
|
||||
" pseudonym CHAR(21) NOT NULL"
|
||||
");";
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
|
||||
"pseudonym information");
|
||||
if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
|
||||
wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
|
||||
sqlite3_free(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static sqlite3 * db_open(const char *db_file)
|
||||
{
|
||||
sqlite3 *db;
|
||||
|
||||
if (sqlite3_open(db_file, &db)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
|
||||
"%s: %s", db_file, sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!db_table_exists(db, "pseudonyms") &&
|
||||
db_table_create_pseudonym(db) < 0) {
|
||||
sqlite3_close(db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
static int valid_pseudonym_string(const char *pseudonym)
|
||||
{
|
||||
const char *pos = pseudonym;
|
||||
while (*pos) {
|
||||
if ((*pos < '0' || *pos > '9') &&
|
||||
(*pos < 'a' || *pos > 'f'))
|
||||
return 0;
|
||||
pos++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_add_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
|
||||
size_t identity_len, char *pseudonym)
|
||||
{
|
||||
char cmd[128];
|
||||
unsigned long long imsi;
|
||||
|
||||
if (!valid_pseudonym_string(pseudonym) || identity_len >= sizeof(cmd))
|
||||
{
|
||||
os_free(pseudonym);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(cmd, identity, identity_len);
|
||||
cmd[identity_len] = '\0';
|
||||
imsi = atoll(cmd);
|
||||
|
||||
os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
|
||||
"(imsi, pseudonym) VALUES (%llu , '%s');",
|
||||
imsi, pseudonym);
|
||||
os_free(pseudonym);
|
||||
if (sqlite3_exec(data->sqlite_db, cmd, NULL, data, NULL) != SQLITE_OK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
|
||||
{
|
||||
struct eap_sim_db_data *data = ctx;
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (os_strcmp(col[i], "imsi") == 0 && argv[i]) {
|
||||
len = os_strlen(argv[i]);
|
||||
if (len > sizeof(data->db_tmp_identity))
|
||||
continue;
|
||||
os_memcpy(data->db_tmp_identity, argv[i], len);
|
||||
data->db_tmp_pseudonym.identity =
|
||||
data->db_tmp_identity;
|
||||
data->db_tmp_pseudonym.identity_len = len;
|
||||
} else if (os_strcmp(col[i], "pseudonym") == 0 && argv[i]) {
|
||||
len = os_strlen(argv[i]);
|
||||
if (len >= sizeof(data->db_tmp_pseudonym_str))
|
||||
continue;
|
||||
os_memcpy(data->db_tmp_pseudonym_str, argv[i], len);
|
||||
data->db_tmp_pseudonym_str[len] = '\0';
|
||||
data->db_tmp_pseudonym.pseudonym =
|
||||
data->db_tmp_pseudonym_str;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct eap_sim_pseudonym *
|
||||
db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
|
||||
{
|
||||
char cmd[128];
|
||||
|
||||
if (!valid_pseudonym_string(pseudonym))
|
||||
return NULL;
|
||||
os_memset(&data->db_tmp_pseudonym, 0, sizeof(data->db_tmp_pseudonym));
|
||||
os_strlcpy(data->db_tmp_pseudonym_str, pseudonym,
|
||||
sizeof(data->db_tmp_pseudonym_str));
|
||||
data->db_tmp_pseudonym.pseudonym = data->db_tmp_pseudonym_str;
|
||||
os_snprintf(cmd, sizeof(cmd),
|
||||
"SELECT imsi FROM pseudonyms WHERE pseudonym='%s';",
|
||||
pseudonym);
|
||||
if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
|
||||
SQLITE_OK)
|
||||
return NULL;
|
||||
if (data->db_tmp_pseudonym.identity == NULL)
|
||||
return NULL;
|
||||
return &data->db_tmp_pseudonym;
|
||||
}
|
||||
|
||||
|
||||
static struct eap_sim_pseudonym *
|
||||
db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
|
||||
size_t identity_len)
|
||||
{
|
||||
char cmd[128];
|
||||
unsigned long long imsi;
|
||||
|
||||
if (identity_len >= sizeof(cmd))
|
||||
return NULL;
|
||||
os_memcpy(cmd, identity, identity_len);
|
||||
cmd[identity_len] = '\0';
|
||||
imsi = atoll(cmd);
|
||||
|
||||
os_memset(&data->db_tmp_pseudonym, 0, sizeof(data->db_tmp_pseudonym));
|
||||
if (identity_len > sizeof(data->db_tmp_identity))
|
||||
return NULL;
|
||||
os_memcpy(data->db_tmp_identity, identity, identity_len);
|
||||
data->db_tmp_pseudonym.identity = data->db_tmp_identity;
|
||||
data->db_tmp_pseudonym.identity_len = identity_len;
|
||||
os_snprintf(cmd, sizeof(cmd),
|
||||
"SELECT pseudonym FROM pseudonyms WHERE imsi=%llu;", imsi);
|
||||
if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
|
||||
SQLITE_OK)
|
||||
return NULL;
|
||||
if (data->db_tmp_pseudonym.pseudonym == NULL)
|
||||
return NULL;
|
||||
return &data->db_tmp_pseudonym;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
static struct eap_sim_db_pending *
|
||||
eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
|
||||
size_t imsi_len, int aka)
|
||||
|
@ -395,6 +579,7 @@ void * eap_sim_db_init(const char *config,
|
|||
void *ctx)
|
||||
{
|
||||
struct eap_sim_db_data *data;
|
||||
char *pos;
|
||||
|
||||
data = os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
|
@ -406,6 +591,16 @@ void * eap_sim_db_init(const char *config,
|
|||
data->fname = os_strdup(config);
|
||||
if (data->fname == NULL)
|
||||
goto fail;
|
||||
pos = os_strstr(data->fname, " db=");
|
||||
if (pos) {
|
||||
*pos = '\0';
|
||||
#ifdef CONFIG_SQLITE
|
||||
pos += 4;
|
||||
data->sqlite_db = db_open(pos);
|
||||
if (data->sqlite_db == NULL)
|
||||
goto fail;
|
||||
#endif /* CONFIG_SQLITE */
|
||||
}
|
||||
|
||||
if (os_strncmp(data->fname, "unix:", 5) == 0) {
|
||||
if (eap_sim_db_open_socket(data)) {
|
||||
|
@ -452,6 +647,13 @@ void eap_sim_db_deinit(void *priv)
|
|||
struct eap_sim_reauth *r, *prevr;
|
||||
struct eap_sim_db_pending *pending, *prev_pending;
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (data->sqlite_db) {
|
||||
sqlite3_close(data->sqlite_db);
|
||||
data->sqlite_db = NULL;
|
||||
}
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
eap_sim_db_close_socket(data);
|
||||
os_free(data->fname);
|
||||
|
||||
|
@ -669,6 +871,14 @@ eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
|
|||
os_memcpy(pseudonym, identity, len);
|
||||
pseudonym[len] = '\0';
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (data->sqlite_db) {
|
||||
p = db_get_pseudonym(data, pseudonym);
|
||||
os_free(pseudonym);
|
||||
return p;
|
||||
}
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
p = data->pseudonyms;
|
||||
while (p) {
|
||||
if (os_strcmp(p->pseudonym, pseudonym) == 0)
|
||||
|
@ -694,6 +904,11 @@ eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
|
|||
identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (data->sqlite_db)
|
||||
return db_get_pseudonym_id(data, identity, identity_len);
|
||||
#endif /* CONFIG_SQLITE */
|
||||
|
||||
p = data->pseudonyms;
|
||||
while (p) {
|
||||
if (identity_len == p->identity_len &&
|
||||
|
@ -939,6 +1154,11 @@ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
|
|||
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
|
||||
|
||||
/* TODO: could store last two pseudonyms */
|
||||
#ifdef CONFIG_SQLITE
|
||||
if (data->sqlite_db)
|
||||
return db_add_pseudonym(data, identity, identity_len,
|
||||
pseudonym);
|
||||
#endif /* CONFIG_SQLITE */
|
||||
p = eap_sim_db_get_pseudonym(data, identity, identity_len);
|
||||
if (p == NULL)
|
||||
p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
|
||||
|
|
Loading…
Reference in a new issue