~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/radius/radius_server.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * hostapd / RADIUS authentication server
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
 
 
15
 
#include "includes.h"
16
 
#include <net/if.h>
17
 
 
18
 
#include "common.h"
19
 
#include "radius.h"
20
 
#include "eloop.h"
21
 
#include "defs.h"
22
 
#include "eap_server/eap.h"
23
 
#include "radius_server.h"
24
 
 
25
 
#define RADIUS_SESSION_TIMEOUT 60
26
 
#define RADIUS_MAX_SESSION 100
27
 
#define RADIUS_MAX_MSG_LEN 3000
28
 
 
29
 
static struct eapol_callbacks radius_server_eapol_cb;
30
 
 
31
 
struct radius_client;
32
 
struct radius_server_data;
33
 
 
34
 
struct radius_server_counters {
35
 
        u32 access_requests;
36
 
        u32 invalid_requests;
37
 
        u32 dup_access_requests;
38
 
        u32 access_accepts;
39
 
        u32 access_rejects;
40
 
        u32 access_challenges;
41
 
        u32 malformed_access_requests;
42
 
        u32 bad_authenticators;
43
 
        u32 packets_dropped;
44
 
        u32 unknown_types;
45
 
};
46
 
 
47
 
struct radius_session {
48
 
        struct radius_session *next;
49
 
        struct radius_client *client;
50
 
        struct radius_server_data *server;
51
 
        unsigned int sess_id;
52
 
        struct eap_sm *eap;
53
 
        u8 *eapKeyData, *eapReqData;
54
 
        size_t eapKeyDataLen, eapReqDataLen;
55
 
        Boolean eapSuccess, eapRestart, eapFail, eapResp, eapReq, eapNoReq;
56
 
        Boolean portEnabled, eapTimeout;
57
 
 
58
 
        struct radius_msg *last_msg;
59
 
        char *last_from_addr;
60
 
        int last_from_port;
61
 
        struct sockaddr_storage last_from;
62
 
        socklen_t last_fromlen;
63
 
        u8 last_identifier;
64
 
        struct radius_msg *last_reply;
65
 
        u8 last_authenticator[16];
66
 
};
67
 
 
68
 
struct radius_client {
69
 
        struct radius_client *next;
70
 
        struct in_addr addr;
71
 
        struct in_addr mask;
72
 
#ifdef CONFIG_IPV6
73
 
        struct in6_addr addr6;
74
 
        struct in6_addr mask6;
75
 
#endif /* CONFIG_IPV6 */
76
 
        char *shared_secret;
77
 
        int shared_secret_len;
78
 
        struct radius_session *sessions;
79
 
        struct radius_server_counters counters;
80
 
};
81
 
 
82
 
struct radius_server_data {
83
 
        int auth_sock;
84
 
        struct radius_client *clients;
85
 
        unsigned int next_sess_id;
86
 
        void *conf_ctx;
87
 
        int num_sess;
88
 
        void *eap_sim_db_priv;
89
 
        void *ssl_ctx;
90
 
        int ipv6;
91
 
        struct os_time start_time;
92
 
        struct radius_server_counters counters;
93
 
        int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
94
 
                            int phase2, struct eap_user *user);
95
 
};
96
 
 
97
 
 
98
 
extern int wpa_debug_level;
99
 
 
100
 
#define RADIUS_DEBUG(args...) \
101
 
wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
102
 
#define RADIUS_ERROR(args...) \
103
 
wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
104
 
#define RADIUS_DUMP(args...) \
105
 
wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
106
 
#define RADIUS_DUMP_ASCII(args...) \
107
 
wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
108
 
 
109
 
 
110
 
static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
111
 
 
112
 
 
113
 
 
114
 
static struct radius_client *
115
 
radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
116
 
                         int ipv6)
117
 
{
118
 
        struct radius_client *client = data->clients;
119
 
 
120
 
        while (client) {
121
 
#ifdef CONFIG_IPV6
122
 
                if (ipv6) {
123
 
                        struct in6_addr *addr6;
124
 
                        int i;
125
 
 
126
 
                        addr6 = (struct in6_addr *) addr;
127
 
                        for (i = 0; i < 16; i++) {
128
 
                                if ((addr6->s6_addr[i] &
129
 
                                     client->mask6.s6_addr[i]) !=
130
 
                                    (client->addr6.s6_addr[i] &
131
 
                                     client->mask6.s6_addr[i])) {
132
 
                                        i = 17;
133
 
                                        break;
134
 
                                }
135
 
                        }
136
 
                        if (i == 16) {
137
 
                                break;
138
 
                        }
139
 
                }
140
 
#endif /* CONFIG_IPV6 */
141
 
                if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
142
 
                    (addr->s_addr & client->mask.s_addr)) {
143
 
                        break;
144
 
                }
145
 
 
146
 
                client = client->next;
147
 
        }
148
 
 
149
 
        return client;
150
 
}
151
 
 
152
 
 
153
 
static struct radius_session *
154
 
radius_server_get_session(struct radius_client *client, unsigned int sess_id)
155
 
{
156
 
        struct radius_session *sess = client->sessions;
157
 
 
158
 
        while (sess) {
159
 
                if (sess->sess_id == sess_id) {
160
 
                        break;
161
 
                }
162
 
                sess = sess->next;
163
 
        }
164
 
 
165
 
        return sess;
166
 
}
167
 
 
168
 
 
169
 
static void radius_server_session_free(struct radius_server_data *data,
170
 
                                       struct radius_session *sess)
171
 
{
172
 
        eloop_cancel_timeout(radius_server_session_timeout, data, sess);
173
 
        free(sess->eapKeyData);
174
 
        free(sess->eapReqData);
175
 
        eap_server_sm_deinit(sess->eap);
176
 
        if (sess->last_msg) {
177
 
                radius_msg_free(sess->last_msg);
178
 
                free(sess->last_msg);
179
 
        }
180
 
        free(sess->last_from_addr);
181
 
        if (sess->last_reply) {
182
 
                radius_msg_free(sess->last_reply);
183
 
                free(sess->last_reply);
184
 
        }
185
 
        free(sess);
186
 
        data->num_sess--;
187
 
}
188
 
 
189
 
 
190
 
static void radius_server_session_remove_timeout(void *eloop_ctx,
191
 
                                                 void *timeout_ctx);
