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