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