2 * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
3 * Copyright (c) 2005-2007, 2012-2017, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
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.
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
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 * GSM-AUTH-REQ <IMSI> RAND1:RAND2[:RAND3]
22 * GSM-AUTH-RESP <IMSI> Kc1:SRES1:Kc2:SRES2[:Kc3:SRES3]
23 * GSM-AUTH-RESP <IMSI> FAILURE
25 * EAP-AKA / UMTS query/response:
27 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
28 * AKA-RESP-AUTH <IMSI> FAILURE
30 * EAP-AKA / UMTS AUTS (re-synchronization):
31 * AKA-AUTS <IMSI> <AUTS> <RAND>
33 * IMSI and max_chal are sent as an ASCII string,
34 * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
36 * An example implementation here reads GSM authentication triplets from a
37 * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
38 * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
39 * for real life authentication, but it is useful both as an example
40 * implementation and for EAP-SIM/AKA/AKA' testing.
42 * For a stronger example design, Milenage and GSM-Milenage algorithms can be
43 * used to dynamically generate authenticatipn information for EAP-AKA/AKA' and
44 * EAP-SIM, respectively, if Ki is known.
46 * SQN generation follows the not time-based Profile 2 described in
47 * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
48 * can be changed with a command line options if needed.
55 #endif /* CONFIG_SQLITE */
58 #include "crypto/milenage.h"
59 #include "crypto/random.h"
61 static const char *default_socket_path
= "/tmp/hlr_auc_gw.sock";
62 static const char *socket_path
;
63 static int serv_sock
= -1;
64 static char *milenage_file
= NULL
;
65 static int update_milenage
= 0;
66 static int sqn_changes
= 0;
67 static int ind_len
= 5;
68 static int stdout_debug
= 1;
72 struct gsm_triplet
*next
;
79 static struct gsm_triplet
*gsm_db
= NULL
, *gsm_db_pos
= NULL
;
81 /* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
82 struct milenage_parameters
{
83 struct milenage_parameters
*next
;
93 static struct milenage_parameters
*milenage_db
= NULL
;
95 #define EAP_SIM_MAX_CHAL 3
97 #define EAP_AKA_RAND_LEN 16
98 #define EAP_AKA_AUTN_LEN 16
99 #define EAP_AKA_AUTS_LEN 14
100 #define EAP_AKA_RES_MIN_LEN 4
101 #define EAP_AKA_RES_MAX_LEN 16
102 #define EAP_AKA_IK_LEN 16
103 #define EAP_AKA_CK_LEN 16
108 static sqlite3
*sqlite_db
= NULL
;
109 static struct milenage_parameters db_tmp_milenage
;
112 static int db_table_exists(sqlite3
*db
, const char *name
)
115 os_snprintf(cmd
, sizeof(cmd
), "SELECT 1 FROM %s;", name
);
116 return sqlite3_exec(db
, cmd
, NULL
, NULL
, NULL
) == SQLITE_OK
;
120 static int db_table_create_milenage(sqlite3
*db
)
124 "CREATE TABLE milenage("
125 " imsi INTEGER PRIMARY KEY NOT NULL,"
126 " ki CHAR(32) NOT NULL,"
127 " opc CHAR(32) NOT NULL,"
128 " amf CHAR(4) NOT NULL,"
129 " sqn CHAR(12) NOT NULL,"
133 printf("Adding database table for milenage information\n");
134 if (sqlite3_exec(db
, sql
, NULL
, NULL
, &err
) != SQLITE_OK
) {
135 printf("SQLite error: %s\n", err
);
144 static sqlite3
* db_open(const char *db_file
)
148 if (sqlite3_open(db_file
, &db
)) {
149 printf("Failed to open database %s: %s\n",
150 db_file
, sqlite3_errmsg(db
));
155 if (!db_table_exists(db
, "milenage") &&
156 db_table_create_milenage(db
) < 0) {
165 static int get_milenage_cb(void *ctx
, int argc
, char *argv
[], char *col
[])
167 struct milenage_parameters
*m
= ctx
;
172 for (i
= 0; i
< argc
; i
++) {
173 if (os_strcmp(col
[i
], "ki") == 0 && argv
[i
] &&
174 hexstr2bin(argv
[i
], m
->ki
, sizeof(m
->ki
))) {
175 printf("Invalid ki value in database\n");
179 if (os_strcmp(col
[i
], "opc") == 0 && argv
[i
] &&
180 hexstr2bin(argv
[i
], m
->opc
, sizeof(m
->opc
))) {
181 printf("Invalid opcvalue in database\n");
185 if (os_strcmp(col
[i
], "amf") == 0 && argv
[i
] &&
186 hexstr2bin(argv
[i
], m
->amf
, sizeof(m
->amf
))) {
187 printf("Invalid amf value in database\n");
191 if (os_strcmp(col
[i
], "sqn") == 0 && argv
[i
] &&
192 hexstr2bin(argv
[i
], m
->sqn
, sizeof(m
->sqn
))) {
193 printf("Invalid sqn value in database\n");
197 if (os_strcmp(col
[i
], "res_len") == 0 && argv
[i
]) {
198 m
->res_len
= atoi(argv
[i
]);
206 static struct milenage_parameters
* db_get_milenage(const char *imsi_txt
)
209 unsigned long long imsi
;
211 os_memset(&db_tmp_milenage
, 0, sizeof(db_tmp_milenage
));
212 imsi
= atoll(imsi_txt
);
213 os_snprintf(db_tmp_milenage
.imsi
, sizeof(db_tmp_milenage
.imsi
),
215 os_snprintf(cmd
, sizeof(cmd
),
216 "SELECT * FROM milenage WHERE imsi=%llu;", imsi
);
217 if (sqlite3_exec(sqlite_db
, cmd
, get_milenage_cb
, &db_tmp_milenage
,
221 if (!db_tmp_milenage
.set
)
223 return &db_tmp_milenage
;
227 static int db_update_milenage_sqn(struct milenage_parameters
*m
)
229 char cmd
[128], val
[13], *pos
;
231 if (sqlite_db
== NULL
)
235 pos
+= wpa_snprintf_hex(pos
, sizeof(val
), m
->sqn
, 6);
237 os_snprintf(cmd
, sizeof(cmd
),
238 "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
240 if (sqlite3_exec(sqlite_db
, cmd
, NULL
, NULL
, NULL
) != SQLITE_OK
) {
241 printf("Failed to update SQN in database for IMSI %s\n",
248 #endif /* CONFIG_SQLITE */
251 static int open_socket(const char *path
)
253 struct sockaddr_un addr
;
256 s
= socket(PF_UNIX
, SOCK_DGRAM
, 0);
258 perror("socket(PF_UNIX)");
262 memset(&addr
, 0, sizeof(addr
));
263 addr
.sun_family
= AF_UNIX
;
264 os_strlcpy(addr
.sun_path
, path
, sizeof(addr
.sun_path
));
265 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
266 perror("hlr-auc-gw: bind(PF_UNIX)");
275 static int read_gsm_triplets(const char *fname
)
278 char buf
[200], *pos
, *pos2
;
279 struct gsm_triplet
*g
= NULL
;
285 f
= fopen(fname
, "r");
287 printf("Could not open GSM triplet data file '%s'\n", fname
);
292 while (fgets(buf
, sizeof(buf
), f
)) {
295 /* Parse IMSI:Kc:SRES:RAND */
296 buf
[sizeof(buf
) - 1] = '\0';
300 while (*pos
!= '\0' && *pos
!= '\n')
308 g
= os_zalloc(sizeof(*g
));
316 pos
= str_token(buf
, ":", &pos2
);
317 if (!pos
|| os_strlen(pos
) >= sizeof(g
->imsi
)) {
318 printf("%s:%d - Invalid IMSI\n", fname
, line
);
322 os_strlcpy(g
->imsi
, pos
, sizeof(g
->imsi
));
325 pos
= str_token(buf
, ":", &pos2
);
326 if (!pos
|| os_strlen(pos
) != 16 || hexstr2bin(pos
, g
->kc
, 8)) {
327 printf("%s:%d - Invalid Kc\n", fname
, line
);
333 pos
= str_token(buf
, ":", &pos2
);
334 if (!pos
|| os_strlen(pos
) != 8 ||
335 hexstr2bin(pos
, g
->sres
, 4)) {
336 printf("%s:%d - Invalid SRES\n", fname
, line
);
342 pos
= str_token(buf
, ":", &pos2
);
343 if (!pos
|| os_strlen(pos
) != 32 ||
344 hexstr2bin(pos
, g
->_rand
, 16)) {
345 printf("%s:%d - Invalid RAND\n", fname
, line
);
362 static struct gsm_triplet
* get_gsm_triplet(const char *imsi
)
364 struct gsm_triplet
*g
= gsm_db_pos
;
367 if (strcmp(g
->imsi
, imsi
) == 0) {
368 gsm_db_pos
= g
->next
;
375 while (g
&& g
!= gsm_db_pos
) {
376 if (strcmp(g
->imsi
, imsi
) == 0) {
377 gsm_db_pos
= g
->next
;
387 static int read_milenage(const char *fname
)
390 char buf
[200], *pos
, *pos2
;
391 struct milenage_parameters
*m
= NULL
;
397 f
= fopen(fname
, "r");
399 printf("Could not open Milenage data file '%s'\n", fname
);
404 while (fgets(buf
, sizeof(buf
), f
)) {
407 /* Parse IMSI Ki OPc AMF SQN [RES_len] */
408 buf
[sizeof(buf
) - 1] = '\0';
412 while (*pos
!= '\0' && *pos
!= '\n')
420 m
= os_zalloc(sizeof(*m
));
428 pos
= str_token(buf
, " ", &pos2
);
429 if (!pos
|| os_strlen(pos
) >= sizeof(m
->imsi
)) {
430 printf("%s:%d - Invalid IMSI\n", fname
, line
);
434 os_strlcpy(m
->imsi
, pos
, sizeof(m
->imsi
));
437 pos
= str_token(buf
, " ", &pos2
);
438 if (!pos
|| os_strlen(pos
) != 32 ||
439 hexstr2bin(pos
, m
->ki
, 16)) {
440 printf("%s:%d - Invalid Ki\n", fname
, line
);
446 pos
= str_token(buf
, " ", &pos2
);
447 if (!pos
|| os_strlen(pos
) != 32 ||
448 hexstr2bin(pos
, m
->opc
, 16)) {
449 printf("%s:%d - Invalid OPc\n", fname
, line
);
455 pos
= str_token(buf
, " ", &pos2
);
456 if (!pos
|| os_strlen(pos
) != 4 || hexstr2bin(pos
, m
->amf
, 2)) {
457 printf("%s:%d - Invalid AMF\n", fname
, line
);
463 pos
= str_token(buf
, " ", &pos2
);
464 if (!pos
|| os_strlen(pos
) != 12 ||
465 hexstr2bin(pos
, m
->sqn
, 6)) {
466 printf("%s:%d - Invalid SEQ\n", fname
, line
);
471 pos
= str_token(buf
, " ", &pos2
);
473 m
->res_len
= atoi(pos
);
475 (m
->res_len
< EAP_AKA_RES_MIN_LEN
||
476 m
->res_len
> EAP_AKA_RES_MAX_LEN
)) {
477 printf("%s:%d - Invalid RES_len\n",
484 m
->next
= milenage_db
;
496 static void update_milenage_file(const char *fname
)
499 char name
[500], buf
[500], *pos
;
500 char *end
= buf
+ sizeof(buf
);
501 struct milenage_parameters
*m
;
504 f
= fopen(fname
, "r");
506 printf("Could not open Milenage data file '%s'\n", fname
);
510 snprintf(name
, sizeof(name
), "%s.new", fname
);
511 f2
= fopen(name
, "w");
513 printf("Could not write Milenage data file '%s'\n", name
);
518 while (fgets(buf
, sizeof(buf
), f
)) {
519 /* IMSI Ki OPc AMF SQN */
520 buf
[sizeof(buf
) - 1] = '\0';
522 pos
= strchr(buf
, ' ');
523 if (buf
[0] == '#' || pos
== NULL
|| pos
- buf
>= 20)
526 imsi_len
= pos
- buf
;
528 for (m
= milenage_db
; m
; m
= m
->next
) {
529 if (strncmp(buf
, m
->imsi
, imsi_len
) == 0 &&
530 m
->imsi
[imsi_len
] == '\0')
538 pos
+= snprintf(pos
, end
- pos
, "%s ", m
->imsi
);
539 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->ki
, 16);
541 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->opc
, 16);
543 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->amf
, 2);
545 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->sqn
, 6);
549 fprintf(f2
, "%s", buf
);
555 snprintf(name
, sizeof(name
), "%s.bak", fname
);
556 if (rename(fname
, name
) < 0) {
561 snprintf(name
, sizeof(name
), "%s.new", fname
);
562 if (rename(name
, fname
) < 0) {
570 static struct milenage_parameters
* get_milenage(const char *imsi
)
572 struct milenage_parameters
*m
= milenage_db
;
575 if (strcmp(m
->imsi
, imsi
) == 0)
582 m
= db_get_milenage(imsi
);
583 #endif /* CONFIG_SQLITE */
589 static int sim_req_auth(char *imsi
, char *resp
, size_t resp_len
)
591 int count
, max_chal
, ret
;
594 struct milenage_parameters
*m
;
595 struct gsm_triplet
*g
;
599 pos
= strchr(imsi
, ' ');
602 max_chal
= atoi(pos
);
603 if (max_chal
< 1 || max_chal
> EAP_SIM_MAX_CHAL
)
604 max_chal
= EAP_SIM_MAX_CHAL
;
606 max_chal
= EAP_SIM_MAX_CHAL
;
608 rend
= resp
+ resp_len
;
610 ret
= snprintf(rpos
, rend
- rpos
, "SIM-RESP-AUTH %s", imsi
);
611 if (ret
< 0 || ret
>= rend
- rpos
)
615 m
= get_milenage(imsi
);
617 u8 _rand
[16], sres
[4], kc
[8];
618 for (count
= 0; count
< max_chal
; count
++) {
619 if (random_get_bytes(_rand
, 16) < 0)
621 gsm_milenage(m
->opc
, m
->ki
, _rand
, sres
, kc
);
623 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, kc
, 8);
625 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, sres
, 4);
627 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, _rand
, 16);
634 while (count
< max_chal
&& (g
= get_gsm_triplet(imsi
))) {
635 if (strcmp(g
->imsi
, imsi
) != 0)
640 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->kc
, 8);
643 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->sres
, 4);
646 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->_rand
, 16);
651 printf("No GSM triplets found for %s\n", imsi
);
652 ret
= snprintf(rpos
, rend
- rpos
, " FAILURE");
653 if (ret
< 0 || ret
>= rend
- rpos
)
662 static int gsm_auth_req(char *imsi
, char *resp
, size_t resp_len
)
665 char *pos
, *rpos
, *rend
;
666 struct milenage_parameters
*m
;
670 pos
= os_strchr(imsi
, ' ');
675 rend
= resp
+ resp_len
;
677 ret
= os_snprintf(rpos
, rend
- rpos
, "GSM-AUTH-RESP %s", imsi
);
678 if (os_snprintf_error(rend
- rpos
, ret
))
682 m
= get_milenage(imsi
);
684 u8 _rand
[16], sres
[4], kc
[8];
685 for (count
= 0; count
< EAP_SIM_MAX_CHAL
; count
++) {
686 if (hexstr2bin(pos
, _rand
, 16) != 0)
688 gsm_milenage(m
->opc
, m
->ki
, _rand
, sres
, kc
);
689 *rpos
++ = count
== 0 ? ' ' : ':';
690 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, kc
, 8);
692 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, sres
, 4);
702 printf("No GSM triplets found for %s\n", imsi
);
703 ret
= os_snprintf(rpos
, rend
- rpos
, " FAILURE");
704 if (os_snprintf_error(rend
- rpos
, ret
))
712 static void inc_sqn(u8
*sqn
)
717 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
719 * The mechanism used here is not time-based, so SEQ2 is void and
720 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
721 * of SEQ1 is 48 - ind_len bits.
724 /* Increment both SEQ and IND by one */
725 val
= ((u64
) WPA_GET_BE32(sqn
) << 16) | ((u64
) WPA_GET_BE16(sqn
+ 4));
726 seq
= (val
>> ind_len
) + 1;
727 ind
= (val
+ 1) & ((1 << ind_len
) - 1);
728 val
= (seq
<< ind_len
) | ind
;
729 WPA_PUT_BE32(sqn
, val
>> 16);
730 WPA_PUT_BE16(sqn
+ 4, val
& 0xffff);
734 static int aka_req_auth(char *imsi
, char *resp
, size_t resp_len
)
736 /* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
738 u8 _rand
[EAP_AKA_RAND_LEN
];
739 u8 autn
[EAP_AKA_AUTN_LEN
];
740 u8 ik
[EAP_AKA_IK_LEN
];
741 u8 ck
[EAP_AKA_CK_LEN
];
742 u8 res
[EAP_AKA_RES_MAX_LEN
];
745 struct milenage_parameters
*m
;
748 m
= get_milenage(imsi
);
750 if (random_get_bytes(_rand
, EAP_AKA_RAND_LEN
) < 0)
752 res_len
= EAP_AKA_RES_MAX_LEN
;
755 db_update_milenage_sqn(m
);
756 #endif /* CONFIG_SQLITE */
759 printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
760 m
->sqn
[0], m
->sqn
[1], m
->sqn
[2],
761 m
->sqn
[3], m
->sqn
[4], m
->sqn
[5]);
763 milenage_generate(m
->opc
, m
->amf
, m
->ki
, m
->sqn
, _rand
,
764 autn
, ik
, ck
, res
, &res_len
);
765 if (m
->res_len
>= EAP_AKA_RES_MIN_LEN
&&
766 m
->res_len
<= EAP_AKA_RES_MAX_LEN
&&
767 m
->res_len
< res_len
)
768 res_len
= m
->res_len
;
770 printf("Unknown IMSI: %s\n", imsi
);
771 #ifdef AKA_USE_FIXED_TEST_VALUES
772 printf("Using fixed test values for AKA\n");
773 memset(_rand
, '0', EAP_AKA_RAND_LEN
);
774 memset(autn
, '1', EAP_AKA_AUTN_LEN
);
775 memset(ik
, '3', EAP_AKA_IK_LEN
);
776 memset(ck
, '4', EAP_AKA_CK_LEN
);
777 memset(res
, '2', EAP_AKA_RES_MAX_LEN
);
778 res_len
= EAP_AKA_RES_MAX_LEN
;
779 #else /* AKA_USE_FIXED_TEST_VALUES */
781 #endif /* AKA_USE_FIXED_TEST_VALUES */
785 end
= resp
+ resp_len
;
786 ret
= snprintf(pos
, end
- pos
, "AKA-RESP-AUTH %s ", imsi
);
787 if (ret
< 0 || ret
>= end
- pos
)
791 ret
= snprintf(pos
, end
- pos
, "FAILURE");
792 if (ret
< 0 || ret
>= end
- pos
)
797 pos
+= wpa_snprintf_hex(pos
, end
- pos
, _rand
, EAP_AKA_RAND_LEN
);
799 pos
+= wpa_snprintf_hex(pos
, end
- pos
, autn
, EAP_AKA_AUTN_LEN
);
801 pos
+= wpa_snprintf_hex(pos
, end
- pos
, ik
, EAP_AKA_IK_LEN
);
803 pos
+= wpa_snprintf_hex(pos
, end
- pos
, ck
, EAP_AKA_CK_LEN
);
805 pos
+= wpa_snprintf_hex(pos
, end
- pos
, res
, res_len
);
811 static int aka_auts(char *imsi
, char *resp
, size_t resp_len
)
814 u8 _auts
[EAP_AKA_AUTS_LEN
], _rand
[EAP_AKA_RAND_LEN
], sqn
[6];
815 struct milenage_parameters
*m
;
819 /* AKA-AUTS <IMSI> <AUTS> <RAND> */
821 auts
= strchr(imsi
, ' ');
826 __rand
= strchr(auts
, ' ');
832 printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
835 if (hexstr2bin(auts
, _auts
, EAP_AKA_AUTS_LEN
) ||
836 hexstr2bin(__rand
, _rand
, EAP_AKA_RAND_LEN
)) {
837 printf("Could not parse AUTS/RAND\n");
841 m
= get_milenage(imsi
);
843 printf("Unknown IMSI: %s\n", imsi
);
847 if (milenage_auts(m
->opc
, m
->ki
, _rand
, _auts
, sqn
)) {
848 printf("AKA-AUTS: Incorrect MAC-S\n");
850 memcpy(m
->sqn
, sqn
, 6);
852 printf("AKA-AUTS: Re-synchronized: "
853 "SQN=%02x%02x%02x%02x%02x%02x\n",
854 sqn
[0], sqn
[1], sqn
[2], sqn
[3], sqn
[4], sqn
[5]);
857 db_update_milenage_sqn(m
);
858 #endif /* CONFIG_SQLITE */
866 static int process_cmd(char *cmd
, char *resp
, size_t resp_len
)
868 if (os_strncmp(cmd
, "SIM-REQ-AUTH ", 13) == 0)
869 return sim_req_auth(cmd
+ 13, resp
, resp_len
);
871 if (os_strncmp(cmd
, "GSM-AUTH-REQ ", 13) == 0)
872 return gsm_auth_req(cmd
+ 13, resp
, resp_len
);
874 if (os_strncmp(cmd
, "AKA-REQ-AUTH ", 13) == 0)
875 return aka_req_auth(cmd
+ 13, resp
, resp_len
);
877 if (os_strncmp(cmd
, "AKA-AUTS ", 9) == 0)
878 return aka_auts(cmd
+ 9, resp
, resp_len
);
880 printf("Unknown request: %s\n", cmd
);
885 static int process(int s
)
887 char buf
[1000], resp
[1000];
888 struct sockaddr_un from
;
892 fromlen
= sizeof(from
);
893 res
= recvfrom(s
, buf
, sizeof(buf
), 0, (struct sockaddr
*) &from
,
903 if ((size_t) res
>= sizeof(buf
))
904 res
= sizeof(buf
) - 1;
907 printf("Received: %s\n", buf
);
909 if (process_cmd(buf
, resp
, sizeof(resp
)) < 0) {
910 printf("Failed to process request\n");
914 if (resp
[0] == '\0') {
915 printf("No response\n");
919 printf("Send: %s\n", resp
);
921 if (sendto(s
, resp
, os_strlen(resp
), 0, (struct sockaddr
*) &from
,
929 static void cleanup(void)
931 struct gsm_triplet
*g
, *gprev
;
932 struct milenage_parameters
*m
, *prev
;
934 if (update_milenage
&& milenage_file
&& sqn_changes
)
935 update_milenage_file(milenage_file
);
958 sqlite3_close(sqlite_db
);
961 #endif /* CONFIG_SQLITE */
965 static void handle_term(int sig
)
967 printf("Signal %d - terminate\n", sig
);
972 static void usage(void)
974 printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
975 "database/authenticator\n"
976 "Copyright (c) 2005-2017, Jouni Malinen <j@w1.fi>\n"
979 "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
980 "[-m<milenage file>] \\\n"
981 " [-D<DB file>] [-i<IND len in bits>] [command]\n"
984 " -h = show this usage help\n"
985 " -u = update SQN in Milenage file on exit\n"
986 " -s<socket path> = path for UNIX domain socket\n"
988 " -g<triplet file> = path for GSM authentication triplets\n"
989 " -m<milenage file> = path for Milenage keys\n"
990 " -D<DB file> = path to SQLite database\n"
991 " -i<IND len in bits> = IND length for SQN (default: 5)\n"
993 "If the optional command argument, like "
994 "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
995 "command is processed with response sent to stdout. Otherwise, "
997 "a control interface and processes commands sent through it "
998 "(e.g., by EAP server\n"
1000 default_socket_path
);
1004 int main(int argc
, char *argv
[])
1007 char *gsm_triplet_file
= NULL
;
1008 char *sqlite_db_file
= NULL
;
1011 if (os_program_init())
1014 socket_path
= default_socket_path
;
1017 c
= getopt(argc
, argv
, "D:g:hi:m:s:u");
1022 #ifdef CONFIG_SQLITE
1023 sqlite_db_file
= optarg
;
1025 #else /* CONFIG_SQLITE */
1026 printf("No SQLite support included in the build\n");
1028 #endif /* CONFIG_SQLITE */
1030 gsm_triplet_file
= optarg
;
1036 ind_len
= atoi(optarg
);
1037 if (ind_len
< 0 || ind_len
> 32) {
1038 printf("Invalid IND length\n");
1043 milenage_file
= optarg
;
1046 socket_path
= optarg
;
1049 update_milenage
= 1;
1057 if (!gsm_triplet_file
&& !milenage_file
&& !sqlite_db_file
) {
1062 #ifdef CONFIG_SQLITE
1063 if (sqlite_db_file
&& (sqlite_db
= db_open(sqlite_db_file
)) == NULL
)
1065 #endif /* CONFIG_SQLITE */
1067 if (gsm_triplet_file
&& read_gsm_triplets(gsm_triplet_file
) < 0)
1070 if (milenage_file
&& read_milenage(milenage_file
) < 0)
1073 if (optind
== argc
) {
1074 serv_sock
= open_socket(socket_path
);
1078 printf("Listening for requests on %s\n", socket_path
);
1081 signal(SIGTERM
, handle_term
);
1082 signal(SIGINT
, handle_term
);
1090 if (process_cmd(argv
[optind
], buf
, sizeof(buf
)) < 0) {
1094 printf("%s\n", buf
);
1099 #ifdef CONFIG_SQLITE
1101 sqlite3_close(sqlite_db
);
1104 #endif /* CONFIG_SQLITE */
1106 os_program_deinit();