192
 
 
193
 
static void radius_server_session_remove(struct radius_server_data *data,
194
 
                                         struct radius_session *sess)
195
 
{
196
 
        struct radius_client *client = sess->client;
197
 
        struct radius_session *session, *prev;
198
 
 
199
 
        eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
200
 
 
201
 
        prev = NULL;
202
 
        session = client->sessions;
203
 
        while (session) {
204
 
                if (session == sess) {
205
 
                        if (prev == NULL) {
206
 
                                client->sessions = sess->next;
207
 
                        } else {
208
 
                                prev->next = sess->next;
209
 
                        }
210
 
                        radius_server_session_free(data, sess);
211
 
                        break;
212
 
                }
213
 
                prev = session;
214
 
                session = session->next;
215
 
        }
216
 
}
217
 
 
218
 
 
219
 
static void radius_server_session_remove_timeout(void *eloop_ctx,
220
 
                                                 void *timeout_ctx)
221
 
{
222
 
        struct radius_server_data *data = eloop_ctx;
223
 
        struct radius_session *sess = timeout_ctx;
224
 
        RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
225
 
        radius_server_session_remove(data, sess);
226
 
}
227
 
 
228
 
 
229
 
static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
230
 
{
231
 
        struct radius_server_data *data = eloop_ctx;
232
 
        struct radius_session *sess = timeout_ctx;
233
 
 
234
 
        RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
235
 
        radius_server_session_remove(data, sess);
236
 
}
237
 
 
238
 
 
239
 
static struct radius_session *
240
 
radius_server_new_session(struct radius_server_data *data,
241
 
                          struct radius_client *client)
242
 
{
243
 
        struct radius_session *sess;
244
 
 
245
 
        if (data->num_sess >= RADIUS_MAX_SESSION) {
246
 
                RADIUS_DEBUG("Maximum number of existing session - no room "
247
 
                             "for a new session");
248
 
                return NULL;
249
 
        }
250
 
 
251
 
        sess = os_zalloc(sizeof(*sess));
252
 
        if (sess == NULL)
253
 
                return NULL;
254
 
 
255
 
        sess->server = data;
256
 
        sess->client = client;
257
 
        sess->sess_id = data->next_sess_id++;
258
 
        sess->next = client->sessions;
259
 
        client->sessions = sess;
260
 
        eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
261
 
                               radius_server_session_timeout, data, sess);
262
 
        data->num_sess++;
263
 
        return sess;
264
 
}
265
 
 
266
 
 
267
 
static struct radius_session *
268
 
radius_server_get_new_session(struct radius_server_data *data,
269
 
                              struct radius_client *client,
270
 
                              struct radius_msg *msg)
271
 
{
272
 
        u8 *user;
273
 
        size_t user_len;
274
 
        int res;
275
 
        struct radius_session *sess;
276
 
        struct eap_config eap_conf;
277
 
 
278
 
        RADIUS_DEBUG("Creating a new session");
279
 
 
280
 
        user = malloc(256);
281
 
        if (user == NULL) {
282
 
                return NULL;
283
 
        }
284
 
        res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
285
 
        if (res < 0 || res > 256) {
286
 
                RADIUS_DEBUG("Could not get User-Name");
287
 
                free(user);
288
 
                return NULL;
289
 
        }
290
 
        user_len = res;
291
 
        RADIUS_DUMP_ASCII("User-Name", user, user_len);
292
 
 
293
 
        res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
294
 
        free(user);
295
 
 
296
 
        if (res == 0) {
297
 
                RADIUS_DEBUG("Matching user entry found");
298
 
                sess = radius_server_new_session(data, client);
299
 
                if (sess == NULL) {
300
 
                        RADIUS_DEBUG("Failed to create a new session");
301
 
                        return NULL;
302
 
                }
303
 
        } else {
304
 
                RADIUS_DEBUG("User-Name not found from user database");
305
 
                return NULL;
306
 
        }
307
 
 
308
 
        memset(&eap_conf, 0, sizeof(eap_conf));
309
 
        eap_conf.ssl_ctx = data->ssl_ctx;
310
 
        eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
311
 
        eap_conf.backend_auth = TRUE;
312
 
        sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
313
 
                                       &eap_conf);
314
 
        if (sess->eap == NULL) {
315
 
                RADIUS_DEBUG("Failed to initialize EAP state machine for the "
316
 
                             "new session");
317
 
                radius_server_session_free(data, sess);
318
 
                return NULL;
319
 
        }
320
 
        sess->eapRestart = TRUE;
321
 
        sess->portEnabled = TRUE;
322
 
 
323
 
        RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
324
 
 
325
 
        return sess;
326
 
}
327
 
 
328
 
 
329
 
static struct radius_msg *
330
 
radius_server_encapsulate_eap(struct radius_server_data *data,
331
 
                              struct radius_client *client,
332
 
                              struct radius_session *sess,
333
 
                              struct radius_msg *request)
334
 
{
335
 
        struct radius_msg *msg;
336
 
        int code;
337
 
        unsigned int sess_id;
338
 
 
339
 
        if (sess->eapFail) {
340
 
                code = RADIUS_CODE_ACCESS_REJECT;
341
 
        } else if (sess->eapSuccess) {
342
 
                code = RADIUS_CODE_ACCESS_ACCEPT;
343
 
        } else {
344
 
                code = RADIUS_CODE_ACCESS_CHALLENGE;
345
 
        }
346
 
 
347
 
        msg = radius_msg_new(code, request->hdr->identifier);
348
 
        if (msg == NULL) {
349
 
                RADIUS_DEBUG("Failed to allocate reply message");
350
 
                return NULL;
351
 
        }
352
 
 
353
 
        sess_id = htonl(sess->sess_id);
354
 
        if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
355
 
            !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
356
 
                                 (u8 *) &sess_id, sizeof(sess_id))) {
357
 
                RADIUS_DEBUG("Failed to add State attribute");
358
 
        }
359
 
 
360
 
        if (sess->eapReqData &&
361
 
            !radius_msg_add_eap(msg, sess->eapReqData, sess->eapReqDataLen)) {
362
 
                RADIUS_DEBUG("Failed to add EAP-Message attribute");
363
 
        }
