139beb93cSSam Leffler /*
239beb93cSSam Leffler  * hostapd / EAP-SIM database/authenticator gateway
3f05cddf9SRui Paulo  * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  *
839beb93cSSam Leffler  * This is an example implementation of the EAP-SIM/AKA database/authentication
939beb93cSSam Leffler  * gateway interface that is using an external program as an SS7 gateway to
1039beb93cSSam Leffler  * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
1139beb93cSSam Leffler  * implementation of such a gateway program. This eap_sim_db.c takes care of
1239beb93cSSam Leffler  * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
1339beb93cSSam Leffler  * gateway implementations for HLR/AuC access. Alternatively, it can also be
1439beb93cSSam Leffler  * completely replaced if the in-memory database of pseudonyms/re-auth
1539beb93cSSam Leffler  * identities is not suitable for some cases.
1639beb93cSSam Leffler  */
1739beb93cSSam Leffler 
1839beb93cSSam Leffler #include "includes.h"
1939beb93cSSam Leffler #include <sys/un.h>
20f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
21f05cddf9SRui Paulo #include <sqlite3.h>
22f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
2339beb93cSSam Leffler 
2439beb93cSSam Leffler #include "common.h"
25f05cddf9SRui Paulo #include "crypto/random.h"
2639beb93cSSam Leffler #include "eap_common/eap_sim_common.h"
2739beb93cSSam Leffler #include "eap_server/eap_sim_db.h"
2839beb93cSSam Leffler #include "eloop.h"
2939beb93cSSam Leffler 
3039beb93cSSam Leffler struct eap_sim_pseudonym {
3139beb93cSSam Leffler 	struct eap_sim_pseudonym *next;
32f05cddf9SRui Paulo 	char *permanent; /* permanent username */
33f05cddf9SRui Paulo 	char *pseudonym; /* pseudonym username */
3439beb93cSSam Leffler };
3539beb93cSSam Leffler 
3639beb93cSSam Leffler struct eap_sim_db_pending {
3739beb93cSSam Leffler 	struct eap_sim_db_pending *next;
38f05cddf9SRui Paulo 	char imsi[20];
3939beb93cSSam Leffler 	enum { PENDING, SUCCESS, FAILURE } state;
4039beb93cSSam Leffler 	void *cb_session_ctx;
4139beb93cSSam Leffler 	int aka;
4239beb93cSSam Leffler 	union {
4339beb93cSSam Leffler 		struct {
4439beb93cSSam Leffler 			u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
4539beb93cSSam Leffler 			u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
4639beb93cSSam Leffler 			u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
4739beb93cSSam Leffler 			int num_chal;
4839beb93cSSam Leffler 		} sim;
4939beb93cSSam Leffler 		struct {
5039beb93cSSam Leffler 			u8 rand[EAP_AKA_RAND_LEN];
5139beb93cSSam Leffler 			u8 autn[EAP_AKA_AUTN_LEN];
5239beb93cSSam Leffler 			u8 ik[EAP_AKA_IK_LEN];
5339beb93cSSam Leffler 			u8 ck[EAP_AKA_CK_LEN];
5439beb93cSSam Leffler 			u8 res[EAP_AKA_RES_MAX_LEN];
5539beb93cSSam Leffler 			size_t res_len;
5639beb93cSSam Leffler 		} aka;
5739beb93cSSam Leffler 	} u;
5839beb93cSSam Leffler };
5939beb93cSSam Leffler 
6039beb93cSSam Leffler struct eap_sim_db_data {
6139beb93cSSam Leffler 	int sock;
6239beb93cSSam Leffler 	char *fname;
6339beb93cSSam Leffler 	char *local_sock;
6439beb93cSSam Leffler 	void (*get_complete_cb)(void *ctx, void *session_ctx);
6539beb93cSSam Leffler 	void *ctx;
6639beb93cSSam Leffler 	struct eap_sim_pseudonym *pseudonyms;
6739beb93cSSam Leffler 	struct eap_sim_reauth *reauths;
6839beb93cSSam Leffler 	struct eap_sim_db_pending *pending;
69*780fb4a2SCy Schubert 	unsigned int eap_sim_db_timeout;
70f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
71f05cddf9SRui Paulo 	sqlite3 *sqlite_db;
72f05cddf9SRui Paulo 	char db_tmp_identity[100];
73f05cddf9SRui Paulo 	char db_tmp_pseudonym_str[100];
74f05cddf9SRui Paulo 	struct eap_sim_pseudonym db_tmp_pseudonym;
75f05cddf9SRui Paulo 	struct eap_sim_reauth db_tmp_reauth;
76f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
7739beb93cSSam Leffler };
7839beb93cSSam Leffler 
7939beb93cSSam Leffler 
80*780fb4a2SCy Schubert static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
81*780fb4a2SCy Schubert static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
82*780fb4a2SCy Schubert 
83*780fb4a2SCy Schubert 
84f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
85f05cddf9SRui Paulo 
db_table_exists(sqlite3 * db,const char * name)86f05cddf9SRui Paulo static int db_table_exists(sqlite3 *db, const char *name)
87f05cddf9SRui Paulo {
88f05cddf9SRui Paulo 	char cmd[128];
89f05cddf9SRui Paulo 	os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
90f05cddf9SRui Paulo 	return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
91f05cddf9SRui Paulo }
92f05cddf9SRui Paulo 
93f05cddf9SRui Paulo 
db_table_create_pseudonym(sqlite3 * db)94f05cddf9SRui Paulo static int db_table_create_pseudonym(sqlite3 *db)
95f05cddf9SRui Paulo {
96f05cddf9SRui Paulo 	char *err = NULL;
97f05cddf9SRui Paulo 	const char *sql =
98f05cddf9SRui Paulo 		"CREATE TABLE pseudonyms("
99f05cddf9SRui Paulo 		"  permanent CHAR(21) PRIMARY KEY,"
100f05cddf9SRui Paulo 		"  pseudonym CHAR(21) NOT NULL"
101f05cddf9SRui Paulo 		");";
102f05cddf9SRui Paulo 
103f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
104f05cddf9SRui Paulo 		   "pseudonym information");
105f05cddf9SRui Paulo 	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
106f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
107f05cddf9SRui Paulo 		sqlite3_free(err);
108f05cddf9SRui Paulo 		return -1;
109f05cddf9SRui Paulo 	}
110f05cddf9SRui Paulo 
111f05cddf9SRui Paulo 	return 0;
112f05cddf9SRui Paulo }
113f05cddf9SRui Paulo 
114f05cddf9SRui Paulo 
db_table_create_reauth(sqlite3 * db)115f05cddf9SRui Paulo static int db_table_create_reauth(sqlite3 *db)
116f05cddf9SRui Paulo {
117f05cddf9SRui Paulo 	char *err = NULL;
118f05cddf9SRui Paulo 	const char *sql =
119f05cddf9SRui Paulo 		"CREATE TABLE reauth("
120f05cddf9SRui Paulo 		"  permanent CHAR(21) PRIMARY KEY,"
121f05cddf9SRui Paulo 		"  reauth_id CHAR(21) NOT NULL,"
122f05cddf9SRui Paulo 		"  counter INTEGER,"
123f05cddf9SRui Paulo 		"  mk CHAR(40),"
124f05cddf9SRui Paulo 		"  k_encr CHAR(32),"
125f05cddf9SRui Paulo 		"  k_aut CHAR(64),"
126f05cddf9SRui Paulo 		"  k_re CHAR(64)"
127f05cddf9SRui Paulo 		");";
128f05cddf9SRui Paulo 
129f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
130f05cddf9SRui Paulo 		   "reauth information");
131f05cddf9SRui Paulo 	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
132f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
133f05cddf9SRui Paulo 		sqlite3_free(err);
134f05cddf9SRui Paulo 		return -1;
135f05cddf9SRui Paulo 	}
136f05cddf9SRui Paulo 
137f05cddf9SRui Paulo 	return 0;
138f05cddf9SRui Paulo }
139f05cddf9SRui Paulo 
140f05cddf9SRui Paulo 
db_open(const char * db_file)141f05cddf9SRui Paulo static sqlite3 * db_open(const char *db_file)
142f05cddf9SRui Paulo {
143f05cddf9SRui Paulo 	sqlite3 *db;
144f05cddf9SRui Paulo 
145f05cddf9SRui Paulo 	if (sqlite3_open(db_file, &db)) {
146f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
147f05cddf9SRui Paulo 			   "%s: %s", db_file, sqlite3_errmsg(db));
148f05cddf9SRui Paulo 		sqlite3_close(db);
149f05cddf9SRui Paulo 		return NULL;
150f05cddf9SRui Paulo 	}
151f05cddf9SRui Paulo 
152f05cddf9SRui Paulo 	if (!db_table_exists(db, "pseudonyms") &&
153f05cddf9SRui Paulo 	    db_table_create_pseudonym(db) < 0) {
154f05cddf9SRui Paulo 		sqlite3_close(db);
155f05cddf9SRui Paulo 		return NULL;
156f05cddf9SRui Paulo 	}
157f05cddf9SRui Paulo 
158f05cddf9SRui Paulo 	if (!db_table_exists(db, "reauth") &&
159f05cddf9SRui Paulo 	    db_table_create_reauth(db) < 0) {
160f05cddf9SRui Paulo 		sqlite3_close(db);
161f05cddf9SRui Paulo 		return NULL;
162f05cddf9SRui Paulo 	}
163f05cddf9SRui Paulo 
164f05cddf9SRui Paulo 	return db;
165f05cddf9SRui Paulo }
166f05cddf9SRui Paulo 
167f05cddf9SRui Paulo 
valid_db_string(const char * str)168f05cddf9SRui Paulo static int valid_db_string(const char *str)
169f05cddf9SRui Paulo {
170f05cddf9SRui Paulo 	const char *pos = str;
171f05cddf9SRui Paulo 	while (*pos) {
172f05cddf9SRui Paulo 		if ((*pos < '0' || *pos > '9') &&
173f05cddf9SRui Paulo 		    (*pos < 'a' || *pos > 'f'))
174f05cddf9SRui Paulo 			return 0;
175f05cddf9SRui Paulo 		pos++;
176f05cddf9SRui Paulo 	}
177f05cddf9SRui Paulo 	return 1;
178f05cddf9SRui Paulo }
179f05cddf9SRui Paulo 
180f05cddf9SRui Paulo 
db_add_pseudonym(struct eap_sim_db_data * data,const char * permanent,char * pseudonym)181f05cddf9SRui Paulo static int db_add_pseudonym(struct eap_sim_db_data *data,
182f05cddf9SRui Paulo 			    const char *permanent, char *pseudonym)
183f05cddf9SRui Paulo {
184f05cddf9SRui Paulo 	char cmd[128];
185f05cddf9SRui Paulo 	char *err = NULL;
186f05cddf9SRui Paulo 
187f05cddf9SRui Paulo 	if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
188f05cddf9SRui Paulo 		os_free(pseudonym);
189f05cddf9SRui Paulo 		return -1;
190f05cddf9SRui Paulo 	}
191f05cddf9SRui Paulo 
192f05cddf9SRui Paulo 	os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
193f05cddf9SRui Paulo 		    "(permanent, pseudonym) VALUES ('%s', '%s');",
194f05cddf9SRui Paulo 		    permanent, pseudonym);
195f05cddf9SRui Paulo 	os_free(pseudonym);
196f05cddf9SRui Paulo 	if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
197f05cddf9SRui Paulo 	{
198f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
199f05cddf9SRui Paulo 		sqlite3_free(err);
200f05cddf9SRui Paulo 		return -1;
201f05cddf9SRui Paulo 	}
202f05cddf9SRui Paulo 
203f05cddf9SRui Paulo 	return 0;
204f05cddf9SRui Paulo }
205f05cddf9SRui Paulo 
206f05cddf9SRui Paulo 
get_pseudonym_cb(void * ctx,int argc,char * argv[],char * col[])207f05cddf9SRui Paulo static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
208f05cddf9SRui Paulo {
209f05cddf9SRui Paulo 	struct eap_sim_db_data *data = ctx;
210f05cddf9SRui Paulo 	int i;
211f05cddf9SRui Paulo 
212f05cddf9SRui Paulo 	for (i = 0; i < argc; i++) {
213f05cddf9SRui Paulo 		if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
214f05cddf9SRui Paulo 			os_strlcpy(data->db_tmp_identity, argv[i],
215f05cddf9SRui Paulo 				   sizeof(data->db_tmp_identity));
216f05cddf9SRui Paulo 		}
217f05cddf9SRui Paulo 	}
218f05cddf9SRui Paulo 
219f05cddf9SRui Paulo 	return 0;
220f05cddf9SRui Paulo }
221f05cddf9SRui Paulo 
222f05cddf9SRui Paulo 
223f05cddf9SRui Paulo static char *
db_get_pseudonym(struct eap_sim_db_data * data,const char * pseudonym)224f05cddf9SRui Paulo db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
225f05cddf9SRui Paulo {
226f05cddf9SRui Paulo 	char cmd[128];
227f05cddf9SRui Paulo 
228f05cddf9SRui Paulo 	if (!valid_db_string(pseudonym))
229f05cddf9SRui Paulo 		return NULL;
230f05cddf9SRui Paulo 	os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
231f05cddf9SRui Paulo 	os_snprintf(cmd, sizeof(cmd),
232f05cddf9SRui Paulo 		    "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
233f05cddf9SRui Paulo 		    pseudonym);
234f05cddf9SRui Paulo 	if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
235f05cddf9SRui Paulo 	    SQLITE_OK)
236f05cddf9SRui Paulo 		return NULL;
237f05cddf9SRui Paulo 	if (data->db_tmp_identity[0] == '\0')
238f05cddf9SRui Paulo 		return NULL;
239f05cddf9SRui Paulo 	return data->db_tmp_identity;
240f05cddf9SRui Paulo }
241f05cddf9SRui Paulo 
242f05cddf9SRui Paulo 
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)243f05cddf9SRui Paulo static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
244f05cddf9SRui Paulo 			 char *reauth_id, u16 counter, const u8 *mk,
245f05cddf9SRui Paulo 			 const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
246f05cddf9SRui Paulo {
247f05cddf9SRui Paulo 	char cmd[2000], *pos, *end;
248f05cddf9SRui Paulo 	char *err = NULL;
249f05cddf9SRui Paulo 
250f05cddf9SRui Paulo 	if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
251f05cddf9SRui Paulo 		os_free(reauth_id);
252f05cddf9SRui Paulo 		return -1;
253f05cddf9SRui Paulo 	}
254f05cddf9SRui Paulo 
255f05cddf9SRui Paulo 	pos = cmd;
256f05cddf9SRui Paulo 	end = pos + sizeof(cmd);
257f05cddf9SRui Paulo 	pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
258f05cddf9SRui Paulo 			   "(permanent, reauth_id, counter%s%s%s%s) "
259f05cddf9SRui Paulo 			   "VALUES ('%s', '%s', %u",
260f05cddf9SRui Paulo 			   mk ? ", mk" : "",
261f05cddf9SRui Paulo 			   k_encr ? ", k_encr" : "",
262f05cddf9SRui Paulo 			   k_aut ? ", k_aut" : "",
263f05cddf9SRui Paulo 			   k_re ? ", k_re" : "",
264f05cddf9SRui Paulo 			   permanent, reauth_id, counter);
265f05cddf9SRui Paulo 	os_free(reauth_id);
266f05cddf9SRui Paulo 
267f05cddf9SRui Paulo 	if (mk) {
268f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, ", '");
269f05cddf9SRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
270f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, "'");
271f05cddf9SRui Paulo 	}
272f05cddf9SRui Paulo 
273f05cddf9SRui Paulo 	if (k_encr) {
274f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, ", '");
275f05cddf9SRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, k_encr,
276f05cddf9SRui Paulo 					EAP_SIM_K_ENCR_LEN);
277f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, "'");
278f05cddf9SRui Paulo 	}
279f05cddf9SRui Paulo 
280f05cddf9SRui Paulo 	if (k_aut) {
281f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, ", '");
282f05cddf9SRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, k_aut,
283f05cddf9SRui Paulo 					EAP_AKA_PRIME_K_AUT_LEN);
284f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, "'");
285f05cddf9SRui Paulo 	}
286f05cddf9SRui Paulo 
287f05cddf9SRui Paulo 	if (k_re) {
288f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, ", '");
289f05cddf9SRui Paulo 		pos += wpa_snprintf_hex(pos, end - pos, k_re,
290f05cddf9SRui Paulo 					EAP_AKA_PRIME_K_RE_LEN);
291f05cddf9SRui Paulo 		pos += os_snprintf(pos, end - pos, "'");
292f05cddf9SRui Paulo 	}
293f05cddf9SRui Paulo 
294f05cddf9SRui Paulo 	os_snprintf(pos, end - pos, ");");
295f05cddf9SRui Paulo 
296f05cddf9SRui Paulo 	if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
297f05cddf9SRui Paulo 	{
298f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
299f05cddf9SRui Paulo 		sqlite3_free(err);
300f05cddf9SRui Paulo 		return -1;
301f05cddf9SRui Paulo 	}
302f05cddf9SRui Paulo 
303f05cddf9SRui Paulo 	return 0;
304f05cddf9SRui Paulo }
305f05cddf9SRui Paulo 
306f05cddf9SRui Paulo 
get_reauth_cb(void * ctx,int argc,char * argv[],char * col[])307f05cddf9SRui Paulo static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
308f05cddf9SRui Paulo {
309f05cddf9SRui Paulo 	struct eap_sim_db_data *data = ctx;
310f05cddf9SRui Paulo 	int i;
311f05cddf9SRui Paulo 	struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
312f05cddf9SRui Paulo 
313f05cddf9SRui Paulo 	for (i = 0; i < argc; i++) {
314f05cddf9SRui Paulo 		if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
315f05cddf9SRui Paulo 			os_strlcpy(data->db_tmp_identity, argv[i],
316f05cddf9SRui Paulo 				   sizeof(data->db_tmp_identity));
317f05cddf9SRui Paulo 			reauth->permanent = data->db_tmp_identity;
318f05cddf9SRui Paulo 		} else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
319f05cddf9SRui Paulo 			reauth->counter = atoi(argv[i]);
320f05cddf9SRui Paulo 		} else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
321f05cddf9SRui Paulo 			hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
322f05cddf9SRui Paulo 		} else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
323f05cddf9SRui Paulo 			hexstr2bin(argv[i], reauth->k_encr,
324f05cddf9SRui Paulo 				   sizeof(reauth->k_encr));
325f05cddf9SRui Paulo 		} else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
326f05cddf9SRui Paulo 			hexstr2bin(argv[i], reauth->k_aut,
327f05cddf9SRui Paulo 				   sizeof(reauth->k_aut));
328f05cddf9SRui Paulo 		} else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
329f05cddf9SRui Paulo 			hexstr2bin(argv[i], reauth->k_re,
330f05cddf9SRui Paulo 				   sizeof(reauth->k_re));
331f05cddf9SRui Paulo 		}
332f05cddf9SRui Paulo 	}
333f05cddf9SRui Paulo 
334f05cddf9SRui Paulo 	return 0;
335f05cddf9SRui Paulo }
336f05cddf9SRui Paulo 
337f05cddf9SRui Paulo 
338f05cddf9SRui Paulo static struct eap_sim_reauth *
db_get_reauth(struct eap_sim_db_data * data,const char * reauth_id)339f05cddf9SRui Paulo db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
340f05cddf9SRui Paulo {
341f05cddf9SRui Paulo 	char cmd[256];
342f05cddf9SRui Paulo 
343f05cddf9SRui Paulo 	if (!valid_db_string(reauth_id))
344f05cddf9SRui Paulo 		return NULL;
345f05cddf9SRui Paulo 	os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
346f05cddf9SRui Paulo 	os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
347f05cddf9SRui Paulo 		   sizeof(data->db_tmp_pseudonym_str));
348f05cddf9SRui Paulo 	data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
349f05cddf9SRui Paulo 	os_snprintf(cmd, sizeof(cmd),
350f05cddf9SRui Paulo 		    "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
351f05cddf9SRui Paulo 	if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
352f05cddf9SRui Paulo 	    SQLITE_OK)
353f05cddf9SRui Paulo 		return NULL;
354f05cddf9SRui Paulo 	if (data->db_tmp_reauth.permanent == NULL)
355f05cddf9SRui Paulo 		return NULL;
356f05cddf9SRui Paulo 	return &data->db_tmp_reauth;
357f05cddf9SRui Paulo }
358f05cddf9SRui Paulo 
359f05cddf9SRui Paulo 
db_remove_reauth(struct eap_sim_db_data * data,struct eap_sim_reauth * reauth)360f05cddf9SRui Paulo static void db_remove_reauth(struct eap_sim_db_data *data,
361f05cddf9SRui Paulo 			     struct eap_sim_reauth *reauth)
362f05cddf9SRui Paulo {
363f05cddf9SRui Paulo 	char cmd[256];
364f05cddf9SRui Paulo 
365f05cddf9SRui Paulo 	if (!valid_db_string(reauth->permanent))
366f05cddf9SRui Paulo 		return;
367f05cddf9SRui Paulo 	os_snprintf(cmd, sizeof(cmd),
368f05cddf9SRui Paulo 		    "DELETE FROM reauth WHERE permanent='%s';",
369f05cddf9SRui Paulo 		    reauth->permanent);
370f05cddf9SRui Paulo 	sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
371f05cddf9SRui Paulo }
372f05cddf9SRui Paulo 
373f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
374f05cddf9SRui Paulo 
375f05cddf9SRui Paulo 
37639beb93cSSam Leffler static struct eap_sim_db_pending *
eap_sim_db_get_pending(struct eap_sim_db_data * data,const char * imsi,int aka)377f05cddf9SRui Paulo eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
37839beb93cSSam Leffler {
37939beb93cSSam Leffler 	struct eap_sim_db_pending *entry, *prev = NULL;
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 	entry = data->pending;
38239beb93cSSam Leffler 	while (entry) {
383f05cddf9SRui Paulo 		if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
38439beb93cSSam Leffler 			if (prev)
38539beb93cSSam Leffler 				prev->next = entry->next;
38639beb93cSSam Leffler 			else
38739beb93cSSam Leffler 				data->pending = entry->next;
38839beb93cSSam Leffler 			break;
38939beb93cSSam Leffler 		}
39039beb93cSSam Leffler 		prev = entry;
39139beb93cSSam Leffler 		entry = entry->next;
39239beb93cSSam Leffler 	}
39339beb93cSSam Leffler 	return entry;
39439beb93cSSam Leffler }
39539beb93cSSam Leffler 
39639beb93cSSam Leffler 
eap_sim_db_add_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)39739beb93cSSam Leffler static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
39839beb93cSSam Leffler 				   struct eap_sim_db_pending *entry)
39939beb93cSSam Leffler {
40039beb93cSSam Leffler 	entry->next = data->pending;
40139beb93cSSam Leffler 	data->pending = entry;
40239beb93cSSam Leffler }
40339beb93cSSam Leffler 
40439beb93cSSam Leffler 
eap_sim_db_free_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)405*780fb4a2SCy Schubert static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
406*780fb4a2SCy Schubert 				    struct eap_sim_db_pending *entry)
407*780fb4a2SCy Schubert {
408*780fb4a2SCy Schubert 	eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
409*780fb4a2SCy Schubert 	eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
410*780fb4a2SCy Schubert 	os_free(entry);
411*780fb4a2SCy Schubert }
412*780fb4a2SCy Schubert 
413*780fb4a2SCy Schubert 
eap_sim_db_del_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)414*780fb4a2SCy Schubert static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
415*780fb4a2SCy Schubert 				   struct eap_sim_db_pending *entry)
416*780fb4a2SCy Schubert {
417*780fb4a2SCy Schubert 	struct eap_sim_db_pending **pp = &data->pending;
418*780fb4a2SCy Schubert 
419*780fb4a2SCy Schubert 	while (*pp != NULL) {
420*780fb4a2SCy Schubert 		if (*pp == entry) {
421*780fb4a2SCy Schubert 			*pp = entry->next;
422*780fb4a2SCy Schubert 			eap_sim_db_free_pending(data, entry);
423*780fb4a2SCy Schubert 			return;
424*780fb4a2SCy Schubert 		}
425*780fb4a2SCy Schubert 		pp = &(*pp)->next;
426*780fb4a2SCy Schubert 	}
427*780fb4a2SCy Schubert }
428*780fb4a2SCy Schubert 
429*780fb4a2SCy Schubert 
eap_sim_db_del_timeout(void * eloop_ctx,void * user_ctx)430*780fb4a2SCy Schubert static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
431*780fb4a2SCy Schubert {
432*780fb4a2SCy Schubert 	struct eap_sim_db_data *data = eloop_ctx;
433*780fb4a2SCy Schubert 	struct eap_sim_db_pending *entry = user_ctx;
434*780fb4a2SCy Schubert 
435*780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
436*780fb4a2SCy Schubert 	eap_sim_db_del_pending(data, entry);
437*780fb4a2SCy Schubert }
438*780fb4a2SCy Schubert 
439*780fb4a2SCy Schubert 
eap_sim_db_query_timeout(void * eloop_ctx,void * user_ctx)440*780fb4a2SCy Schubert static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
441*780fb4a2SCy Schubert {
442*780fb4a2SCy Schubert 	struct eap_sim_db_data *data = eloop_ctx;
443*780fb4a2SCy Schubert 	struct eap_sim_db_pending *entry = user_ctx;
444*780fb4a2SCy Schubert 
445*780fb4a2SCy Schubert 	/*
446*780fb4a2SCy Schubert 	 * Report failure and allow some time for EAP server to process it
447*780fb4a2SCy Schubert 	 * before deleting the query.
448*780fb4a2SCy Schubert 	 */
449*780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
450*780fb4a2SCy Schubert 	entry->state = FAILURE;
451*780fb4a2SCy Schubert 	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
452*780fb4a2SCy Schubert 	eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
453*780fb4a2SCy Schubert }
454*780fb4a2SCy Schubert 
455*780fb4a2SCy Schubert 
eap_sim_db_sim_resp_auth(struct eap_sim_db_data * data,const char * imsi,char * buf)45639beb93cSSam Leffler static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
45739beb93cSSam Leffler 				     const char *imsi, char *buf)
45839beb93cSSam Leffler {
45939beb93cSSam Leffler 	char *start, *end, *pos;
46039beb93cSSam Leffler 	struct eap_sim_db_pending *entry;
46139beb93cSSam Leffler 	int num_chal;
46239beb93cSSam Leffler 
46339beb93cSSam Leffler 	/*
46439beb93cSSam Leffler 	 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
46539beb93cSSam Leffler 	 * SIM-RESP-AUTH <IMSI> FAILURE
46639beb93cSSam Leffler 	 * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
46739beb93cSSam Leffler 	 */
46839beb93cSSam Leffler 
469f05cddf9SRui Paulo 	entry = eap_sim_db_get_pending(data, imsi, 0);
47039beb93cSSam Leffler 	if (entry == NULL) {
47139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
47239beb93cSSam Leffler 			   "received message found");
47339beb93cSSam Leffler 		return;
47439beb93cSSam Leffler 	}
47539beb93cSSam Leffler 
47639beb93cSSam Leffler 	start = buf;
47739beb93cSSam Leffler 	if (os_strncmp(start, "FAILURE", 7) == 0) {
47839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
47939beb93cSSam Leffler 			   "failure");
48039beb93cSSam Leffler 		entry->state = FAILURE;
48139beb93cSSam Leffler 		eap_sim_db_add_pending(data, entry);
48239beb93cSSam Leffler 		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
48339beb93cSSam Leffler 		return;
48439beb93cSSam Leffler 	}
48539beb93cSSam Leffler 
48639beb93cSSam Leffler 	num_chal = 0;
48739beb93cSSam Leffler 	while (num_chal < EAP_SIM_MAX_CHAL) {
48839beb93cSSam Leffler 		end = os_strchr(start, ' ');
48939beb93cSSam Leffler 		if (end)
49039beb93cSSam Leffler 			*end = '\0';
49139beb93cSSam Leffler 
49239beb93cSSam Leffler 		pos = os_strchr(start, ':');
49339beb93cSSam Leffler 		if (pos == NULL)
49439beb93cSSam Leffler 			goto parse_fail;
49539beb93cSSam Leffler 		*pos = '\0';
49639beb93cSSam Leffler 		if (hexstr2bin(start, entry->u.sim.kc[num_chal],
49739beb93cSSam Leffler 			       EAP_SIM_KC_LEN))
49839beb93cSSam Leffler 			goto parse_fail;
49939beb93cSSam Leffler 
50039beb93cSSam Leffler 		start = pos + 1;
50139beb93cSSam Leffler 		pos = os_strchr(start, ':');
50239beb93cSSam Leffler 		if (pos == NULL)
50339beb93cSSam Leffler 			goto parse_fail;
50439beb93cSSam Leffler 		*pos = '\0';
50539beb93cSSam Leffler 		if (hexstr2bin(start, entry->u.sim.sres[num_chal],
50639beb93cSSam Leffler 			       EAP_SIM_SRES_LEN))
50739beb93cSSam Leffler 			goto parse_fail;
50839beb93cSSam Leffler 
50939beb93cSSam Leffler 		start = pos + 1;
51039beb93cSSam Leffler 		if (hexstr2bin(start, entry->u.sim.rand[num_chal],
51139beb93cSSam Leffler 			       GSM_RAND_LEN))
51239beb93cSSam Leffler 			goto parse_fail;
51339beb93cSSam Leffler 
51439beb93cSSam Leffler 		num_chal++;
51539beb93cSSam Leffler 		if (end == NULL)
51639beb93cSSam Leffler 			break;
51739beb93cSSam Leffler 		else
51839beb93cSSam Leffler 			start = end + 1;
51939beb93cSSam Leffler 	}
52039beb93cSSam Leffler 	entry->u.sim.num_chal = num_chal;
52139beb93cSSam Leffler 
52239beb93cSSam Leffler 	entry->state = SUCCESS;
52339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
52439beb93cSSam Leffler 		   "successfully - callback");
52539beb93cSSam Leffler 	eap_sim_db_add_pending(data, entry);
52639beb93cSSam Leffler 	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
52739beb93cSSam Leffler 	return;
52839beb93cSSam Leffler 
52939beb93cSSam Leffler parse_fail:
53039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
531*780fb4a2SCy Schubert 	eap_sim_db_free_pending(data, entry);
53239beb93cSSam Leffler }
53339beb93cSSam Leffler 
53439beb93cSSam Leffler 
eap_sim_db_aka_resp_auth(struct eap_sim_db_data * data,const char * imsi,char * buf)53539beb93cSSam Leffler static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
53639beb93cSSam Leffler 				     const char *imsi, char *buf)
53739beb93cSSam Leffler {
53839beb93cSSam Leffler 	char *start, *end;
53939beb93cSSam Leffler 	struct eap_sim_db_pending *entry;
54039beb93cSSam Leffler 
54139beb93cSSam Leffler 	/*
54239beb93cSSam Leffler 	 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
54339beb93cSSam Leffler 	 * AKA-RESP-AUTH <IMSI> FAILURE
54439beb93cSSam Leffler 	 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
54539beb93cSSam Leffler 	 */
54639beb93cSSam Leffler 
547f05cddf9SRui Paulo 	entry = eap_sim_db_get_pending(data, imsi, 1);
54839beb93cSSam Leffler 	if (entry == NULL) {
54939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
55039beb93cSSam Leffler 			   "received message found");
55139beb93cSSam Leffler 		return;
55239beb93cSSam Leffler 	}
55339beb93cSSam Leffler 
55439beb93cSSam Leffler 	start = buf;
55539beb93cSSam Leffler 	if (os_strncmp(start, "FAILURE", 7) == 0) {
55639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
55739beb93cSSam Leffler 			   "failure");
55839beb93cSSam Leffler 		entry->state = FAILURE;
55939beb93cSSam Leffler 		eap_sim_db_add_pending(data, entry);
56039beb93cSSam Leffler 		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
56139beb93cSSam Leffler 		return;
56239beb93cSSam Leffler 	}
56339beb93cSSam Leffler 
56439beb93cSSam Leffler 	end = os_strchr(start, ' ');
56539beb93cSSam Leffler 	if (end == NULL)
56639beb93cSSam Leffler 		goto parse_fail;
56739beb93cSSam Leffler 	*end = '\0';
56839beb93cSSam Leffler 	if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
56939beb93cSSam Leffler 		goto parse_fail;
57039beb93cSSam Leffler 
57139beb93cSSam Leffler 	start = end + 1;
57239beb93cSSam Leffler 	end = os_strchr(start, ' ');
57339beb93cSSam Leffler 	if (end == NULL)
57439beb93cSSam Leffler 		goto parse_fail;
57539beb93cSSam Leffler 	*end = '\0';
57639beb93cSSam Leffler 	if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
57739beb93cSSam Leffler 		goto parse_fail;
57839beb93cSSam Leffler 
57939beb93cSSam Leffler 	start = end + 1;
58039beb93cSSam Leffler 	end = os_strchr(start, ' ');
58139beb93cSSam Leffler 	if (end == NULL)
58239beb93cSSam Leffler 		goto parse_fail;
58339beb93cSSam Leffler 	*end = '\0';
58439beb93cSSam Leffler 	if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
58539beb93cSSam Leffler 		goto parse_fail;
58639beb93cSSam Leffler 
58739beb93cSSam Leffler 	start = end + 1;
58839beb93cSSam Leffler 	end = os_strchr(start, ' ');
58939beb93cSSam Leffler 	if (end == NULL)
59039beb93cSSam Leffler 		goto parse_fail;
59139beb93cSSam Leffler 	*end = '\0';
59239beb93cSSam Leffler 	if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
59339beb93cSSam Leffler 		goto parse_fail;
59439beb93cSSam Leffler 
59539beb93cSSam Leffler 	start = end + 1;
59639beb93cSSam Leffler 	end = os_strchr(start, ' ');
59739beb93cSSam Leffler 	if (end)
59839beb93cSSam Leffler 		*end = '\0';
59939beb93cSSam Leffler 	else {
60039beb93cSSam Leffler 		end = start;
60139beb93cSSam Leffler 		while (*end)
60239beb93cSSam Leffler 			end++;
60339beb93cSSam Leffler 	}
60439beb93cSSam Leffler 	entry->u.aka.res_len = (end - start) / 2;
60539beb93cSSam Leffler 	if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
60639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
60739beb93cSSam Leffler 		entry->u.aka.res_len = 0;
60839beb93cSSam Leffler 		goto parse_fail;
60939beb93cSSam Leffler 	}
61039beb93cSSam Leffler 	if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
61139beb93cSSam Leffler 		goto parse_fail;
61239beb93cSSam Leffler 
61339beb93cSSam Leffler 	entry->state = SUCCESS;
61439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
61539beb93cSSam Leffler 		   "successfully - callback");
61639beb93cSSam Leffler 	eap_sim_db_add_pending(data, entry);
61739beb93cSSam Leffler 	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
61839beb93cSSam Leffler 	return;
61939beb93cSSam Leffler 
62039beb93cSSam Leffler parse_fail:
62139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
622*780fb4a2SCy Schubert 	eap_sim_db_free_pending(data, entry);
62339beb93cSSam Leffler }
62439beb93cSSam Leffler 
62539beb93cSSam Leffler 
eap_sim_db_receive(int sock,void * eloop_ctx,void * sock_ctx)62639beb93cSSam Leffler static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
62739beb93cSSam Leffler {
62839beb93cSSam Leffler 	struct eap_sim_db_data *data = eloop_ctx;
62939beb93cSSam Leffler 	char buf[1000], *pos, *cmd, *imsi;
63039beb93cSSam Leffler 	int res;
63139beb93cSSam Leffler 
6325b9c547cSRui Paulo 	res = recv(sock, buf, sizeof(buf) - 1, 0);
63339beb93cSSam Leffler 	if (res < 0)
63439beb93cSSam Leffler 		return;
6355b9c547cSRui Paulo 	buf[res] = '\0';
63639beb93cSSam Leffler 	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
63739beb93cSSam Leffler 			      "external source", (u8 *) buf, res);
63839beb93cSSam Leffler 	if (res == 0)
63939beb93cSSam Leffler 		return;
64039beb93cSSam Leffler 
64139beb93cSSam Leffler 	if (data->get_complete_cb == NULL) {
64239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
64339beb93cSSam Leffler 			   "registered");
64439beb93cSSam Leffler 		return;
64539beb93cSSam Leffler 	}
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	/* <cmd> <IMSI> ... */
64839beb93cSSam Leffler 
64939beb93cSSam Leffler 	cmd = buf;
65039beb93cSSam Leffler 	pos = os_strchr(cmd, ' ');
65139beb93cSSam Leffler 	if (pos == NULL)
65239beb93cSSam Leffler 		goto parse_fail;
65339beb93cSSam Leffler 	*pos = '\0';
65439beb93cSSam Leffler 	imsi = pos + 1;
65539beb93cSSam Leffler 	pos = os_strchr(imsi, ' ');
65639beb93cSSam Leffler 	if (pos == NULL)
65739beb93cSSam Leffler 		goto parse_fail;
65839beb93cSSam Leffler 	*pos = '\0';
65939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
66039beb93cSSam Leffler 		   cmd, imsi);
66139beb93cSSam Leffler 
66239beb93cSSam Leffler 	if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
66339beb93cSSam Leffler 		eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
66439beb93cSSam Leffler 	else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
66539beb93cSSam Leffler 		eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
66639beb93cSSam Leffler 	else
66739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
66839beb93cSSam Leffler 			   "'%s'", cmd);
66939beb93cSSam Leffler 	return;
67039beb93cSSam Leffler 
67139beb93cSSam Leffler parse_fail:
67239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
67339beb93cSSam Leffler }
67439beb93cSSam Leffler 
67539beb93cSSam Leffler 
eap_sim_db_open_socket(struct eap_sim_db_data * data)67639beb93cSSam Leffler static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
67739beb93cSSam Leffler {
67839beb93cSSam Leffler 	struct sockaddr_un addr;
67939beb93cSSam Leffler 	static int counter = 0;
68039beb93cSSam Leffler 
68139beb93cSSam Leffler 	if (os_strncmp(data->fname, "unix:", 5) != 0)
68239beb93cSSam Leffler 		return -1;
68339beb93cSSam Leffler 
68439beb93cSSam Leffler 	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
68539beb93cSSam Leffler 	if (data->sock < 0) {
6865b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
68739beb93cSSam Leffler 		return -1;
68839beb93cSSam Leffler 	}
68939beb93cSSam Leffler 
69039beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
69139beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
69239beb93cSSam Leffler 	os_snprintf(addr.sun_path, sizeof(addr.sun_path),
69339beb93cSSam Leffler 		    "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
694f05cddf9SRui Paulo 	os_free(data->local_sock);
69539beb93cSSam Leffler 	data->local_sock = os_strdup(addr.sun_path);
6965b9c547cSRui Paulo 	if (data->local_sock == NULL) {
6975b9c547cSRui Paulo 		close(data->sock);
6985b9c547cSRui Paulo 		data->sock = -1;
6995b9c547cSRui Paulo 		return -1;
7005b9c547cSRui Paulo 	}
70139beb93cSSam Leffler 	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
7025b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
70339beb93cSSam Leffler 		close(data->sock);
70439beb93cSSam Leffler 		data->sock = -1;
70539beb93cSSam Leffler 		return -1;
70639beb93cSSam Leffler 	}
70739beb93cSSam Leffler 
70839beb93cSSam Leffler 	os_memset(&addr, 0, sizeof(addr));
70939beb93cSSam Leffler 	addr.sun_family = AF_UNIX;
71039beb93cSSam Leffler 	os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
71139beb93cSSam Leffler 	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
7125b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
7135b9c547cSRui Paulo 			   strerror(errno));
71439beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
71539beb93cSSam Leffler 				  (u8 *) addr.sun_path,
71639beb93cSSam Leffler 				  os_strlen(addr.sun_path));
71739beb93cSSam Leffler 		close(data->sock);
71839beb93cSSam Leffler 		data->sock = -1;
7195b9c547cSRui Paulo 		unlink(data->local_sock);
7205b9c547cSRui Paulo 		os_free(data->local_sock);
7215b9c547cSRui Paulo 		data->local_sock = NULL;
72239beb93cSSam Leffler 		return -1;
72339beb93cSSam Leffler 	}
72439beb93cSSam Leffler 
72539beb93cSSam Leffler 	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
72639beb93cSSam Leffler 
72739beb93cSSam Leffler 	return 0;
72839beb93cSSam Leffler }
72939beb93cSSam Leffler 
73039beb93cSSam Leffler 
eap_sim_db_close_socket(struct eap_sim_db_data * data)73139beb93cSSam Leffler static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
73239beb93cSSam Leffler {
73339beb93cSSam Leffler 	if (data->sock >= 0) {
73439beb93cSSam Leffler 		eloop_unregister_read_sock(data->sock);
73539beb93cSSam Leffler 		close(data->sock);
73639beb93cSSam Leffler 		data->sock = -1;
73739beb93cSSam Leffler 	}
73839beb93cSSam Leffler 	if (data->local_sock) {
73939beb93cSSam Leffler 		unlink(data->local_sock);
74039beb93cSSam Leffler 		os_free(data->local_sock);
74139beb93cSSam Leffler 		data->local_sock = NULL;
74239beb93cSSam Leffler 	}
74339beb93cSSam Leffler }
74439beb93cSSam Leffler 
74539beb93cSSam Leffler 
74639beb93cSSam Leffler /**
74739beb93cSSam Leffler  * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
74839beb93cSSam Leffler  * @config: Configuration data (e.g., file name)
749*780fb4a2SCy Schubert  * @db_timeout: Database lookup timeout
75039beb93cSSam Leffler  * @get_complete_cb: Callback function for reporting availability of triplets
75139beb93cSSam Leffler  * @ctx: Context pointer for get_complete_cb
75239beb93cSSam Leffler  * Returns: Pointer to a private data structure or %NULL on failure
75339beb93cSSam Leffler  */
754f05cddf9SRui Paulo struct eap_sim_db_data *
eap_sim_db_init(const char * config,unsigned int db_timeout,void (* get_complete_cb)(void * ctx,void * session_ctx),void * ctx)755*780fb4a2SCy Schubert eap_sim_db_init(const char *config, unsigned int db_timeout,
75639beb93cSSam Leffler 		void (*get_complete_cb)(void *ctx, void *session_ctx),
75739beb93cSSam Leffler 		void *ctx)
75839beb93cSSam Leffler {
75939beb93cSSam Leffler 	struct eap_sim_db_data *data;
760f05cddf9SRui Paulo 	char *pos;
76139beb93cSSam Leffler 
76239beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
76339beb93cSSam Leffler 	if (data == NULL)
76439beb93cSSam Leffler 		return NULL;
76539beb93cSSam Leffler 
76639beb93cSSam Leffler 	data->sock = -1;
76739beb93cSSam Leffler 	data->get_complete_cb = get_complete_cb;
76839beb93cSSam Leffler 	data->ctx = ctx;
769*780fb4a2SCy Schubert 	data->eap_sim_db_timeout = db_timeout;
77039beb93cSSam Leffler 	data->fname = os_strdup(config);
77139beb93cSSam Leffler 	if (data->fname == NULL)
77239beb93cSSam Leffler 		goto fail;
773f05cddf9SRui Paulo 	pos = os_strstr(data->fname, " db=");
774f05cddf9SRui Paulo 	if (pos) {
775f05cddf9SRui Paulo 		*pos = '\0';
776f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
777f05cddf9SRui Paulo 		pos += 4;
778f05cddf9SRui Paulo 		data->sqlite_db = db_open(pos);
779f05cddf9SRui Paulo 		if (data->sqlite_db == NULL)
780f05cddf9SRui Paulo 			goto fail;
781f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
782f05cddf9SRui Paulo 	}
78339beb93cSSam Leffler 
78439beb93cSSam Leffler 	if (os_strncmp(data->fname, "unix:", 5) == 0) {
785f05cddf9SRui Paulo 		if (eap_sim_db_open_socket(data)) {
786f05cddf9SRui Paulo 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
787f05cddf9SRui Paulo 				   "connection not available - will retry "
788f05cddf9SRui Paulo 				   "later");
789f05cddf9SRui Paulo 		}
79039beb93cSSam Leffler 	}
79139beb93cSSam Leffler 
79239beb93cSSam Leffler 	return data;
79339beb93cSSam Leffler 
79439beb93cSSam Leffler fail:
79539beb93cSSam Leffler 	eap_sim_db_close_socket(data);
79639beb93cSSam Leffler 	os_free(data->fname);
79739beb93cSSam Leffler 	os_free(data);
79839beb93cSSam Leffler 	return NULL;
79939beb93cSSam Leffler }
80039beb93cSSam Leffler 
80139beb93cSSam Leffler 
eap_sim_db_free_pseudonym(struct eap_sim_pseudonym * p)80239beb93cSSam Leffler static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
80339beb93cSSam Leffler {
804f05cddf9SRui Paulo 	os_free(p->permanent);
80539beb93cSSam Leffler 	os_free(p->pseudonym);
80639beb93cSSam Leffler 	os_free(p);
80739beb93cSSam Leffler }
80839beb93cSSam Leffler 
80939beb93cSSam Leffler 
eap_sim_db_free_reauth(struct eap_sim_reauth * r)81039beb93cSSam Leffler static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
81139beb93cSSam Leffler {
812f05cddf9SRui Paulo 	os_free(r->permanent);
81339beb93cSSam Leffler 	os_free(r->reauth_id);
81439beb93cSSam Leffler 	os_free(r);
81539beb93cSSam Leffler }
81639beb93cSSam Leffler 
81739beb93cSSam Leffler 
81839beb93cSSam Leffler /**
81939beb93cSSam Leffler  * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
82039beb93cSSam Leffler  * @priv: Private data pointer from eap_sim_db_init()
82139beb93cSSam Leffler  */
eap_sim_db_deinit(void * priv)82239beb93cSSam Leffler void eap_sim_db_deinit(void *priv)
82339beb93cSSam Leffler {
82439beb93cSSam Leffler 	struct eap_sim_db_data *data = priv;
82539beb93cSSam Leffler 	struct eap_sim_pseudonym *p, *prev;
82639beb93cSSam Leffler 	struct eap_sim_reauth *r, *prevr;
82739beb93cSSam Leffler 	struct eap_sim_db_pending *pending, *prev_pending;
82839beb93cSSam Leffler 
829f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
830f05cddf9SRui Paulo 	if (data->sqlite_db) {
831f05cddf9SRui Paulo 		sqlite3_close(data->sqlite_db);
832f05cddf9SRui Paulo 		data->sqlite_db = NULL;
833f05cddf9SRui Paulo 	}
834f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
835f05cddf9SRui Paulo 
83639beb93cSSam Leffler 	eap_sim_db_close_socket(data);
83739beb93cSSam Leffler 	os_free(data->fname);
83839beb93cSSam Leffler 
83939beb93cSSam Leffler 	p = data->pseudonyms;
84039beb93cSSam Leffler 	while (p) {
84139beb93cSSam Leffler 		prev = p;
84239beb93cSSam Leffler 		p = p->next;
84339beb93cSSam Leffler 		eap_sim_db_free_pseudonym(prev);
84439beb93cSSam Leffler 	}
84539beb93cSSam Leffler 
84639beb93cSSam Leffler 	r = data->reauths;
84739beb93cSSam Leffler 	while (r) {
84839beb93cSSam Leffler 		prevr = r;
84939beb93cSSam Leffler 		r = r->next;
85039beb93cSSam Leffler 		eap_sim_db_free_reauth(prevr);
85139beb93cSSam Leffler 	}
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 	pending = data->pending;
85439beb93cSSam Leffler 	while (pending) {
85539beb93cSSam Leffler 		prev_pending = pending;
85639beb93cSSam Leffler 		pending = pending->next;
857*780fb4a2SCy Schubert 		eap_sim_db_free_pending(data, prev_pending);
85839beb93cSSam Leffler 	}
85939beb93cSSam Leffler 
86039beb93cSSam Leffler 	os_free(data);
86139beb93cSSam Leffler }
86239beb93cSSam Leffler 
86339beb93cSSam Leffler 
eap_sim_db_send(struct eap_sim_db_data * data,const char * msg,size_t len)86439beb93cSSam Leffler static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
86539beb93cSSam Leffler 			   size_t len)
86639beb93cSSam Leffler {
86739beb93cSSam Leffler 	int _errno = 0;
86839beb93cSSam Leffler 
86939beb93cSSam Leffler 	if (send(data->sock, msg, len, 0) < 0) {
87039beb93cSSam Leffler 		_errno = errno;
8715b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
8725b9c547cSRui Paulo 			   strerror(errno));
87339beb93cSSam Leffler 	}
87439beb93cSSam Leffler 
87539beb93cSSam Leffler 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
87639beb93cSSam Leffler 	    _errno == ECONNREFUSED) {
87739beb93cSSam Leffler 		/* Try to reconnect */
87839beb93cSSam Leffler 		eap_sim_db_close_socket(data);
87939beb93cSSam Leffler 		if (eap_sim_db_open_socket(data) < 0)
88039beb93cSSam Leffler 			return -1;
88139beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
88239beb93cSSam Leffler 			   "external server");
88339beb93cSSam Leffler 		if (send(data->sock, msg, len, 0) < 0) {
8845b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
8855b9c547cSRui Paulo 				   strerror(errno));
88639beb93cSSam Leffler 			return -1;
88739beb93cSSam Leffler 		}
88839beb93cSSam Leffler 	}
88939beb93cSSam Leffler 
89039beb93cSSam Leffler 	return 0;
89139beb93cSSam Leffler }
89239beb93cSSam Leffler 
89339beb93cSSam Leffler 
eap_sim_db_expire_pending(struct eap_sim_db_data * data,struct eap_sim_db_pending * entry)894*780fb4a2SCy Schubert static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
895*780fb4a2SCy Schubert 				      struct eap_sim_db_pending *entry)
89639beb93cSSam Leffler {
897*780fb4a2SCy Schubert 	eloop_register_timeout(data->eap_sim_db_timeout, 0,
898*780fb4a2SCy Schubert 			       eap_sim_db_query_timeout, data, entry);
89939beb93cSSam Leffler }
90039beb93cSSam Leffler 
90139beb93cSSam Leffler 
90239beb93cSSam Leffler /**
90339beb93cSSam Leffler  * eap_sim_db_get_gsm_triplets - Get GSM triplets
904f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
905f05cddf9SRui Paulo  * @username: Permanent username (prefix | IMSI)
90639beb93cSSam Leffler  * @max_chal: Maximum number of triplets
90739beb93cSSam Leffler  * @_rand: Buffer for RAND values
90839beb93cSSam Leffler  * @kc: Buffer for Kc values
90939beb93cSSam Leffler  * @sres: Buffer for SRES values
91039beb93cSSam Leffler  * @cb_session_ctx: Session callback context for get_complete_cb()
91139beb93cSSam Leffler  * Returns: Number of triplets received (has to be less than or equal to
91239beb93cSSam Leffler  * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
91339beb93cSSam Leffler  * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
91439beb93cSSam Leffler  * callback function registered with eap_sim_db_init() will be called once the
91539beb93cSSam Leffler  * results become available.
91639beb93cSSam Leffler  *
91739beb93cSSam Leffler  * When using an external server for GSM triplets, this function can always
91839beb93cSSam Leffler  * start a request and return EAP_SIM_DB_PENDING immediately if authentication
91939beb93cSSam Leffler  * triplets are not available. Once the triplets are received, callback
92039beb93cSSam Leffler  * function registered with eap_sim_db_init() is called to notify EAP state
92139beb93cSSam Leffler  * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
92239beb93cSSam Leffler  * function will then be called again and the newly received triplets will then
92339beb93cSSam Leffler  * be given to the caller.
92439beb93cSSam Leffler  */
eap_sim_db_get_gsm_triplets(struct eap_sim_db_data * data,const char * username,int max_chal,u8 * _rand,u8 * kc,u8 * sres,void * cb_session_ctx)925f05cddf9SRui Paulo int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
926f05cddf9SRui Paulo 				const char *username, int max_chal,
92739beb93cSSam Leffler 				u8 *_rand, u8 *kc, u8 *sres,
92839beb93cSSam Leffler 				void *cb_session_ctx)
92939beb93cSSam Leffler {
93039beb93cSSam Leffler 	struct eap_sim_db_pending *entry;
93139beb93cSSam Leffler 	int len, ret;
93239beb93cSSam Leffler 	char msg[40];
933f05cddf9SRui Paulo 	const char *imsi;
934f05cddf9SRui Paulo 	size_t imsi_len;
93539beb93cSSam Leffler 
936f05cddf9SRui Paulo 	if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
937f05cddf9SRui Paulo 	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
938f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
939f05cddf9SRui Paulo 			   username);
94039beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
94139beb93cSSam Leffler 	}
942f05cddf9SRui Paulo 	imsi = username + 1;
943f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
944f05cddf9SRui Paulo 		   imsi);
94539beb93cSSam Leffler 
946f05cddf9SRui Paulo 	entry = eap_sim_db_get_pending(data, imsi, 0);
94739beb93cSSam Leffler 	if (entry) {
94839beb93cSSam Leffler 		int num_chal;
94939beb93cSSam Leffler 		if (entry->state == FAILURE) {
95039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
95139beb93cSSam Leffler 				   "failure");
952*780fb4a2SCy Schubert 			eap_sim_db_free_pending(data, entry);
95339beb93cSSam Leffler 			return EAP_SIM_DB_FAILURE;
95439beb93cSSam Leffler 		}
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 		if (entry->state == PENDING) {
95739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
95839beb93cSSam Leffler 				   "still pending");
95939beb93cSSam Leffler 			eap_sim_db_add_pending(data, entry);
96039beb93cSSam Leffler 			return EAP_SIM_DB_PENDING;
96139beb93cSSam Leffler 		}
96239beb93cSSam Leffler 
96339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
96439beb93cSSam Leffler 			   "%d challenges", entry->u.sim.num_chal);
96539beb93cSSam Leffler 		num_chal = entry->u.sim.num_chal;
96639beb93cSSam Leffler 		if (num_chal > max_chal)
96739beb93cSSam Leffler 			num_chal = max_chal;
96839beb93cSSam Leffler 		os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
96939beb93cSSam Leffler 		os_memcpy(sres, entry->u.sim.sres,
97039beb93cSSam Leffler 			  num_chal * EAP_SIM_SRES_LEN);
97139beb93cSSam Leffler 		os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
972*780fb4a2SCy Schubert 		eap_sim_db_free_pending(data, entry);
97339beb93cSSam Leffler 		return num_chal;
97439beb93cSSam Leffler 	}
97539beb93cSSam Leffler 
97639beb93cSSam Leffler 	if (data->sock < 0) {
97739beb93cSSam Leffler 		if (eap_sim_db_open_socket(data) < 0)
97839beb93cSSam Leffler 			return EAP_SIM_DB_FAILURE;
97939beb93cSSam Leffler 	}
98039beb93cSSam Leffler 
981f05cddf9SRui Paulo 	imsi_len = os_strlen(imsi);
98239beb93cSSam Leffler 	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
9835b9c547cSRui Paulo 	if (os_snprintf_error(sizeof(msg), len) ||
9845b9c547cSRui Paulo 	    len + imsi_len >= sizeof(msg))
98539beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
986f05cddf9SRui Paulo 	os_memcpy(msg + len, imsi, imsi_len);
987f05cddf9SRui Paulo 	len += imsi_len;
98839beb93cSSam Leffler 	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
9895b9c547cSRui Paulo 	if (os_snprintf_error(sizeof(msg) - len, ret))
99039beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
99139beb93cSSam Leffler 	len += ret;
99239beb93cSSam Leffler 
993f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
994f05cddf9SRui Paulo 		   "data for IMSI '%s'", imsi);
99539beb93cSSam Leffler 	if (eap_sim_db_send(data, msg, len) < 0)
99639beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
99739beb93cSSam Leffler 
99839beb93cSSam Leffler 	entry = os_zalloc(sizeof(*entry));
99939beb93cSSam Leffler 	if (entry == NULL)
100039beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
100139beb93cSSam Leffler 
1002f05cddf9SRui Paulo 	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
100339beb93cSSam Leffler 	entry->cb_session_ctx = cb_session_ctx;
100439beb93cSSam Leffler 	entry->state = PENDING;
100539beb93cSSam Leffler 	eap_sim_db_add_pending(data, entry);
1006*780fb4a2SCy Schubert 	eap_sim_db_expire_pending(data, entry);
1007*780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
100839beb93cSSam Leffler 
100939beb93cSSam Leffler 	return EAP_SIM_DB_PENDING;
101039beb93cSSam Leffler }
101139beb93cSSam Leffler 
101239beb93cSSam Leffler 
eap_sim_db_get_next(struct eap_sim_db_data * data,char prefix)101339beb93cSSam Leffler static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
101439beb93cSSam Leffler {
101539beb93cSSam Leffler 	char *id, *pos, *end;
101639beb93cSSam Leffler 	u8 buf[10];
101739beb93cSSam Leffler 
1018f05cddf9SRui Paulo 	if (random_get_bytes(buf, sizeof(buf)))
101939beb93cSSam Leffler 		return NULL;
102039beb93cSSam Leffler 	id = os_malloc(sizeof(buf) * 2 + 2);
102139beb93cSSam Leffler 	if (id == NULL)
102239beb93cSSam Leffler 		return NULL;
102339beb93cSSam Leffler 
102439beb93cSSam Leffler 	pos = id;
102539beb93cSSam Leffler 	end = id + sizeof(buf) * 2 + 2;
102639beb93cSSam Leffler 	*pos++ = prefix;
10275b9c547cSRui Paulo 	wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
102839beb93cSSam Leffler 
102939beb93cSSam Leffler 	return id;
103039beb93cSSam Leffler }
103139beb93cSSam Leffler 
103239beb93cSSam Leffler 
103339beb93cSSam Leffler /**
103439beb93cSSam Leffler  * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
1035f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1036f05cddf9SRui Paulo  * @method: EAP method (SIM/AKA/AKA')
103739beb93cSSam Leffler  * Returns: Next pseudonym (allocated string) or %NULL on failure
103839beb93cSSam Leffler  *
103939beb93cSSam Leffler  * This function is used to generate a pseudonym for EAP-SIM. The returned
104039beb93cSSam Leffler  * pseudonym is not added to database at this point; it will need to be added
104139beb93cSSam Leffler  * with eap_sim_db_add_pseudonym() once the authentication has been completed
104239beb93cSSam Leffler  * successfully. Caller is responsible for freeing the returned buffer.
104339beb93cSSam Leffler  */
eap_sim_db_get_next_pseudonym(struct eap_sim_db_data * data,enum eap_sim_db_method method)1044f05cddf9SRui Paulo char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
1045f05cddf9SRui Paulo 				     enum eap_sim_db_method method)
104639beb93cSSam Leffler {
1047f05cddf9SRui Paulo 	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1048f05cddf9SRui Paulo 
1049f05cddf9SRui Paulo 	switch (method) {
1050f05cddf9SRui Paulo 	case EAP_SIM_DB_SIM:
1051f05cddf9SRui Paulo 		prefix = EAP_SIM_PSEUDONYM_PREFIX;
1052f05cddf9SRui Paulo 		break;
1053f05cddf9SRui Paulo 	case EAP_SIM_DB_AKA:
1054f05cddf9SRui Paulo 		prefix = EAP_AKA_PSEUDONYM_PREFIX;
1055f05cddf9SRui Paulo 		break;
1056f05cddf9SRui Paulo 	case EAP_SIM_DB_AKA_PRIME:
1057f05cddf9SRui Paulo 		prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
1058f05cddf9SRui Paulo 		break;
1059f05cddf9SRui Paulo 	}
1060f05cddf9SRui Paulo 
1061f05cddf9SRui Paulo 	return eap_sim_db_get_next(data, prefix);
106239beb93cSSam Leffler }
106339beb93cSSam Leffler 
106439beb93cSSam Leffler 
106539beb93cSSam Leffler /**
106639beb93cSSam Leffler  * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
1067f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1068f05cddf9SRui Paulo  * @method: EAP method (SIM/AKA/AKA')
106939beb93cSSam Leffler  * Returns: Next reauth_id (allocated string) or %NULL on failure
107039beb93cSSam Leffler  *
107139beb93cSSam Leffler  * This function is used to generate a fast re-authentication identity for
107239beb93cSSam Leffler  * EAP-SIM. The returned reauth_id is not added to database at this point; it
107339beb93cSSam Leffler  * will need to be added with eap_sim_db_add_reauth() once the authentication
107439beb93cSSam Leffler  * has been completed successfully. Caller is responsible for freeing the
107539beb93cSSam Leffler  * returned buffer.
107639beb93cSSam Leffler  */
eap_sim_db_get_next_reauth_id(struct eap_sim_db_data * data,enum eap_sim_db_method method)1077f05cddf9SRui Paulo char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
1078f05cddf9SRui Paulo 				     enum eap_sim_db_method method)
107939beb93cSSam Leffler {
1080f05cddf9SRui Paulo 	char prefix = EAP_SIM_REAUTH_ID_PREFIX;
1081f05cddf9SRui Paulo 
1082f05cddf9SRui Paulo 	switch (method) {
1083f05cddf9SRui Paulo 	case EAP_SIM_DB_SIM:
1084f05cddf9SRui Paulo 		prefix = EAP_SIM_REAUTH_ID_PREFIX;
1085f05cddf9SRui Paulo 		break;
1086f05cddf9SRui Paulo 	case EAP_SIM_DB_AKA:
1087f05cddf9SRui Paulo 		prefix = EAP_AKA_REAUTH_ID_PREFIX;
1088f05cddf9SRui Paulo 		break;
1089f05cddf9SRui Paulo 	case EAP_SIM_DB_AKA_PRIME:
1090f05cddf9SRui Paulo 		prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
1091f05cddf9SRui Paulo 		break;
1092f05cddf9SRui Paulo 	}
1093f05cddf9SRui Paulo 
1094f05cddf9SRui Paulo 	return eap_sim_db_get_next(data, prefix);
109539beb93cSSam Leffler }
109639beb93cSSam Leffler 
109739beb93cSSam Leffler 
109839beb93cSSam Leffler /**
109939beb93cSSam Leffler  * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
1100f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1101f05cddf9SRui Paulo  * @permanent: Permanent username
110239beb93cSSam Leffler  * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
110339beb93cSSam Leffler  * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
110439beb93cSSam Leffler  * free it.
110539beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
110639beb93cSSam Leffler  *
110739beb93cSSam Leffler  * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
110839beb93cSSam Leffler  * responsible of freeing pseudonym buffer once it is not needed anymore.
110939beb93cSSam Leffler  */
eap_sim_db_add_pseudonym(struct eap_sim_db_data * data,const char * permanent,char * pseudonym)1110f05cddf9SRui Paulo int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
1111f05cddf9SRui Paulo 			     const char *permanent, char *pseudonym)
111239beb93cSSam Leffler {
111339beb93cSSam Leffler 	struct eap_sim_pseudonym *p;
1114f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
1115f05cddf9SRui Paulo 		   "username '%s'", pseudonym, permanent);
111639beb93cSSam Leffler 
111739beb93cSSam Leffler 	/* TODO: could store last two pseudonyms */
1118f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1119f05cddf9SRui Paulo 	if (data->sqlite_db)
1120f05cddf9SRui Paulo 		return db_add_pseudonym(data, permanent, pseudonym);
1121f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
1122f05cddf9SRui Paulo 	for (p = data->pseudonyms; p; p = p->next) {
1123f05cddf9SRui Paulo 		if (os_strcmp(permanent, p->permanent) == 0)
1124f05cddf9SRui Paulo 			break;
1125f05cddf9SRui Paulo 	}
112639beb93cSSam Leffler 	if (p) {
112739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
112839beb93cSSam Leffler 			   "pseudonym: %s", p->pseudonym);
112939beb93cSSam Leffler 		os_free(p->pseudonym);
113039beb93cSSam Leffler 		p->pseudonym = pseudonym;
113139beb93cSSam Leffler 		return 0;
113239beb93cSSam Leffler 	}
113339beb93cSSam Leffler 
113439beb93cSSam Leffler 	p = os_zalloc(sizeof(*p));
113539beb93cSSam Leffler 	if (p == NULL) {
113639beb93cSSam Leffler 		os_free(pseudonym);
113739beb93cSSam Leffler 		return -1;
113839beb93cSSam Leffler 	}
113939beb93cSSam Leffler 
114039beb93cSSam Leffler 	p->next = data->pseudonyms;
1141f05cddf9SRui Paulo 	p->permanent = os_strdup(permanent);
1142f05cddf9SRui Paulo 	if (p->permanent == NULL) {
114339beb93cSSam Leffler 		os_free(p);
114439beb93cSSam Leffler 		os_free(pseudonym);
114539beb93cSSam Leffler 		return -1;
114639beb93cSSam Leffler 	}
114739beb93cSSam Leffler 	p->pseudonym = pseudonym;
114839beb93cSSam Leffler 	data->pseudonyms = p;
114939beb93cSSam Leffler 
115039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
115139beb93cSSam Leffler 	return 0;
115239beb93cSSam Leffler }
115339beb93cSSam Leffler 
115439beb93cSSam Leffler 
115539beb93cSSam Leffler static struct eap_sim_reauth *
eap_sim_db_add_reauth_data(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter)1156f05cddf9SRui Paulo eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
1157f05cddf9SRui Paulo 			   const char *permanent,
1158f05cddf9SRui Paulo 			   char *reauth_id, u16 counter)
115939beb93cSSam Leffler {
116039beb93cSSam Leffler 	struct eap_sim_reauth *r;
116139beb93cSSam Leffler 
1162f05cddf9SRui Paulo 	for (r = data->reauths; r; r = r->next) {
1163f05cddf9SRui Paulo 		if (os_strcmp(r->permanent, permanent) == 0)
1164f05cddf9SRui Paulo 			break;
1165f05cddf9SRui Paulo 	}
116639beb93cSSam Leffler 
116739beb93cSSam Leffler 	if (r) {
116839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
116939beb93cSSam Leffler 			   "reauth_id: %s", r->reauth_id);
117039beb93cSSam Leffler 		os_free(r->reauth_id);
117139beb93cSSam Leffler 		r->reauth_id = reauth_id;
117239beb93cSSam Leffler 	} else {
117339beb93cSSam Leffler 		r = os_zalloc(sizeof(*r));
117439beb93cSSam Leffler 		if (r == NULL) {
117539beb93cSSam Leffler 			os_free(reauth_id);
117639beb93cSSam Leffler 			return NULL;
117739beb93cSSam Leffler 		}
117839beb93cSSam Leffler 
117939beb93cSSam Leffler 		r->next = data->reauths;
1180f05cddf9SRui Paulo 		r->permanent = os_strdup(permanent);
1181f05cddf9SRui Paulo 		if (r->permanent == NULL) {
118239beb93cSSam Leffler 			os_free(r);
118339beb93cSSam Leffler 			os_free(reauth_id);
118439beb93cSSam Leffler 			return NULL;
118539beb93cSSam Leffler 		}
118639beb93cSSam Leffler 		r->reauth_id = reauth_id;
118739beb93cSSam Leffler 		data->reauths = r;
118839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
118939beb93cSSam Leffler 	}
119039beb93cSSam Leffler 
119139beb93cSSam Leffler 	r->counter = counter;
119239beb93cSSam Leffler 
119339beb93cSSam Leffler 	return r;
119439beb93cSSam Leffler }
119539beb93cSSam Leffler 
119639beb93cSSam Leffler 
119739beb93cSSam Leffler /**
119839beb93cSSam Leffler  * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
119939beb93cSSam Leffler  * @priv: Private data pointer from eap_sim_db_init()
1200f05cddf9SRui Paulo  * @permanent: Permanent username
120139beb93cSSam Leffler  * @identity_len: Length of identity
120239beb93cSSam Leffler  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
120339beb93cSSam Leffler  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
120439beb93cSSam Leffler  * free it.
120539beb93cSSam Leffler  * @counter: AT_COUNTER value for fast re-authentication
120639beb93cSSam Leffler  * @mk: 16-byte MK from the previous full authentication or %NULL
120739beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
120839beb93cSSam Leffler  *
120939beb93cSSam Leffler  * This function adds a new re-authentication entry for an EAP-SIM user.
121039beb93cSSam Leffler  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
121139beb93cSSam Leffler  * anymore.
121239beb93cSSam Leffler  */
eap_sim_db_add_reauth(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter,const u8 * mk)1213f05cddf9SRui Paulo int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
1214f05cddf9SRui Paulo 			  char *reauth_id, u16 counter, const u8 *mk)
121539beb93cSSam Leffler {
121639beb93cSSam Leffler 	struct eap_sim_reauth *r;
121739beb93cSSam Leffler 
1218f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1219f05cddf9SRui Paulo 		   "identity '%s'", reauth_id, permanent);
1220f05cddf9SRui Paulo 
1221f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1222f05cddf9SRui Paulo 	if (data->sqlite_db)
1223f05cddf9SRui Paulo 		return db_add_reauth(data, permanent, reauth_id, counter, mk,
1224f05cddf9SRui Paulo 				     NULL, NULL, NULL);
1225f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
1226f05cddf9SRui Paulo 	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
122739beb93cSSam Leffler 	if (r == NULL)
122839beb93cSSam Leffler 		return -1;
122939beb93cSSam Leffler 
123039beb93cSSam Leffler 	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
123139beb93cSSam Leffler 
123239beb93cSSam Leffler 	return 0;
123339beb93cSSam Leffler }
123439beb93cSSam Leffler 
123539beb93cSSam Leffler 
1236e28a4053SRui Paulo #ifdef EAP_SERVER_AKA_PRIME
123739beb93cSSam Leffler /**
123839beb93cSSam Leffler  * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
1239f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1240f05cddf9SRui Paulo  * @permanent: Permanent username
124139beb93cSSam Leffler  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
124239beb93cSSam Leffler  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
124339beb93cSSam Leffler  * free it.
124439beb93cSSam Leffler  * @counter: AT_COUNTER value for fast re-authentication
124539beb93cSSam Leffler  * @k_encr: K_encr from the previous full authentication
124639beb93cSSam Leffler  * @k_aut: K_aut from the previous full authentication
124739beb93cSSam Leffler  * @k_re: 32-byte K_re from the previous full authentication
124839beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
124939beb93cSSam Leffler  *
125039beb93cSSam Leffler  * This function adds a new re-authentication entry for an EAP-AKA' user.
125139beb93cSSam Leffler  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
125239beb93cSSam Leffler  * anymore.
125339beb93cSSam Leffler  */
eap_sim_db_add_reauth_prime(struct eap_sim_db_data * data,const char * permanent,char * reauth_id,u16 counter,const u8 * k_encr,const u8 * k_aut,const u8 * k_re)1254f05cddf9SRui Paulo int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
1255f05cddf9SRui Paulo 				const char *permanent, char *reauth_id,
1256f05cddf9SRui Paulo 				u16 counter, const u8 *k_encr,
1257f05cddf9SRui Paulo 				const u8 *k_aut, const u8 *k_re)
125839beb93cSSam Leffler {
125939beb93cSSam Leffler 	struct eap_sim_reauth *r;
126039beb93cSSam Leffler 
1261f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
1262f05cddf9SRui Paulo 		   "identity '%s'", reauth_id, permanent);
1263f05cddf9SRui Paulo 
1264f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1265f05cddf9SRui Paulo 	if (data->sqlite_db)
1266f05cddf9SRui Paulo 		return db_add_reauth(data, permanent, reauth_id, counter, NULL,
1267f05cddf9SRui Paulo 				     k_encr, k_aut, k_re);
1268f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
1269f05cddf9SRui Paulo 	r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
127039beb93cSSam Leffler 	if (r == NULL)
127139beb93cSSam Leffler 		return -1;
127239beb93cSSam Leffler 
127339beb93cSSam Leffler 	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
127439beb93cSSam Leffler 	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
127539beb93cSSam Leffler 	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
127639beb93cSSam Leffler 
127739beb93cSSam Leffler 	return 0;
127839beb93cSSam Leffler }
1279e28a4053SRui Paulo #endif /* EAP_SERVER_AKA_PRIME */
128039beb93cSSam Leffler 
128139beb93cSSam Leffler 
128239beb93cSSam Leffler /**
128339beb93cSSam Leffler  * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
1284f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1285f05cddf9SRui Paulo  * @pseudonym: Pseudonym username
1286f05cddf9SRui Paulo  * Returns: Pointer to permanent username or %NULL if not found
128739beb93cSSam Leffler  */
1288f05cddf9SRui Paulo const char *
eap_sim_db_get_permanent(struct eap_sim_db_data * data,const char * pseudonym)1289f05cddf9SRui Paulo eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
129039beb93cSSam Leffler {
129139beb93cSSam Leffler 	struct eap_sim_pseudonym *p;
129239beb93cSSam Leffler 
1293f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1294f05cddf9SRui Paulo 	if (data->sqlite_db)
1295f05cddf9SRui Paulo 		return db_get_pseudonym(data, pseudonym);
1296f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
129739beb93cSSam Leffler 
1298f05cddf9SRui Paulo 	p = data->pseudonyms;
1299f05cddf9SRui Paulo 	while (p) {
1300f05cddf9SRui Paulo 		if (os_strcmp(p->pseudonym, pseudonym) == 0)
1301f05cddf9SRui Paulo 			return p->permanent;
1302f05cddf9SRui Paulo 		p = p->next;
1303f05cddf9SRui Paulo 	}
130439beb93cSSam Leffler 
1305f05cddf9SRui Paulo 	return NULL;
130639beb93cSSam Leffler }
130739beb93cSSam Leffler 
130839beb93cSSam Leffler 
130939beb93cSSam Leffler /**
131039beb93cSSam Leffler  * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
1311f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1312f05cddf9SRui Paulo  * @reauth_id: Fast re-authentication username
131339beb93cSSam Leffler  * Returns: Pointer to the re-auth entry, or %NULL if not found
131439beb93cSSam Leffler  */
131539beb93cSSam Leffler struct eap_sim_reauth *
eap_sim_db_get_reauth_entry(struct eap_sim_db_data * data,const char * reauth_id)1316f05cddf9SRui Paulo eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
1317f05cddf9SRui Paulo 			    const char *reauth_id)
131839beb93cSSam Leffler {
131939beb93cSSam Leffler 	struct eap_sim_reauth *r;
132039beb93cSSam Leffler 
1321f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1322f05cddf9SRui Paulo 	if (data->sqlite_db)
1323f05cddf9SRui Paulo 		return db_get_reauth(data, reauth_id);
1324f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
1325f05cddf9SRui Paulo 
1326f05cddf9SRui Paulo 	r = data->reauths;
1327f05cddf9SRui Paulo 	while (r) {
1328f05cddf9SRui Paulo 		if (os_strcmp(r->reauth_id, reauth_id) == 0)
1329f05cddf9SRui Paulo 			break;
1330f05cddf9SRui Paulo 		r = r->next;
1331f05cddf9SRui Paulo 	}
1332f05cddf9SRui Paulo 
133339beb93cSSam Leffler 	return r;
133439beb93cSSam Leffler }
133539beb93cSSam Leffler 
133639beb93cSSam Leffler 
133739beb93cSSam Leffler /**
133839beb93cSSam Leffler  * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
1339f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
134039beb93cSSam Leffler  * @reauth: Pointer to re-authentication entry from
134139beb93cSSam Leffler  * eap_sim_db_get_reauth_entry()
134239beb93cSSam Leffler  */
eap_sim_db_remove_reauth(struct eap_sim_db_data * data,struct eap_sim_reauth * reauth)1343f05cddf9SRui Paulo void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
1344f05cddf9SRui Paulo 			      struct eap_sim_reauth *reauth)
134539beb93cSSam Leffler {
134639beb93cSSam Leffler 	struct eap_sim_reauth *r, *prev = NULL;
1347f05cddf9SRui Paulo #ifdef CONFIG_SQLITE
1348f05cddf9SRui Paulo 	if (data->sqlite_db) {
1349f05cddf9SRui Paulo 		db_remove_reauth(data, reauth);
1350f05cddf9SRui Paulo 		return;
1351f05cddf9SRui Paulo 	}
1352f05cddf9SRui Paulo #endif /* CONFIG_SQLITE */
135339beb93cSSam Leffler 	r = data->reauths;
135439beb93cSSam Leffler 	while (r) {
135539beb93cSSam Leffler 		if (r == reauth) {
135639beb93cSSam Leffler 			if (prev)
135739beb93cSSam Leffler 				prev->next = r->next;
135839beb93cSSam Leffler 			else
135939beb93cSSam Leffler 				data->reauths = r->next;
136039beb93cSSam Leffler 			eap_sim_db_free_reauth(r);
136139beb93cSSam Leffler 			return;
136239beb93cSSam Leffler 		}
136339beb93cSSam Leffler 		prev = r;
136439beb93cSSam Leffler 		r = r->next;
136539beb93cSSam Leffler 	}
136639beb93cSSam Leffler }
136739beb93cSSam Leffler 
136839beb93cSSam Leffler 
136939beb93cSSam Leffler /**
137039beb93cSSam Leffler  * eap_sim_db_get_aka_auth - Get AKA authentication values
1371f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1372f05cddf9SRui Paulo  * @username: Permanent username (prefix | IMSI)
137339beb93cSSam Leffler  * @_rand: Buffer for RAND value
137439beb93cSSam Leffler  * @autn: Buffer for AUTN value
137539beb93cSSam Leffler  * @ik: Buffer for IK value
137639beb93cSSam Leffler  * @ck: Buffer for CK value
137739beb93cSSam Leffler  * @res: Buffer for RES value
137839beb93cSSam Leffler  * @res_len: Buffer for RES length
137939beb93cSSam Leffler  * @cb_session_ctx: Session callback context for get_complete_cb()
138039beb93cSSam Leffler  * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
138139beb93cSSam Leffler  * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
138239beb93cSSam Leffler  * case, the callback function registered with eap_sim_db_init() will be
138339beb93cSSam Leffler  * called once the results become available.
138439beb93cSSam Leffler  *
138539beb93cSSam Leffler  * When using an external server for AKA authentication, this function can
138639beb93cSSam Leffler  * always start a request and return EAP_SIM_DB_PENDING immediately if
138739beb93cSSam Leffler  * authentication triplets are not available. Once the authentication data are
138839beb93cSSam Leffler  * received, callback function registered with eap_sim_db_init() is called to
138939beb93cSSam Leffler  * notify EAP state machine to reprocess the message. This
139039beb93cSSam Leffler  * eap_sim_db_get_aka_auth() function will then be called again and the newly
139139beb93cSSam Leffler  * received triplets will then be given to the caller.
139239beb93cSSam Leffler  */
eap_sim_db_get_aka_auth(struct eap_sim_db_data * data,const char * username,u8 * _rand,u8 * autn,u8 * ik,u8 * ck,u8 * res,size_t * res_len,void * cb_session_ctx)1393f05cddf9SRui Paulo int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
1394f05cddf9SRui Paulo 			    u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
1395f05cddf9SRui Paulo 			    u8 *res, size_t *res_len, void *cb_session_ctx)
139639beb93cSSam Leffler {
139739beb93cSSam Leffler 	struct eap_sim_db_pending *entry;
139839beb93cSSam Leffler 	int len;
139939beb93cSSam Leffler 	char msg[40];
1400f05cddf9SRui Paulo 	const char *imsi;
1401f05cddf9SRui Paulo 	size_t imsi_len;
140239beb93cSSam Leffler 
1403f05cddf9SRui Paulo 	if (username == NULL ||
1404f05cddf9SRui Paulo 	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1405f05cddf9SRui Paulo 	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1406f05cddf9SRui Paulo 	    username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
1407f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1408f05cddf9SRui Paulo 			   username);
140939beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
141039beb93cSSam Leffler 	}
1411f05cddf9SRui Paulo 	imsi = username + 1;
1412f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1413f05cddf9SRui Paulo 		   imsi);
141439beb93cSSam Leffler 
1415f05cddf9SRui Paulo 	entry = eap_sim_db_get_pending(data, imsi, 1);
141639beb93cSSam Leffler 	if (entry) {
141739beb93cSSam Leffler 		if (entry->state == FAILURE) {
1418*780fb4a2SCy Schubert 			eap_sim_db_free_pending(data, entry);
141939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
142039beb93cSSam Leffler 			return EAP_SIM_DB_FAILURE;
142139beb93cSSam Leffler 		}
142239beb93cSSam Leffler 
142339beb93cSSam Leffler 		if (entry->state == PENDING) {
142439beb93cSSam Leffler 			eap_sim_db_add_pending(data, entry);
142539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
142639beb93cSSam Leffler 			return EAP_SIM_DB_PENDING;
142739beb93cSSam Leffler 		}
142839beb93cSSam Leffler 
142939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
143039beb93cSSam Leffler 			   "received authentication data");
143139beb93cSSam Leffler 		os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
143239beb93cSSam Leffler 		os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
143339beb93cSSam Leffler 		os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
143439beb93cSSam Leffler 		os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
143539beb93cSSam Leffler 		os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
143639beb93cSSam Leffler 		*res_len = entry->u.aka.res_len;
1437*780fb4a2SCy Schubert 		eap_sim_db_free_pending(data, entry);
143839beb93cSSam Leffler 		return 0;
143939beb93cSSam Leffler 	}
144039beb93cSSam Leffler 
144139beb93cSSam Leffler 	if (data->sock < 0) {
144239beb93cSSam Leffler 		if (eap_sim_db_open_socket(data) < 0)
144339beb93cSSam Leffler 			return EAP_SIM_DB_FAILURE;
144439beb93cSSam Leffler 	}
144539beb93cSSam Leffler 
1446f05cddf9SRui Paulo 	imsi_len = os_strlen(imsi);
144739beb93cSSam Leffler 	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
14485b9c547cSRui Paulo 	if (os_snprintf_error(sizeof(msg), len) ||
14495b9c547cSRui Paulo 	    len + imsi_len >= sizeof(msg))
145039beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
1451f05cddf9SRui Paulo 	os_memcpy(msg + len, imsi, imsi_len);
1452f05cddf9SRui Paulo 	len += imsi_len;
145339beb93cSSam Leffler 
1454f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
1455f05cddf9SRui Paulo 		    "data for IMSI '%s'", imsi);
145639beb93cSSam Leffler 	if (eap_sim_db_send(data, msg, len) < 0)
145739beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
145839beb93cSSam Leffler 
145939beb93cSSam Leffler 	entry = os_zalloc(sizeof(*entry));
146039beb93cSSam Leffler 	if (entry == NULL)
146139beb93cSSam Leffler 		return EAP_SIM_DB_FAILURE;
146239beb93cSSam Leffler 
146339beb93cSSam Leffler 	entry->aka = 1;
1464f05cddf9SRui Paulo 	os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
146539beb93cSSam Leffler 	entry->cb_session_ctx = cb_session_ctx;
146639beb93cSSam Leffler 	entry->state = PENDING;
146739beb93cSSam Leffler 	eap_sim_db_add_pending(data, entry);
1468*780fb4a2SCy Schubert 	eap_sim_db_expire_pending(data, entry);
1469*780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
147039beb93cSSam Leffler 
147139beb93cSSam Leffler 	return EAP_SIM_DB_PENDING;
147239beb93cSSam Leffler }
147339beb93cSSam Leffler 
147439beb93cSSam Leffler 
147539beb93cSSam Leffler /**
147639beb93cSSam Leffler  * eap_sim_db_resynchronize - Resynchronize AKA AUTN
1477f05cddf9SRui Paulo  * @data: Private data pointer from eap_sim_db_init()
1478f05cddf9SRui Paulo  * @username: Permanent username
147939beb93cSSam Leffler  * @auts: AUTS value from the peer
148039beb93cSSam Leffler  * @_rand: RAND value used in the rejected message
148139beb93cSSam Leffler  * Returns: 0 on success, -1 on failure
148239beb93cSSam Leffler  *
148339beb93cSSam Leffler  * This function is called when the peer reports synchronization failure in the
148439beb93cSSam Leffler  * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
148539beb93cSSam Leffler  * HLR/AuC to allow it to resynchronize with the peer. After this,
148639beb93cSSam Leffler  * eap_sim_db_get_aka_auth() will be called again to to fetch updated
148739beb93cSSam Leffler  * RAND/AUTN values for the next challenge.
148839beb93cSSam Leffler  */
eap_sim_db_resynchronize(struct eap_sim_db_data * data,const char * username,const u8 * auts,const u8 * _rand)1489f05cddf9SRui Paulo int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
1490f05cddf9SRui Paulo 			     const char *username,
1491f05cddf9SRui Paulo 			     const u8 *auts, const u8 *_rand)
149239beb93cSSam Leffler {
1493f05cddf9SRui Paulo 	const char *imsi;
1494f05cddf9SRui Paulo 	size_t imsi_len;
149539beb93cSSam Leffler 
1496f05cddf9SRui Paulo 	if (username == NULL ||
1497f05cddf9SRui Paulo 	    (username[0] != EAP_AKA_PERMANENT_PREFIX &&
1498f05cddf9SRui Paulo 	     username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
1499f05cddf9SRui Paulo 	    username[1] == '\0' || os_strlen(username) > 20) {
1500f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
1501f05cddf9SRui Paulo 			   username);
150239beb93cSSam Leffler 		return -1;
150339beb93cSSam Leffler 	}
1504f05cddf9SRui Paulo 	imsi = username + 1;
1505f05cddf9SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
1506f05cddf9SRui Paulo 		   imsi);
150739beb93cSSam Leffler 
150839beb93cSSam Leffler 	if (data->sock >= 0) {
150939beb93cSSam Leffler 		char msg[100];
151039beb93cSSam Leffler 		int len, ret;
151139beb93cSSam Leffler 
1512f05cddf9SRui Paulo 		imsi_len = os_strlen(imsi);
151339beb93cSSam Leffler 		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
15145b9c547cSRui Paulo 		if (os_snprintf_error(sizeof(msg), len) ||
15155b9c547cSRui Paulo 		    len + imsi_len >= sizeof(msg))
151639beb93cSSam Leffler 			return -1;
1517f05cddf9SRui Paulo 		os_memcpy(msg + len, imsi, imsi_len);
1518f05cddf9SRui Paulo 		len += imsi_len;
151939beb93cSSam Leffler 
152039beb93cSSam Leffler 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
15215b9c547cSRui Paulo 		if (os_snprintf_error(sizeof(msg) - len, ret))
152239beb93cSSam Leffler 			return -1;
152339beb93cSSam Leffler 		len += ret;
152439beb93cSSam Leffler 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
152539beb93cSSam Leffler 					auts, EAP_AKA_AUTS_LEN);
152639beb93cSSam Leffler 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
15275b9c547cSRui Paulo 		if (os_snprintf_error(sizeof(msg) - len, ret))
152839beb93cSSam Leffler 			return -1;
152939beb93cSSam Leffler 		len += ret;
153039beb93cSSam Leffler 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
153139beb93cSSam Leffler 					_rand, EAP_AKA_RAND_LEN);
1532f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
1533f05cddf9SRui Paulo 			   "IMSI '%s'", imsi);
153439beb93cSSam Leffler 		if (eap_sim_db_send(data, msg, len) < 0)
153539beb93cSSam Leffler 			return -1;
153639beb93cSSam Leffler 	}
153739beb93cSSam Leffler 
153839beb93cSSam Leffler 	return 0;
153939beb93cSSam Leffler }
1540f05cddf9SRui Paulo 
1541f05cddf9SRui Paulo 
1542f05cddf9SRui Paulo /**
1543f05cddf9SRui Paulo  * sim_get_username - Extract username from SIM identity
1544f05cddf9SRui Paulo  * @identity: Identity
1545f05cddf9SRui Paulo  * @identity_len: Identity length
1546f05cddf9SRui Paulo  * Returns: Allocated buffer with the username part of the identity
1547f05cddf9SRui Paulo  *
1548f05cddf9SRui Paulo  * Caller is responsible for freeing the returned buffer with os_free().
1549f05cddf9SRui Paulo  */
sim_get_username(const u8 * identity,size_t identity_len)1550f05cddf9SRui Paulo char * sim_get_username(const u8 *identity, size_t identity_len)
1551f05cddf9SRui Paulo {
1552f05cddf9SRui Paulo 	size_t pos;
1553f05cddf9SRui Paulo 
1554f05cddf9SRui Paulo 	if (identity == NULL)
1555f05cddf9SRui Paulo 		return NULL;
1556f05cddf9SRui Paulo 
1557f05cddf9SRui Paulo 	for (pos = 0; pos < identity_len; pos++) {
1558f05cddf9SRui Paulo 		if (identity[pos] == '@' || identity[pos] == '\0')
1559f05cddf9SRui Paulo 			break;
1560f05cddf9SRui Paulo 	}
1561f05cddf9SRui Paulo 
15625b9c547cSRui Paulo 	return dup_binstr(identity, pos);
1563f05cddf9SRui Paulo }
1564