~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to src/hlr_auc_gw/hlr_auc_gw.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

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