364
 
 
365
 
        if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eapKeyData) {
366
 
                int len;
367
 
                if (sess->eapKeyDataLen > 64) {
368
 
                        len = 32;
369
 
                } else {
370
 
                        len = sess->eapKeyDataLen / 2;
371
 
                }
372
 
                if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,
373
 
                                              (u8 *) client->shared_secret,
374
 
                                              client->shared_secret_len,
375
 
                                              sess->eapKeyData + len, len,
376
 
                                              sess->eapKeyData, len)) {
377
 
                        RADIUS_DEBUG("Failed to add MPPE key attributes");
378
 
                }
379
 
        }
380
 
 
381
 
        if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
382
 
                                  client->shared_secret_len,
383
 
                                  request->hdr->authenticator) < 0) {
384
 
                RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
385
 
        }
386
 
 
387
 
        return msg;
388
 
}
389
 
 
390
 
 
391
 
static int radius_server_reject(struct radius_server_data *data,
392
 
                                struct radius_client *client,
393
 
                                struct radius_msg *request,
394
 
                                struct sockaddr *from, socklen_t fromlen,
395
 
                                const char *from_addr, int from_port)
396
 
{
397
 
        struct radius_msg *msg;
398
 
        int ret = 0;
399
 
        struct eap_hdr eapfail;
400
 
 
401
 
        RADIUS_DEBUG("Reject invalid request from %s:%d",
402
 
                     from_addr, from_port);
403
 
 
404
 
        msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,
405
 
                             request->hdr->identifier);
406
 
        if (msg == NULL) {
407
 
                return -1;
408
 
        }
409
 
 
410
 
        memset(&eapfail, 0, sizeof(eapfail));
411
 
        eapfail.code = EAP_CODE_FAILURE;
412
 
        eapfail.identifier = 0;
413
 
        eapfail.length = host_to_be16(sizeof(eapfail));
414
 
 
415
 
        if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
416
 
                RADIUS_DEBUG("Failed to add EAP-Message attribute");
417
 
        }
418
 
 
419
 
 
420
 
        if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
421
 
                                  client->shared_secret_len,
422
 
                                  request->hdr->authenticator) < 0) {
423
 
                RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
424
 
        }
425
 
 
426
 
        if (wpa_debug_level <= MSG_MSGDUMP) {
427
 
                radius_msg_dump(msg);
428
 
        }
429
 
 
430
 
        data->counters.access_rejects++;
431
 
        client->counters.access_rejects++;
432
 
        if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,
433
 
                   (struct sockaddr *) from, sizeof(*from)) < 0) {
434
 
                perror("sendto[RADIUS SRV]");
435
 
                ret = -1;
436
 
        }
437
 
 
438
 
        radius_msg_free(msg);
439
 
        free(msg);
440
 
 
441
 
        return ret;
442
 
}
443
 
 
444
 
 
445
 
static int radius_server_request(struct radius_server_data *data,
446
 
                                 struct radius_msg *msg,
447
 
                                 struct sockaddr *from, socklen_t fromlen,
448
 
                                 struct radius_client *client,
449
 
                                 const char *from_addr, int from_port,
450
 
                                 struct radius_session *force_sess)
451
 
{
452
 
        u8 *eap = NULL;
453
 
        size_t eap_len;
454
 
        int res, state_included = 0;
455
 
        u8 statebuf[4], resp_id;
456
 
        unsigned int state;
457
 
        struct radius_session *sess;
458
 
        struct radius_msg *reply;
459
 
        struct eap_hdr *hdr;
460
 
 
461
 
        if (force_sess)
462
 
                sess = force_sess;
463
 
        else {
464
 
                res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
465
 
                                          sizeof(statebuf));
466
 
                state_included = res >= 0;
467
 
                if (res == sizeof(statebuf)) {
468
 
                        state = WPA_GET_BE32(statebuf);
469
 
                        sess = radius_server_get_session(client, state);
470
 
                } else {
471
 
                        sess = NULL;
472
 
                }
473
 
        }
474
 
 
475
 
        if (sess) {
476
 
                RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
477
 
        } else if (state_included) {
478
 
                RADIUS_DEBUG("State attribute included but no session found");
479
 
                radius_server_reject(data, client, msg, from, fromlen,
480
 
                                     from_addr, from_port);
481
 
                return -1;
482
 
        } else {
483
 
                sess = radius_server_get_new_session(data, client, msg);
484
 
                if (sess == NULL) {
485
 
                        RADIUS_DEBUG("Could not create a new session");
486
 
                        radius_server_reject(data, client, msg, from, fromlen,
487
 
                                             from_addr, from_port);
488
 
                        return -1;
489
 
                }
490
 
        }
491
 
 
492
 
        if (sess->last_from_port == from_port &&
493
 
            sess->last_identifier == msg->hdr->identifier &&
494
 
            os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) ==
495
 
            0) {
496
 
                RADIUS_DEBUG("Duplicate message from %s", from_addr);
497
 
                data->counters.dup_access_requests++;
498
 
                client->counters.dup_access_requests++;
499
 
 
500
 
                if (sess->last_reply) {
501
 
                        res = sendto(data->auth_sock, sess->last_reply->buf,
502
 
                                     sess->last_reply->buf_used, 0,
503
 
                                     (struct sockaddr *) from, fromlen);
504
 
                        if (res < 0) {
505
 
                                perror("sendto[RADIUS SRV]");
506
 
                        }
507
 
                        return 0;
508
 
                }
509
 
 
510
 
                RADIUS_DEBUG("No previous reply available for duplicate "
511
 
                             "message");
512
 
                return -1;
513
 
        }
514
 
                      
515
 
        eap = radius_msg_get_eap(msg, &eap_len);
516
 
        if (eap == NULL) {
517
 
                RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
518
 
                             from_addr);
519
 
                data->counters.packets_dropped++;
520
 
                client->counters.packets_dropped++;
521
 
                return -1;
522
 
        }
523
 
 
524
 
        RADIUS_DUMP("Received EAP data", eap, eap_len);
525
 
        if (eap_len >= sizeof(*hdr)) {
526
 
                hdr = (struct eap_hdr *) eap;
527
 
                resp_id = hdr->identifier;
528
 
        } else {
529
 
                resp_id = 0;
530
 
        }
531
 
 
532
 
        /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
533
 
         * RFC3579 Sect. 2.6.2.
534
 
         * Include EAP-Response/Nak with no preferred method if
