From 29813cfdc0b04363fe741971c17937732598e7d4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 30 Aug 2012 16:55:36 +0300 Subject: [PATCH] EAP-SIM DB: Optional use of SQLite database for reauth data If hostapd is built and configured to use SQLite database, store EAP-SIM/AKA reauth data into the database to allow this to persist over hostapd restarts. Signed-hostap: Jouni Malinen --- src/eap_server/eap_sim_db.c | 256 +++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 1 deletion(-) diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c index a9921acec..a1a0fd2d9 100644 --- a/src/eap_server/eap_sim_db.c +++ b/src/eap_server/eap_sim_db.c @@ -74,6 +74,7 @@ struct eap_sim_db_data { u8 db_tmp_identity[100]; char db_tmp_pseudonym_str[100]; struct eap_sim_pseudonym db_tmp_pseudonym; + struct eap_sim_reauth db_tmp_reauth; #endif /* CONFIG_SQLITE */ }; @@ -109,6 +110,33 @@ static int db_table_create_pseudonym(sqlite3 *db) } +static int db_table_create_reauth(sqlite3 *db) +{ + char *err = NULL; + const char *sql = + "CREATE TABLE reauth(" + " imsi INTEGER PRIMARY KEY NOT NULL," + " reauth_id CHAR(21) NOT NULL," + " counter INTEGER," + " aka_prime BOOL," + " mk CHAR(40)," + " k_encr CHAR(32)," + " k_aut CHAR(64)," + " k_re CHAR(64)" + ");"; + + wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for " + "reauth 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; @@ -126,6 +154,12 @@ static sqlite3 * db_open(const char *db_file) return NULL; } + if (!db_table_exists(db, "reauth") && + db_table_create_reauth(db) < 0) { + sqlite3_close(db); + return NULL; + } + return db; } @@ -148,6 +182,7 @@ static int db_add_pseudonym(struct eap_sim_db_data *data, const u8 *identity, { char cmd[128]; unsigned long long imsi; + char *err = NULL; if (!valid_pseudonym_string(pseudonym) || identity_len >= sizeof(cmd)) { @@ -162,8 +197,12 @@ static int db_add_pseudonym(struct eap_sim_db_data *data, const u8 *identity, "(imsi, pseudonym) VALUES (%llu , '%s');", imsi, pseudonym); os_free(pseudonym); - if (sqlite3_exec(data->sqlite_db, cmd, NULL, data, NULL) != SQLITE_OK) + if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) + { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); return -1; + } return 0; } @@ -251,8 +290,192 @@ db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, return &data->db_tmp_pseudonym; } + +static int db_add_reauth(struct eap_sim_db_data *data, const u8 *identity, + size_t identity_len, char *reauth_id, u16 counter, + const u8 *mk, int aka_prime, const u8 *k_encr, + const u8 *k_aut, const u8 *k_re) +{ + char cmd[2000], *pos, *end; + unsigned long long imsi; + char *err = NULL; + + if (!valid_pseudonym_string(reauth_id) || identity_len >= sizeof(cmd)) + { + os_free(reauth_id); + return -1; + } + os_memcpy(cmd, identity, identity_len); + cmd[identity_len] = '\0'; + imsi = atoll(cmd); + + pos = cmd; + end = pos + sizeof(cmd); + pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth " + "(imsi, reauth_id, counter, aka_prime%s%s%s%s) " + "VALUES (%llu, '%s', %u, %d", + mk ? ", mk" : "", + k_encr ? ", k_encr" : "", + k_aut ? ", k_aut" : "", + k_re ? ", k_re" : "", + imsi, reauth_id, counter, aka_prime); + os_free(reauth_id); + + if (mk) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_encr) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_encr, + EAP_SIM_K_ENCR_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_aut) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_aut, + EAP_AKA_PRIME_K_AUT_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + if (k_re) { + pos += os_snprintf(pos, end - pos, ", '"); + pos += wpa_snprintf_hex(pos, end - pos, k_re, + EAP_AKA_PRIME_K_RE_LEN); + pos += os_snprintf(pos, end - pos, "'"); + } + + os_snprintf(pos, end - pos, ");"); + + if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK) + { + wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err); + sqlite3_free(err); + return -1; + } + + return 0; +} + + +static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[]) +{ + struct eap_sim_db_data *data = ctx; + int i; + size_t len; + struct eap_sim_reauth *reauth = &data->db_tmp_reauth; + + 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); + reauth->identity = data->db_tmp_identity; + reauth->identity_len = len; + } else if (os_strcmp(col[i], "reauth_id") == 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'; + reauth->reauth_id = data->db_tmp_pseudonym_str; + } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) { + reauth->counter = atoi(argv[i]); + } else if (os_strcmp(col[i], "aka_prime") == 0 && argv[i]) { + reauth->aka_prime = atoi(argv[i]); + } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk)); + } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_encr, + sizeof(reauth->k_encr)); + } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_aut, + sizeof(reauth->k_aut)); + } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) { + hexstr2bin(argv[i], reauth->k_re, + sizeof(reauth->k_re)); + } + } + + return 0; +} + + +static struct eap_sim_reauth * +db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id) +{ + char cmd[256]; + + if (!valid_pseudonym_string(reauth_id)) + return NULL; + os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth)); + os_strlcpy(data->db_tmp_pseudonym_str, reauth_id, + sizeof(data->db_tmp_pseudonym_str)); + data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str; + os_snprintf(cmd, sizeof(cmd), + "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id); + if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) != + SQLITE_OK) + return NULL; + if (data->db_tmp_reauth.identity == NULL) + return NULL; + return &data->db_tmp_reauth; +} + + +static struct eap_sim_reauth * +db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, + size_t identity_len) +{ + char cmd[256]; + 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_reauth, 0, sizeof(data->db_tmp_reauth)); + if (identity_len > sizeof(data->db_tmp_identity)) + return NULL; + os_memcpy(data->db_tmp_identity, identity, identity_len); + data->db_tmp_reauth.identity = data->db_tmp_identity; + data->db_tmp_reauth.identity_len = identity_len; + os_snprintf(cmd, sizeof(cmd), + "SELECT * FROM reauth WHERE imsi=%llu;", imsi); + if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) != + SQLITE_OK) + return NULL; + if (data->db_tmp_reauth.reauth_id == NULL) + return NULL; + return &data->db_tmp_reauth; +} + + +static void db_remove_reauth(struct eap_sim_db_data *data, + struct eap_sim_reauth *reauth) +{ + char cmd[256]; + unsigned long long imsi; + + if (reauth->identity_len >= sizeof(cmd)) + return; + os_memcpy(cmd, reauth->identity, reauth->identity_len); + cmd[reauth->identity_len] = '\0'; + imsi = atoll(cmd); + os_snprintf(cmd, sizeof(cmd), + "DELETE FROM reauth WHERE imsi=%llu;", imsi); + sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL); +} + #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) @@ -949,6 +1172,14 @@ eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, os_memcpy(reauth_id, identity, len); reauth_id[len] = '\0'; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) { + r = db_get_reauth(data, reauth_id); + os_free(reauth_id); + return r; + } +#endif /* CONFIG_SQLITE */ + r = data->reauths; while (r) { if (os_strcmp(r->reauth_id, reauth_id) == 0) @@ -980,6 +1211,11 @@ eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, identity_len = p->identity_len; } +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_get_reauth_id(data, identity, identity_len); +#endif /* CONFIG_SQLITE */ + r = data->reauths; while (r) { if (identity_len == r->identity_len && @@ -1263,6 +1499,12 @@ int eap_sim_db_add_reauth(void *priv, const u8 *identity, struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_add_reauth(data, identity, identity_len, + reauth_id, counter, mk, 0, NULL, NULL, + NULL); +#endif /* CONFIG_SQLITE */ r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, counter); if (r == NULL) @@ -1302,6 +1544,12 @@ int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity, struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) + return db_add_reauth(data, identity, identity_len, + reauth_id, counter, NULL, 1, + k_encr, k_aut, k_re); +#endif /* CONFIG_SQLITE */ r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id, counter); if (r == NULL) @@ -1379,6 +1627,12 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) { struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r, *prev = NULL; +#ifdef CONFIG_SQLITE + if (data->sqlite_db) { + db_remove_reauth(data, reauth); + return; + } +#endif /* CONFIG_SQLITE */ r = data->reauths; while (r) { if (r == reauth) {