Home | History | Annotate | Line # | Download | only in hostapd
hlr_auc_gw.c revision 1.1.1.3
      1 /*
      2  * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
      3  * Copyright (c) 2005-2007, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  *
     14  * This is an example implementation of the EAP-SIM/AKA database/authentication
     15  * gateway interface to HLR/AuC. It is expected to be replaced with an
     16  * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
     17  * a local implementation of SIM triplet and AKA authentication data generator.
     18  *
     19  * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
     20  * to and external program, e.g., this hlr_auc_gw. This interface uses simple
     21  * text-based format:
     22  *
     23  * EAP-SIM / GSM triplet query/response:
     24  * SIM-REQ-AUTH <IMSI> <max_chal>
     25  * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
     26  * SIM-RESP-AUTH <IMSI> FAILURE
     27  *
     28  * EAP-AKA / UMTS query/response:
     29  * AKA-REQ-AUTH <IMSI>
     30  * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
     31  * AKA-RESP-AUTH <IMSI> FAILURE
     32  *
     33  * EAP-AKA / UMTS AUTS (re-synchronization):
     34  * AKA-AUTS <IMSI> <AUTS> <RAND>
     35  *
     36  * IMSI and max_chal are sent as an ASCII string,
     37  * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
     38  *
     39  * The example implementation here reads GSM authentication triplets from a
     40  * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
     41  * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
     42  * for real life authentication, but it is useful both as an example
     43  * implementation and for EAP-SIM/AKA/AKA' testing.
     44  *
     45  * SQN generation follows the not time-based Profile 2 described in
     46  * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
     47  * can be changed with a command line options if needed.
     48  */
     49 
     50 #include "includes.h"
     51 #include <sys/un.h>
     52 
     53 #include "common.h"
     54 #include "crypto/milenage.h"
     55 #include "crypto/random.h"
     56 
     57 static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
     58 static const char *socket_path;
     59 static int serv_sock = -1;
     60 static int ind_len = 5;
     61 
     62 /* GSM triplets */
     63 struct gsm_triplet {
     64 	struct gsm_triplet *next;
     65 	char imsi[20];
     66 	u8 kc[8];
     67 	u8 sres[4];
     68 	u8 _rand[16];
     69 };
     70 
     71 static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
     72 
     73 /* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
     74 struct milenage_parameters {
     75 	struct milenage_parameters *next;
     76 	char imsi[20];
     77 	u8 ki[16];
     78 	u8 opc[16];
     79 	u8 amf[2];
     80 	u8 sqn[6];
     81 };
     82 
     83 static struct milenage_parameters *milenage_db = NULL;
     84 
     85 #define EAP_SIM_MAX_CHAL 3
     86 
     87 #define EAP_AKA_RAND_LEN 16
     88 #define EAP_AKA_AUTN_LEN 16
     89 #define EAP_AKA_AUTS_LEN 14
     90 #define EAP_AKA_RES_MAX_LEN 16
     91 #define EAP_AKA_IK_LEN 16
     92 #define EAP_AKA_CK_LEN 16
     93 
     94 
     95 static int open_socket(const char *path)
     96 {
     97 	struct sockaddr_un addr;
     98 	int s;
     99 
    100 	s = socket(PF_UNIX, SOCK_DGRAM, 0);
    101 	if (s < 0) {
    102 		perror("socket(PF_UNIX)");
    103 		return -1;
    104 	}
    105 
    106 	memset(&addr, 0, sizeof(addr));
    107 	addr.sun_family = AF_UNIX;
    108 	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
    109 	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    110 		perror("bind(PF_UNIX)");
    111 		close(s);
    112 		return -1;
    113 	}
    114 
    115 	return s;
    116 }
    117 
    118 
    119 static int read_gsm_triplets(const char *fname)
    120 {
    121 	FILE *f;
    122 	char buf[200], *pos, *pos2;
    123 	struct gsm_triplet *g = NULL;
    124 	int line, ret = 0;
    125 
    126 	if (fname == NULL)
    127 		return -1;
    128 
    129 	f = fopen(fname, "r");
    130 	if (f == NULL) {
    131 		printf("Could not open GSM tripler data file '%s'\n", fname);
    132 		return -1;
    133 	}
    134 
    135 	line = 0;
    136 	while (fgets(buf, sizeof(buf), f)) {
    137 		line++;
    138 
    139 		/* Parse IMSI:Kc:SRES:RAND */
    140 		buf[sizeof(buf) - 1] = '\0';
    141 		if (buf[0] == '#')
    142 			continue;
    143 		pos = buf;
    144 		while (*pos != '\0' && *pos != '\n')
    145 			pos++;
    146 		if (*pos == '\n')
    147 			*pos = '\0';
    148 		pos = buf;
    149 		if (*pos == '\0')
    150 			continue;
    151 
    152 		g = os_zalloc(sizeof(*g));
    153 		if (g == NULL) {
    154 			ret = -1;
    155 			break;
    156 		}
    157 
    158 		/* IMSI */
    159 		pos2 = strchr(pos, ':');
    160 		if (pos2 == NULL) {
    161 			printf("%s:%d - Invalid IMSI (%s)\n",
    162 			       fname, line, pos);
    163 			ret = -1;
    164 			break;
    165 		}
    166 		*pos2 = '\0';
    167 		if (strlen(pos) >= sizeof(g->imsi)) {
    168 			printf("%s:%d - Too long IMSI (%s)\n",
    169 			       fname, line, pos);
    170 			ret = -1;
    171 			break;
    172 		}
    173 		os_strlcpy(g->imsi, pos, sizeof(g->imsi));
    174 		pos = pos2 + 1;
    175 
    176 		/* Kc */
    177 		pos2 = strchr(pos, ':');
    178 		if (pos2 == NULL) {
    179 			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
    180 			ret = -1;
    181 			break;
    182 		}
    183 		*pos2 = '\0';
    184 		if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
    185 			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
    186 			ret = -1;
    187 			break;
    188 		}
    189 		pos = pos2 + 1;
    190 
    191 		/* SRES */
    192 		pos2 = strchr(pos, ':');
    193 		if (pos2 == NULL) {
    194 			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
    195 			       pos);
    196 			ret = -1;
    197 			break;
    198 		}
    199 		*pos2 = '\0';
    200 		if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
    201 			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
    202 			       pos);
    203 			ret = -1;
    204 			break;
    205 		}
    206 		pos = pos2 + 1;
    207 
    208 		/* RAND */
    209 		pos2 = strchr(pos, ':');
    210 		if (pos2)
    211 			*pos2 = '\0';
    212 		if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
    213 			printf("%s:%d - Invalid RAND (%s)\n", fname, line,
    214 			       pos);
    215 			ret = -1;
    216 			break;
    217 		}
    218 		pos = pos2 + 1;
    219 
    220 		g->next = gsm_db;
    221 		gsm_db = g;
    222 		g = NULL;
    223 	}
    224 	free(g);
    225 
    226 	fclose(f);
    227 
    228 	return ret;
    229 }
    230 
    231 
    232 static struct gsm_triplet * get_gsm_triplet(const char *imsi)
    233 {
    234 	struct gsm_triplet *g = gsm_db_pos;
    235 
    236 	while (g) {
    237 		if (strcmp(g->imsi, imsi) == 0) {
    238 			gsm_db_pos = g->next;
    239 			return g;
    240 		}
    241 		g = g->next;
    242 	}
    243 
    244 	g = gsm_db;
    245 	while (g && g != gsm_db_pos) {
    246 		if (strcmp(g->imsi, imsi) == 0) {
    247 			gsm_db_pos = g->next;
    248 			return g;
    249 		}
    250 		g = g->next;
    251 	}
    252 
    253 	return NULL;
    254 }
    255 
    256 
    257 static int read_milenage(const char *fname)
    258 {
    259 	FILE *f;
    260 	char buf[200], *pos, *pos2;
    261 	struct milenage_parameters *m = NULL;
    262 	int line, ret = 0;
    263 
    264 	if (fname == NULL)
    265 		return -1;
    266 
    267 	f = fopen(fname, "r");
    268 	if (f == NULL) {
    269 		printf("Could not open Milenage data file '%s'\n", fname);
    270 		return -1;
    271 	}
    272 
    273 	line = 0;
    274 	while (fgets(buf, sizeof(buf), f)) {
    275 		line++;
    276 
    277 		/* Parse IMSI Ki OPc AMF SQN */
    278 		buf[sizeof(buf) - 1] = '\0';
    279 		if (buf[0] == '#')
    280 			continue;
    281 		pos = buf;
    282 		while (*pos != '\0' && *pos != '\n')
    283 			pos++;
    284 		if (*pos == '\n')
    285 			*pos = '\0';
    286 		pos = buf;
    287 		if (*pos == '\0')
    288 			continue;
    289 
    290 		m = os_zalloc(sizeof(*m));
    291 		if (m == NULL) {
    292 			ret = -1;
    293 			break;
    294 		}
    295 
    296 		/* IMSI */
    297 		pos2 = strchr(pos, ' ');
    298 		if (pos2 == NULL) {
    299 			printf("%s:%d - Invalid IMSI (%s)\n",
    300 			       fname, line, pos);
    301 			ret = -1;
    302 			break;
    303 		}
    304 		*pos2 = '\0';
    305 		if (strlen(pos) >= sizeof(m->imsi)) {
    306 			printf("%s:%d - Too long IMSI (%s)\n",
    307 			       fname, line, pos);
    308 			ret = -1;
    309 			break;
    310 		}
    311 		os_strlcpy(m->imsi, pos, sizeof(m->imsi));
    312 		pos = pos2 + 1;
    313 
    314 		/* Ki */
    315 		pos2 = strchr(pos, ' ');
    316 		if (pos2 == NULL) {
    317 			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
    318 			ret = -1;
    319 			break;
    320 		}
    321 		*pos2 = '\0';
    322 		if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
    323 			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
    324 			ret = -1;
    325 			break;
    326 		}
    327 		pos = pos2 + 1;
    328 
    329 		/* OPc */
    330 		pos2 = strchr(pos, ' ');
    331 		if (pos2 == NULL) {
    332 			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
    333 			ret = -1;
    334 			break;
    335 		}
    336 		*pos2 = '\0';
    337 		if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
    338 			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
    339 			ret = -1;
    340 			break;
    341 		}
    342 		pos = pos2 + 1;
    343 
    344 		/* AMF */
    345 		pos2 = strchr(pos, ' ');
    346 		if (pos2 == NULL) {
    347 			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
    348 			ret = -1;
    349 			break;
    350 		}
    351 		*pos2 = '\0';
    352 		if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
    353 			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
    354 			ret = -1;
    355 			break;
    356 		}
    357 		pos = pos2 + 1;
    358 
    359 		/* SQN */
    360 		pos2 = strchr(pos, ' ');
    361 		if (pos2)
    362 			*pos2 = '\0';
    363 		if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
    364 			printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
    365 			ret = -1;
    366 			break;
    367 		}
    368 		pos = pos2 + 1;
    369 
    370 		m->next = milenage_db;
    371 		milenage_db = m;
    372 		m = NULL;
    373 	}
    374 	free(m);
    375 
    376 	fclose(f);
    377 
    378 	return ret;
    379 }
    380 
    381 
    382 static struct milenage_parameters * get_milenage(const char *imsi)
    383 {
    384 	struct milenage_parameters *m = milenage_db;
    385 
    386 	while (m) {
    387 		if (strcmp(m->imsi, imsi) == 0)
    388 			break;
    389 		m = m->next;
    390 	}
    391 
    392 	return m;
    393 }
    394 
    395 
    396 static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
    397 			 char *imsi)
    398 {
    399 	int count, max_chal, ret;
    400 	char *pos;
    401 	char reply[1000], *rpos, *rend;
    402 	struct milenage_parameters *m;
    403 	struct gsm_triplet *g;
    404 
    405 	reply[0] = '\0';
    406 
    407 	pos = strchr(imsi, ' ');
    408 	if (pos) {
    409 		*pos++ = '\0';
    410 		max_chal = atoi(pos);
    411 		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
    412 			max_chal = EAP_SIM_MAX_CHAL;
    413 	} else
    414 		max_chal = EAP_SIM_MAX_CHAL;
    415 
    416 	rend = &reply[sizeof(reply)];
    417 	rpos = reply;
    418 	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
    419 	if (ret < 0 || ret >= rend - rpos)
    420 		return;
    421 	rpos += ret;
    422 
    423 	m = get_milenage(imsi);
    424 	if (m) {
    425 		u8 _rand[16], sres[4], kc[8];
    426 		for (count = 0; count < max_chal; count++) {
    427 			if (random_get_bytes(_rand, 16) < 0)
    428 				return;
    429 			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
    430 			*rpos++ = ' ';
    431 			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
    432 			*rpos++ = ':';
    433 			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
    434 			*rpos++ = ':';
    435 			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
    436 		}
    437 		*rpos = '\0';
    438 		goto send;
    439 	}
    440 
    441 	count = 0;
    442 	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
    443 		if (strcmp(g->imsi, imsi) != 0)
    444 			continue;
    445 
    446 		if (rpos < rend)
    447 			*rpos++ = ' ';
    448 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
    449 		if (rpos < rend)
    450 			*rpos++ = ':';
    451 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
    452 		if (rpos < rend)
    453 			*rpos++ = ':';
    454 		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
    455 		count++;
    456 	}
    457 
    458 	if (count == 0) {
    459 		printf("No GSM triplets found for %s\n", imsi);
    460 		ret = snprintf(rpos, rend - rpos, " FAILURE");
    461 		if (ret < 0 || ret >= rend - rpos)
    462 			return;
    463 		rpos += ret;
    464 	}
    465 
    466 send:
    467 	printf("Send: %s\n", reply);
    468 	if (sendto(s, reply, rpos - reply, 0,
    469 		   (struct sockaddr *) from, fromlen) < 0)
    470 		perror("send");
    471 }
    472 
    473 
    474 static void inc_sqn(u8 *sqn)
    475 {
    476 	u64 val, seq, ind;
    477 
    478 	/*
    479 	 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
    480 	 *
    481 	 * The mechanism used here is not time-based, so SEQ2 is void and
    482 	 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
    483 	 * of SEQ1 is 48 - ind_len bits.
    484 	 */
    485 
    486 	/* Increment both SEQ and IND by one */
    487 	val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
    488 	seq = (val >> ind_len) + 1;
    489 	ind = (val + 1) & ((1 << ind_len) - 1);
    490 	val = (seq << ind_len) | ind;
    491 	WPA_PUT_BE32(sqn, val >> 16);
    492 	WPA_PUT_BE16(sqn + 4, val & 0xffff);
    493 }
    494 
    495 
    496 static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
    497 			 char *imsi)
    498 {
    499 	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
    500 	char reply[1000], *pos, *end;
    501 	u8 _rand[EAP_AKA_RAND_LEN];
    502 	u8 autn[EAP_AKA_AUTN_LEN];
    503 	u8 ik[EAP_AKA_IK_LEN];
    504 	u8 ck[EAP_AKA_CK_LEN];
    505 	u8 res[EAP_AKA_RES_MAX_LEN];
    506 	size_t res_len;
    507 	int ret;
    508 	struct milenage_parameters *m;
    509 
    510 	m = get_milenage(imsi);
    511 	if (m) {
    512 		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
    513 			return;
    514 		res_len = EAP_AKA_RES_MAX_LEN;
    515 		inc_sqn(m->sqn);
    516 		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
    517 		       m->sqn[0], m->sqn[1], m->sqn[2],
    518 		       m->sqn[3], m->sqn[4], m->sqn[5]);
    519 		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
    520 				  autn, ik, ck, res, &res_len);
    521 	} else {
    522 		printf("Unknown IMSI: %s\n", imsi);
    523 #ifdef AKA_USE_FIXED_TEST_VALUES
    524 		printf("Using fixed test values for AKA\n");
    525 		memset(_rand, '0', EAP_AKA_RAND_LEN);
    526 		memset(autn, '1', EAP_AKA_AUTN_LEN);
    527 		memset(ik, '3', EAP_AKA_IK_LEN);
    528 		memset(ck, '4', EAP_AKA_CK_LEN);
    529 		memset(res, '2', EAP_AKA_RES_MAX_LEN);
    530 		res_len = EAP_AKA_RES_MAX_LEN;
    531 #else /* AKA_USE_FIXED_TEST_VALUES */
    532 		return;
    533 #endif /* AKA_USE_FIXED_TEST_VALUES */
    534 	}
    535 
    536 	pos = reply;
    537 	end = &reply[sizeof(reply)];
    538 	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
    539 	if (ret < 0 || ret >= end - pos)
    540 		return;
    541 	pos += ret;
    542 	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
    543 	*pos++ = ' ';
    544 	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
    545 	*pos++ = ' ';
    546 	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
    547 	*pos++ = ' ';
    548 	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
    549 	*pos++ = ' ';
    550 	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
    551 
    552 	printf("Send: %s\n", reply);
    553 
    554 	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
    555 		   fromlen) < 0)
    556 		perror("send");
    557 }
    558 
    559 
    560 static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
    561 		     char *imsi)
    562 {
    563 	char *auts, *__rand;
    564 	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
    565 	struct milenage_parameters *m;
    566 
    567 	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
    568 
    569 	auts = strchr(imsi, ' ');
    570 	if (auts == NULL)
    571 		return;
    572 	*auts++ = '\0';
    573 
    574 	__rand = strchr(auts, ' ');
    575 	if (__rand == NULL)
    576 		return;
    577 	*__rand++ = '\0';
    578 
    579 	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
    580 	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
    581 	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
    582 		printf("Could not parse AUTS/RAND\n");
    583 		return;
    584 	}
    585 
    586 	m = get_milenage(imsi);
    587 	if (m == NULL) {
    588 		printf("Unknown IMSI: %s\n", imsi);
    589 		return;
    590 	}
    591 
    592 	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
    593 		printf("AKA-AUTS: Incorrect MAC-S\n");
    594 	} else {
    595 		memcpy(m->sqn, sqn, 6);
    596 		printf("AKA-AUTS: Re-synchronized: "
    597 		       "SQN=%02x%02x%02x%02x%02x%02x\n",
    598 		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
    599 	}
    600 }
    601 
    602 
    603 static int process(int s)
    604 {
    605 	char buf[1000];
    606 	struct sockaddr_un from;
    607 	socklen_t fromlen;
    608 	ssize_t res;
    609 
    610 	fromlen = sizeof(from);
    611 	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
    612 		       &fromlen);
    613 	if (res < 0) {
    614 		perror("recvfrom");
    615 		return -1;
    616 	}
    617 
    618 	if (res == 0)
    619 		return 0;
    620 
    621 	if ((size_t) res >= sizeof(buf))
    622 		res = sizeof(buf) - 1;
    623 	buf[res] = '\0';
    624 
    625 	printf("Received: %s\n", buf);
    626 
    627 	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
    628 		sim_req_auth(s, &from, fromlen, buf + 13);
    629 	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
    630 		aka_req_auth(s, &from, fromlen, buf + 13);
    631 	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
    632 		aka_auts(s, &from, fromlen, buf + 9);
    633 	else
    634 		printf("Unknown request: %s\n", buf);
    635 
    636 	return 0;
    637 }
    638 
    639 
    640 static void cleanup(void)
    641 {
    642 	struct gsm_triplet *g, *gprev;
    643 	struct milenage_parameters *m, *prev;
    644 
    645 	g = gsm_db;
    646 	while (g) {
    647 		gprev = g;
    648 		g = g->next;
    649 		free(gprev);
    650 	}
    651 
    652 	m = milenage_db;
    653 	while (m) {
    654 		prev = m;
    655 		m = m->next;
    656 		free(prev);
    657 	}
    658 
    659 	close(serv_sock);
    660 	unlink(socket_path);
    661 }
    662 
    663 
    664 static void handle_term(int sig)
    665 {
    666 	printf("Signal %d - terminate\n", sig);
    667 	exit(0);
    668 }
    669 
    670 
    671 static void usage(void)
    672 {
    673 	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
    674 	       "database/authenticator\n"
    675 	       "Copyright (c) 2005-2007, Jouni Malinen <j (at) w1.fi>\n"
    676 	       "\n"
    677 	       "usage:\n"
    678 	       "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
    679 	       "[-m<milenage file>] \\\n"
    680 	       "        [-i<IND len in bits>]\n"
    681 	       "\n"
    682 	       "options:\n"
    683 	       "  -h = show this usage help\n"
    684 	       "  -s<socket path> = path for UNIX domain socket\n"
    685 	       "                    (default: %s)\n"
    686 	       "  -g<triplet file> = path for GSM authentication triplets\n"
    687 	       "  -m<milenage file> = path for Milenage keys\n"
    688 	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
    689 	       default_socket_path);
    690 }
    691 
    692 
    693 int main(int argc, char *argv[])
    694 {
    695 	int c;
    696 	char *milenage_file = NULL;
    697 	char *gsm_triplet_file = NULL;
    698 
    699 	socket_path = default_socket_path;
    700 
    701 	for (;;) {
    702 		c = getopt(argc, argv, "g:hi:m:s:");
    703 		if (c < 0)
    704 			break;
    705 		switch (c) {
    706 		case 'g':
    707 			gsm_triplet_file = optarg;
    708 			break;
    709 		case 'h':
    710 			usage();
    711 			return 0;
    712 		case 'i':
    713 			ind_len = atoi(optarg);
    714 			if (ind_len < 0 || ind_len > 32) {
    715 				printf("Invalid IND length\n");
    716 				return -1;
    717 			}
    718 			break;
    719 		case 'm':
    720 			milenage_file = optarg;
    721 			break;
    722 		case 's':
    723 			socket_path = optarg;
    724 			break;
    725 		default:
    726 			usage();
    727 			return -1;
    728 		}
    729 	}
    730 
    731 	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
    732 		return -1;
    733 
    734 	if (milenage_file && read_milenage(milenage_file) < 0)
    735 		return -1;
    736 
    737 	serv_sock = open_socket(socket_path);
    738 	if (serv_sock < 0)
    739 		return -1;
    740 
    741 	printf("Listening for requests on %s\n", socket_path);
    742 
    743 	atexit(cleanup);
    744 	signal(SIGTERM, handle_term);
    745 	signal(SIGINT, handle_term);
    746 
    747 	for (;;)
    748 		process(serv_sock);
    749 
    750 	return 0;
    751 }
    752