535
 
         * code == request.
536
 
         * If code is not 1-4, discard the packet silently.
537
 
         * Or is this already done by the EAP state machine? */
538
 
 
539
 
        eap_set_eapRespData(sess->eap, eap, eap_len);
540
 
        free(eap);
541
 
        eap = NULL;
542
 
        sess->eapResp = TRUE;
543
 
        eap_server_sm_step(sess->eap);
544
 
 
545
 
        if (sess->eapReqData) {
546
 
                RADIUS_DUMP("EAP data from the state machine",
547
 
                            sess->eapReqData, sess->eapReqDataLen);
548
 
        } else if (sess->eapFail) {
549
 
                RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
550
 
                             "set - generate EAP-Failure");
551
 
                hdr = os_zalloc(sizeof(*hdr));
552
 
                if (hdr) {
553
 
                        hdr->identifier = resp_id;
554
 
                        hdr->length = host_to_be16(sizeof(*hdr));
555
 
                        sess->eapReqData = (u8 *) hdr;
556
 
                        sess->eapReqDataLen = sizeof(*hdr);
557
 
                }
558
 
        } else if (eap_sm_method_pending(sess->eap)) {
559
 
                if (sess->last_msg) {
560
 
                        radius_msg_free(sess->last_msg);
561
 
                        free(sess->last_msg);
562
 
                }
563
 
                sess->last_msg = msg;
564
 
                sess->last_from_port = from_port;
565
 
                free(sess->last_from_addr);
566
 
                sess->last_from_addr = strdup(from_addr);
567
 
                sess->last_fromlen = fromlen;
568
 
                memcpy(&sess->last_from, from, fromlen);
569
 
                return -2;
570
 
        } else {
571
 
                RADIUS_DEBUG("No EAP data from the state machine - ignore this"
572
 
                             " Access-Request silently (assuming it was a "
573
 
                             "duplicate)");
574
 
                data->counters.packets_dropped++;
575
 
                client->counters.packets_dropped++;
576
 
                return -1;
577
 
        }
578
 
 
579
 
        reply = radius_server_encapsulate_eap(data, client, sess, msg);
580
 
 
581
 
        free(sess->eapReqData);
582
 
        sess->eapReqData = NULL;
583
 
        sess->eapReqDataLen = 0;
584
 
 
585
 
        if (reply) {
586
 
                RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
587
 
                if (wpa_debug_level <= MSG_MSGDUMP) {
588
 
                        radius_msg_dump(reply);
589
 
                }
590
 
 
591
 
                switch (reply->hdr->code) {
592
 
                case RADIUS_CODE_ACCESS_ACCEPT:
593
 
                        data->counters.access_accepts++;
594
 
                        client->counters.access_accepts++;
595
 
                        break;
596
 
                case RADIUS_CODE_ACCESS_REJECT:
597
 
                        data->counters.access_rejects++;
598
 
                        client->counters.access_rejects++;
599
 
                        break;
600
 
                case RADIUS_CODE_ACCESS_CHALLENGE:
601
 
                        data->counters.access_challenges++;
602
 
                        client->counters.access_challenges++;
603
 
                        break;
604
 
                }
605
 
                res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
606
 
                             (struct sockaddr *) from, fromlen);
607
 
                if (res < 0) {
608
 
                        perror("sendto[RADIUS SRV]");
609
 
                }
610
 
                if (sess->last_reply) {
611
 
                        radius_msg_free(sess->last_reply);
612
 
                        free(sess->last_reply);
613
 
                }
614
 
                sess->last_reply = reply;
615
 
                sess->last_from_port = from_port;
616
 
                sess->last_identifier = msg->hdr->identifier;
617
 
                os_memcpy(sess->last_authenticator, msg->hdr->authenticator,
618
 
                          16);
619
 
        } else {
620
 
                data->counters.packets_dropped++;
621
 
                client->counters.packets_dropped++;
622
 
        }
623
 
 
624
 
        if (sess->eapSuccess || sess->eapFail) {
625
 
                RADIUS_DEBUG("Removing completed session 0x%x after timeout",
626
 
                             sess->sess_id);
627
 
                eloop_cancel_timeout(radius_server_session_remove_timeout,
628
 
                                     data, sess);
629
 
                eloop_register_timeout(10, 0,
630
 
                                       radius_server_session_remove_timeout,
631
 
                                       data, sess);
632
 
        }
633
 
 
634
 
        return 0;
635
 
}
636
 
 
637
 
 
638
 
static void radius_server_receive_auth(int sock, void *eloop_ctx,
639
 
                                       void *sock_ctx)
640
 
{
641
 
        struct radius_server_data *data = eloop_ctx;
642
 
        u8 *buf = NULL;
643
 
        struct sockaddr_storage from;
644
 
        socklen_t fromlen;
645
 
        int len;
646
 
        struct radius_client *client = NULL;
647
 
        struct radius_msg *msg = NULL;
648
 
        char abuf[50];
649
 
        int from_port = 0;
650
 
 
651
 
        buf = malloc(RADIUS_MAX_MSG_LEN);
652
 
        if (buf == NULL) {
653
 
                goto fail;
654
 
        }
655
 
 
656
 
        fromlen = sizeof(from);
657
 
        len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
658
 
                       (struct sockaddr *) &from, &fromlen);
659
 
        if (len < 0) {
660
 
                perror("recvfrom[radius_server]");
661
 
                goto fail;
662
 
        }
663
 
 
664
 
#ifdef CONFIG_IPV6
665
 
        if (data->ipv6) {
666
 
                struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from;
667
 
                if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf))
668
 
                    == NULL)
669
 
                        abuf[0] = '\0';
670
 
                from_port = ntohs(from6->sin6_port);
671
 
                RADIUS_DEBUG("Received %d bytes from %s:%d",
672
 
                             len, abuf, from_port);
673
 
 
674
 
                client = radius_server_get_client(data,
675
 
                                                  (struct in_addr *)
676
 
                                                  &from6->sin6_addr, 1);
677
 
        }
678
 
