2 * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
3 * Copyright (c) 2005-2007, 2012-2013, 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 tripler 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
));
315 pos2
= strchr(pos
, ':');
317 printf("%s:%d - Invalid IMSI (%s)\n",
323 if (strlen(pos
) >= sizeof(g
->imsi
)) {
324 printf("%s:%d - Too long IMSI (%s)\n",
329 os_strlcpy(g
->imsi
, pos
, sizeof(g
->imsi
));
333 pos2
= strchr(pos
, ':');
335 printf("%s:%d - Invalid Kc (%s)\n", fname
, line
, pos
);
340 if (strlen(pos
) != 16 || hexstr2bin(pos
, g
->kc
, 8)) {
341 printf("%s:%d - Invalid Kc (%s)\n", fname
, line
, pos
);
348 pos2
= strchr(pos
, ':');
350 printf("%s:%d - Invalid SRES (%s)\n", fname
, line
,
356 if (strlen(pos
) != 8 || hexstr2bin(pos
, g
->sres
, 4)) {
357 printf("%s:%d - Invalid SRES (%s)\n", fname
, line
,
365 pos2
= strchr(pos
, ':');
368 if (strlen(pos
) != 32 || hexstr2bin(pos
, g
->_rand
, 16)) {
369 printf("%s:%d - Invalid RAND (%s)\n", fname
, line
,
387 static struct gsm_triplet
* get_gsm_triplet(const char *imsi
)
389 struct gsm_triplet
*g
= gsm_db_pos
;
392 if (strcmp(g
->imsi
, imsi
) == 0) {
393 gsm_db_pos
= g
->next
;
400 while (g
&& g
!= gsm_db_pos
) {
401 if (strcmp(g
->imsi
, imsi
) == 0) {
402 gsm_db_pos
= g
->next
;
412 static int read_milenage(const char *fname
)
415 char buf
[200], *pos
, *pos2
;
416 struct milenage_parameters
*m
= NULL
;
422 f
= fopen(fname
, "r");
424 printf("Could not open Milenage data file '%s'\n", fname
);
429 while (fgets(buf
, sizeof(buf
), f
)) {
432 /* Parse IMSI Ki OPc AMF SQN [RES_len] */
433 buf
[sizeof(buf
) - 1] = '\0';
437 while (*pos
!= '\0' && *pos
!= '\n')
445 m
= os_zalloc(sizeof(*m
));
452 pos2
= strchr(pos
, ' ');
454 printf("%s:%d - Invalid IMSI (%s)\n",
460 if (strlen(pos
) >= sizeof(m
->imsi
)) {
461 printf("%s:%d - Too long IMSI (%s)\n",
466 os_strlcpy(m
->imsi
, pos
, sizeof(m
->imsi
));
470 pos2
= strchr(pos
, ' ');
472 printf("%s:%d - Invalid Ki (%s)\n", fname
, line
, pos
);
477 if (strlen(pos
) != 32 || hexstr2bin(pos
, m
->ki
, 16)) {
478 printf("%s:%d - Invalid Ki (%s)\n", fname
, line
, pos
);
485 pos2
= strchr(pos
, ' ');
487 printf("%s:%d - Invalid OPc (%s)\n", fname
, line
, pos
);
492 if (strlen(pos
) != 32 || hexstr2bin(pos
, m
->opc
, 16)) {
493 printf("%s:%d - Invalid OPc (%s)\n", fname
, line
, pos
);
500 pos2
= strchr(pos
, ' ');
502 printf("%s:%d - Invalid AMF (%s)\n", fname
, line
, pos
);
507 if (strlen(pos
) != 4 || hexstr2bin(pos
, m
->amf
, 2)) {
508 printf("%s:%d - Invalid AMF (%s)\n", fname
, line
, pos
);
515 pos2
= strchr(pos
, ' ');
518 if (strlen(pos
) != 12 || hexstr2bin(pos
, m
->sqn
, 6)) {
519 printf("%s:%d - Invalid SEQ (%s)\n", fname
, line
, pos
);
526 m
->res_len
= atoi(pos
);
528 (m
->res_len
< EAP_AKA_RES_MIN_LEN
||
529 m
->res_len
> EAP_AKA_RES_MAX_LEN
)) {
530 printf("%s:%d - Invalid RES_len (%s)\n",
537 m
->next
= milenage_db
;
549 static void update_milenage_file(const char *fname
)
552 char name
[500], buf
[500], *pos
;
553 char *end
= buf
+ sizeof(buf
);
554 struct milenage_parameters
*m
;
557 f
= fopen(fname
, "r");
559 printf("Could not open Milenage data file '%s'\n", fname
);
563 snprintf(name
, sizeof(name
), "%s.new", fname
);
564 f2
= fopen(name
, "w");
566 printf("Could not write Milenage data file '%s'\n", name
);
571 while (fgets(buf
, sizeof(buf
), f
)) {
572 /* IMSI Ki OPc AMF SQN */
573 buf
[sizeof(buf
) - 1] = '\0';
575 pos
= strchr(buf
, ' ');
576 if (buf
[0] == '#' || pos
== NULL
|| pos
- buf
>= 20)
579 imsi_len
= pos
- buf
;
581 for (m
= milenage_db
; m
; m
= m
->next
) {
582 if (strncmp(buf
, m
->imsi
, imsi_len
) == 0 &&
583 m
->imsi
[imsi_len
] == '\0')
591 pos
+= snprintf(pos
, end
- pos
, "%s ", m
->imsi
);
592 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->ki
, 16);
594 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->opc
, 16);
596 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->amf
, 2);
598 pos
+= wpa_snprintf_hex(pos
, end
- pos
, m
->sqn
, 6);
602 fprintf(f2
, "%s", buf
);
608 snprintf(name
, sizeof(name
), "%s.bak", fname
);
609 if (rename(fname
, name
) < 0) {
614 snprintf(name
, sizeof(name
), "%s.new", fname
);
615 if (rename(name
, fname
) < 0) {
623 static struct milenage_parameters
* get_milenage(const char *imsi
)
625 struct milenage_parameters
*m
= milenage_db
;
628 if (strcmp(m
->imsi
, imsi
) == 0)
635 m
= db_get_milenage(imsi
);
636 #endif /* CONFIG_SQLITE */
642 static int sim_req_auth(char *imsi
, char *resp
, size_t resp_len
)
644 int count
, max_chal
, ret
;
647 struct milenage_parameters
*m
;
648 struct gsm_triplet
*g
;
652 pos
= strchr(imsi
, ' ');
655 max_chal
= atoi(pos
);
656 if (max_chal
< 1 || max_chal
> EAP_SIM_MAX_CHAL
)
657 max_chal
= EAP_SIM_MAX_CHAL
;
659 max_chal
= EAP_SIM_MAX_CHAL
;
661 rend
= resp
+ resp_len
;
663 ret
= snprintf(rpos
, rend
- rpos
, "SIM-RESP-AUTH %s", imsi
);
664 if (ret
< 0 || ret
>= rend
- rpos
)
668 m
= get_milenage(imsi
);
670 u8 _rand
[16], sres
[4], kc
[8];
671 for (count
= 0; count
< max_chal
; count
++) {
672 if (random_get_bytes(_rand
, 16) < 0)
674 gsm_milenage(m
->opc
, m
->ki
, _rand
, sres
, kc
);
676 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, kc
, 8);
678 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, sres
, 4);
680 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, _rand
, 16);
687 while (count
< max_chal
&& (g
= get_gsm_triplet(imsi
))) {
688 if (strcmp(g
->imsi
, imsi
) != 0)
693 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->kc
, 8);
696 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->sres
, 4);
699 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, g
->_rand
, 16);
704 printf("No GSM triplets found for %s\n", imsi
);
705 ret
= snprintf(rpos
, rend
- rpos
, " FAILURE");
706 if (ret
< 0 || ret
>= rend
- rpos
)
715 static int gsm_auth_req(char *imsi
, char *resp
, size_t resp_len
)
718 char *pos
, *rpos
, *rend
;
719 struct milenage_parameters
*m
;
723 pos
= os_strchr(imsi
, ' ');
728 rend
= resp
+ resp_len
;
730 ret
= os_snprintf(rpos
, rend
- rpos
, "GSM-AUTH-RESP %s", imsi
);
731 if (os_snprintf_error(rend
- rpos
, ret
))
735 m
= get_milenage(imsi
);
737 u8 _rand
[16], sres
[4], kc
[8];
738 for (count
= 0; count
< EAP_SIM_MAX_CHAL
; count
++) {
739 if (hexstr2bin(pos
, _rand
, 16) != 0)
741 gsm_milenage(m
->opc
, m
->ki
, _rand
, sres
, kc
);
742 *rpos
++ = count
== 0 ? ' ' : ':';
743 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, kc
, 8);
745 rpos
+= wpa_snprintf_hex(rpos
, rend
- rpos
, sres
, 4);
755 printf("No GSM triplets found for %s\n", imsi
);
756 ret
= os_snprintf(rpos
, rend
- rpos
, " FAILURE");
757 if (os_snprintf_error(rend
- rpos
, ret
))
765 static void inc_sqn(u8
*sqn
)
770 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
772 * The mechanism used here is not time-based, so SEQ2 is void and
773 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
774 * of SEQ1 is 48 - ind_len bits.
777 /* Increment both SEQ and IND by one */
778 val
= ((u64
) WPA_GET_BE32(sqn
) << 16) | ((u64
) WPA_GET_BE16(sqn
+ 4));
779 seq
= (val
>> ind_len
) + 1;
780 ind
= (val
+ 1) & ((1 << ind_len
) - 1);
781 val
= (seq
<< ind_len
) | ind
;
782 WPA_PUT_BE32(sqn
, val
>> 16);
783 WPA_PUT_BE16(sqn
+ 4, val
& 0xffff);
787 static int aka_req_auth(char *imsi
, char *resp
, size_t resp_len
)
789 /* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
791 u8 _rand
[EAP_AKA_RAND_LEN
];
792 u8 autn
[EAP_AKA_AUTN_LEN
];
793 u8 ik
[EAP_AKA_IK_LEN
];
794 u8 ck
[EAP_AKA_CK_LEN
];
795 u8 res
[EAP_AKA_RES_MAX_LEN
];
798 struct milenage_parameters
*m
;
801 m
= get_milenage(imsi
);
803 if (random_get_bytes(_rand
, EAP_AKA_RAND_LEN
) < 0)
805 res_len
= EAP_AKA_RES_MAX_LEN
;
808 db_update_milenage_sqn(m
);
809 #endif /* CONFIG_SQLITE */
812 printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
813 m
->sqn
[0], m
->sqn
[1], m
->sqn
[2],
814 m
->sqn
[3], m
->sqn
[4], m
->sqn
[5]);
816 milenage_generate(m
->opc
, m
->amf
, m
->ki
, m
->sqn
, _rand
,
817 autn
, ik
, ck
, res
, &res_len
);
818 if (m
->res_len
>= EAP_AKA_RES_MIN_LEN
&&
819 m
->res_len
<= EAP_AKA_RES_MAX_LEN
&&
820 m
->res_len
< res_len
)
821 res_len
= m
->res_len
;
823 printf("Unknown IMSI: %s\n", imsi
);
824 #ifdef AKA_USE_FIXED_TEST_VALUES
825 printf("Using fixed test values for AKA\n");
826 memset(_rand
, '0', EAP_AKA_RAND_LEN
);
827 memset(autn
, '1', EAP_AKA_AUTN_LEN
);
828 memset(ik
, '3', EAP_AKA_IK_LEN
);
829 memset(ck
, '4', EAP_AKA_CK_LEN
);
830 memset(res
, '2', EAP_AKA_RES_MAX_LEN
);
831 res_len
= EAP_AKA_RES_MAX_LEN
;
832 #else /* AKA_USE_FIXED_TEST_VALUES */
834 #endif /* AKA_USE_FIXED_TEST_VALUES */
838 end
= resp
+ resp_len
;
839 ret
= snprintf(pos
, end
- pos
, "AKA-RESP-AUTH %s ", imsi
);
840 if (ret
< 0 || ret
>= end
- pos
)
844 ret
= snprintf(pos
, end
- pos
, "FAILURE");
845 if (ret
< 0 || ret
>= end
- pos
)
850 pos
+= wpa_snprintf_hex(pos
, end
- pos
, _rand
, EAP_AKA_RAND_LEN
);
852 pos
+= wpa_snprintf_hex(pos
, end
- pos
, autn
, EAP_AKA_AUTN_LEN
);
854 pos
+= wpa_snprintf_hex(pos
, end
- pos
, ik
, EAP_AKA_IK_LEN
);
856 pos
+= wpa_snprintf_hex(pos
, end
- pos
, ck
, EAP_AKA_CK_LEN
);
858 pos
+= wpa_snprintf_hex(pos
, end
- pos
, res
, res_len
);
864 static int aka_auts(char *imsi
, char *resp
, size_t resp_len
)
867 u8 _auts
[EAP_AKA_AUTS_LEN
], _rand
[EAP_AKA_RAND_LEN
], sqn
[6];
868 struct milenage_parameters
*m
;
872 /* AKA-AUTS <IMSI> <AUTS> <RAND> */
874 auts
= strchr(imsi
, ' ');
879 __rand
= strchr(auts
, ' ');
885 printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n",
888 if (hexstr2bin(auts
, _auts
, EAP_AKA_AUTS_LEN
) ||
889 hexstr2bin(__rand
, _rand
, EAP_AKA_RAND_LEN
)) {
890 printf("Could not parse AUTS/RAND\n");
894 m
= get_milenage(imsi
);
896 printf("Unknown IMSI: %s\n", imsi
);
900 if (milenage_auts(m
->opc
, m
->ki
, _rand
, _auts
, sqn
)) {
901 printf("AKA-AUTS: Incorrect MAC-S\n");
903 memcpy(m
->sqn
, sqn
, 6);
905 printf("AKA-AUTS: Re-synchronized: "
906 "SQN=%02x%02x%02x%02x%02x%02x\n",
907 sqn
[0], sqn
[1], sqn
[2], sqn
[3], sqn
[4], sqn
[5]);
910 db_update_milenage_sqn(m
);
911 #endif /* CONFIG_SQLITE */
919 static int process_cmd(char *cmd
, char *resp
, size_t resp_len
)
921 if (os_strncmp(cmd
, "SIM-REQ-AUTH ", 13) == 0)
922 return sim_req_auth(cmd
+ 13, resp
, resp_len
);
924 if (os_strncmp(cmd
, "GSM-AUTH-REQ ", 13) == 0)
925 return gsm_auth_req(cmd
+ 13, resp
, resp_len
);
927 if (os_strncmp(cmd
, "AKA-REQ-AUTH ", 13) == 0)
928 return aka_req_auth(cmd
+ 13, resp
, resp_len
);
930 if (os_strncmp(cmd
, "AKA-AUTS ", 9) == 0)
931 return aka_auts(cmd
+ 9, resp
, resp_len
);
933 printf("Unknown request: %s\n", cmd
);
938 static int process(int s
)
940 char buf
[1000], resp
[1000];
941 struct sockaddr_un from
;
945 fromlen
= sizeof(from
);
946 res
= recvfrom(s
, buf
, sizeof(buf
), 0, (struct sockaddr
*) &from
,
956 if ((size_t) res
>= sizeof(buf
))
957 res
= sizeof(buf
) - 1;
960 printf("Received: %s\n", buf
);
962 if (process_cmd(buf
, resp
, sizeof(resp
)) < 0) {
963 printf("Failed to process request\n");
967 if (resp
[0] == '\0') {
968 printf("No response\n");
972 printf("Send: %s\n", resp
);
974 if (sendto(s
, resp
, os_strlen(resp
), 0, (struct sockaddr
*) &from
,
982 static void cleanup(void)
984 struct gsm_triplet
*g
, *gprev
;
985 struct milenage_parameters
*m
, *prev
;
987 if (update_milenage
&& milenage_file
&& sqn_changes
)
988 update_milenage_file(milenage_file
);
1007 unlink(socket_path
);
1009 #ifdef CONFIG_SQLITE
1011 sqlite3_close(sqlite_db
);
1014 #endif /* CONFIG_SQLITE */
1018 static void handle_term(int sig
)
1020 printf("Signal %d - terminate\n", sig
);
1025 static void usage(void)
1027 printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
1028 "database/authenticator\n"
1029 "Copyright (c) 2005-2007, 2012-2013, Jouni Malinen <j@w1.fi>\n"
1032 "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
1033 "[-m<milenage file>] \\\n"
1034 " [-D<DB file>] [-i<IND len in bits>] [command]\n"
1037 " -h = show this usage help\n"
1038 " -u = update SQN in Milenage file on exit\n"
1039 " -s<socket path> = path for UNIX domain socket\n"
1041 " -g<triplet file> = path for GSM authentication triplets\n"
1042 " -m<milenage file> = path for Milenage keys\n"
1043 " -D<DB file> = path to SQLite database\n"
1044 " -i<IND len in bits> = IND length for SQN (default: 5)\n"
1046 "If the optional command argument, like "
1047 "\"AKA-REQ-AUTH <IMSI>\" is used, a single\n"
1048 "command is processed with response sent to stdout. Otherwise, "
1049 "hlr_auc_gw opens\n"
1050 "a control interface and processes commands sent through it "
1051 "(e.g., by EAP server\n"
1053 default_socket_path
);
1057 int main(int argc
, char *argv
[])
1060 char *gsm_triplet_file
= NULL
;
1061 char *sqlite_db_file
= NULL
;
1064 if (os_program_init())
1067 socket_path
= default_socket_path
;
1070 c
= getopt(argc
, argv
, "D:g:hi:m:s:u");
1075 #ifdef CONFIG_SQLITE
1076 sqlite_db_file
= optarg
;
1078 #else /* CONFIG_SQLITE */
1079 printf("No SQLite support included in the build\n");
1081 #endif /* CONFIG_SQLITE */
1083 gsm_triplet_file
= optarg
;
1089 ind_len
= atoi(optarg
);
1090 if (ind_len
< 0 || ind_len
> 32) {
1091 printf("Invalid IND length\n");
1096 milenage_file
= optarg
;
1099 socket_path
= optarg
;
1102 update_milenage
= 1;
1110 if (!gsm_triplet_file
&& !milenage_file
&& !sqlite_db_file
) {
1115 #ifdef CONFIG_SQLITE
1116 if (sqlite_db_file
&& (sqlite_db
= db_open(sqlite_db_file
)) == NULL
)
1118 #endif /* CONFIG_SQLITE */
1120 if (gsm_triplet_file
&& read_gsm_triplets(gsm_triplet_file
) < 0)
1123 if (milenage_file
&& read_milenage(milenage_file
) < 0)
1126 if (optind
== argc
) {
1127 serv_sock
= open_socket(socket_path
);
1131 printf("Listening for requests on %s\n", socket_path
);
1134 signal(SIGTERM
, handle_term
);
1135 signal(SIGINT
, handle_term
);
1143 if (process_cmd(argv
[optind
], buf
, sizeof(buf
)) < 0) {
1147 printf("%s\n", buf
);
1152 #ifdef CONFIG_SQLITE
1154 sqlite3_close(sqlite_db
);
1157 #endif /* CONFIG_SQLITE */
1159 os_program_deinit();