2008-02-27 20:34:43 -05:00
|
|
|
/*
|
|
|
|
* hostapd / EAP-SIM database/authenticator gateway
|
2012-05-02 13:45:01 -04:00
|
|
|
* Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
|
2008-02-27 20:34:43 -05:00
|
|
|
*
|
2012-02-11 09:46:35 -05:00
|
|
|
* This software may be distributed under the terms of the BSD license.
|
|
|
|
* See README for more details.
|
2008-02-27 20:34:43 -05:00
|
|
|
*
|
|
|
|
* This is an example implementation of the EAP-SIM/AKA database/authentication
|
|
|
|
* gateway interface that is using an external program as an SS7 gateway to
|
|
|
|
* GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
|
|
|
|
* implementation of such a gateway program. This eap_sim_db.c takes care of
|
|
|
|
* EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
|
|
|
|
* gateway implementations for HLR/AuC access. Alternatively, it can also be
|
|
|
|
* completely replaced if the in-memory database of pseudonyms/re-auth
|
|
|
|
* identities is not suitable for some cases.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "includes.h"
|
|
|
|
#include <sys/un.h>
|
2012-08-30 09:04:52 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
#include <sqlite3.h>
|
|
|
|
#endif /* CONFIG_SQLITE */
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
#include "common.h"
|
2010-11-23 18:05:20 -05:00
|
|
|
#include "crypto/random.h"
|
2008-02-27 20:34:43 -05:00
|
|
|
#include "eap_common/eap_sim_common.h"
|
|
|
|
#include "eap_server/eap_sim_db.h"
|
|
|
|
#include "eloop.h"
|
|
|
|
|
|
|
|
struct eap_sim_pseudonym {
|
|
|
|
struct eap_sim_pseudonym *next;
|
2012-09-01 14:10:19 -04:00
|
|
|
char *permanent; /* permanent username */
|
|
|
|
char *pseudonym; /* pseudonym username */
|
2008-02-27 20:34:43 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct eap_sim_db_pending {
|
|
|
|
struct eap_sim_db_pending *next;
|
2012-09-01 14:10:19 -04:00
|
|
|
char imsi[20];
|
2008-02-27 20:34:43 -05:00
|
|
|
enum { PENDING, SUCCESS, FAILURE } state;
|
|
|
|
void *cb_session_ctx;
|
|
|
|
struct os_time timestamp;
|
|
|
|
int aka;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
|
|
|
|
u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
|
|
|
|
u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
|
|
|
|
int num_chal;
|
|
|
|
} sim;
|
|
|
|
struct {
|
|
|
|
u8 rand[EAP_AKA_RAND_LEN];
|
|
|
|
u8 autn[EAP_AKA_AUTN_LEN];
|
|
|
|
u8 ik[EAP_AKA_IK_LEN];
|
|
|
|
u8 ck[EAP_AKA_CK_LEN];
|
|
|
|
u8 res[EAP_AKA_RES_MAX_LEN];
|
|
|
|
size_t res_len;
|
|
|
|
} aka;
|
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct eap_sim_db_data {
|
|
|
|
int sock;
|
|
|
|
char *fname;
|
|
|
|
char *local_sock;
|
|
|
|
void (*get_complete_cb)(void *ctx, void *session_ctx);
|
|
|
|
void *ctx;
|
|
|
|
struct eap_sim_pseudonym *pseudonyms;
|
|
|
|
struct eap_sim_reauth *reauths;
|
|
|
|
struct eap_sim_db_pending *pending;
|
2012-08-30 09:04:52 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
sqlite3 *sqlite_db;
|
2012-09-01 14:10:19 -04:00
|
|
|
char db_tmp_identity[100];
|
2012-08-30 09:04:52 -04:00
|
|
|
char db_tmp_pseudonym_str[100];
|
|
|
|
struct eap_sim_pseudonym db_tmp_pseudonym;
|
2012-08-30 09:55:36 -04:00
|
|
|
struct eap_sim_reauth db_tmp_reauth;
|
2012-08-30 09:04:52 -04:00
|
|
|
#endif /* CONFIG_SQLITE */
|
2008-02-27 20:34:43 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-08-30 09:04:52 -04:00
|
|
|
#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("
|
2012-09-01 14:22:15 -04:00
|
|
|
" permanent CHAR(21) PRIMARY KEY,"
|
2012-08-30 09:04:52 -04:00
|
|
|
" 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:55:36 -04:00
|
|
|
static int db_table_create_reauth(sqlite3 *db)
|
|
|
|
{
|
|
|
|
char *err = NULL;
|
|
|
|
const char *sql =
|
|
|
|
"CREATE TABLE reauth("
|
2012-09-01 14:22:15 -04:00
|
|
|
" permanent CHAR(21) PRIMARY KEY,"
|
2012-08-30 09:55:36 -04:00
|
|
|
" reauth_id CHAR(21) NOT NULL,"
|
|
|
|
" counter INTEGER,"
|
|
|
|
" 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-30 09:04:52 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-08-30 09:55:36 -04:00
|
|
|
if (!db_table_exists(db, "reauth") &&
|
|
|
|
db_table_create_reauth(db) < 0) {
|
|
|
|
sqlite3_close(db);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-08-30 09:04:52 -04:00
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-01 14:17:48 -04:00
|
|
|
static int valid_db_string(const char *str)
|
2012-08-30 09:04:52 -04:00
|
|
|
{
|
2012-09-01 14:17:48 -04:00
|
|
|
const char *pos = str;
|
2012-08-30 09:04:52 -04:00
|
|
|
while (*pos) {
|
|
|
|
if ((*pos < '0' || *pos > '9') &&
|
|
|
|
(*pos < 'a' || *pos > 'f'))
|
|
|
|
return 0;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
static int db_add_pseudonym(struct eap_sim_db_data *data,
|
|
|
|
const char *permanent, char *pseudonym)
|
2012-08-30 09:04:52 -04:00
|
|
|
{
|
|
|
|
char cmd[128];
|
2012-08-30 09:55:36 -04:00
|
|
|
char *err = NULL;
|
2012-08-30 09:04:52 -04:00
|
|
|
|
2012-09-01 14:22:15 -04:00
|
|
|
if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
|
2012-08-30 09:04:52 -04:00
|
|
|
os_free(pseudonym);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
|
2012-09-01 14:22:15 -04:00
|
|
|
"(permanent, pseudonym) VALUES ('%s', '%s');",
|
|
|
|
permanent, pseudonym);
|
2012-08-30 09:04:52 -04:00
|
|
|
os_free(pseudonym);
|
2012-08-30 09:55:36 -04:00
|
|
|
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);
|
2012-08-30 09:04:52 -04:00
|
|
|
return -1;
|
2012-08-30 09:55:36 -04:00
|
|
|
}
|
2012-08-30 09:04:52 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = ctx;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
2012-09-01 14:22:15 -04:00
|
|
|
if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
|
2012-09-01 14:10:19 -04:00
|
|
|
os_strlcpy(data->db_tmp_identity, argv[i],
|
|
|
|
sizeof(data->db_tmp_identity));
|
2012-08-30 09:04:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-01 14:32:22 -04:00
|
|
|
static char *
|
2012-08-30 09:04:52 -04:00
|
|
|
db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
|
|
|
|
{
|
|
|
|
char cmd[128];
|
|
|
|
|
2012-09-01 14:17:48 -04:00
|
|
|
if (!valid_db_string(pseudonym))
|
2012-08-30 09:04:52 -04:00
|
|
|
return NULL;
|
2012-09-01 14:32:22 -04:00
|
|
|
os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
|
2012-08-30 09:04:52 -04:00
|
|
|
os_snprintf(cmd, sizeof(cmd),
|
2012-09-01 14:22:15 -04:00
|
|
|
"SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
|
2012-08-30 09:04:52 -04:00
|
|
|
pseudonym);
|
|
|
|
if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
|
|
|
|
SQLITE_OK)
|
|
|
|
return NULL;
|
2012-09-01 14:32:22 -04:00
|
|
|
if (data->db_tmp_identity[0] == '\0')
|
2012-08-30 09:04:52 -04:00
|
|
|
return NULL;
|
2012-09-01 14:32:22 -04:00
|
|
|
return data->db_tmp_identity;
|
2012-08-30 09:04:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
|
|
|
|
char *reauth_id, u16 counter, const u8 *mk,
|
|
|
|
const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
|
2012-08-30 09:55:36 -04:00
|
|
|
{
|
|
|
|
char cmd[2000], *pos, *end;
|
|
|
|
char *err = NULL;
|
|
|
|
|
2012-09-01 14:22:15 -04:00
|
|
|
if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
|
2012-08-30 09:55:36 -04:00
|
|
|
os_free(reauth_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = cmd;
|
|
|
|
end = pos + sizeof(cmd);
|
|
|
|
pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
|
2012-09-01 14:22:15 -04:00
|
|
|
"(permanent, reauth_id, counter%s%s%s%s) "
|
|
|
|
"VALUES ('%s', '%s', %u",
|
2012-08-30 09:55:36 -04:00
|
|
|
mk ? ", mk" : "",
|
|
|
|
k_encr ? ", k_encr" : "",
|
|
|
|
k_aut ? ", k_aut" : "",
|
|
|
|
k_re ? ", k_re" : "",
|
2012-09-01 14:22:15 -04:00
|
|
|
permanent, reauth_id, counter);
|
2012-08-30 09:55:36 -04:00
|
|
|
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;
|
|
|
|
struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
|
|
|
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
2012-09-01 14:22:15 -04:00
|
|
|
if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
|
2012-09-01 14:10:19 -04:00
|
|
|
os_strlcpy(data->db_tmp_identity, argv[i],
|
|
|
|
sizeof(data->db_tmp_identity));
|
|
|
|
reauth->permanent = data->db_tmp_identity;
|
2012-08-30 09:55:36 -04:00
|
|
|
} else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
|
|
|
|
reauth->counter = 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];
|
|
|
|
|
2012-09-01 14:17:48 -04:00
|
|
|
if (!valid_db_string(reauth_id))
|
2012-08-30 09:55:36 -04:00
|
|
|
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;
|
2012-09-01 14:10:19 -04:00
|
|
|
if (data->db_tmp_reauth.permanent == NULL)
|
2012-08-30 09:55:36 -04:00
|
|
|
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];
|
|
|
|
|
2012-09-01 14:22:15 -04:00
|
|
|
if (!valid_db_string(reauth->permanent))
|
|
|
|
return;
|
2012-08-30 09:55:36 -04:00
|
|
|
os_snprintf(cmd, sizeof(cmd),
|
2012-09-01 14:22:15 -04:00
|
|
|
"DELETE FROM reauth WHERE permanent='%s';",
|
|
|
|
reauth->permanent);
|
2012-08-30 09:55:36 -04:00
|
|
|
sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
|
2012-08-30 09:04:52 -04:00
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
|
|
2012-08-30 09:55:36 -04:00
|
|
|
|
2008-02-27 20:34:43 -05:00
|
|
|
static struct eap_sim_db_pending *
|
2012-09-01 14:10:19 -04:00
|
|
|
eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_pending *entry, *prev = NULL;
|
|
|
|
|
|
|
|
entry = data->pending;
|
|
|
|
while (entry) {
|
2012-09-01 14:10:19 -04:00
|
|
|
if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
|
2008-02-27 20:34:43 -05:00
|
|
|
if (prev)
|
|
|
|
prev->next = entry->next;
|
|
|
|
else
|
|
|
|
data->pending = entry->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = entry;
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
|
|
|
|
struct eap_sim_db_pending *entry)
|
|
|
|
{
|
|
|
|
entry->next = data->pending;
|
|
|
|
data->pending = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
|
|
|
|
const char *imsi, char *buf)
|
|
|
|
{
|
|
|
|
char *start, *end, *pos;
|
|
|
|
struct eap_sim_db_pending *entry;
|
|
|
|
int num_chal;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
|
|
|
|
* SIM-RESP-AUTH <IMSI> FAILURE
|
|
|
|
* (IMSI = ASCII string, Kc/SRES/RAND = hex string)
|
|
|
|
*/
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
entry = eap_sim_db_get_pending(data, imsi, 0);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (entry == NULL) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
|
|
|
|
"received message found");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = buf;
|
|
|
|
if (os_strncmp(start, "FAILURE", 7) == 0) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
|
|
|
|
"failure");
|
|
|
|
entry->state = FAILURE;
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
data->get_complete_cb(data->ctx, entry->cb_session_ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_chal = 0;
|
|
|
|
while (num_chal < EAP_SIM_MAX_CHAL) {
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end)
|
|
|
|
*end = '\0';
|
|
|
|
|
|
|
|
pos = os_strchr(start, ':');
|
|
|
|
if (pos == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*pos = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.sim.kc[num_chal],
|
|
|
|
EAP_SIM_KC_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = pos + 1;
|
|
|
|
pos = os_strchr(start, ':');
|
|
|
|
if (pos == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*pos = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.sim.sres[num_chal],
|
|
|
|
EAP_SIM_SRES_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = pos + 1;
|
|
|
|
if (hexstr2bin(start, entry->u.sim.rand[num_chal],
|
|
|
|
GSM_RAND_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
num_chal++;
|
|
|
|
if (end == NULL)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
start = end + 1;
|
|
|
|
}
|
|
|
|
entry->u.sim.num_chal = num_chal;
|
|
|
|
|
|
|
|
entry->state = SUCCESS;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
|
|
|
|
"successfully - callback");
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
data->get_complete_cb(data->ctx, entry->cb_session_ctx);
|
|
|
|
return;
|
|
|
|
|
|
|
|
parse_fail:
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
|
|
|
|
os_free(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
|
|
|
|
const char *imsi, char *buf)
|
|
|
|
{
|
|
|
|
char *start, *end;
|
|
|
|
struct eap_sim_db_pending *entry;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
|
|
|
|
* AKA-RESP-AUTH <IMSI> FAILURE
|
|
|
|
* (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
|
|
|
|
*/
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
entry = eap_sim_db_get_pending(data, imsi, 1);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (entry == NULL) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
|
|
|
|
"received message found");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = buf;
|
|
|
|
if (os_strncmp(start, "FAILURE", 7) == 0) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
|
|
|
|
"failure");
|
|
|
|
entry->state = FAILURE;
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
data->get_complete_cb(data->ctx, entry->cb_session_ctx);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*end = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = end + 1;
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*end = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = end + 1;
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*end = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = end + 1;
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*end = '\0';
|
|
|
|
if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
start = end + 1;
|
|
|
|
end = os_strchr(start, ' ');
|
|
|
|
if (end)
|
|
|
|
*end = '\0';
|
|
|
|
else {
|
|
|
|
end = start;
|
|
|
|
while (*end)
|
|
|
|
end++;
|
|
|
|
}
|
|
|
|
entry->u.aka.res_len = (end - start) / 2;
|
|
|
|
if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
|
|
|
|
entry->u.aka.res_len = 0;
|
|
|
|
goto parse_fail;
|
|
|
|
}
|
|
|
|
if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
|
|
|
|
goto parse_fail;
|
|
|
|
|
|
|
|
entry->state = SUCCESS;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
|
|
|
|
"successfully - callback");
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
data->get_complete_cb(data->ctx, entry->cb_session_ctx);
|
|
|
|
return;
|
|
|
|
|
|
|
|
parse_fail:
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
|
|
|
|
os_free(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = eloop_ctx;
|
|
|
|
char buf[1000], *pos, *cmd, *imsi;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
res = recv(sock, buf, sizeof(buf), 0);
|
|
|
|
if (res < 0)
|
|
|
|
return;
|
|
|
|
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
|
|
|
|
"external source", (u8 *) buf, res);
|
|
|
|
if (res == 0)
|
|
|
|
return;
|
|
|
|
if (res >= (int) sizeof(buf))
|
|
|
|
res = sizeof(buf) - 1;
|
|
|
|
buf[res] = '\0';
|
|
|
|
|
|
|
|
if (data->get_complete_cb == NULL) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
|
|
|
|
"registered");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* <cmd> <IMSI> ... */
|
|
|
|
|
|
|
|
cmd = buf;
|
|
|
|
pos = os_strchr(cmd, ' ');
|
|
|
|
if (pos == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*pos = '\0';
|
|
|
|
imsi = pos + 1;
|
|
|
|
pos = os_strchr(imsi, ' ');
|
|
|
|
if (pos == NULL)
|
|
|
|
goto parse_fail;
|
|
|
|
*pos = '\0';
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
|
|
|
|
cmd, imsi);
|
|
|
|
|
|
|
|
if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
|
|
|
|
eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
|
|
|
|
else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
|
|
|
|
eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
|
|
|
|
else
|
|
|
|
wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
|
|
|
|
"'%s'", cmd);
|
|
|
|
return;
|
|
|
|
|
|
|
|
parse_fail:
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
|
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
static int counter = 0;
|
|
|
|
|
|
|
|
if (os_strncmp(data->fname, "unix:", 5) != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (data->sock < 0) {
|
|
|
|
perror("socket(eap_sim_db)");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
os_memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
os_snprintf(addr.sun_path, sizeof(addr.sun_path),
|
|
|
|
"/tmp/eap_sim_db_%d-%d", getpid(), counter++);
|
2012-08-19 14:17:26 -04:00
|
|
|
os_free(data->local_sock);
|
2008-02-27 20:34:43 -05:00
|
|
|
data->local_sock = os_strdup(addr.sun_path);
|
|
|
|
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
|
|
perror("bind(eap_sim_db)");
|
|
|
|
close(data->sock);
|
|
|
|
data->sock = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
os_memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
|
|
|
|
if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
|
|
perror("connect(eap_sim_db)");
|
|
|
|
wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
|
|
|
|
(u8 *) addr.sun_path,
|
|
|
|
os_strlen(addr.sun_path));
|
|
|
|
close(data->sock);
|
|
|
|
data->sock = -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
|
|
|
|
{
|
|
|
|
if (data->sock >= 0) {
|
|
|
|
eloop_unregister_read_sock(data->sock);
|
|
|
|
close(data->sock);
|
|
|
|
data->sock = -1;
|
|
|
|
}
|
|
|
|
if (data->local_sock) {
|
|
|
|
unlink(data->local_sock);
|
|
|
|
os_free(data->local_sock);
|
|
|
|
data->local_sock = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
|
|
|
|
* @config: Configuration data (e.g., file name)
|
|
|
|
* @get_complete_cb: Callback function for reporting availability of triplets
|
|
|
|
* @ctx: Context pointer for get_complete_cb
|
|
|
|
* Returns: Pointer to a private data structure or %NULL on failure
|
|
|
|
*/
|
|
|
|
void * eap_sim_db_init(const char *config,
|
|
|
|
void (*get_complete_cb)(void *ctx, void *session_ctx),
|
|
|
|
void *ctx)
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data;
|
2012-08-30 09:04:52 -04:00
|
|
|
char *pos;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
data = os_zalloc(sizeof(*data));
|
|
|
|
if (data == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
data->sock = -1;
|
|
|
|
data->get_complete_cb = get_complete_cb;
|
|
|
|
data->ctx = ctx;
|
|
|
|
data->fname = os_strdup(config);
|
|
|
|
if (data->fname == NULL)
|
|
|
|
goto fail;
|
2012-08-30 09:04:52 -04:00
|
|
|
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 */
|
|
|
|
}
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
if (os_strncmp(data->fname, "unix:", 5) == 0) {
|
2012-08-19 13:51:21 -04:00
|
|
|
if (eap_sim_db_open_socket(data)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
|
|
|
|
"connection not available - will retry "
|
|
|
|
"later");
|
|
|
|
}
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
eap_sim_db_close_socket(data);
|
|
|
|
os_free(data->fname);
|
|
|
|
os_free(data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
|
|
|
|
{
|
2012-09-01 14:10:19 -04:00
|
|
|
os_free(p->permanent);
|
2008-02-27 20:34:43 -05:00
|
|
|
os_free(p->pseudonym);
|
|
|
|
os_free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
|
|
|
|
{
|
2012-09-01 14:10:19 -04:00
|
|
|
os_free(r->permanent);
|
2008-02-27 20:34:43 -05:00
|
|
|
os_free(r->reauth_id);
|
|
|
|
os_free(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
|
|
|
*/
|
|
|
|
void eap_sim_db_deinit(void *priv)
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_pseudonym *p, *prev;
|
|
|
|
struct eap_sim_reauth *r, *prevr;
|
|
|
|
struct eap_sim_db_pending *pending, *prev_pending;
|
|
|
|
|
2012-08-30 09:04:52 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db) {
|
|
|
|
sqlite3_close(data->sqlite_db);
|
|
|
|
data->sqlite_db = NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
|
|
2008-02-27 20:34:43 -05:00
|
|
|
eap_sim_db_close_socket(data);
|
|
|
|
os_free(data->fname);
|
|
|
|
|
|
|
|
p = data->pseudonyms;
|
|
|
|
while (p) {
|
|
|
|
prev = p;
|
|
|
|
p = p->next;
|
|
|
|
eap_sim_db_free_pseudonym(prev);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = data->reauths;
|
|
|
|
while (r) {
|
|
|
|
prevr = r;
|
|
|
|
r = r->next;
|
|
|
|
eap_sim_db_free_reauth(prevr);
|
|
|
|
}
|
|
|
|
|
|
|
|
pending = data->pending;
|
|
|
|
while (pending) {
|
|
|
|
prev_pending = pending;
|
|
|
|
pending = pending->next;
|
|
|
|
os_free(prev_pending);
|
|
|
|
}
|
|
|
|
|
|
|
|
os_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
int _errno = 0;
|
|
|
|
|
|
|
|
if (send(data->sock, msg, len, 0) < 0) {
|
|
|
|
_errno = errno;
|
|
|
|
perror("send[EAP-SIM DB UNIX]");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
|
|
|
|
_errno == ECONNREFUSED) {
|
|
|
|
/* Try to reconnect */
|
|
|
|
eap_sim_db_close_socket(data);
|
|
|
|
if (eap_sim_db_open_socket(data) < 0)
|
|
|
|
return -1;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
|
|
|
|
"external server");
|
|
|
|
if (send(data->sock, msg, len, 0) < 0) {
|
|
|
|
perror("send[EAP-SIM DB UNIX]");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
|
|
|
|
{
|
|
|
|
/* TODO: add limit for maximum length for pending list; remove latest
|
|
|
|
* (i.e., last) entry from the list if the limit is reached; could also
|
|
|
|
* use timeout to expire pending entries */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_gsm_triplets - Get GSM triplets
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @username: Permanent username (prefix | IMSI)
|
2008-02-27 20:34:43 -05:00
|
|
|
* @max_chal: Maximum number of triplets
|
|
|
|
* @_rand: Buffer for RAND values
|
|
|
|
* @kc: Buffer for Kc values
|
|
|
|
* @sres: Buffer for SRES values
|
|
|
|
* @cb_session_ctx: Session callback context for get_complete_cb()
|
|
|
|
* Returns: Number of triplets received (has to be less than or equal to
|
|
|
|
* max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
|
|
|
|
* -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
|
|
|
|
* callback function registered with eap_sim_db_init() will be called once the
|
|
|
|
* results become available.
|
|
|
|
*
|
|
|
|
* When using an external server for GSM triplets, this function can always
|
|
|
|
* start a request and return EAP_SIM_DB_PENDING immediately if authentication
|
|
|
|
* triplets are not available. Once the triplets are received, callback
|
|
|
|
* function registered with eap_sim_db_init() is called to notify EAP state
|
|
|
|
* machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
|
|
|
|
* function will then be called again and the newly received triplets will then
|
|
|
|
* be given to the caller.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_get_gsm_triplets(void *priv, const char *username, int max_chal,
|
2008-02-27 20:34:43 -05:00
|
|
|
u8 *_rand, u8 *kc, u8 *sres,
|
|
|
|
void *cb_session_ctx)
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_db_pending *entry;
|
|
|
|
int len, ret;
|
|
|
|
char msg[40];
|
2012-09-01 14:10:19 -04:00
|
|
|
const char *imsi;
|
|
|
|
size_t imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
|
|
|
|
username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
|
|
|
|
username);
|
2008-02-27 20:34:43 -05:00
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi = username + 1;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
|
|
|
|
imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
entry = eap_sim_db_get_pending(data, imsi, 0);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (entry) {
|
|
|
|
int num_chal;
|
|
|
|
if (entry->state == FAILURE) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
|
|
|
|
"failure");
|
|
|
|
os_free(entry);
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->state == PENDING) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
|
|
|
|
"still pending");
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
return EAP_SIM_DB_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
|
|
|
|
"%d challenges", entry->u.sim.num_chal);
|
|
|
|
num_chal = entry->u.sim.num_chal;
|
|
|
|
if (num_chal > max_chal)
|
|
|
|
num_chal = max_chal;
|
|
|
|
os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
|
|
|
|
os_memcpy(sres, entry->u.sim.sres,
|
|
|
|
num_chal * EAP_SIM_SRES_LEN);
|
|
|
|
os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
|
|
|
|
os_free(entry);
|
|
|
|
return num_chal;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->sock < 0) {
|
|
|
|
if (eap_sim_db_open_socket(data) < 0)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi_len = os_strlen(imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
|
2012-09-01 14:10:19 -04:00
|
|
|
if (len < 0 || len + imsi_len >= sizeof(msg))
|
2008-02-27 20:34:43 -05:00
|
|
|
return EAP_SIM_DB_FAILURE;
|
2012-09-01 14:10:19 -04:00
|
|
|
os_memcpy(msg + len, imsi, imsi_len);
|
|
|
|
len += imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
|
|
|
|
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
len += ret;
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
|
|
|
|
"data for IMSI '%s'", imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (eap_sim_db_send(data, msg, len) < 0)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
|
|
|
|
entry = os_zalloc(sizeof(*entry));
|
|
|
|
if (entry == NULL)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
|
|
|
|
os_get_time(&entry->timestamp);
|
2012-09-01 14:10:19 -04:00
|
|
|
os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
|
2008-02-27 20:34:43 -05:00
|
|
|
entry->cb_session_ctx = cb_session_ctx;
|
|
|
|
entry->state = PENDING;
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
eap_sim_db_expire_pending(data);
|
|
|
|
|
|
|
|
return EAP_SIM_DB_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
|
|
|
|
{
|
|
|
|
char *id, *pos, *end;
|
|
|
|
u8 buf[10];
|
|
|
|
|
2010-11-23 18:05:20 -05:00
|
|
|
if (random_get_bytes(buf, sizeof(buf)))
|
2008-02-27 20:34:43 -05:00
|
|
|
return NULL;
|
|
|
|
id = os_malloc(sizeof(buf) * 2 + 2);
|
|
|
|
if (id == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pos = id;
|
|
|
|
end = id + sizeof(buf) * 2 + 2;
|
|
|
|
*pos++ = prefix;
|
|
|
|
pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-05-02 13:45:01 -04:00
|
|
|
* @method: EAP method (SIM/AKA/AKA')
|
2008-02-27 20:34:43 -05:00
|
|
|
* Returns: Next pseudonym (allocated string) or %NULL on failure
|
|
|
|
*
|
|
|
|
* This function is used to generate a pseudonym for EAP-SIM. The returned
|
|
|
|
* pseudonym is not added to database at this point; it will need to be added
|
|
|
|
* with eap_sim_db_add_pseudonym() once the authentication has been completed
|
|
|
|
* successfully. Caller is responsible for freeing the returned buffer.
|
|
|
|
*/
|
2012-05-02 13:45:01 -04:00
|
|
|
char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
2012-05-02 13:45:01 -04:00
|
|
|
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case EAP_SIM_DB_SIM:
|
|
|
|
prefix = EAP_SIM_PSEUDONYM_PREFIX;
|
|
|
|
break;
|
|
|
|
case EAP_SIM_DB_AKA:
|
|
|
|
prefix = EAP_AKA_PSEUDONYM_PREFIX;
|
|
|
|
break;
|
|
|
|
case EAP_SIM_DB_AKA_PRIME:
|
|
|
|
prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eap_sim_db_get_next(data, prefix);
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-05-02 13:45:01 -04:00
|
|
|
* @method: EAP method (SIM/AKA/AKA')
|
2008-02-27 20:34:43 -05:00
|
|
|
* Returns: Next reauth_id (allocated string) or %NULL on failure
|
|
|
|
*
|
|
|
|
* This function is used to generate a fast re-authentication identity for
|
|
|
|
* EAP-SIM. The returned reauth_id is not added to database at this point; it
|
|
|
|
* will need to be added with eap_sim_db_add_reauth() once the authentication
|
|
|
|
* has been completed successfully. Caller is responsible for freeing the
|
|
|
|
* returned buffer.
|
|
|
|
*/
|
2012-05-02 13:45:01 -04:00
|
|
|
char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
2012-05-02 13:45:01 -04:00
|
|
|
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case EAP_SIM_DB_SIM:
|
|
|
|
prefix = EAP_SIM_REAUTH_ID_PREFIX;
|
|
|
|
break;
|
|
|
|
case EAP_SIM_DB_AKA:
|
|
|
|
prefix = EAP_AKA_REAUTH_ID_PREFIX;
|
|
|
|
break;
|
|
|
|
case EAP_SIM_DB_AKA_PRIME:
|
|
|
|
prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eap_sim_db_get_next(data, prefix);
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @permanent: Permanent username
|
2008-02-27 20:34:43 -05:00
|
|
|
* @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
|
|
|
|
* e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
|
|
|
|
* free it.
|
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
|
|
|
|
* responsible of freeing pseudonym buffer once it is not needed anymore.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_add_pseudonym(void *priv, const char *permanent,
|
|
|
|
char *pseudonym)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_pseudonym *p;
|
2012-09-01 14:10:19 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
|
|
|
|
"username '%s'", pseudonym, permanent);
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
/* TODO: could store last two pseudonyms */
|
2012-08-30 09:04:52 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db)
|
2012-09-01 14:10:19 -04:00
|
|
|
return db_add_pseudonym(data, permanent, pseudonym);
|
2012-08-30 09:04:52 -04:00
|
|
|
#endif /* CONFIG_SQLITE */
|
2012-09-01 14:10:19 -04:00
|
|
|
for (p = data->pseudonyms; p; p = p->next) {
|
|
|
|
if (os_strcmp(permanent, p->permanent) == 0)
|
|
|
|
break;
|
|
|
|
}
|
2008-02-27 20:34:43 -05:00
|
|
|
if (p) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
|
|
|
|
"pseudonym: %s", p->pseudonym);
|
|
|
|
os_free(p->pseudonym);
|
|
|
|
p->pseudonym = pseudonym;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = os_zalloc(sizeof(*p));
|
|
|
|
if (p == NULL) {
|
|
|
|
os_free(pseudonym);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->next = data->pseudonyms;
|
2012-09-01 14:10:19 -04:00
|
|
|
p->permanent = os_strdup(permanent);
|
|
|
|
if (p->permanent == NULL) {
|
2008-02-27 20:34:43 -05:00
|
|
|
os_free(p);
|
|
|
|
os_free(pseudonym);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
p->pseudonym = pseudonym;
|
|
|
|
data->pseudonyms = p;
|
|
|
|
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-03 12:22:20 -05:00
|
|
|
static struct eap_sim_reauth *
|
2012-09-01 14:10:19 -04:00
|
|
|
eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
|
|
|
|
const char *permanent,
|
|
|
|
char *reauth_id, u16 counter)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_reauth *r;
|
2008-12-03 12:22:20 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
for (r = data->reauths; r; r = r->next) {
|
|
|
|
if (os_strcmp(r->permanent, permanent) == 0)
|
|
|
|
break;
|
|
|
|
}
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
if (r) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
|
|
|
|
"reauth_id: %s", r->reauth_id);
|
|
|
|
os_free(r->reauth_id);
|
|
|
|
r->reauth_id = reauth_id;
|
|
|
|
} else {
|
|
|
|
r = os_zalloc(sizeof(*r));
|
|
|
|
if (r == NULL) {
|
|
|
|
os_free(reauth_id);
|
2008-12-03 12:22:20 -05:00
|
|
|
return NULL;
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
r->next = data->reauths;
|
2012-09-01 14:10:19 -04:00
|
|
|
r->permanent = os_strdup(permanent);
|
|
|
|
if (r->permanent == NULL) {
|
2008-02-27 20:34:43 -05:00
|
|
|
os_free(r);
|
|
|
|
os_free(reauth_id);
|
2008-12-03 12:22:20 -05:00
|
|
|
return NULL;
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
r->reauth_id = reauth_id;
|
|
|
|
data->reauths = r;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
|
|
|
|
}
|
|
|
|
|
|
|
|
r->counter = counter;
|
2008-12-03 12:22:20 -05:00
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @permanent: Permanent username
|
2008-12-03 12:22:20 -05:00
|
|
|
* @identity_len: Length of identity
|
|
|
|
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
|
|
|
|
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
|
|
|
|
* free it.
|
2009-01-02 15:28:04 -05:00
|
|
|
* @counter: AT_COUNTER value for fast re-authentication
|
2008-12-03 12:22:20 -05:00
|
|
|
* @mk: 16-byte MK from the previous full authentication or %NULL
|
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* This function adds a new re-authentication entry for an EAP-SIM user.
|
|
|
|
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
|
|
|
|
* anymore.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_add_reauth(void *priv, const char *permanent, char *reauth_id,
|
|
|
|
u16 counter, const u8 *mk)
|
2008-12-03 12:22:20 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_reauth *r;
|
|
|
|
|
2012-09-01 14:41:23 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
|
|
|
|
"identity '%s'", reauth_id, permanent);
|
|
|
|
|
2012-08-30 09:55:36 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db)
|
2012-09-01 14:10:19 -04:00
|
|
|
return db_add_reauth(data, permanent, reauth_id, counter, mk,
|
|
|
|
NULL, NULL, NULL);
|
2012-08-30 09:55:36 -04:00
|
|
|
#endif /* CONFIG_SQLITE */
|
2012-09-01 14:10:19 -04:00
|
|
|
r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
|
2008-12-03 12:22:20 -05:00
|
|
|
if (r == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2008-02-27 20:34:43 -05:00
|
|
|
os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
|
2008-12-03 12:22:20 -05:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-25 06:06:19 -04:00
|
|
|
#ifdef EAP_SERVER_AKA_PRIME
|
2008-12-03 12:22:20 -05:00
|
|
|
/**
|
|
|
|
* eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @permanent: Permanent username
|
2008-12-03 12:22:20 -05:00
|
|
|
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
|
|
|
|
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
|
|
|
|
* free it.
|
2009-01-02 15:28:04 -05:00
|
|
|
* @counter: AT_COUNTER value for fast re-authentication
|
|
|
|
* @k_encr: K_encr from the previous full authentication
|
|
|
|
* @k_aut: K_aut from the previous full authentication
|
|
|
|
* @k_re: 32-byte K_re from the previous full authentication
|
2008-12-03 12:22:20 -05:00
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* This function adds a new re-authentication entry for an EAP-AKA' user.
|
|
|
|
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
|
|
|
|
* anymore.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_add_reauth_prime(void *priv, const char *permanent,
|
|
|
|
char *reauth_id, u16 counter, const u8 *k_encr,
|
|
|
|
const u8 *k_aut, const u8 *k_re)
|
2008-12-03 12:22:20 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_reauth *r;
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
|
|
|
|
"identity '%s'", reauth_id, permanent);
|
|
|
|
|
2012-08-30 09:55:36 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db)
|
2012-09-01 14:10:19 -04:00
|
|
|
return db_add_reauth(data, permanent, reauth_id, counter, NULL,
|
2012-08-30 09:55:36 -04:00
|
|
|
k_encr, k_aut, k_re);
|
|
|
|
#endif /* CONFIG_SQLITE */
|
2012-09-01 14:10:19 -04:00
|
|
|
r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
|
2008-12-03 12:22:20 -05:00
|
|
|
if (r == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
|
|
|
|
os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
|
|
|
|
os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2009-03-25 06:06:19 -04:00
|
|
|
#endif /* EAP_SERVER_AKA_PRIME */
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @pseudonym: Pseudonym username
|
|
|
|
* Returns: Pointer to permanent username or %NULL if not found
|
2008-02-27 20:34:43 -05:00
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
const char * eap_sim_db_get_permanent(void *priv, const char *pseudonym)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
2012-09-01 14:37:17 -04:00
|
|
|
struct eap_sim_pseudonym *p;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:37:17 -04:00
|
|
|
if (pseudonym[0] != EAP_SIM_PSEUDONYM_PREFIX &&
|
|
|
|
pseudonym[0] != EAP_AKA_PSEUDONYM_PREFIX &&
|
|
|
|
pseudonym[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX)
|
2008-02-27 20:34:43 -05:00
|
|
|
return NULL;
|
|
|
|
|
2012-09-01 14:37:17 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db)
|
|
|
|
return db_get_pseudonym(data, pseudonym);
|
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
|
|
|
|
|
p = data->pseudonyms;
|
|
|
|
while (p) {
|
|
|
|
if (os_strcmp(p->pseudonym, pseudonym) == 0)
|
|
|
|
return p->permanent;
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2008-02-27 20:34:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @reauth_id: Fast re-authentication username
|
2008-02-27 20:34:43 -05:00
|
|
|
* Returns: Pointer to the re-auth entry, or %NULL if not found
|
|
|
|
*/
|
|
|
|
struct eap_sim_reauth *
|
2012-09-01 14:10:19 -04:00
|
|
|
eap_sim_db_get_reauth_entry(void *priv, const char *reauth_id)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_reauth *r;
|
|
|
|
|
2012-09-01 14:37:17 -04:00
|
|
|
if (reauth_id[0] != EAP_SIM_REAUTH_ID_PREFIX &&
|
|
|
|
reauth_id[0] != EAP_AKA_REAUTH_ID_PREFIX &&
|
|
|
|
reauth_id[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
|
2008-02-27 20:34:43 -05:00
|
|
|
return NULL;
|
2012-09-01 14:37:17 -04:00
|
|
|
|
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db)
|
|
|
|
return db_get_reauth(data, reauth_id);
|
|
|
|
#endif /* CONFIG_SQLITE */
|
|
|
|
|
|
|
|
r = data->reauths;
|
|
|
|
while (r) {
|
|
|
|
if (os_strcmp(r->reauth_id, reauth_id) == 0)
|
|
|
|
break;
|
|
|
|
r = r->next;
|
|
|
|
}
|
|
|
|
|
2008-02-27 20:34:43 -05:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
|
|
|
* @reauth: Pointer to re-authentication entry from
|
|
|
|
* eap_sim_db_get_reauth_entry()
|
|
|
|
*/
|
|
|
|
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;
|
2012-08-30 09:55:36 -04:00
|
|
|
#ifdef CONFIG_SQLITE
|
|
|
|
if (data->sqlite_db) {
|
|
|
|
db_remove_reauth(data, reauth);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_SQLITE */
|
2008-02-27 20:34:43 -05:00
|
|
|
r = data->reauths;
|
|
|
|
while (r) {
|
|
|
|
if (r == reauth) {
|
|
|
|
if (prev)
|
|
|
|
prev->next = r->next;
|
|
|
|
else
|
|
|
|
data->reauths = r->next;
|
|
|
|
eap_sim_db_free_reauth(r);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = r;
|
|
|
|
r = r->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_get_aka_auth - Get AKA authentication values
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @username: Permanent username (prefix | IMSI)
|
2008-02-27 20:34:43 -05:00
|
|
|
* @_rand: Buffer for RAND value
|
|
|
|
* @autn: Buffer for AUTN value
|
|
|
|
* @ik: Buffer for IK value
|
|
|
|
* @ck: Buffer for CK value
|
|
|
|
* @res: Buffer for RES value
|
|
|
|
* @res_len: Buffer for RES length
|
|
|
|
* @cb_session_ctx: Session callback context for get_complete_cb()
|
|
|
|
* Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
|
|
|
|
* found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
|
|
|
|
* case, the callback function registered with eap_sim_db_init() will be
|
|
|
|
* called once the results become available.
|
|
|
|
*
|
|
|
|
* When using an external server for AKA authentication, this function can
|
|
|
|
* always start a request and return EAP_SIM_DB_PENDING immediately if
|
|
|
|
* authentication triplets are not available. Once the authentication data are
|
|
|
|
* received, callback function registered with eap_sim_db_init() is called to
|
|
|
|
* notify EAP state machine to reprocess the message. This
|
|
|
|
* eap_sim_db_get_aka_auth() function will then be called again and the newly
|
|
|
|
* received triplets will then be given to the caller.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_get_aka_auth(void *priv, const char *username, u8 *_rand,
|
|
|
|
u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
|
2008-02-27 20:34:43 -05:00
|
|
|
void *cb_session_ctx)
|
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
|
|
|
struct eap_sim_db_pending *entry;
|
|
|
|
int len;
|
|
|
|
char msg[40];
|
2012-09-01 14:10:19 -04:00
|
|
|
const char *imsi;
|
|
|
|
size_t imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
if (username == NULL ||
|
|
|
|
(username[0] != EAP_AKA_PERMANENT_PREFIX &&
|
|
|
|
username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
|
|
|
|
username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
|
|
|
|
username);
|
2008-02-27 20:34:43 -05:00
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi = username + 1;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
|
|
|
|
imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
entry = eap_sim_db_get_pending(data, imsi, 1);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (entry) {
|
|
|
|
if (entry->state == FAILURE) {
|
|
|
|
os_free(entry);
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->state == PENDING) {
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
|
|
|
|
return EAP_SIM_DB_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
|
|
|
|
"received authentication data");
|
|
|
|
os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
|
|
|
|
os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
|
|
|
|
os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
|
|
|
|
os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
|
|
|
|
os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
|
|
|
|
*res_len = entry->u.aka.res_len;
|
|
|
|
os_free(entry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->sock < 0) {
|
|
|
|
if (eap_sim_db_open_socket(data) < 0)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi_len = os_strlen(imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
|
2012-09-01 14:10:19 -04:00
|
|
|
if (len < 0 || len + imsi_len >= sizeof(msg))
|
2008-02-27 20:34:43 -05:00
|
|
|
return EAP_SIM_DB_FAILURE;
|
2012-09-01 14:10:19 -04:00
|
|
|
os_memcpy(msg + len, imsi, imsi_len);
|
|
|
|
len += imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
|
|
|
|
"data for IMSI '%s'", imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (eap_sim_db_send(data, msg, len) < 0)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
|
|
|
|
entry = os_zalloc(sizeof(*entry));
|
|
|
|
if (entry == NULL)
|
|
|
|
return EAP_SIM_DB_FAILURE;
|
|
|
|
|
|
|
|
os_get_time(&entry->timestamp);
|
|
|
|
entry->aka = 1;
|
2012-09-01 14:10:19 -04:00
|
|
|
os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
|
2008-02-27 20:34:43 -05:00
|
|
|
entry->cb_session_ctx = cb_session_ctx;
|
|
|
|
entry->state = PENDING;
|
|
|
|
eap_sim_db_add_pending(data, entry);
|
|
|
|
eap_sim_db_expire_pending(data);
|
|
|
|
|
|
|
|
return EAP_SIM_DB_PENDING;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* eap_sim_db_resynchronize - Resynchronize AKA AUTN
|
|
|
|
* @priv: Private data pointer from eap_sim_db_init()
|
2012-09-01 14:10:19 -04:00
|
|
|
* @username: Permanent username
|
2008-02-27 20:34:43 -05:00
|
|
|
* @auts: AUTS value from the peer
|
|
|
|
* @_rand: RAND value used in the rejected message
|
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* This function is called when the peer reports synchronization failure in the
|
|
|
|
* AUTN value by sending AUTS. The AUTS and RAND values should be sent to
|
|
|
|
* HLR/AuC to allow it to resynchronize with the peer. After this,
|
|
|
|
* eap_sim_db_get_aka_auth() will be called again to to fetch updated
|
|
|
|
* RAND/AUTN values for the next challenge.
|
|
|
|
*/
|
2012-09-01 14:10:19 -04:00
|
|
|
int eap_sim_db_resynchronize(void *priv, const char *username,
|
|
|
|
const u8 *auts, const u8 *_rand)
|
2008-02-27 20:34:43 -05:00
|
|
|
{
|
|
|
|
struct eap_sim_db_data *data = priv;
|
2012-09-01 14:10:19 -04:00
|
|
|
const char *imsi;
|
|
|
|
size_t imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
if (username == NULL ||
|
|
|
|
(username[0] != EAP_AKA_PERMANENT_PREFIX &&
|
|
|
|
username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
|
|
|
|
username[1] == '\0' || os_strlen(username) > 20) {
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
|
|
|
|
username);
|
2008-02-27 20:34:43 -05:00
|
|
|
return -1;
|
|
|
|
}
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi = username + 1;
|
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
|
|
|
|
imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
if (data->sock >= 0) {
|
|
|
|
char msg[100];
|
|
|
|
int len, ret;
|
|
|
|
|
2012-09-01 14:10:19 -04:00
|
|
|
imsi_len = os_strlen(imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
|
2012-09-01 14:10:19 -04:00
|
|
|
if (len < 0 || len + imsi_len >= sizeof(msg))
|
2008-02-27 20:34:43 -05:00
|
|
|
return -1;
|
2012-09-01 14:10:19 -04:00
|
|
|
os_memcpy(msg + len, imsi, imsi_len);
|
|
|
|
len += imsi_len;
|
2008-02-27 20:34:43 -05:00
|
|
|
|
|
|
|
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
|
|
|
|
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
|
|
|
|
return -1;
|
|
|
|
len += ret;
|
|
|
|
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
|
|
|
|
auts, EAP_AKA_AUTS_LEN);
|
|
|
|
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
|
|
|
|
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
|
|
|
|
return -1;
|
|
|
|
len += ret;
|
|
|
|
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
|
|
|
|
_rand, EAP_AKA_RAND_LEN);
|
2012-09-01 14:10:19 -04:00
|
|
|
wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
|
|
|
|
"IMSI '%s'", imsi);
|
2008-02-27 20:34:43 -05:00
|
|
|
if (eap_sim_db_send(data, msg, len) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-01 12:10:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sim_get_username - Extract username from SIM identity
|
|
|
|
* @identity: Identity
|
|
|
|
* @identity_len: Identity length
|
|
|
|
* Returns: Allocated buffer with the username part of the identity
|
|
|
|
*
|
|
|
|
* Caller is responsible for freeing the returned buffer with os_free().
|
|
|
|
*/
|
|
|
|
char * sim_get_username(const u8 *identity, size_t identity_len)
|
|
|
|
{
|
|
|
|
char *username;
|
|
|
|
size_t pos;
|
|
|
|
|
|
|
|
for (pos = 0; pos < identity_len; pos++) {
|
|
|
|
if (identity[pos] == '@' || identity[pos] == '\0')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
username = os_malloc(pos + 1);
|
|
|
|
if (username == NULL)
|
|
|
|
return NULL;
|
|
|
|
os_memcpy(username, identity, pos);
|
|
|
|
username[pos] = '\0';
|
|
|
|
|
|
|
|
return username;
|
|
|
|
}
|