#endif /* CONFIG_IPV6 */
679
 
 
680
 
        if (!data->ipv6) {
681
 
                struct sockaddr_in *from4 = (struct sockaddr_in *) &from;
682
 
                os_strlcpy(abuf, inet_ntoa(from4->sin_addr), sizeof(abuf));
683
 
                from_port = ntohs(from4->sin_port);
684
 
                RADIUS_DEBUG("Received %d bytes from %s:%d",
685
 
                             len, abuf, from_port);
686
 
 
687
 
                client = radius_server_get_client(data, &from4->sin_addr, 0);
688
 
        }
689
 
 
690
 
        RADIUS_DUMP("Received data", buf, len);
691
 
 
692
 
        if (client == NULL) {
693
 
                RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
694
 
                data->counters.invalid_requests++;
695
 
                goto fail;
696
 
        }
697
 
 
698
 
        msg = radius_msg_parse(buf, len);
699
 
        if (msg == NULL) {
700
 
                RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
701
 
                data->counters.malformed_access_requests++;
702
 
                client->counters.malformed_access_requests++;
703
 
                goto fail;
704
 
        }
705
 
 
706
 
        free(buf);
707
 
        buf = NULL;
708
 
 
709
 
        if (wpa_debug_level <= MSG_MSGDUMP) {
710
 
                radius_msg_dump(msg);
711
 
        }
712
 
 
713
 
        if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
714
 
                RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
715
 
                data->counters.unknown_types++;
716
 
                client->counters.unknown_types++;
717
 
                goto fail;
718
 
        }
719
 
 
720
 
        data->counters.access_requests++;
721
 
        client->counters.access_requests++;
722
 
 
723
 
        if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
724
 
                                       client->shared_secret_len, NULL)) {
725
 
                RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
726
 
                data->counters.bad_authenticators++;
727
 
                client->counters.bad_authenticators++;
728
 
                goto fail;
729
 
        }
730
 
 
731
 
        if (radius_server_request(data, msg, (struct sockaddr *) &from,
732
 
                                  fromlen, client, abuf, from_port, NULL) ==
733
 
            -2)
734
 
                return; /* msg was stored with the session */
735
 
 
736
 
fail:
737
 
        if (msg) {
738
 
                radius_msg_free(msg);
739
 
                free(msg);
740
 
        }
741
 
        free(buf);
742
 
}
743
 
 
744
 
 
745
 
static int radius_server_open_socket(int port)
746
 
{
747
 
        int s;
748
 
        struct sockaddr_in addr;
749
 
 
750
 
        s = socket(PF_INET, SOCK_DGRAM, 0);
751
 
        if (s < 0) {
752
 
                perror("socket");
753
 
                return -1;
754
 
        }
755
 
 
756
 
        memset(&addr, 0, sizeof(addr));
757
 
        addr.sin_family = AF_INET;
758
 
        addr.sin_port = htons(port);
759
 
        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
760
 
                perror("bind");
761
 
                close(s);
762
 
                return -1;
763
 
        }
764
 
 
765
 
        return s;
766
 
}
767
 
 
768
 
 
769
 
#ifdef CONFIG_IPV6
770
 
static int radius_server_open_socket6(int port)
771
 
{
772
 
        int s;
773
 
        struct sockaddr_in6 addr;
774
 
 
775
 
        s = socket(PF_INET6, SOCK_DGRAM, 0);
776
 
        if (s < 0) {
777
 
                perror("socket[IPv6]");
778
 
                return -1;
779
 
        }
780
 
 
781
 
        memset(&addr, 0, sizeof(addr));
782
 
        addr.sin6_family = AF_INET6;
783
 
        memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
784
 
        addr.sin6_port = htons(port);
785
 
        if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
786
 
                perror("bind");
787
 
                close(s);
788
 
                return -1;
789
 
        }
790
 
 
791
 
        return s;
792
 
}
793
 
#endif /* CONFIG_IPV6 */
794
 
 
795
 
 
796
 
static void radius_server_free_sessions(struct radius_server_data *data,
797
 
                                        struct radius_session *sessions)
798
 
{
799
 
        struct radius_session *session, *prev;
800
 
 
801
 
        session = sessions;
802
 
        while (session) {
803
 
                prev = session;
804
 
                session = session->next;
805
 
                radius_server_session_free(data, prev);
806
 
        }
807
 
}
808
 
 
809
 
 
810
 
static void radius_server_free_clients(struct radius_server_data *data,
811
 
                                       struct radius_client *clients)
812
 
{
813
 
        struct radius_client *client, *prev;
814
 
 
815
 
        client = clients;
816
 
        while (client) {
817
 
                prev = client;
818
 
                client = client->next;
819
 
 
820
 
                radius_server_free_sessions(data, prev->sessions);
821
 
                free(prev->shared_secret);
822
 
                free(prev);
823
 
        }
824
 
}
825
 
 
826
 
 
827
 
static struct radius_client *
828
 
radius_server_read_clients(const char *client_file, int ipv6)
829
 
