1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
3e5b75505Sopenharmony_ci * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci *
8e5b75505Sopenharmony_ci * This is an example implementation of the EAP-SIM/AKA database/authentication
9e5b75505Sopenharmony_ci * gateway interface to HLR/AuC. It is expected to be replaced with an
10e5b75505Sopenharmony_ci * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
11e5b75505Sopenharmony_ci * a local implementation of SIM triplet and AKA authentication data generator.
12e5b75505Sopenharmony_ci *
13e5b75505Sopenharmony_ci * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
14e5b75505Sopenharmony_ci * to and external program, e.g., this hlr_auc_gw. This interface uses simple
15e5b75505Sopenharmony_ci * text-based format:
16e5b75505Sopenharmony_ci *
17e5b75505Sopenharmony_ci * EAP-SIM / GSM triplet query/response:
18e5b75505Sopenharmony_ci * SIM-REQ-AUTH <IMSI> <max_chal>
19e5b75505Sopenharmony_ci * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
20e5b75505Sopenharmony_ci * SIM-RESP-AUTH <IMSI> FAILURE
21e5b75505Sopenharmony_ci * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
22e5b75505Sopenharmony_ci * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
23e5b75505Sopenharmony_ci * GSM-AUTH-RESP <IMSI> FAILURE
24e5b75505Sopenharmony_ci *
25e5b75505Sopenharmony_ci * EAP-AKA / UMTS query/response:
26e5b75505Sopenharmony_ci * AKA-REQ-AUTH <IMSI>
27e5b75505Sopenharmony_ci * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
28e5b75505Sopenharmony_ci * AKA-RESP-AUTH <IMSI> FAILURE
29e5b75505Sopenharmony_ci *
30e5b75505Sopenharmony_ci * EAP-AKA / UMTS AUTS (re-synchronization):
31e5b75505Sopenharmony_ci * AKA-AUTS <IMSI> <AUTS> <RAND>
32e5b75505Sopenharmony_ci *
33e5b75505Sopenharmony_ci * IMSI and max_chal are sent as an ASCII string,
34e5b75505Sopenharmony_ci * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
35e5b75505Sopenharmony_ci *
36e5b75505Sopenharmony_ci * An example implementation here reads GSM authentication triplets from a
37e5b75505Sopenharmony_ci * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
38e5b75505Sopenharmony_ci * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
39e5b75505Sopenharmony_ci * for real life authentication, but it is useful both as an example
40e5b75505Sopenharmony_ci * implementation and for EAP-SIM/AKA/AKA' testing.
41e5b75505Sopenharmony_ci *
42e5b75505Sopenharmony_ci * For a stronger example design, Milenage and GSM-Milenage algorithms can be
43e5b75505Sopenharmony_ci * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
44e5b75505Sopenharmony_ci * EAP-SIM, respectively, if Ki is known.
45e5b75505Sopenharmony_ci *
46e5b75505Sopenharmony_ci * SQN generation follows the not time-based Profile 2 described in
47e5b75505Sopenharmony_ci * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
48e5b75505Sopenharmony_ci * can be changed with a command line options if needed.
49e5b75505Sopenharmony_ci */
50e5b75505Sopenharmony_ci
51e5b75505Sopenharmony_ci#include "includes.h"
52e5b75505Sopenharmony_ci#include <sys/un.h>
53e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
54e5b75505Sopenharmony_ci#include <sqlite3.h>
55e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
56e5b75505Sopenharmony_ci
57e5b75505Sopenharmony_ci#include "common.h"
58e5b75505Sopenharmony_ci#include "crypto/milenage.h"
59e5b75505Sopenharmony_ci#include "crypto/random.h"
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_cistatic const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
62e5b75505Sopenharmony_cistatic const char *socket_path;
63e5b75505Sopenharmony_cistatic int serv_sock = -1;
64e5b75505Sopenharmony_cistatic char *milenage_file = NULL;
65e5b75505Sopenharmony_cistatic int update_milenage = 0;
66e5b75505Sopenharmony_cistatic int sqn_changes = 0;
67e5b75505Sopenharmony_cistatic int ind_len = 5;
68e5b75505Sopenharmony_cistatic int stdout_debug = 1;
69e5b75505Sopenharmony_ci
70e5b75505Sopenharmony_ci/* GSM triplets */
71e5b75505Sopenharmony_cistruct gsm_triplet {
72e5b75505Sopenharmony_ci	struct gsm_triplet *next;
73e5b75505Sopenharmony_ci	char imsi[20];
74e5b75505Sopenharmony_ci	u8 kc[8];
75e5b75505Sopenharmony_ci	u8 sres[4];
76e5b75505Sopenharmony_ci	u8 _rand[16];
77e5b75505Sopenharmony_ci};
78e5b75505Sopenharmony_ci
79e5b75505Sopenharmony_cistatic struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
80e5b75505Sopenharmony_ci
81e5b75505Sopenharmony_ci/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
82e5b75505Sopenharmony_cistruct milenage_parameters {
83e5b75505Sopenharmony_ci	struct milenage_parameters *next;
84e5b75505Sopenharmony_ci	char imsi[20];
85e5b75505Sopenharmony_ci	u8 ki[16];
86e5b75505Sopenharmony_ci	u8 opc[16];
87e5b75505Sopenharmony_ci	u8 amf[2];
88e5b75505Sopenharmony_ci	u8 sqn[6];
89e5b75505Sopenharmony_ci	int set;
90e5b75505Sopenharmony_ci	size_t res_len;
91e5b75505Sopenharmony_ci};
92e5b75505Sopenharmony_ci
93e5b75505Sopenharmony_cistatic struct milenage_parameters *milenage_db = NULL;
94e5b75505Sopenharmony_ci
95e5b75505Sopenharmony_ci#define EAP_SIM_MAX_CHAL 3
96e5b75505Sopenharmony_ci
97e5b75505Sopenharmony_ci#define EAP_AKA_RAND_LEN 16
98e5b75505Sopenharmony_ci#define EAP_AKA_AUTN_LEN 16
99e5b75505Sopenharmony_ci#define EAP_AKA_AUTS_LEN 14
100e5b75505Sopenharmony_ci#define EAP_AKA_RES_MIN_LEN 4
101e5b75505Sopenharmony_ci#define EAP_AKA_RES_MAX_LEN 16
102e5b75505Sopenharmony_ci#define EAP_AKA_IK_LEN 16
103e5b75505Sopenharmony_ci#define EAP_AKA_CK_LEN 16
104e5b75505Sopenharmony_ci
105e5b75505Sopenharmony_ci
106e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
107e5b75505Sopenharmony_ci
108e5b75505Sopenharmony_cistatic sqlite3 *sqlite_db = NULL;
109e5b75505Sopenharmony_cistatic struct milenage_parameters db_tmp_milenage;
110e5b75505Sopenharmony_ci
111e5b75505Sopenharmony_ci
112e5b75505Sopenharmony_cistatic int db_table_exists(sqlite3 *db, const char *name)
113e5b75505Sopenharmony_ci{
114e5b75505Sopenharmony_ci	char cmd[128];
115e5b75505Sopenharmony_ci	os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
116e5b75505Sopenharmony_ci	return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
117e5b75505Sopenharmony_ci}
118e5b75505Sopenharmony_ci
119e5b75505Sopenharmony_ci
120e5b75505Sopenharmony_cistatic int db_table_create_milenage(sqlite3 *db)
121e5b75505Sopenharmony_ci{
122e5b75505Sopenharmony_ci	char *err = NULL;
123e5b75505Sopenharmony_ci	const char *sql =
124e5b75505Sopenharmony_ci		"CREATE TABLE milenage("
125e5b75505Sopenharmony_ci		"  imsi INTEGER PRIMARY KEY NOT NULL,"
126e5b75505Sopenharmony_ci		"  ki CHAR(32) NOT NULL,"
127e5b75505Sopenharmony_ci		"  opc CHAR(32) NOT NULL,"
128e5b75505Sopenharmony_ci		"  amf CHAR(4) NOT NULL,"
129e5b75505Sopenharmony_ci		"  sqn CHAR(12) NOT NULL,"
130e5b75505Sopenharmony_ci		"  res_len INTEGER"
131e5b75505Sopenharmony_ci		");";
132e5b75505Sopenharmony_ci
133e5b75505Sopenharmony_ci	printf("Adding database table for milenage information\n");
134e5b75505Sopenharmony_ci	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
135e5b75505Sopenharmony_ci		printf("SQLite error: %s\n", err);
136e5b75505Sopenharmony_ci		sqlite3_free(err);
137e5b75505Sopenharmony_ci		return -1;
138e5b75505Sopenharmony_ci	}
139e5b75505Sopenharmony_ci
140e5b75505Sopenharmony_ci	return 0;
141e5b75505Sopenharmony_ci}
142e5b75505Sopenharmony_ci
143e5b75505Sopenharmony_ci
144e5b75505Sopenharmony_cistatic sqlite3 * db_open(const char *db_file)
145e5b75505Sopenharmony_ci{
146e5b75505Sopenharmony_ci	sqlite3 *db;
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ci	if (sqlite3_open(db_file, &db)) {
149e5b75505Sopenharmony_ci		printf("Failed to open database %s: %s\n",
150e5b75505Sopenharmony_ci		       db_file, sqlite3_errmsg(db));
151e5b75505Sopenharmony_ci		sqlite3_close(db);
152e5b75505Sopenharmony_ci		return NULL;
153e5b75505Sopenharmony_ci	}
154e5b75505Sopenharmony_ci
155e5b75505Sopenharmony_ci	if (!db_table_exists(db, "milenage") &&
156e5b75505Sopenharmony_ci	    db_table_create_milenage(db) < 0) {
157e5b75505Sopenharmony_ci		sqlite3_close(db);
158e5b75505Sopenharmony_ci		return NULL;
159e5b75505Sopenharmony_ci	}
160e5b75505Sopenharmony_ci
161e5b75505Sopenharmony_ci	return db;
162e5b75505Sopenharmony_ci}
163e5b75505Sopenharmony_ci
164e5b75505Sopenharmony_ci
165e5b75505Sopenharmony_cistatic int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
166e5b75505Sopenharmony_ci{
167e5b75505Sopenharmony_ci	struct milenage_parameters *m = ctx;
168e5b75505Sopenharmony_ci	int i;
169e5b75505Sopenharmony_ci
170e5b75505Sopenharmony_ci	m->set = 1;
171e5b75505Sopenharmony_ci
172e5b75505Sopenharmony_ci	for (i = 0; i < argc; i++) {
173e5b75505Sopenharmony_ci		if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
174e5b75505Sopenharmony_ci		    hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
175e5b75505Sopenharmony_ci			printf("Invalid ki value in database\n");
176e5b75505Sopenharmony_ci			return -1;
177e5b75505Sopenharmony_ci		}
178e5b75505Sopenharmony_ci
179e5b75505Sopenharmony_ci		if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
180e5b75505Sopenharmony_ci		    hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
181e5b75505Sopenharmony_ci			printf("Invalid opcvalue in database\n");
182e5b75505Sopenharmony_ci			return -1;
183e5b75505Sopenharmony_ci		}
184e5b75505Sopenharmony_ci
185e5b75505Sopenharmony_ci		if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
186e5b75505Sopenharmony_ci		    hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
187e5b75505Sopenharmony_ci			printf("Invalid amf value in database\n");
188e5b75505Sopenharmony_ci			return -1;
189e5b75505Sopenharmony_ci		}
190e5b75505Sopenharmony_ci
191e5b75505Sopenharmony_ci		if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
192e5b75505Sopenharmony_ci		    hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
193e5b75505Sopenharmony_ci			printf("Invalid sqn value in database\n");
194e5b75505Sopenharmony_ci			return -1;
195e5b75505Sopenharmony_ci		}
196e5b75505Sopenharmony_ci
197e5b75505Sopenharmony_ci		if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
198e5b75505Sopenharmony_ci			m->res_len = atoi(argv[i]);
199e5b75505Sopenharmony_ci		}
200e5b75505Sopenharmony_ci	}
201e5b75505Sopenharmony_ci
202e5b75505Sopenharmony_ci	return 0;
203e5b75505Sopenharmony_ci}
204e5b75505Sopenharmony_ci
205e5b75505Sopenharmony_ci
206e5b75505Sopenharmony_cistatic struct milenage_parameters * db_get_milenage(const char *imsi_txt)
207e5b75505Sopenharmony_ci{
208e5b75505Sopenharmony_ci	char cmd[128];
209e5b75505Sopenharmony_ci	unsigned long long imsi;
210e5b75505Sopenharmony_ci
211e5b75505Sopenharmony_ci	os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
212e5b75505Sopenharmony_ci	imsi = atoll(imsi_txt);
213e5b75505Sopenharmony_ci	os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
214e5b75505Sopenharmony_ci		    "%llu", imsi);
215e5b75505Sopenharmony_ci	os_snprintf(cmd, sizeof(cmd),
216e5b75505Sopenharmony_ci		    "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
217e5b75505Sopenharmony_ci	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
218e5b75505Sopenharmony_ci			 NULL) != SQLITE_OK)
219e5b75505Sopenharmony_ci		return NULL;
220e5b75505Sopenharmony_ci
221e5b75505Sopenharmony_ci	if (!db_tmp_milenage.set)
222e5b75505Sopenharmony_ci		return NULL;
223e5b75505Sopenharmony_ci	return &db_tmp_milenage;
224e5b75505Sopenharmony_ci}
225e5b75505Sopenharmony_ci
226e5b75505Sopenharmony_ci
227e5b75505Sopenharmony_cistatic int db_update_milenage_sqn(struct milenage_parameters *m)
228e5b75505Sopenharmony_ci{
229e5b75505Sopenharmony_ci	char cmd[128], val[13], *pos;
230e5b75505Sopenharmony_ci
231e5b75505Sopenharmony_ci	if (sqlite_db == NULL)
232e5b75505Sopenharmony_ci		return 0;
233e5b75505Sopenharmony_ci
234e5b75505Sopenharmony_ci	pos = val;
235e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
236e5b75505Sopenharmony_ci	*pos = '\0';
237e5b75505Sopenharmony_ci	os_snprintf(cmd, sizeof(cmd),
238e5b75505Sopenharmony_ci		    "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
239e5b75505Sopenharmony_ci		    val, m->imsi);
240e5b75505Sopenharmony_ci	if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
241e5b75505Sopenharmony_ci		printf("Failed to update SQN in database for IMSI %s\n",
242e5b75505Sopenharmony_ci		       m->imsi);
243e5b75505Sopenharmony_ci		return -1;
244e5b75505Sopenharmony_ci	}
245e5b75505Sopenharmony_ci	return 0;
246e5b75505Sopenharmony_ci}
247e5b75505Sopenharmony_ci
248e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ci
251e5b75505Sopenharmony_cistatic int open_socket(const char *path)
252e5b75505Sopenharmony_ci{
253e5b75505Sopenharmony_ci	struct sockaddr_un addr;
254e5b75505Sopenharmony_ci	int s;
255e5b75505Sopenharmony_ci
256e5b75505Sopenharmony_ci	s = socket(PF_UNIX, SOCK_DGRAM, 0);
257e5b75505Sopenharmony_ci	if (s < 0) {
258e5b75505Sopenharmony_ci		perror("socket(PF_UNIX)");
259e5b75505Sopenharmony_ci		return -1;
260e5b75505Sopenharmony_ci	}
261e5b75505Sopenharmony_ci
262e5b75505Sopenharmony_ci	memset(&addr, 0, sizeof(addr));
263e5b75505Sopenharmony_ci	addr.sun_family = AF_UNIX;
264e5b75505Sopenharmony_ci	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
265e5b75505Sopenharmony_ci	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
266e5b75505Sopenharmony_ci		perror("hlr-auc-gw: bind(PF_UNIX)");
267e5b75505Sopenharmony_ci		close(s);
268e5b75505Sopenharmony_ci		return -1;
269e5b75505Sopenharmony_ci	}
270e5b75505Sopenharmony_ci
271e5b75505Sopenharmony_ci	return s;
272e5b75505Sopenharmony_ci}
273e5b75505Sopenharmony_ci
274e5b75505Sopenharmony_ci
275e5b75505Sopenharmony_cistatic int read_gsm_triplets(const char *fname)
276e5b75505Sopenharmony_ci{
277e5b75505Sopenharmony_ci	FILE *f;
278e5b75505Sopenharmony_ci	char buf[200], *pos, *pos2;
279e5b75505Sopenharmony_ci	struct gsm_triplet *g = NULL;
280e5b75505Sopenharmony_ci	int line, ret = 0;
281e5b75505Sopenharmony_ci
282e5b75505Sopenharmony_ci	if (fname == NULL)
283e5b75505Sopenharmony_ci		return -1;
284e5b75505Sopenharmony_ci
285e5b75505Sopenharmony_ci	f = fopen(fname, "r");
286e5b75505Sopenharmony_ci	if (f == NULL) {
287e5b75505Sopenharmony_ci		printf("Could not open GSM triplet data file '%s'\n", fname);
288e5b75505Sopenharmony_ci		return -1;
289e5b75505Sopenharmony_ci	}
290e5b75505Sopenharmony_ci
291e5b75505Sopenharmony_ci	line = 0;
292e5b75505Sopenharmony_ci	while (fgets(buf, sizeof(buf), f)) {
293e5b75505Sopenharmony_ci		line++;
294e5b75505Sopenharmony_ci
295e5b75505Sopenharmony_ci		/* Parse IMSI:Kc:SRES:RAND */
296e5b75505Sopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
297e5b75505Sopenharmony_ci		if (buf[0] == '#')
298e5b75505Sopenharmony_ci			continue;
299e5b75505Sopenharmony_ci		pos = buf;
300e5b75505Sopenharmony_ci		while (*pos != '\0' && *pos != '\n')
301e5b75505Sopenharmony_ci			pos++;
302e5b75505Sopenharmony_ci		if (*pos == '\n')
303e5b75505Sopenharmony_ci			*pos = '\0';
304e5b75505Sopenharmony_ci		pos = buf;
305e5b75505Sopenharmony_ci		if (*pos == '\0')
306e5b75505Sopenharmony_ci			continue;
307e5b75505Sopenharmony_ci
308e5b75505Sopenharmony_ci		g = os_zalloc(sizeof(*g));
309e5b75505Sopenharmony_ci		if (g == NULL) {
310e5b75505Sopenharmony_ci			ret = -1;
311e5b75505Sopenharmony_ci			break;
312e5b75505Sopenharmony_ci		}
313e5b75505Sopenharmony_ci
314e5b75505Sopenharmony_ci		/* IMSI */
315e5b75505Sopenharmony_ci		pos2 = NULL;
316e5b75505Sopenharmony_ci		pos = str_token(buf, ":", &pos2);
317e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) >= sizeof(g->imsi)) {
318e5b75505Sopenharmony_ci			printf("%s:%d - Invalid IMSI\n", fname, line);
319e5b75505Sopenharmony_ci			ret = -1;
320e5b75505Sopenharmony_ci			break;
321e5b75505Sopenharmony_ci		}
322e5b75505Sopenharmony_ci		os_strlcpy(g->imsi, pos, sizeof(g->imsi));
323e5b75505Sopenharmony_ci
324e5b75505Sopenharmony_ci		/* Kc */
325e5b75505Sopenharmony_ci		pos = str_token(buf, ":", &pos2);
326e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
327e5b75505Sopenharmony_ci			printf("%s:%d - Invalid Kc\n", fname, line);
328e5b75505Sopenharmony_ci			ret = -1;
329e5b75505Sopenharmony_ci			break;
330e5b75505Sopenharmony_ci		}
331e5b75505Sopenharmony_ci
332e5b75505Sopenharmony_ci		/* SRES */
333e5b75505Sopenharmony_ci		pos = str_token(buf, ":", &pos2);
334e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 8 ||
335e5b75505Sopenharmony_ci		    hexstr2bin(pos, g->sres, 4)) {
336e5b75505Sopenharmony_ci			printf("%s:%d - Invalid SRES\n", fname, line);
337e5b75505Sopenharmony_ci			ret = -1;
338e5b75505Sopenharmony_ci			break;
339e5b75505Sopenharmony_ci		}
340e5b75505Sopenharmony_ci
341e5b75505Sopenharmony_ci		/* RAND */
342e5b75505Sopenharmony_ci		pos = str_token(buf, ":", &pos2);
343e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 32 ||
344e5b75505Sopenharmony_ci		    hexstr2bin(pos, g->_rand, 16)) {
345e5b75505Sopenharmony_ci			printf("%s:%d - Invalid RAND\n", fname, line);
346e5b75505Sopenharmony_ci			ret = -1;
347e5b75505Sopenharmony_ci			break;
348e5b75505Sopenharmony_ci		}
349e5b75505Sopenharmony_ci
350e5b75505Sopenharmony_ci		g->next = gsm_db;
351e5b75505Sopenharmony_ci		gsm_db = g;
352e5b75505Sopenharmony_ci		g = NULL;
353e5b75505Sopenharmony_ci	}
354e5b75505Sopenharmony_ci	os_free(g);
355e5b75505Sopenharmony_ci
356e5b75505Sopenharmony_ci	fclose(f);
357e5b75505Sopenharmony_ci
358e5b75505Sopenharmony_ci	return ret;
359e5b75505Sopenharmony_ci}
360e5b75505Sopenharmony_ci
361e5b75505Sopenharmony_ci
362e5b75505Sopenharmony_cistatic struct gsm_triplet * get_gsm_triplet(const char *imsi)
363e5b75505Sopenharmony_ci{
364e5b75505Sopenharmony_ci	struct gsm_triplet *g = gsm_db_pos;
365e5b75505Sopenharmony_ci
366e5b75505Sopenharmony_ci	while (g) {
367e5b75505Sopenharmony_ci		if (strcmp(g->imsi, imsi) == 0) {
368e5b75505Sopenharmony_ci			gsm_db_pos = g->next;
369e5b75505Sopenharmony_ci			return g;
370e5b75505Sopenharmony_ci		}
371e5b75505Sopenharmony_ci		g = g->next;
372e5b75505Sopenharmony_ci	}
373e5b75505Sopenharmony_ci
374e5b75505Sopenharmony_ci	g = gsm_db;
375e5b75505Sopenharmony_ci	while (g && g != gsm_db_pos) {
376e5b75505Sopenharmony_ci		if (strcmp(g->imsi, imsi) == 0) {
377e5b75505Sopenharmony_ci			gsm_db_pos = g->next;
378e5b75505Sopenharmony_ci			return g;
379e5b75505Sopenharmony_ci		}
380e5b75505Sopenharmony_ci		g = g->next;
381e5b75505Sopenharmony_ci	}
382e5b75505Sopenharmony_ci
383e5b75505Sopenharmony_ci	return NULL;
384e5b75505Sopenharmony_ci}
385e5b75505Sopenharmony_ci
386e5b75505Sopenharmony_ci
387e5b75505Sopenharmony_cistatic int read_milenage(const char *fname)
388e5b75505Sopenharmony_ci{
389e5b75505Sopenharmony_ci	FILE *f;
390e5b75505Sopenharmony_ci	char buf[200], *pos, *pos2;
391e5b75505Sopenharmony_ci	struct milenage_parameters *m = NULL;
392e5b75505Sopenharmony_ci	int line, ret = 0;
393e5b75505Sopenharmony_ci
394e5b75505Sopenharmony_ci	if (fname == NULL)
395e5b75505Sopenharmony_ci		return -1;
396e5b75505Sopenharmony_ci
397e5b75505Sopenharmony_ci	f = fopen(fname, "r");
398e5b75505Sopenharmony_ci	if (f == NULL) {
399e5b75505Sopenharmony_ci		printf("Could not open Milenage data file '%s'\n", fname);
400e5b75505Sopenharmony_ci		return -1;
401e5b75505Sopenharmony_ci	}
402e5b75505Sopenharmony_ci
403e5b75505Sopenharmony_ci	line = 0;
404e5b75505Sopenharmony_ci	while (fgets(buf, sizeof(buf), f)) {
405e5b75505Sopenharmony_ci		line++;
406e5b75505Sopenharmony_ci
407e5b75505Sopenharmony_ci		/* Parse IMSI Ki OPc AMF SQN [RES_len] */
408e5b75505Sopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
409e5b75505Sopenharmony_ci		if (buf[0] == '#')
410e5b75505Sopenharmony_ci			continue;
411e5b75505Sopenharmony_ci		pos = buf;
412e5b75505Sopenharmony_ci		while (*pos != '\0' && *pos != '\n')
413e5b75505Sopenharmony_ci			pos++;
414e5b75505Sopenharmony_ci		if (*pos == '\n')
415e5b75505Sopenharmony_ci			*pos = '\0';
416e5b75505Sopenharmony_ci		pos = buf;
417e5b75505Sopenharmony_ci		if (*pos == '\0')
418e5b75505Sopenharmony_ci			continue;
419e5b75505Sopenharmony_ci
420e5b75505Sopenharmony_ci		m = os_zalloc(sizeof(*m));
421e5b75505Sopenharmony_ci		if (m == NULL) {
422e5b75505Sopenharmony_ci			ret = -1;
423e5b75505Sopenharmony_ci			break;
424e5b75505Sopenharmony_ci		}
425e5b75505Sopenharmony_ci
426e5b75505Sopenharmony_ci		/* IMSI */
427e5b75505Sopenharmony_ci		pos2 = NULL;
428e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
429e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) >= sizeof(m->imsi)) {
430e5b75505Sopenharmony_ci			printf("%s:%d - Invalid IMSI\n", fname, line);
431e5b75505Sopenharmony_ci			ret = -1;
432e5b75505Sopenharmony_ci			break;
433e5b75505Sopenharmony_ci		}
434e5b75505Sopenharmony_ci		os_strlcpy(m->imsi, pos, sizeof(m->imsi));
435e5b75505Sopenharmony_ci
436e5b75505Sopenharmony_ci		/* Ki */
437e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
438e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 32 ||
439e5b75505Sopenharmony_ci		    hexstr2bin(pos, m->ki, 16)) {
440e5b75505Sopenharmony_ci			printf("%s:%d - Invalid Ki\n", fname, line);
441e5b75505Sopenharmony_ci			ret = -1;
442e5b75505Sopenharmony_ci			break;
443e5b75505Sopenharmony_ci		}
444e5b75505Sopenharmony_ci
445e5b75505Sopenharmony_ci		/* OPc */
446e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
447e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 32 ||
448e5b75505Sopenharmony_ci		    hexstr2bin(pos, m->opc, 16)) {
449e5b75505Sopenharmony_ci			printf("%s:%d - Invalid OPc\n", fname, line);
450e5b75505Sopenharmony_ci			ret = -1;
451e5b75505Sopenharmony_ci			break;
452e5b75505Sopenharmony_ci		}
453e5b75505Sopenharmony_ci
454e5b75505Sopenharmony_ci		/* AMF */
455e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
456e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
457e5b75505Sopenharmony_ci			printf("%s:%d - Invalid AMF\n", fname, line);
458e5b75505Sopenharmony_ci			ret = -1;
459e5b75505Sopenharmony_ci			break;
460e5b75505Sopenharmony_ci		}
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_ci		/* SQN */
463e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
464e5b75505Sopenharmony_ci		if (!pos || os_strlen(pos) != 12 ||
465e5b75505Sopenharmony_ci		    hexstr2bin(pos, m->sqn, 6)) {
466e5b75505Sopenharmony_ci			printf("%s:%d - Invalid SEQ\n", fname, line);
467e5b75505Sopenharmony_ci			ret = -1;
468e5b75505Sopenharmony_ci			break;
469e5b75505Sopenharmony_ci		}
470e5b75505Sopenharmony_ci
471e5b75505Sopenharmony_ci		pos = str_token(buf, " ", &pos2);
472e5b75505Sopenharmony_ci		if (pos) {
473e5b75505Sopenharmony_ci			m->res_len = atoi(pos);
474e5b75505Sopenharmony_ci			if (m->res_len &&
475e5b75505Sopenharmony_ci			    (m->res_len < EAP_AKA_RES_MIN_LEN ||
476e5b75505Sopenharmony_ci			     m->res_len > EAP_AKA_RES_MAX_LEN)) {
477e5b75505Sopenharmony_ci				printf("%s:%d - Invalid RES_len\n",
478e5b75505Sopenharmony_ci				       fname, line);
479e5b75505Sopenharmony_ci				ret = -1;
480e5b75505Sopenharmony_ci				break;
481e5b75505Sopenharmony_ci			}
482e5b75505Sopenharmony_ci		}
483e5b75505Sopenharmony_ci
484e5b75505Sopenharmony_ci		m->next = milenage_db;
485e5b75505Sopenharmony_ci		milenage_db = m;
486e5b75505Sopenharmony_ci		m = NULL;
487e5b75505Sopenharmony_ci	}
488e5b75505Sopenharmony_ci	os_free(m);
489e5b75505Sopenharmony_ci
490e5b75505Sopenharmony_ci	fclose(f);
491e5b75505Sopenharmony_ci
492e5b75505Sopenharmony_ci	return ret;
493e5b75505Sopenharmony_ci}
494e5b75505Sopenharmony_ci
495e5b75505Sopenharmony_ci
496e5b75505Sopenharmony_cistatic void update_milenage_file(const char *fname)
497e5b75505Sopenharmony_ci{
498e5b75505Sopenharmony_ci	FILE *f, *f2;
499e5b75505Sopenharmony_ci	char name[500], buf[500], *pos;
500e5b75505Sopenharmony_ci	char *end = buf + sizeof(buf);
501e5b75505Sopenharmony_ci	struct milenage_parameters *m;
502e5b75505Sopenharmony_ci	size_t imsi_len;
503e5b75505Sopenharmony_ci
504e5b75505Sopenharmony_ci	f = fopen(fname, "r");
505e5b75505Sopenharmony_ci	if (f == NULL) {
506e5b75505Sopenharmony_ci		printf("Could not open Milenage data file '%s'\n", fname);
507e5b75505Sopenharmony_ci		return;
508e5b75505Sopenharmony_ci	}
509e5b75505Sopenharmony_ci
510e5b75505Sopenharmony_ci	snprintf(name, sizeof(name), "%s.new", fname);
511e5b75505Sopenharmony_ci	f2 = fopen(name, "w");
512e5b75505Sopenharmony_ci	if (f2 == NULL) {
513e5b75505Sopenharmony_ci		printf("Could not write Milenage data file '%s'\n", name);
514e5b75505Sopenharmony_ci		fclose(f);
515e5b75505Sopenharmony_ci		return;
516e5b75505Sopenharmony_ci	}
517e5b75505Sopenharmony_ci
518e5b75505Sopenharmony_ci	while (fgets(buf, sizeof(buf), f)) {
519e5b75505Sopenharmony_ci		/* IMSI Ki OPc AMF SQN */
520e5b75505Sopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
521e5b75505Sopenharmony_ci
522e5b75505Sopenharmony_ci		pos = strchr(buf, ' ');
523e5b75505Sopenharmony_ci		if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
524e5b75505Sopenharmony_ci			goto no_update;
525e5b75505Sopenharmony_ci
526e5b75505Sopenharmony_ci		imsi_len = pos - buf;
527e5b75505Sopenharmony_ci
528e5b75505Sopenharmony_ci		for (m = milenage_db; m; m = m->next) {
529e5b75505Sopenharmony_ci			if (strncmp(buf, m->imsi, imsi_len) == 0 &&
530e5b75505Sopenharmony_ci			    m->imsi[imsi_len] == '\0')
531e5b75505Sopenharmony_ci				break;
532e5b75505Sopenharmony_ci		}
533e5b75505Sopenharmony_ci
534e5b75505Sopenharmony_ci		if (!m)
535e5b75505Sopenharmony_ci			goto no_update;
536e5b75505Sopenharmony_ci
537e5b75505Sopenharmony_ci		pos = buf;
538e5b75505Sopenharmony_ci		pos += snprintf(pos, end - pos, "%s ", m->imsi);
539e5b75505Sopenharmony_ci		pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
540e5b75505Sopenharmony_ci		*pos++ = ' ';
541e5b75505Sopenharmony_ci		pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
542e5b75505Sopenharmony_ci		*pos++ = ' ';
543e5b75505Sopenharmony_ci		pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
544e5b75505Sopenharmony_ci		*pos++ = ' ';
545e5b75505Sopenharmony_ci		pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
546e5b75505Sopenharmony_ci		*pos++ = '\n';
547e5b75505Sopenharmony_ci
548e5b75505Sopenharmony_ci	no_update:
549e5b75505Sopenharmony_ci		fprintf(f2, "%s", buf);
550e5b75505Sopenharmony_ci	}
551e5b75505Sopenharmony_ci
552e5b75505Sopenharmony_ci	fclose(f2);
553e5b75505Sopenharmony_ci	fclose(f);
554e5b75505Sopenharmony_ci
555e5b75505Sopenharmony_ci	snprintf(name, sizeof(name), "%s.bak", fname);
556e5b75505Sopenharmony_ci	if (rename(fname, name) < 0) {
557e5b75505Sopenharmony_ci		perror("rename");
558e5b75505Sopenharmony_ci		return;
559e5b75505Sopenharmony_ci	}
560e5b75505Sopenharmony_ci
561e5b75505Sopenharmony_ci	snprintf(name, sizeof(name), "%s.new", fname);
562e5b75505Sopenharmony_ci	if (rename(name, fname) < 0) {
563e5b75505Sopenharmony_ci		perror("rename");
564e5b75505Sopenharmony_ci		return;
565e5b75505Sopenharmony_ci	}
566e5b75505Sopenharmony_ci
567e5b75505Sopenharmony_ci}
568e5b75505Sopenharmony_ci
569e5b75505Sopenharmony_ci
570e5b75505Sopenharmony_cistatic struct milenage_parameters * get_milenage(const char *imsi)
571e5b75505Sopenharmony_ci{
572e5b75505Sopenharmony_ci	struct milenage_parameters *m = milenage_db;
573e5b75505Sopenharmony_ci
574e5b75505Sopenharmony_ci	while (m) {
575e5b75505Sopenharmony_ci		if (strcmp(m->imsi, imsi) == 0)
576e5b75505Sopenharmony_ci			break;
577e5b75505Sopenharmony_ci		m = m->next;
578e5b75505Sopenharmony_ci	}
579e5b75505Sopenharmony_ci
580e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
581e5b75505Sopenharmony_ci	if (!m)
582e5b75505Sopenharmony_ci		m = db_get_milenage(imsi);
583e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
584e5b75505Sopenharmony_ci
585e5b75505Sopenharmony_ci	return m;
586e5b75505Sopenharmony_ci}
587e5b75505Sopenharmony_ci
588e5b75505Sopenharmony_ci
589e5b75505Sopenharmony_cistatic int sim_req_auth(char *imsi, char *resp, size_t resp_len)
590e5b75505Sopenharmony_ci{
591e5b75505Sopenharmony_ci	int count, max_chal, ret;
592e5b75505Sopenharmony_ci	char *pos;
593e5b75505Sopenharmony_ci	char *rpos, *rend;
594e5b75505Sopenharmony_ci	struct milenage_parameters *m;
595e5b75505Sopenharmony_ci	struct gsm_triplet *g;
596e5b75505Sopenharmony_ci
597e5b75505Sopenharmony_ci	resp[0] = '\0';
598e5b75505Sopenharmony_ci
599e5b75505Sopenharmony_ci	pos = strchr(imsi, ' ');
600e5b75505Sopenharmony_ci	if (pos) {
601e5b75505Sopenharmony_ci		*pos++ = '\0';
602e5b75505Sopenharmony_ci		max_chal = atoi(pos);
603e5b75505Sopenharmony_ci		if (max_chal < 1 || max_chal > EAP_SIM_MAX_CHAL)
604e5b75505Sopenharmony_ci			max_chal = EAP_SIM_MAX_CHAL;
605e5b75505Sopenharmony_ci	} else
606e5b75505Sopenharmony_ci		max_chal = EAP_SIM_MAX_CHAL;
607e5b75505Sopenharmony_ci
608e5b75505Sopenharmony_ci	rend = resp + resp_len;
609e5b75505Sopenharmony_ci	rpos = resp;
610e5b75505Sopenharmony_ci	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
611e5b75505Sopenharmony_ci	if (ret < 0 || ret >= rend - rpos)
612e5b75505Sopenharmony_ci		return -1;
613e5b75505Sopenharmony_ci	rpos += ret;
614e5b75505Sopenharmony_ci
615e5b75505Sopenharmony_ci	m = get_milenage(imsi);
616e5b75505Sopenharmony_ci	if (m) {
617e5b75505Sopenharmony_ci		u8 _rand[16], sres[4], kc[8];
618e5b75505Sopenharmony_ci		for (count = 0; count < max_chal; count++) {
619e5b75505Sopenharmony_ci			if (random_get_bytes(_rand, 16) < 0)
620e5b75505Sopenharmony_ci				return -1;
621e5b75505Sopenharmony_ci			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
622e5b75505Sopenharmony_ci			*rpos++ = ' ';
623e5b75505Sopenharmony_ci			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
624e5b75505Sopenharmony_ci			*rpos++ = ':';
625e5b75505Sopenharmony_ci			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
626e5b75505Sopenharmony_ci			*rpos++ = ':';
627e5b75505Sopenharmony_ci			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
628e5b75505Sopenharmony_ci		}
629e5b75505Sopenharmony_ci		*rpos = '\0';
630e5b75505Sopenharmony_ci		return 0;
631e5b75505Sopenharmony_ci	}
632e5b75505Sopenharmony_ci
633e5b75505Sopenharmony_ci	count = 0;
634e5b75505Sopenharmony_ci	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
635e5b75505Sopenharmony_ci		if (strcmp(g->imsi, imsi) != 0)
636e5b75505Sopenharmony_ci			continue;
637e5b75505Sopenharmony_ci
638e5b75505Sopenharmony_ci		if (rpos < rend)
639e5b75505Sopenharmony_ci			*rpos++ = ' ';
640e5b75505Sopenharmony_ci		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
641e5b75505Sopenharmony_ci		if (rpos < rend)
642e5b75505Sopenharmony_ci			*rpos++ = ':';
643e5b75505Sopenharmony_ci		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
644e5b75505Sopenharmony_ci		if (rpos < rend)
645e5b75505Sopenharmony_ci			*rpos++ = ':';
646e5b75505Sopenharmony_ci		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
647e5b75505Sopenharmony_ci		count++;
648e5b75505Sopenharmony_ci	}
649e5b75505Sopenharmony_ci
650e5b75505Sopenharmony_ci	if (count == 0) {
651e5b75505Sopenharmony_ci		printf("No GSM triplets found for %s\n", imsi);
652e5b75505Sopenharmony_ci		ret = snprintf(rpos, rend - rpos, " FAILURE");
653e5b75505Sopenharmony_ci		if (ret < 0 || ret >= rend - rpos)
654e5b75505Sopenharmony_ci			return -1;
655e5b75505Sopenharmony_ci		rpos += ret;
656e5b75505Sopenharmony_ci	}
657e5b75505Sopenharmony_ci
658e5b75505Sopenharmony_ci	return 0;
659e5b75505Sopenharmony_ci}
660e5b75505Sopenharmony_ci
661e5b75505Sopenharmony_ci
662e5b75505Sopenharmony_cistatic int gsm_auth_req(char *imsi, char *resp, size_t resp_len)
663e5b75505Sopenharmony_ci{
664e5b75505Sopenharmony_ci	int count, ret;
665e5b75505Sopenharmony_ci	char *pos, *rpos, *rend;
666e5b75505Sopenharmony_ci	struct milenage_parameters *m;
667e5b75505Sopenharmony_ci
668e5b75505Sopenharmony_ci	resp[0] = '\0';
669e5b75505Sopenharmony_ci
670e5b75505Sopenharmony_ci	pos = os_strchr(imsi, ' ');
671e5b75505Sopenharmony_ci	if (!pos)
672e5b75505Sopenharmony_ci		return -1;
673e5b75505Sopenharmony_ci	*pos++ = '\0';
674e5b75505Sopenharmony_ci
675e5b75505Sopenharmony_ci	rend = resp + resp_len;
676e5b75505Sopenharmony_ci	rpos = resp;
677e5b75505Sopenharmony_ci	ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
678e5b75505Sopenharmony_ci	if (os_snprintf_error(rend - rpos, ret))
679e5b75505Sopenharmony_ci		return -1;
680e5b75505Sopenharmony_ci	rpos += ret;
681e5b75505Sopenharmony_ci
682e5b75505Sopenharmony_ci	m = get_milenage(imsi);
683e5b75505Sopenharmony_ci	if (m) {
684e5b75505Sopenharmony_ci		u8 _rand[16], sres[4], kc[8];
685e5b75505Sopenharmony_ci		for (count = 0; count < EAP_SIM_MAX_CHAL; count++) {
686e5b75505Sopenharmony_ci			if (hexstr2bin(pos, _rand, 16) != 0)
687e5b75505Sopenharmony_ci				return -1;
688e5b75505Sopenharmony_ci			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
689e5b75505Sopenharmony_ci			*rpos++ = count == 0 ? ' ' : ':';
690e5b75505Sopenharmony_ci			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
691e5b75505Sopenharmony_ci			*rpos++ = ':';
692e5b75505Sopenharmony_ci			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
693e5b75505Sopenharmony_ci			pos += 16 * 2;
694e5b75505Sopenharmony_ci			if (*pos != ':')
695e5b75505Sopenharmony_ci				break;
696e5b75505Sopenharmony_ci			pos++;
697e5b75505Sopenharmony_ci		}
698e5b75505Sopenharmony_ci		*rpos = '\0';
699e5b75505Sopenharmony_ci		return 0;
700e5b75505Sopenharmony_ci	}
701e5b75505Sopenharmony_ci
702e5b75505Sopenharmony_ci	printf("No GSM triplets found for %s\n", imsi);
703e5b75505Sopenharmony_ci	ret = os_snprintf(rpos, rend - rpos, " FAILURE");
704e5b75505Sopenharmony_ci	if (os_snprintf_error(rend - rpos, ret))
705e5b75505Sopenharmony_ci		return -1;
706e5b75505Sopenharmony_ci	rpos += ret;
707e5b75505Sopenharmony_ci
708e5b75505Sopenharmony_ci	return 0;
709e5b75505Sopenharmony_ci}
710e5b75505Sopenharmony_ci
711e5b75505Sopenharmony_ci
712e5b75505Sopenharmony_cistatic void inc_sqn(u8 *sqn)
713e5b75505Sopenharmony_ci{
714e5b75505Sopenharmony_ci	u64 val, seq, ind;
715e5b75505Sopenharmony_ci
716e5b75505Sopenharmony_ci	/*
717e5b75505Sopenharmony_ci	 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
718e5b75505Sopenharmony_ci	 *
719e5b75505Sopenharmony_ci	 * The mechanism used here is not time-based, so SEQ2 is void and
720e5b75505Sopenharmony_ci	 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
721e5b75505Sopenharmony_ci	 * of SEQ1 is 48 - ind_len bits.
722e5b75505Sopenharmony_ci	 */
723e5b75505Sopenharmony_ci
724e5b75505Sopenharmony_ci	/* Increment both SEQ and IND by one */
725e5b75505Sopenharmony_ci	val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
726e5b75505Sopenharmony_ci	seq = (val >> ind_len) + 1;
727e5b75505Sopenharmony_ci	ind = (val + 1) & ((1 << ind_len) - 1);
728e5b75505Sopenharmony_ci	val = (seq << ind_len) | ind;
729e5b75505Sopenharmony_ci	WPA_PUT_BE32(sqn, val >> 16);
730e5b75505Sopenharmony_ci	WPA_PUT_BE16(sqn + 4, val & 0xffff);
731e5b75505Sopenharmony_ci}
732e5b75505Sopenharmony_ci
733e5b75505Sopenharmony_ci
734e5b75505Sopenharmony_cistatic int aka_req_auth(char *imsi, char *resp, size_t resp_len)
735e5b75505Sopenharmony_ci{
736e5b75505Sopenharmony_ci	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
737e5b75505Sopenharmony_ci	char *pos, *end;
738e5b75505Sopenharmony_ci	u8 _rand[EAP_AKA_RAND_LEN];
739e5b75505Sopenharmony_ci	u8 autn[EAP_AKA_AUTN_LEN];
740e5b75505Sopenharmony_ci	u8 ik[EAP_AKA_IK_LEN];
741e5b75505Sopenharmony_ci	u8 ck[EAP_AKA_CK_LEN];
742e5b75505Sopenharmony_ci	u8 res[EAP_AKA_RES_MAX_LEN];
743e5b75505Sopenharmony_ci	size_t res_len;
744e5b75505Sopenharmony_ci	int ret;
745e5b75505Sopenharmony_ci	struct milenage_parameters *m;
746e5b75505Sopenharmony_ci	int failed = 0;
747e5b75505Sopenharmony_ci
748e5b75505Sopenharmony_ci	m = get_milenage(imsi);
749e5b75505Sopenharmony_ci	if (m) {
750e5b75505Sopenharmony_ci		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
751e5b75505Sopenharmony_ci			return -1;
752e5b75505Sopenharmony_ci		res_len = EAP_AKA_RES_MAX_LEN;
753e5b75505Sopenharmony_ci		inc_sqn(m->sqn);
754e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
755e5b75505Sopenharmony_ci		db_update_milenage_sqn(m);
756e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
757e5b75505Sopenharmony_ci		sqn_changes = 1;
758e5b75505Sopenharmony_ci		if (stdout_debug) {
759e5b75505Sopenharmony_ci			printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
760e5b75505Sopenharmony_ci			       m->sqn[0], m->sqn[1], m->sqn[2],
761e5b75505Sopenharmony_ci			       m->sqn[3], m->sqn[4], m->sqn[5]);
762e5b75505Sopenharmony_ci		}
763e5b75505Sopenharmony_ci		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
764e5b75505Sopenharmony_ci				  autn, ik, ck, res, &res_len);
765e5b75505Sopenharmony_ci		if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
766e5b75505Sopenharmony_ci		    m->res_len <= EAP_AKA_RES_MAX_LEN &&
767e5b75505Sopenharmony_ci		    m->res_len < res_len)
768e5b75505Sopenharmony_ci			res_len = m->res_len;
769e5b75505Sopenharmony_ci	} else {
770e5b75505Sopenharmony_ci		printf("Unknown IMSI: %s\n", imsi);
771e5b75505Sopenharmony_ci#ifdef AKA_USE_FIXED_TEST_VALUES
772e5b75505Sopenharmony_ci		printf("Using fixed test values for AKA\n");
773e5b75505Sopenharmony_ci		memset(_rand, '0', EAP_AKA_RAND_LEN);
774e5b75505Sopenharmony_ci		memset(autn, '1', EAP_AKA_AUTN_LEN);
775e5b75505Sopenharmony_ci		memset(ik, '3', EAP_AKA_IK_LEN);
776e5b75505Sopenharmony_ci		memset(ck, '4', EAP_AKA_CK_LEN);
777e5b75505Sopenharmony_ci		memset(res, '2', EAP_AKA_RES_MAX_LEN);
778e5b75505Sopenharmony_ci		res_len = EAP_AKA_RES_MAX_LEN;
779e5b75505Sopenharmony_ci#else /* AKA_USE_FIXED_TEST_VALUES */
780e5b75505Sopenharmony_ci		failed = 1;
781e5b75505Sopenharmony_ci#endif /* AKA_USE_FIXED_TEST_VALUES */
782e5b75505Sopenharmony_ci	}
783e5b75505Sopenharmony_ci
784e5b75505Sopenharmony_ci	pos = resp;
785e5b75505Sopenharmony_ci	end = resp + resp_len;
786e5b75505Sopenharmony_ci	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
787e5b75505Sopenharmony_ci	if (ret < 0 || ret >= end - pos)
788e5b75505Sopenharmony_ci		return -1;
789e5b75505Sopenharmony_ci	pos += ret;
790e5b75505Sopenharmony_ci	if (failed) {
791e5b75505Sopenharmony_ci		ret = snprintf(pos, end - pos, "FAILURE");
792e5b75505Sopenharmony_ci		if (ret < 0 || ret >= end - pos)
793e5b75505Sopenharmony_ci			return -1;
794e5b75505Sopenharmony_ci		pos += ret;
795e5b75505Sopenharmony_ci		return 0;
796e5b75505Sopenharmony_ci	}
797e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
798e5b75505Sopenharmony_ci	*pos++ = ' ';
799e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
800e5b75505Sopenharmony_ci	*pos++ = ' ';
801e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
802e5b75505Sopenharmony_ci	*pos++ = ' ';
803e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
804e5b75505Sopenharmony_ci	*pos++ = ' ';
805e5b75505Sopenharmony_ci	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
806e5b75505Sopenharmony_ci
807e5b75505Sopenharmony_ci	return 0;
808e5b75505Sopenharmony_ci}
809e5b75505Sopenharmony_ci
810e5b75505Sopenharmony_ci
811e5b75505Sopenharmony_cistatic int aka_auts(char *imsi, char *resp, size_t resp_len)
812e5b75505Sopenharmony_ci{
813e5b75505Sopenharmony_ci	char *auts, *__rand;
814e5b75505Sopenharmony_ci	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
815e5b75505Sopenharmony_ci	struct milenage_parameters *m;
816e5b75505Sopenharmony_ci
817e5b75505Sopenharmony_ci	resp[0] = '\0';
818e5b75505Sopenharmony_ci
819e5b75505Sopenharmony_ci	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
820e5b75505Sopenharmony_ci
821e5b75505Sopenharmony_ci	auts = strchr(imsi, ' ');
822e5b75505Sopenharmony_ci	if (auts == NULL)
823e5b75505Sopenharmony_ci		return -1;
824e5b75505Sopenharmony_ci	*auts++ = '\0';
825e5b75505Sopenharmony_ci
826e5b75505Sopenharmony_ci	__rand = strchr(auts, ' ');
827e5b75505Sopenharmony_ci	if (__rand == NULL)
828e5b75505Sopenharmony_ci		return -1;
829e5b75505Sopenharmony_ci	*__rand++ = '\0';
830e5b75505Sopenharmony_ci
831e5b75505Sopenharmony_ci	if (stdout_debug) {
832e5b75505Sopenharmony_ci		printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
833e5b75505Sopenharmony_ci		       imsi, auts, __rand);
834e5b75505Sopenharmony_ci	}
835e5b75505Sopenharmony_ci	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
836e5b75505Sopenharmony_ci	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
837e5b75505Sopenharmony_ci		printf("Could not parse AUTS/RAND\n");
838e5b75505Sopenharmony_ci		return -1;
839e5b75505Sopenharmony_ci	}
840e5b75505Sopenharmony_ci
841e5b75505Sopenharmony_ci	m = get_milenage(imsi);
842e5b75505Sopenharmony_ci	if (m == NULL) {
843e5b75505Sopenharmony_ci		printf("Unknown IMSI: %s\n", imsi);
844e5b75505Sopenharmony_ci		return -1;
845e5b75505Sopenharmony_ci	}
846e5b75505Sopenharmony_ci
847e5b75505Sopenharmony_ci	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
848e5b75505Sopenharmony_ci		printf("AKA-AUTS: Incorrect MAC-S\n");
849e5b75505Sopenharmony_ci	} else {
850e5b75505Sopenharmony_ci		memcpy(m->sqn, sqn, 6);
851e5b75505Sopenharmony_ci		if (stdout_debug) {
852e5b75505Sopenharmony_ci			printf("AKA-AUTS: Re-synchronized: "
853e5b75505Sopenharmony_ci			       "SQN=%02x%02x%02x%02x%02x%02x\n",
854e5b75505Sopenharmony_ci			       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
855e5b75505Sopenharmony_ci		}
856e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
857e5b75505Sopenharmony_ci		db_update_milenage_sqn(m);
858e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
859e5b75505Sopenharmony_ci		sqn_changes = 1;
860e5b75505Sopenharmony_ci	}
861e5b75505Sopenharmony_ci
862e5b75505Sopenharmony_ci	return 0;
863e5b75505Sopenharmony_ci}
864e5b75505Sopenharmony_ci
865e5b75505Sopenharmony_ci
866e5b75505Sopenharmony_cistatic int process_cmd(char *cmd, char *resp, size_t resp_len)
867e5b75505Sopenharmony_ci{
868e5b75505Sopenharmony_ci	if (os_strncmp(cmd, "SIM-REQ-AUTH ", 13) == 0)
869e5b75505Sopenharmony_ci		return sim_req_auth(cmd + 13, resp, resp_len);
870e5b75505Sopenharmony_ci
871e5b75505Sopenharmony_ci	if (os_strncmp(cmd, "GSM-AUTH-REQ ", 13) == 0)
872e5b75505Sopenharmony_ci		return gsm_auth_req(cmd + 13, resp, resp_len);
873e5b75505Sopenharmony_ci
874e5b75505Sopenharmony_ci	if (os_strncmp(cmd, "AKA-REQ-AUTH ", 13) == 0)
875e5b75505Sopenharmony_ci		return aka_req_auth(cmd + 13, resp, resp_len);
876e5b75505Sopenharmony_ci
877e5b75505Sopenharmony_ci	if (os_strncmp(cmd, "AKA-AUTS ", 9) == 0)
878e5b75505Sopenharmony_ci		return aka_auts(cmd + 9, resp, resp_len);
879e5b75505Sopenharmony_ci
880e5b75505Sopenharmony_ci	printf("Unknown request: %s\n", cmd);
881e5b75505Sopenharmony_ci	return -1;
882e5b75505Sopenharmony_ci}
883e5b75505Sopenharmony_ci
884e5b75505Sopenharmony_ci
885e5b75505Sopenharmony_cistatic int process(int s)
886e5b75505Sopenharmony_ci{
887e5b75505Sopenharmony_ci	char buf[1000], resp[1000];
888e5b75505Sopenharmony_ci	struct sockaddr_un from;
889e5b75505Sopenharmony_ci	socklen_t fromlen;
890e5b75505Sopenharmony_ci	ssize_t res;
891e5b75505Sopenharmony_ci
892e5b75505Sopenharmony_ci	fromlen = sizeof(from);
893e5b75505Sopenharmony_ci	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
894e5b75505Sopenharmony_ci		       &fromlen);
895e5b75505Sopenharmony_ci	if (res < 0) {
896e5b75505Sopenharmony_ci		perror("recvfrom");
897e5b75505Sopenharmony_ci		return -1;
898e5b75505Sopenharmony_ci	}
899e5b75505Sopenharmony_ci
900e5b75505Sopenharmony_ci	if (res == 0)
901e5b75505Sopenharmony_ci		return 0;
902e5b75505Sopenharmony_ci
903e5b75505Sopenharmony_ci	if ((size_t) res >= sizeof(buf))
904e5b75505Sopenharmony_ci		res = sizeof(buf) - 1;
905e5b75505Sopenharmony_ci	buf[res] = '\0';
906e5b75505Sopenharmony_ci
907e5b75505Sopenharmony_ci	printf("Received: %s\n", buf);
908e5b75505Sopenharmony_ci
909e5b75505Sopenharmony_ci	if (process_cmd(buf, resp, sizeof(resp)) < 0) {
910e5b75505Sopenharmony_ci		printf("Failed to process request\n");
911e5b75505Sopenharmony_ci		return -1;
912e5b75505Sopenharmony_ci	}
913e5b75505Sopenharmony_ci
914e5b75505Sopenharmony_ci	if (resp[0] == '\0') {
915e5b75505Sopenharmony_ci		printf("No response\n");
916e5b75505Sopenharmony_ci		return 0;
917e5b75505Sopenharmony_ci	}
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_ci	printf("Send: %s\n", resp);
920e5b75505Sopenharmony_ci
921e5b75505Sopenharmony_ci	if (sendto(s, resp, os_strlen(resp), 0, (struct sockaddr *) &from,
922e5b75505Sopenharmony_ci		   fromlen) < 0)
923e5b75505Sopenharmony_ci		perror("send");
924e5b75505Sopenharmony_ci
925e5b75505Sopenharmony_ci	return 0;
926e5b75505Sopenharmony_ci}
927e5b75505Sopenharmony_ci
928e5b75505Sopenharmony_ci
929e5b75505Sopenharmony_cistatic void cleanup(void)
930e5b75505Sopenharmony_ci{
931e5b75505Sopenharmony_ci	struct gsm_triplet *g, *gprev;
932e5b75505Sopenharmony_ci	struct milenage_parameters *m, *prev;
933e5b75505Sopenharmony_ci
934e5b75505Sopenharmony_ci	if (update_milenage && milenage_file && sqn_changes)
935e5b75505Sopenharmony_ci		update_milenage_file(milenage_file);
936e5b75505Sopenharmony_ci
937e5b75505Sopenharmony_ci	g = gsm_db;
938e5b75505Sopenharmony_ci	while (g) {
939e5b75505Sopenharmony_ci		gprev = g;
940e5b75505Sopenharmony_ci		g = g->next;
941e5b75505Sopenharmony_ci		os_free(gprev);
942e5b75505Sopenharmony_ci	}
943e5b75505Sopenharmony_ci
944e5b75505Sopenharmony_ci	m = milenage_db;
945e5b75505Sopenharmony_ci	while (m) {
946e5b75505Sopenharmony_ci		prev = m;
947e5b75505Sopenharmony_ci		m = m->next;
948e5b75505Sopenharmony_ci		os_free(prev);
949e5b75505Sopenharmony_ci	}
950e5b75505Sopenharmony_ci
951e5b75505Sopenharmony_ci	if (serv_sock >= 0)
952e5b75505Sopenharmony_ci		close(serv_sock);
953e5b75505Sopenharmony_ci	if (socket_path)
954e5b75505Sopenharmony_ci		unlink(socket_path);
955e5b75505Sopenharmony_ci
956e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
957e5b75505Sopenharmony_ci	if (sqlite_db) {
958e5b75505Sopenharmony_ci		sqlite3_close(sqlite_db);
959e5b75505Sopenharmony_ci		sqlite_db = NULL;
960e5b75505Sopenharmony_ci	}
961e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
962e5b75505Sopenharmony_ci}
963e5b75505Sopenharmony_ci
964e5b75505Sopenharmony_ci
965e5b75505Sopenharmony_cistatic void handle_term(int sig)
966e5b75505Sopenharmony_ci{
967e5b75505Sopenharmony_ci	printf("Signal %d - terminate\n", sig);
968e5b75505Sopenharmony_ci	exit(0);
969e5b75505Sopenharmony_ci}
970e5b75505Sopenharmony_ci
971e5b75505Sopenharmony_ci
972e5b75505Sopenharmony_cistatic void usage(void)
973e5b75505Sopenharmony_ci{
974e5b75505Sopenharmony_ci	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
975e5b75505Sopenharmony_ci	       "database/authenticator\n"
976e5b75505Sopenharmony_ci	       "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
977e5b75505Sopenharmony_ci	       "\n"
978e5b75505Sopenharmony_ci	       "usage:\n"
979e5b75505Sopenharmony_ci	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
980e5b75505Sopenharmony_ci	       "[-m<milenage file>] \\\n"
981e5b75505Sopenharmony_ci	       "        [-D<DB file>] [-i<IND len in bits>] [command]\n"
982e5b75505Sopenharmony_ci	       "\n"
983e5b75505Sopenharmony_ci	       "options:\n"
984e5b75505Sopenharmony_ci	       "  -h = show this usage help\n"
985e5b75505Sopenharmony_ci	       "  -u = update SQN in Milenage file on exit\n"
986e5b75505Sopenharmony_ci	       "  -s<socket path> = path for UNIX domain socket\n"
987e5b75505Sopenharmony_ci	       "                    (default: %s)\n"
988e5b75505Sopenharmony_ci	       "  -g<triplet file> = path for GSM authentication triplets\n"
989e5b75505Sopenharmony_ci	       "  -m<milenage file> = path for Milenage keys\n"
990e5b75505Sopenharmony_ci	       "  -D<DB file> = path to SQLite database\n"
991e5b75505Sopenharmony_ci	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n"
992e5b75505Sopenharmony_ci	       "\n"
993e5b75505Sopenharmony_ci	       "If the optional command argument, like "
994e5b75505Sopenharmony_ci	       "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
995e5b75505Sopenharmony_ci	       "command is processed with response sent to stdout. Otherwise, "
996e5b75505Sopenharmony_ci	       "hlr_auc_gw opens\n"
997e5b75505Sopenharmony_ci	       "a control interface and processes commands sent through it "
998e5b75505Sopenharmony_ci	       "(e.g., by EAP server\n"
999e5b75505Sopenharmony_ci	       "in hostapd).\n",
1000e5b75505Sopenharmony_ci	       default_socket_path);
1001e5b75505Sopenharmony_ci}
1002e5b75505Sopenharmony_ci
1003e5b75505Sopenharmony_ci
1004e5b75505Sopenharmony_ciint main(int argc, char *argv[])
1005e5b75505Sopenharmony_ci{
1006e5b75505Sopenharmony_ci	int c;
1007e5b75505Sopenharmony_ci	char *gsm_triplet_file = NULL;
1008e5b75505Sopenharmony_ci	char *sqlite_db_file = NULL;
1009e5b75505Sopenharmony_ci	int ret = 0;
1010e5b75505Sopenharmony_ci
1011e5b75505Sopenharmony_ci	if (os_program_init())
1012e5b75505Sopenharmony_ci		return -1;
1013e5b75505Sopenharmony_ci
1014e5b75505Sopenharmony_ci	socket_path = default_socket_path;
1015e5b75505Sopenharmony_ci
1016e5b75505Sopenharmony_ci	for (;;) {
1017e5b75505Sopenharmony_ci		c = getopt(argc, argv, "D:g:hi:m:s:u");
1018e5b75505Sopenharmony_ci		if (c < 0)
1019e5b75505Sopenharmony_ci			break;
1020e5b75505Sopenharmony_ci		switch (c) {
1021e5b75505Sopenharmony_ci		case 'D':
1022e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
1023e5b75505Sopenharmony_ci			sqlite_db_file = optarg;
1024e5b75505Sopenharmony_ci			break;
1025e5b75505Sopenharmony_ci#else /* CONFIG_SQLITE */
1026e5b75505Sopenharmony_ci			printf("No SQLite support included in the build\n");
1027e5b75505Sopenharmony_ci			return -1;
1028e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
1029e5b75505Sopenharmony_ci		case 'g':
1030e5b75505Sopenharmony_ci			gsm_triplet_file = optarg;
1031e5b75505Sopenharmony_ci			break;
1032e5b75505Sopenharmony_ci		case 'h':
1033e5b75505Sopenharmony_ci			usage();
1034e5b75505Sopenharmony_ci			return 0;
1035e5b75505Sopenharmony_ci		case 'i':
1036e5b75505Sopenharmony_ci			ind_len = atoi(optarg);
1037e5b75505Sopenharmony_ci			if (ind_len < 0 || ind_len > 32) {
1038e5b75505Sopenharmony_ci				printf("Invalid IND length\n");
1039e5b75505Sopenharmony_ci				return -1;
1040e5b75505Sopenharmony_ci			}
1041e5b75505Sopenharmony_ci			break;
1042e5b75505Sopenharmony_ci		case 'm':
1043e5b75505Sopenharmony_ci			milenage_file = optarg;
1044e5b75505Sopenharmony_ci			break;
1045e5b75505Sopenharmony_ci		case 's':
1046e5b75505Sopenharmony_ci			socket_path = optarg;
1047e5b75505Sopenharmony_ci			break;
1048e5b75505Sopenharmony_ci		case 'u':
1049e5b75505Sopenharmony_ci			update_milenage = 1;
1050e5b75505Sopenharmony_ci			break;
1051e5b75505Sopenharmony_ci		default:
1052e5b75505Sopenharmony_ci			usage();
1053e5b75505Sopenharmony_ci			return -1;
1054e5b75505Sopenharmony_ci		}
1055e5b75505Sopenharmony_ci	}
1056e5b75505Sopenharmony_ci
1057e5b75505Sopenharmony_ci	if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
1058e5b75505Sopenharmony_ci		usage();
1059e5b75505Sopenharmony_ci		return -1;
1060e5b75505Sopenharmony_ci	}
1061e5b75505Sopenharmony_ci
1062e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
1063e5b75505Sopenharmony_ci	if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
1064e5b75505Sopenharmony_ci		return -1;
1065e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
1066e5b75505Sopenharmony_ci
1067e5b75505Sopenharmony_ci	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
1068e5b75505Sopenharmony_ci		return -1;
1069e5b75505Sopenharmony_ci
1070e5b75505Sopenharmony_ci	if (milenage_file && read_milenage(milenage_file) < 0)
1071e5b75505Sopenharmony_ci		return -1;
1072e5b75505Sopenharmony_ci
1073e5b75505Sopenharmony_ci	if (optind == argc) {
1074e5b75505Sopenharmony_ci		serv_sock = open_socket(socket_path);
1075e5b75505Sopenharmony_ci		if (serv_sock < 0)
1076e5b75505Sopenharmony_ci			return -1;
1077e5b75505Sopenharmony_ci
1078e5b75505Sopenharmony_ci		printf("Listening for requests on %s\n", socket_path);
1079e5b75505Sopenharmony_ci
1080e5b75505Sopenharmony_ci		atexit(cleanup);
1081e5b75505Sopenharmony_ci		signal(SIGTERM, handle_term);
1082e5b75505Sopenharmony_ci		signal(SIGINT, handle_term);
1083e5b75505Sopenharmony_ci
1084e5b75505Sopenharmony_ci		for (;;)
1085e5b75505Sopenharmony_ci			process(serv_sock);
1086e5b75505Sopenharmony_ci	} else {
1087e5b75505Sopenharmony_ci		char buf[1000];
1088e5b75505Sopenharmony_ci		socket_path = NULL;
1089e5b75505Sopenharmony_ci		stdout_debug = 0;
1090e5b75505Sopenharmony_ci		if (process_cmd(argv[optind], buf, sizeof(buf)) < 0) {
1091e5b75505Sopenharmony_ci			printf("FAIL\n");
1092e5b75505Sopenharmony_ci			ret = -1;
1093e5b75505Sopenharmony_ci		} else {
1094e5b75505Sopenharmony_ci			printf("%s\n", buf);
1095e5b75505Sopenharmony_ci		}
1096e5b75505Sopenharmony_ci		cleanup();
1097e5b75505Sopenharmony_ci	}
1098e5b75505Sopenharmony_ci
1099e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE
1100e5b75505Sopenharmony_ci	if (sqlite_db) {
1101e5b75505Sopenharmony_ci		sqlite3_close(sqlite_db);
1102e5b75505Sopenharmony_ci		sqlite_db = NULL;
1103e5b75505Sopenharmony_ci	}
1104e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */
1105e5b75505Sopenharmony_ci
1106e5b75505Sopenharmony_ci	os_program_deinit();
1107e5b75505Sopenharmony_ci
1108e5b75505Sopenharmony_ci	return ret;
1109e5b75505Sopenharmony_ci}
1110