{
830
 
        FILE *f;
831
 
        const int buf_size = 1024;
832
 
        char *buf, *pos;
833
 
        struct radius_client *clients, *tail, *entry;
834
 
        int line = 0, mask, failed = 0, i;
835
 
        struct in_addr addr;
836
 
#ifdef CONFIG_IPV6
837
 
        struct in6_addr addr6;
838
 
#endif /* CONFIG_IPV6 */
839
 
        unsigned int val;
840
 
 
841
 
        f = fopen(client_file, "r");
842
 
        if (f == NULL) {
843
 
                RADIUS_ERROR("Could not open client file '%s'", client_file);
844
 
                return NULL;
845
 
        }
846
 
 
847
 
        buf = malloc(buf_size);
848
 
        if (buf == NULL) {
849
 
                fclose(f);
850
 
                return NULL;
851
 
        }
852
 
 
853
 
        clients = tail = NULL;
854
 
        while (fgets(buf, buf_size, f)) {
855
 
                /* Configuration file format:
856
 
                 * 192.168.1.0/24 secret
857
 
                 * 192.168.1.2 secret
858
 
                 * fe80::211:22ff:fe33:4455/64 secretipv6
859
 
                 */
860
 
                line++;
861
 
                buf[buf_size - 1] = '\0';
862
 
                pos = buf;
863
 
                while (*pos != '\0' && *pos != '\n')
864
 
                        pos++;
865
 
                if (*pos == '\n')
866
 
                        *pos = '\0';
867
 
                if (*buf == '\0' || *buf == '#')
868
 
                        continue;
869
 
 
870
 
                pos = buf;
871
 
                while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
872
 
                       (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
873
 
                       (*pos >= 'A' && *pos <= 'F')) {
874
 
                        pos++;
875
 
                }
876
 
 
877
 
                if (*pos == '\0') {
878
 
                        failed = 1;
879
 
                        break;
880
 
                }
881
 
 
882
 
                if (*pos == '/') {
883
 
                        char *end;
884
 
                        *pos++ = '\0';
885
 
                        mask = strtol(pos, &end, 10);
886
 
                        if ((pos == end) ||
887
 
                            (mask < 0 || mask > (ipv6 ? 128 : 32))) {
888
 
                                failed = 1;
889
 
                                break;
890
 
                        }
891
 
                        pos = end;
892
 
                } else {
893
 
                        mask = ipv6 ? 128 : 32;
894
 
                        *pos++ = '\0';
895
 
                }
896
 
 
897
 
                if (!ipv6 && inet_aton(buf, &addr) == 0) {
898
 
                        failed = 1;
899
 
                        break;
900
 
                }
901
 
#ifdef CONFIG_IPV6
902
 
                if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
903
 
                        if (inet_pton(AF_INET, buf, &addr) <= 0) {
904
 
                                failed = 1;
905
 
                                break;
906
 
                        }
907
 
                        /* Convert IPv4 address to IPv6 */
908
 
                        if (mask <= 32)
909
 
                                mask += (128 - 32);
910
 
                        memset(addr6.s6_addr, 0, 10);
911
 
                        addr6.s6_addr[10] = 0xff;
912
 
                        addr6.s6_addr[11] = 0xff;
913
 
                        memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 4);
914
 
                }
915
 
#endif /* CONFIG_IPV6 */
916
 
 
917
 
                while (*pos == ' ' || *pos == '\t') {
918
 
                        pos++;
919
 
                }
920
 
 
921
 
                if (*pos == '\0') {
922
 
                        failed = 1;
923
 
                        break;
924
 
                }
925
 
 
926
 
                entry = os_zalloc(sizeof(*entry));
927
 
                if (entry == NULL) {
928
 
                        failed = 1;
929
 
                        break;
930
 
                }
931
 
                entry->shared_secret = strdup(pos);
932
 
                if (entry->shared_secret == NULL) {
933
 
                        failed = 1;
934
 
                        free(entry);
935
 
                        break;
936
 
                }
937
 
                entry->shared_secret_len = strlen(entry->shared_secret);
938
 
                entry->addr.s_addr = addr.s_addr;
939
 
                if (!ipv6) {
940
 
                        val = 0;
941
 
                        for (i = 0; i < mask; i++)
942
 
                                val |= 1 << (31 - i);
943
 
                        entry->mask.s_addr = htonl(val);
944
 
                }
945
 
#ifdef CONFIG_IPV6
946
 
                if (ipv6) {
947
 
                        int offset = mask / 8;
948
 
 
949
 
                        memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
950
 
                        memset(entry->mask6.s6_addr, 0xff, offset);
951
 
                        val = 0;
952
 
                        for (i = 0; i < (mask % 8); i++)
953
 
                                val |= 1 << (7 - i);
954
 
                        if (offset < 16)
955
 
                                entry->mask6.s6_addr[offset] = val;
956
 
                }
957
 
#endif /* CONFIG_IPV6 */
958
 
 
959
 
                if (tail == NULL) {
960
 
                        clients = tail = entry;
961
 
                } else {
962
 
                        tail->next = entry;
963
 
                        tail = entry;
964
 
                }
965
 
        }
966
 
 
967
 
        if (failed) {
968
 
                RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
969
 
                radius_server_free_clients(NULL, clients);
970
 
                clients = NULL;
971
 
        }
972
 
 
973
 
        free(buf);
974
 
        fclose(f);
975
 
 
976
 
        return clients;
977
 
}
978
 
 
979
 
 
980
 
struct radius_server_data *
981
 
radius_server_init(struct radius_server_conf *conf)
982
 
{
983
 
        struct radius_server_data *data;
984
 
 
985
 
#ifndef CONFIG_IPV6
986
 
        if (conf->ipv6) {
987
 
                fprintf(stderr, "RADIUS server compiled without IPv6 "
988
 
                        "support.\n");
989
 
                return NULL;
990
 
        }
991
 
#endif /* CONFIG_IPV6 */
992
 
 
993
 
        data = os_zalloc(sizeof(*data));
994
 
        if (data == NULL)
995
 
                return NULL;
996
 
 
997
 
        os_get_time(&data->start_time);
998
 
        data->conf_ctx = conf->conf_ctx;
999
 
        data->eap_sim_db_priv = conf->eap_sim_db_priv;
1000
 
        data->ssl_ctx = conf->ssl_ctx;
1001
 
        data->ipv6 = conf->ipv6;
1002
 
        data->get_eap_user = conf->get_eap_user;
1003
 
 
1004
 
        data->clients = radius_server_read_clients(conf->client_file,
1005
 
                                                   conf->ipv6);
1006
 
        if (data->clients == NULL) {
1007
 
                printf("No RADIUS clients configured.\n");
1008
 
                radius_server_deinit(data);
1009
 
                return NULL;
1010
 
        }
1011
 
 
1012
 
#ifdef CONFIG_IPV6
1013
 
        if (conf->ipv6)
1014
 
                data->auth_sock = radius_server_open_socket6(conf->auth_port);
1015
 
        else
1016
 
#endif /* CONFIG_IPV6 */
1017
 
        data->auth_sock = radius_server_open_socket(conf->auth_port);
1018
 
        if (data->auth_sock < 0) {
1019
 
                printf("Failed to open UDP socket for RADIUS authentication "
1020
 
                       "server\n");
1021
 
                radius_server_deinit(data);
1022
 
                return NULL;
1023
 
        }
1024
 
        if (eloop_register_read_sock(data->auth_sock,
1025
 
                                     radius_server_receive_auth,
1026
 
                                     data, NULL)) {
1027
 
                radius_server_deinit(data);
1028
 
                return NULL;
1029
 
        }
1030
 
 
1031
 
        return data;
1032
 
}
1033
 
 
1034
 
 
1035
 
void radius_server_deinit(struct radius_server_data *data)
1036
 
{
1037
 
        if (data == NULL)
1038
 
                return;
1039
 
 
1040
 
        if (data->auth_sock >= 0) {
1041
 
                eloop_unregister_read_sock(data->auth_sock);
1042
 
                close(data->auth_sock);
1043
 
        }
1044
 
 
1045
 
        radius_server_free_clients(data, data->clients);
1046
 
 
1047
 
        free(data);
1048
 
}
1049
 
 
1050
 
 
1051
 
int radius_server_get_mib(struct radius_server_data *data, char *buf,
1052
 
                          size_t buflen)
1053
 
{
1054
 
        int ret, uptime;
1055
 
        unsigned int idx;
1056
 
        char *end, *pos;
1057
 
        struct os_time now;
1058
 
        struct radius_client *cli;
1059
 
 
1060
 
        /* RFC 2619 - RADIUS Authentication Server MIB */
1061
 
 
1062
 
        if (data == NULL || buflen == 0)
1063
 
                return 0;
1064
 
 
1065
 
        pos = buf;
1066
 
        end = buf + buflen;
1067
 
 
1068
 
        os_get_time(&now);
1069
 
        uptime = (now.sec - data->start_time.sec) * 100 +
1070
 
                ((now.usec - data->start_time.usec) / 10000) % 100;
1071
 
        ret = snprintf(pos, end - pos,
1072
 
                       "RADIUS-AUTH-SERVER-MIB\n"
1073
 
                       "radiusAuthServIdent=hostapd\n"
1074
 
                       "radiusAuthServUpTime=%d\n"
1075
 
                       "radiusAuthServResetTime=0\n"
1076
 
                       "radiusAuthServConfigReset=4\n",
1077
 
                       uptime);
1078
 
        if (ret < 0 || ret >= end - pos) {
1079
 
                *pos = '\0';
1080
 
                return pos - buf;
1081
 
        }
1082
 
        pos += ret;
1083
 
 
1084
 
        ret = snprintf(pos, end - pos,
1085
 
                       "radiusAuthServTotalAccessRequests=%u\n"
1086
 
                       "radiusAuthServTotalInvalidRequests=%u\n"
1087
 
                       "radiusAuthServTotalDupAccessRequests=%u\n"
1088
 
                       "radiusAuthServTotalAccessAccepts=%u\n"
1089
 
                       "radiusAuthServTotalAccessRejects=%u\n"
1090
 
                       "radiusAuthServTotalAccessChallenges=%u\n"
1091
 
                       "radiusAuthServTotalMalformedAccessRequests=%u\n"
1092
 
                       "radiusAuthServTotalBadAuthenticators=%u\n"
1093
 
                       "radiusAuthServTotalPacketsDropped=%u\n"
1094
 
                       "radiusAuthServTotalUnknownTypes=%u\n",
1095
 
                       data->counters.access_requests,
1096
 
                       data->counters.invalid_requests,
1097
 
                       data->counters.dup_access_requests,
1098
 
                       data->counters.access_accepts,
1099
 
                       data->counters.access_rejects,
1100
 
                       data->counters.access_challenges,
1101
 
                       data->counters.malformed_access_requests,
1102
 
                       data->counters.bad_authenticators,
1103
 
                       data->counters.packets_dropped,
1104
 
                       data->counters.unknown_types);
1105
 
        if (ret < 0 || ret >= end - pos) {
1106
 
                *pos = '\0';
1107
 
                return pos - buf;
1108
 
        }
1109
 
        pos += ret;
1110
 
 
1111
 
        for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
1112
 
                char abuf[50], mbuf[50];
1113
 
#ifdef CONFIG_IPV6
1114
 
                if (data->ipv6) {
1115
 
                        if (inet_ntop(AF_INET6, &cli->addr6, abuf,
1116
 
                                      sizeof(abuf)) == NULL)
1117
 
                                abuf[0] = '\0';
1118
 
                        if (inet_ntop(AF_INET6, &cli->mask6, abuf,
1119
 
                                      sizeof(mbuf)) == NULL)
1120
 
                                mbuf[0] = '\0';
1121
 
                }
1122
 
#endif /* CONFIG_IPV6 */
1123
 
                if (!data->ipv6) {
1124
 
                        os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
1125
 
                        os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
1126
 
                }
1127
 
 
1128
 
                ret = snprintf(pos, end - pos,
1129
 
                               "radiusAuthClientIndex=%u\n"
1130
 
                               "radiusAuthClientAddress=%s/%s\n"
1131
 
                               "radiusAuthServAccessRequests=%u\n"
1132
 
                               "radiusAuthServDupAccessRequests=%u\n"
1133
 
                               "radiusAuthServAccessAccepts=%u\n"
1134
 
                               "radiusAuthServAccessRejects=%u\n"
1135
 
                               "radiusAuthServAccessChallenges=%u\n"
1136
 
                               "radiusAuthServMalformedAccessRequests=%u\n"
1137
 
                               "radiusAuthServBadAuthenticators=%u\n"
1138
 
                               "radiusAuthServPacketsDropped=%u\n"
1139
 
                               "radiusAuthServUnknownTypes=%u\n",
1140
 
                               idx,
1141
 
                               abuf, mbuf,
1142
 
                               cli->counters.access_requests,
1143
 
                               cli->counters.dup_access_requests,
1144
 
                               cli->counters.access_accepts,
1145
 
                               cli->counters.access_rejects,
1146
 
                               cli->counters.access_challenges,
1147
 
                               cli->counters.malformed_access_requests,
1148
 
                               cli->counters.bad_authenticators,
1149
 
                               cli->counters.packets_dropped,
1150
 
                               cli->counters.unknown_types);
1151
 
                if (ret < 0 || ret >= end - pos) {
1152
 
                        *pos = '\0';
1153
 
                        return pos - buf;
1154
 
                }
1155
 
                pos += ret;
1156
 
        }
1157
 
 
1158
 
        return pos - buf;
1159
 
}
1160
 
 
1161
 
 
1162
 
static Boolean radius_server_get_bool(void *ctx, enum eapol_bool_var variable)
1163
 
{
1164
 
        struct radius_session *sess = ctx;
1165
 
        if (sess == NULL)
1166
 
                return FALSE;
1167
 
        switch (variable) {
1168
 
        case EAPOL_eapSuccess:
1169
 
                return sess->eapSuccess;
1170
 
        case EAPOL_eapRestart:
1171
 
                return sess->eapRestart;
1172
 
        case EAPOL_eapFail:
1173
 
                return sess->eapFail;
1174
 
        case EAPOL_eapResp:
1175
 
                return sess->eapResp;
1176
 
        case EAPOL_eapReq:
1177
 
                return sess->eapReq;
1178
 
        case EAPOL_eapNoReq:
1179
 
                return sess->eapNoReq;
1180
 
        case EAPOL_portEnabled:
1181
 
                return sess->portEnabled;
1182
 
        case EAPOL_eapTimeout:
1183
 
                return sess->eapTimeout;
1184
 
        }
1185
 
        return FALSE;
1186
 
}
1187
 
 
1188
 
 
1189
 
static void radius_server_set_bool(void *ctx, enum eapol_bool_var variable,
1190
 
                              Boolean value)
1191
 
{
1192
 
        struct radius_session *sess = ctx;
1193
 
        if (sess == NULL)
1194
 
                return;
1195
 
        switch (variable) {
1196
 
        case EAPOL_eapSuccess:
1197
 
                sess->eapSuccess = value;
1198
 
                break;
1199
 
        case EAPOL_eapRestart:
1200
 
                sess->eapRestart = value;
1201
 
                break;
1202
 
        case EAPOL_eapFail:
1203
 
                sess->eapFail = value;
1204
 
                break;
1205
 
        case EAPOL_eapResp:
1206
 
                sess->eapResp = value;
1207
 
                break;
1208
 
        case EAPOL_eapReq:
1209
 
                sess->eapReq = value;
1210
 
                break;
1211
 
        case EAPOL_eapNoReq:
1212
 
                sess->eapNoReq = value;
1213
 
                break;
1214
 
        case EAPOL_portEnabled:
1215
 
                sess->portEnabled = value;
1216
 
                break;
1217
 
        case EAPOL_eapTimeout:
1218
 
                sess->eapTimeout = value;
1219
 
                break;
1220
 
        }
1221
 
}
1222
 
 
1223
 
 
1224
 
static void radius_server_set_eapReqData(void *ctx, const u8 *eapReqData,
1225
 
                                    size_t eapReqDataLen)
1226
 
{
1227
 
        struct radius_session *sess = ctx;
1228
 
        if (sess == NULL)
1229
 
                return;
1230
 
 
1231
 
        free(sess->eapReqData);
1232
 
        sess->eapReqData = malloc(eapReqDataLen);
1233
 
        if (sess->eapReqData) {
1234
 
                memcpy(sess->eapReqData, eapReqData, eapReqDataLen);
1235
 
                sess->eapReqDataLen = eapReqDataLen;
1236
 
        } else {
1237
 
                sess->eapReqDataLen = 0;
1238
 
        }
1239
 
}
1240
 
 
1241
 
 
1242
 
static void radius_server_set_eapKeyData(void *ctx, const u8 *eapKeyData,
1243
 
                                    size_t eapKeyDataLen)
1244
 
{
1245
 
        struct radius_session *sess = ctx;
1246
 
 
1247
 
        if (sess == NULL)
1248
 
                return;
1249
 
 
1250
 
        free(sess->eapKeyData);
1251
 
        if (eapKeyData) {
1252
 
                sess->eapKeyData = malloc(eapKeyDataLen);
1253
 
                if (sess->eapKeyData) {
1254
 
                        memcpy(sess->eapKeyData, eapKeyData, eapKeyDataLen);
1255
 
                        sess->eapKeyDataLen = eapKeyDataLen;
1256
 
                } else {
1257
 
                        sess->eapKeyDataLen = 0;
1258
 
                }
1259
 
        } else {
1260
 
                sess->eapKeyData = NULL;
1261
 
                sess->eapKeyDataLen = 0;
1262
 
        }
1263
 
}
1264
 
 
1265
 
 
1266
 
static int radius_server_get_eap_user(void *ctx, const u8 *identity,
1267
 
                                      size_t identity_len, int phase2,
1268
 
                                      struct eap_user *user)
1269
 
{
1270
 
        struct radius_session *sess = ctx;
1271
 
        struct radius_server_data *data = sess->server;
1272
 
 
1273
 
        return data->get_eap_user(data->conf_ctx, identity, identity_len,
1274
 
                                  phase2, user);
1275
 
}
1276
 
 
1277
 
 
1278
 
static struct eapol_callbacks radius_server_eapol_cb =
1279
 
{
1280
 
        .get_bool = radius_server_get_bool,
1281
 
        .set_bool = radius_server_set_bool,
1282
 
        .set_eapReqData = radius_server_set_eapReqData,
1283
 
        .set_eapKeyData = radius_server_set_eapKeyData,
1284
 
        .get_eap_user = radius_server_get_eap_user,
1285
 
};
1286
 
 
1287
 
 
1288
 
void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
1289
 
{
1290
 
        struct radius_client *cli;
1291
 
        struct radius_session *s, *sess = NULL;
1292
 
        struct radius_msg *msg;
1293
 
 
1294
 
        if (data == NULL)
1295
 
                return;
1296
 
 
1297
 
        for (cli = data->clients; cli; cli = cli->next) {
1298
 
                for (s = cli->sessions; s; s = s->next) {
1299
 
                        if (s->eap == ctx && s->last_msg) {
1300
 
                                sess = s;
1301
 
                                break;
1302
 
                        }
1303
 
                        if (sess)
1304
 
                                break;
1305
 
                }
1306
 
                if (sess)
1307
 
                        break;
1308
 
        }
1309
 
 
1310
 
        if (sess == NULL) {
1311
 
                RADIUS_DEBUG("No session matched callback ctx");
1312
 
                return;
1313
 
        }
1314
 
 
1315
 
        msg = sess->last_msg;
1316
 
        sess->last_msg = NULL;
1317
 
        eap_sm_pending_cb(sess->eap);
1318
 
        if (radius_server_request(data, msg,
1319
 
                                  (struct sockaddr *) &sess->last_from,
1320
 
                                  sess->last_fromlen, cli,
1321
 
                                  sess->last_from_addr,
1322
 
                                  sess->last_from_port, sess) == -2)
1323
 
                return; /* msg was stored with the session */
1324
 
 
1325
 
        radius_msg_free(msg);
1326
 
        free(msg);
1327
 
}