Import hostapd 0.5.8
[dragonfly.git] / contrib / hostapd-0.5.8 / radius_client.c
1 /*
2  * hostapd / RADIUS client
3  * Copyright (c) 2002-2005, 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
17 #include "hostapd.h"
18 #include "radius.h"
19 #include "radius_client.h"
20 #include "eloop.h"
21
22 /* Defaults for RADIUS retransmit values (exponential backoff) */
23 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
24 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
25 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
26                                       * before entry is removed from retransmit
27                                       * list */
28 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
29                                       * list (oldest will be removed, if this
30                                       * limit is exceeded) */
31 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
32                                       * many failed retry attempts */
33
34
35 struct radius_rx_handler {
36         RadiusRxResult (*handler)(struct radius_msg *msg,
37                                   struct radius_msg *req,
38                                   u8 *shared_secret, size_t shared_secret_len,
39                                   void *data);
40         void *data;
41 };
42
43
44 /* RADIUS message retransmit list */
45 struct radius_msg_list {
46         u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
47                             * for the same STA. */
48         struct radius_msg *msg;
49         RadiusType msg_type;
50         os_time_t first_try;
51         os_time_t next_try;
52         int attempts;
53         int next_wait;
54         struct os_time last_attempt;
55
56         u8 *shared_secret;
57         size_t shared_secret_len;
58
59         /* TODO: server config with failover to backup server(s) */
60
61         struct radius_msg_list *next;
62 };
63
64
65 struct radius_client_data {
66         void *ctx;
67         struct hostapd_radius_servers *conf;
68
69         int auth_serv_sock; /* socket for authentication RADIUS messages */
70         int acct_serv_sock; /* socket for accounting RADIUS messages */
71         int auth_serv_sock6;
72         int acct_serv_sock6;
73         int auth_sock; /* currently used socket */
74         int acct_sock; /* currently used socket */
75
76         struct radius_rx_handler *auth_handlers;
77         size_t num_auth_handlers;
78         struct radius_rx_handler *acct_handlers;
79         size_t num_acct_handlers;
80
81         struct radius_msg_list *msgs;
82         size_t num_msgs;
83
84         u8 next_radius_identifier;
85 };
86
87
88 static int
89 radius_change_server(struct radius_client_data *radius,
90                      struct hostapd_radius_server *nserv,
91                      struct hostapd_radius_server *oserv,
92                      int sock, int sock6, int auth);
93 static int radius_client_init_acct(struct radius_client_data *radius);
94 static int radius_client_init_auth(struct radius_client_data *radius);
95
96
97 static void radius_client_msg_free(struct radius_msg_list *req)
98 {
99         radius_msg_free(req->msg);
100         os_free(req->msg);
101         os_free(req);
102 }
103
104
105 int radius_client_register(struct radius_client_data *radius,
106                            RadiusType msg_type,
107                            RadiusRxResult (*handler)(struct radius_msg *msg,
108                                                      struct radius_msg *req,
109                                                      u8 *shared_secret,
110                                                      size_t shared_secret_len,
111                                                      void *data),
112                            void *data)
113 {
114         struct radius_rx_handler **handlers, *newh;
115         size_t *num;
116
117         if (msg_type == RADIUS_ACCT) {
118                 handlers = &radius->acct_handlers;
119                 num = &radius->num_acct_handlers;
120         } else {
121                 handlers = &radius->auth_handlers;
122                 num = &radius->num_auth_handlers;
123         }
124
125         newh = os_realloc(*handlers,
126                           (*num + 1) * sizeof(struct radius_rx_handler));
127         if (newh == NULL)
128                 return -1;
129
130         newh[*num].handler = handler;
131         newh[*num].data = data;
132         (*num)++;
133         *handlers = newh;
134
135         return 0;
136 }
137
138
139 static void radius_client_handle_send_error(struct radius_client_data *radius,
140                                             int s, RadiusType msg_type)
141 {
142 #ifndef CONFIG_NATIVE_WINDOWS
143         int _errno = errno;
144         perror("send[RADIUS]");
145         if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
146                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
147                                HOSTAPD_LEVEL_INFO,
148                                "Send failed - maybe interface status changed -"
149                                " try to connect again");
150                 eloop_unregister_read_sock(s);
151                 close(s);
152                 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
153                         radius_client_init_acct(radius);
154                 else
155                         radius_client_init_auth(radius);
156         }
157 #endif /* CONFIG_NATIVE_WINDOWS */
158 }
159
160
161 static int radius_client_retransmit(struct radius_client_data *radius,
162                                     struct radius_msg_list *entry,
163                                     os_time_t now)
164 {
165         struct hostapd_radius_servers *conf = radius->conf;
166         int s;
167
168         if (entry->msg_type == RADIUS_ACCT ||
169             entry->msg_type == RADIUS_ACCT_INTERIM) {
170                 s = radius->acct_sock;
171                 if (entry->attempts == 0)
172                         conf->acct_server->requests++;
173                 else {
174                         conf->acct_server->timeouts++;
175                         conf->acct_server->retransmissions++;
176                 }
177         } else {
178                 s = radius->auth_sock;
179                 if (entry->attempts == 0)
180                         conf->auth_server->requests++;
181                 else {
182                         conf->auth_server->timeouts++;
183                         conf->auth_server->retransmissions++;
184                 }
185         }
186
187         /* retransmit; remove entry if too many attempts */
188         entry->attempts++;
189         hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
190                        HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
191                        entry->msg->hdr->identifier);
192
193         os_get_time(&entry->last_attempt);
194         if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
195                 radius_client_handle_send_error(radius, s, entry->msg_type);
196
197         entry->next_try = now + entry->next_wait;
198         entry->next_wait *= 2;
199         if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
200                 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
201         if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
202                 printf("Removing un-ACKed RADIUS message due to too many "
203                        "failed retransmit attempts\n");
204                 return 1;
205         }
206
207         return 0;
208 }
209
210
211 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
212 {
213         struct radius_client_data *radius = eloop_ctx;
214         struct hostapd_radius_servers *conf = radius->conf;
215         struct os_time now;
216         os_time_t first;
217         struct radius_msg_list *entry, *prev, *tmp;
218         int auth_failover = 0, acct_failover = 0;
219         char abuf[50];
220
221         entry = radius->msgs;
222         if (!entry)
223                 return;
224
225         os_get_time(&now);
226         first = 0;
227
228         prev = NULL;
229         while (entry) {
230                 if (now.sec >= entry->next_try &&
231                     radius_client_retransmit(radius, entry, now.sec)) {
232                         if (prev)
233                                 prev->next = entry->next;
234                         else
235                                 radius->msgs = entry->next;
236
237                         tmp = entry;
238                         entry = entry->next;
239                         radius_client_msg_free(tmp);
240                         radius->num_msgs--;
241                         continue;
242                 }
243
244                 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
245                         if (entry->msg_type == RADIUS_ACCT ||
246                             entry->msg_type == RADIUS_ACCT_INTERIM)
247                                 acct_failover++;
248                         else
249                                 auth_failover++;
250                 }
251
252                 if (first == 0 || entry->next_try < first)
253                         first = entry->next_try;
254
255                 prev = entry;
256                 entry = entry->next;
257         }
258
259         if (radius->msgs) {
260                 if (first < now.sec)
261                         first = now.sec;
262                 eloop_register_timeout(first - now.sec, 0,
263                                        radius_client_timer, radius, NULL);
264                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
265                                HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
266                                "retransmit in %ld seconds",
267                                (long int) (first - now.sec));
268         }
269
270         if (auth_failover && conf->num_auth_servers > 1) {
271                 struct hostapd_radius_server *next, *old;
272                 old = conf->auth_server;
273                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
274                                HOSTAPD_LEVEL_NOTICE,
275                                "No response from Authentication server "
276                                "%s:%d - failover",
277                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
278                                old->port);
279
280                 for (entry = radius->msgs; entry; entry = entry->next) {
281                         if (entry->msg_type == RADIUS_AUTH)
282                                 old->timeouts++;
283                 }
284
285                 next = old + 1;
286                 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
287                         next = conf->auth_servers;
288                 conf->auth_server = next;
289                 radius_change_server(radius, next, old,
290                                      radius->auth_serv_sock,
291                                      radius->auth_serv_sock6, 1);
292         }
293
294         if (acct_failover && conf->num_acct_servers > 1) {
295                 struct hostapd_radius_server *next, *old;
296                 old = conf->acct_server;
297                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
298                                HOSTAPD_LEVEL_NOTICE,
299                                "No response from Accounting server "
300                                "%s:%d - failover",
301                                hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
302                                old->port);
303
304                 for (entry = radius->msgs; entry; entry = entry->next) {
305                         if (entry->msg_type == RADIUS_ACCT ||
306                             entry->msg_type == RADIUS_ACCT_INTERIM)
307                                 old->timeouts++;
308                 }
309
310                 next = old + 1;
311                 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
312                         next = conf->acct_servers;
313                 conf->acct_server = next;
314                 radius_change_server(radius, next, old,
315                                      radius->acct_serv_sock,
316                                      radius->acct_serv_sock6, 0);
317         }
318 }
319
320
321 static void radius_client_update_timeout(struct radius_client_data *radius)
322 {
323         struct os_time now;
324         os_time_t first;
325         struct radius_msg_list *entry;
326
327         eloop_cancel_timeout(radius_client_timer, radius, NULL);
328
329         if (radius->msgs == NULL) {
330                 return;
331         }
332
333         first = 0;
334         for (entry = radius->msgs; entry; entry = entry->next) {
335                 if (first == 0 || entry->next_try < first)
336                         first = entry->next_try;
337         }
338
339         os_get_time(&now);
340         if (first < now.sec)
341                 first = now.sec;
342         eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
343                                NULL);
344         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
345                        HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
346                        " %ld seconds\n", (long int) (first - now.sec));
347 }
348
349
350 static void radius_client_list_add(struct radius_client_data *radius,
351                                    struct radius_msg *msg,
352                                    RadiusType msg_type, u8 *shared_secret,
353                                    size_t shared_secret_len, const u8 *addr)
354 {
355         struct radius_msg_list *entry, *prev;
356
357         if (eloop_terminated()) {
358                 /* No point in adding entries to retransmit queue since event
359                  * loop has already been terminated. */
360                 radius_msg_free(msg);
361                 os_free(msg);
362                 return;
363         }
364
365         entry = wpa_zalloc(sizeof(*entry));
366         if (entry == NULL) {
367                 printf("Failed to add RADIUS packet into retransmit list\n");
368                 radius_msg_free(msg);
369                 os_free(msg);
370                 return;
371         }
372
373         if (addr)
374                 os_memcpy(entry->addr, addr, ETH_ALEN);
375         entry->msg = msg;
376         entry->msg_type = msg_type;
377         entry->shared_secret = shared_secret;
378         entry->shared_secret_len = shared_secret_len;
379         os_get_time(&entry->last_attempt);
380         entry->first_try = entry->last_attempt.sec;
381         entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
382         entry->attempts = 1;
383         entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
384         entry->next = radius->msgs;
385         radius->msgs = entry;
386         radius_client_update_timeout(radius);
387
388         if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
389                 printf("Removing the oldest un-ACKed RADIUS packet due to "
390                        "retransmit list limits.\n");
391                 prev = NULL;
392                 while (entry->next) {
393                         prev = entry;
394                         entry = entry->next;
395                 }
396                 if (prev) {
397                         prev->next = NULL;
398                         radius_client_msg_free(entry);
399                 }
400         } else
401                 radius->num_msgs++;
402 }
403
404
405 static void radius_client_list_del(struct radius_client_data *radius,
406                                    RadiusType msg_type, const u8 *addr)
407 {
408         struct radius_msg_list *entry, *prev, *tmp;
409
410         if (addr == NULL)
411                 return;
412
413         entry = radius->msgs;
414         prev = NULL;
415         while (entry) {
416                 if (entry->msg_type == msg_type &&
417                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
418                         if (prev)
419                                 prev->next = entry->next;
420                         else
421                                 radius->msgs = entry->next;
422                         tmp = entry;
423                         entry = entry->next;
424                         hostapd_logger(radius->ctx, addr,
425                                        HOSTAPD_MODULE_RADIUS,
426                                        HOSTAPD_LEVEL_DEBUG,
427                                        "Removing matching RADIUS message");
428                         radius_client_msg_free(tmp);
429                         radius->num_msgs--;
430                         continue;
431                 }
432                 prev = entry;
433                 entry = entry->next;
434         }
435 }
436
437
438 int radius_client_send(struct radius_client_data *radius,
439                        struct radius_msg *msg, RadiusType msg_type,
440                        const u8 *addr)
441 {
442         struct hostapd_radius_servers *conf = radius->conf;
443         u8 *shared_secret;
444         size_t shared_secret_len;
445         char *name;
446         int s, res;
447
448         if (msg_type == RADIUS_ACCT_INTERIM) {
449                 /* Remove any pending interim acct update for the same STA. */
450                 radius_client_list_del(radius, msg_type, addr);
451         }
452
453         if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
454                 shared_secret = conf->acct_server->shared_secret;
455                 shared_secret_len = conf->acct_server->shared_secret_len;
456                 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
457                 name = "accounting";
458                 s = radius->acct_sock;
459                 conf->acct_server->requests++;
460         } else {
461                 shared_secret = conf->auth_server->shared_secret;
462                 shared_secret_len = conf->auth_server->shared_secret_len;
463                 radius_msg_finish(msg, shared_secret, shared_secret_len);
464                 name = "authentication";
465                 s = radius->auth_sock;
466                 conf->auth_server->requests++;
467         }
468
469         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
470                        HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
471                        "server", name);
472         if (conf->msg_dumps)
473                 radius_msg_dump(msg);
474
475         res = send(s, msg->buf, msg->buf_used, 0);
476         if (res < 0)
477                 radius_client_handle_send_error(radius, s, msg_type);
478
479         radius_client_list_add(radius, msg, msg_type, shared_secret,
480                                shared_secret_len, addr);
481
482         return res;
483 }
484
485
486 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
487 {
488         struct radius_client_data *radius = eloop_ctx;
489         struct hostapd_radius_servers *conf = radius->conf;
490         RadiusType msg_type = (RadiusType) sock_ctx;
491         int len, roundtrip;
492         unsigned char buf[3000];
493         struct radius_msg *msg;
494         struct radius_rx_handler *handlers;
495         size_t num_handlers, i;
496         struct radius_msg_list *req, *prev_req;
497         struct os_time now;
498         struct hostapd_radius_server *rconf;
499         int invalid_authenticator = 0;
500
501         if (msg_type == RADIUS_ACCT) {
502                 handlers = radius->acct_handlers;
503                 num_handlers = radius->num_acct_handlers;
504                 rconf = conf->acct_server;
505         } else {
506                 handlers = radius->auth_handlers;
507                 num_handlers = radius->num_auth_handlers;
508                 rconf = conf->auth_server;
509         }
510
511         len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
512         if (len < 0) {
513                 perror("recv[RADIUS]");
514                 return;
515         }
516         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
517                        HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
518                        "server", len);
519         if (len == sizeof(buf)) {
520                 printf("Possibly too long UDP frame for our buffer - "
521                        "dropping it\n");
522                 return;
523         }
524
525         msg = radius_msg_parse(buf, len);
526         if (msg == NULL) {
527                 printf("Parsing incoming RADIUS frame failed\n");
528                 rconf->malformed_responses++;
529                 return;
530         }
531
532         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
533                        HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
534         if (conf->msg_dumps)
535                 radius_msg_dump(msg);
536
537         switch (msg->hdr->code) {
538         case RADIUS_CODE_ACCESS_ACCEPT:
539                 rconf->access_accepts++;
540                 break;
541         case RADIUS_CODE_ACCESS_REJECT:
542                 rconf->access_rejects++;
543                 break;
544         case RADIUS_CODE_ACCESS_CHALLENGE:
545                 rconf->access_challenges++;
546                 break;
547         case RADIUS_CODE_ACCOUNTING_RESPONSE:
548                 rconf->responses++;
549                 break;
550         }
551
552         prev_req = NULL;
553         req = radius->msgs;
554         while (req) {
555                 /* TODO: also match by src addr:port of the packet when using
556                  * alternative RADIUS servers (?) */
557                 if ((req->msg_type == msg_type ||
558                      (req->msg_type == RADIUS_ACCT_INTERIM &&
559                       msg_type == RADIUS_ACCT)) &&
560                     req->msg->hdr->identifier == msg->hdr->identifier)
561                         break;
562
563                 prev_req = req;
564                 req = req->next;
565         }
566
567         if (req == NULL) {
568                 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
569                                HOSTAPD_LEVEL_DEBUG,
570                                "No matching RADIUS request found (type=%d "
571                                "id=%d) - dropping packet",
572                                msg_type, msg->hdr->identifier);
573                 goto fail;
574         }
575
576         os_get_time(&now);
577         roundtrip = (now.sec - req->last_attempt.sec) * 100 +
578                 (now.usec - req->last_attempt.usec) / 10000;
579         hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
580                        HOSTAPD_LEVEL_DEBUG,
581                        "Received RADIUS packet matched with a pending "
582                        "request, round trip time %d.%02d sec",
583                        roundtrip / 100, roundtrip % 100);
584         rconf->round_trip_time = roundtrip;
585
586         /* Remove ACKed RADIUS packet from retransmit list */
587         if (prev_req)
588                 prev_req->next = req->next;
589         else
590                 radius->msgs = req->next;
591         radius->num_msgs--;
592
593         for (i = 0; i < num_handlers; i++) {
594                 RadiusRxResult res;
595                 res = handlers[i].handler(msg, req->msg, req->shared_secret,
596                                           req->shared_secret_len,
597                                           handlers[i].data);
598                 switch (res) {
599                 case RADIUS_RX_PROCESSED:
600                         radius_msg_free(msg);
601                         os_free(msg);
602                         /* continue */
603                 case RADIUS_RX_QUEUED:
604                         radius_client_msg_free(req);
605                         return;
606                 case RADIUS_RX_INVALID_AUTHENTICATOR:
607                         invalid_authenticator++;
608                         /* continue */
609                 case RADIUS_RX_UNKNOWN:
610                         /* continue with next handler */
611                         break;
612                 }
613         }
614
615         if (invalid_authenticator)
616                 rconf->bad_authenticators++;
617         else
618                 rconf->unknown_types++;
619         hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
620                        HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
621                        "(type=%d code=%d id=%d)%s - dropping packet",
622                        msg_type, msg->hdr->code, msg->hdr->identifier,
623                        invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
624                        "");
625         radius_client_msg_free(req);
626
627  fail:
628         radius_msg_free(msg);
629         os_free(msg);
630 }
631
632
633 u8 radius_client_get_id(struct radius_client_data *radius)
634 {
635         struct radius_msg_list *entry, *prev, *_remove;
636         u8 id = radius->next_radius_identifier++;
637
638         /* remove entries with matching id from retransmit list to avoid
639          * using new reply from the RADIUS server with an old request */
640         entry = radius->msgs;
641         prev = NULL;
642         while (entry) {
643                 if (entry->msg->hdr->identifier == id) {
644                         hostapd_logger(radius->ctx, entry->addr,
645                                        HOSTAPD_MODULE_RADIUS,
646                                        HOSTAPD_LEVEL_DEBUG,
647                                        "Removing pending RADIUS message, "
648                                        "since its id (%d) is reused", id);
649                         if (prev)
650                                 prev->next = entry->next;
651                         else
652                                 radius->msgs = entry->next;
653                         _remove = entry;
654                 } else {
655                         _remove = NULL;
656                         prev = entry;
657                 }
658                 entry = entry->next;
659
660                 if (_remove)
661                         radius_client_msg_free(_remove);
662         }
663
664         return id;
665 }
666
667
668 void radius_client_flush(struct radius_client_data *radius, int only_auth)
669 {
670         struct radius_msg_list *entry, *prev, *tmp;
671
672         if (!radius)
673                 return;
674
675         prev = NULL;
676         entry = radius->msgs;
677
678         while (entry) {
679                 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
680                         if (prev)
681                                 prev->next = entry->next;
682                         else
683                                 radius->msgs = entry->next;
684
685                         tmp = entry;
686                         entry = entry->next;
687                         radius_client_msg_free(tmp);
688                         radius->num_msgs--;
689                 } else {
690                         prev = entry;
691                         entry = entry->next;
692                 }
693         }
694
695         if (radius->msgs == NULL)
696                 eloop_cancel_timeout(radius_client_timer, radius, NULL);
697 }
698
699
700 void radius_client_update_acct_msgs(struct radius_client_data *radius,
701                                     u8 *shared_secret,
702                                     size_t shared_secret_len)
703 {
704         struct radius_msg_list *entry;
705
706         if (!radius)
707                 return;
708
709         for (entry = radius->msgs; entry; entry = entry->next) {
710                 if (entry->msg_type == RADIUS_ACCT) {
711                         entry->shared_secret = shared_secret;
712                         entry->shared_secret_len = shared_secret_len;
713                         radius_msg_finish_acct(entry->msg, shared_secret,
714                                                shared_secret_len);
715                 }
716         }
717 }
718
719
720 static int
721 radius_change_server(struct radius_client_data *radius,
722                      struct hostapd_radius_server *nserv,
723                      struct hostapd_radius_server *oserv,
724                      int sock, int sock6, int auth)
725 {
726         struct sockaddr_in serv;
727 #ifdef CONFIG_IPV6
728         struct sockaddr_in6 serv6;
729 #endif /* CONFIG_IPV6 */
730         struct sockaddr *addr;
731         socklen_t addrlen;
732         char abuf[50];
733         int sel_sock;
734         struct radius_msg_list *entry;
735
736         hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
737                        HOSTAPD_LEVEL_INFO,
738                        "%s server %s:%d",
739                        auth ? "Authentication" : "Accounting",
740                        hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
741                        nserv->port);
742
743         if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
744             os_memcmp(nserv->shared_secret, oserv->shared_secret,
745                       nserv->shared_secret_len) != 0) {
746                 /* Pending RADIUS packets used different shared secret, so
747                  * they need to be modified. Update accounting message
748                  * authenticators here. Authentication messages are removed
749                  * since they would require more changes and the new RADIUS
750                  * server may not be prepared to receive them anyway due to
751                  * missing state information. Client will likely retry
752                  * authentication, so this should not be an issue. */
753                 if (auth)
754                         radius_client_flush(radius, 1);
755                 else {
756                         radius_client_update_acct_msgs(
757                                 radius, nserv->shared_secret,
758                                 nserv->shared_secret_len);
759                 }
760         }
761
762         /* Reset retry counters for the new server */
763         for (entry = radius->msgs; entry; entry = entry->next) {
764                 if ((auth && entry->msg_type != RADIUS_AUTH) ||
765                     (!auth && entry->msg_type != RADIUS_ACCT))
766                         continue;
767                 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
768                 entry->attempts = 0;
769                 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
770         }
771
772         if (radius->msgs) {
773                 eloop_cancel_timeout(radius_client_timer, radius, NULL);
774                 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
775                                        radius_client_timer, radius, NULL);
776         }
777
778         switch (nserv->addr.af) {
779         case AF_INET:
780                 os_memset(&serv, 0, sizeof(serv));
781                 serv.sin_family = AF_INET;
782                 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
783                 serv.sin_port = htons(nserv->port);
784                 addr = (struct sockaddr *) &serv;
785                 addrlen = sizeof(serv);
786                 sel_sock = sock;
787                 break;
788 #ifdef CONFIG_IPV6
789         case AF_INET6:
790                 os_memset(&serv6, 0, sizeof(serv6));
791                 serv6.sin6_family = AF_INET6;
792                 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
793                           sizeof(struct in6_addr));
794                 serv6.sin6_port = htons(nserv->port);
795                 addr = (struct sockaddr *) &serv6;
796                 addrlen = sizeof(serv6);
797                 sel_sock = sock6;
798                 break;
799 #endif /* CONFIG_IPV6 */
800         default:
801                 return -1;
802         }
803
804         if (connect(sel_sock, addr, addrlen) < 0) {
805                 perror("connect[radius]");
806                 return -1;
807         }
808
809         if (auth)
810                 radius->auth_sock = sel_sock;
811         else
812                 radius->acct_sock = sel_sock;
813
814         return 0;
815 }
816
817
818 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
819 {
820         struct radius_client_data *radius = eloop_ctx;
821         struct hostapd_radius_servers *conf = radius->conf;
822         struct hostapd_radius_server *oserv;
823
824         if (radius->auth_sock >= 0 && conf->auth_servers &&
825             conf->auth_server != conf->auth_servers) {
826                 oserv = conf->auth_server;
827                 conf->auth_server = conf->auth_servers;
828                 radius_change_server(radius, conf->auth_server, oserv,
829                                      radius->auth_serv_sock,
830                                      radius->auth_serv_sock6, 1);
831         }
832
833         if (radius->acct_sock >= 0 && conf->acct_servers &&
834             conf->acct_server != conf->acct_servers) {
835                 oserv = conf->acct_server;
836                 conf->acct_server = conf->acct_servers;
837                 radius_change_server(radius, conf->acct_server, oserv,
838                                      radius->acct_serv_sock,
839                                      radius->acct_serv_sock6, 0);
840         }
841
842         if (conf->retry_primary_interval)
843                 eloop_register_timeout(conf->retry_primary_interval, 0,
844                                        radius_retry_primary_timer, radius,
845                                        NULL);
846 }
847
848
849 static int radius_client_init_auth(struct radius_client_data *radius)
850 {
851         struct hostapd_radius_servers *conf = radius->conf;
852         int ok = 0;
853
854         radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
855         if (radius->auth_serv_sock < 0)
856                 perror("socket[PF_INET,SOCK_DGRAM]");
857         else
858                 ok++;
859
860 #ifdef CONFIG_IPV6
861         radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
862         if (radius->auth_serv_sock6 < 0)
863                 perror("socket[PF_INET6,SOCK_DGRAM]");
864         else
865                 ok++;
866 #endif /* CONFIG_IPV6 */
867
868         if (ok == 0)
869                 return -1;
870
871         radius_change_server(radius, conf->auth_server, NULL,
872                              radius->auth_serv_sock, radius->auth_serv_sock6,
873                              1);
874
875         if (radius->auth_serv_sock >= 0 &&
876             eloop_register_read_sock(radius->auth_serv_sock,
877                                      radius_client_receive, radius,
878                                      (void *) RADIUS_AUTH)) {
879                 printf("Could not register read socket for authentication "
880                        "server\n");
881                 return -1;
882         }
883
884 #ifdef CONFIG_IPV6
885         if (radius->auth_serv_sock6 >= 0 &&
886             eloop_register_read_sock(radius->auth_serv_sock6,
887                                      radius_client_receive, radius,
888                                      (void *) RADIUS_AUTH)) {
889                 printf("Could not register read socket for authentication "
890                        "server\n");
891                 return -1;
892         }
893 #endif /* CONFIG_IPV6 */
894
895         return 0;
896 }
897
898
899 static int radius_client_init_acct(struct radius_client_data *radius)
900 {
901         struct hostapd_radius_servers *conf = radius->conf;
902         int ok = 0;
903
904         radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
905         if (radius->acct_serv_sock < 0)
906                 perror("socket[PF_INET,SOCK_DGRAM]");
907         else
908                 ok++;
909
910 #ifdef CONFIG_IPV6
911         radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
912         if (radius->acct_serv_sock6 < 0)
913                 perror("socket[PF_INET6,SOCK_DGRAM]");
914         else
915                 ok++;
916 #endif /* CONFIG_IPV6 */
917
918         if (ok == 0)
919                 return -1;
920
921         radius_change_server(radius, conf->acct_server, NULL,
922                              radius->acct_serv_sock, radius->acct_serv_sock6,
923                              0);
924
925         if (radius->acct_serv_sock >= 0 &&
926             eloop_register_read_sock(radius->acct_serv_sock,
927                                      radius_client_receive, radius,
928                                      (void *) RADIUS_ACCT)) {
929                 printf("Could not register read socket for accounting "
930                        "server\n");
931                 return -1;
932         }
933
934 #ifdef CONFIG_IPV6
935         if (radius->acct_serv_sock6 >= 0 &&
936             eloop_register_read_sock(radius->acct_serv_sock6,
937                                      radius_client_receive, radius,
938                                      (void *) RADIUS_ACCT)) {
939                 printf("Could not register read socket for accounting "
940                        "server\n");
941                 return -1;
942         }
943 #endif /* CONFIG_IPV6 */
944
945         return 0;
946 }
947
948
949 struct radius_client_data *
950 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
951 {
952         struct radius_client_data *radius;
953
954         radius = wpa_zalloc(sizeof(struct radius_client_data));
955         if (radius == NULL)
956                 return NULL;
957
958         radius->ctx = ctx;
959         radius->conf = conf;
960         radius->auth_serv_sock = radius->acct_serv_sock =
961                 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
962                 radius->auth_sock = radius->acct_sock = -1;
963
964         if (conf->auth_server && radius_client_init_auth(radius)) {
965                 radius_client_deinit(radius);
966                 return NULL;
967         }
968
969         if (conf->acct_server && radius_client_init_acct(radius)) {
970                 radius_client_deinit(radius);
971                 return NULL;
972         }
973
974         if (conf->retry_primary_interval)
975                 eloop_register_timeout(conf->retry_primary_interval, 0,
976                                        radius_retry_primary_timer, radius,
977                                        NULL);
978
979         return radius;
980 }
981
982
983 void radius_client_deinit(struct radius_client_data *radius)
984 {
985         if (!radius)
986                 return;
987
988         if (radius->auth_serv_sock >= 0)
989                 eloop_unregister_read_sock(radius->auth_serv_sock);
990         if (radius->acct_serv_sock >= 0)
991                 eloop_unregister_read_sock(radius->acct_serv_sock);
992
993         eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
994
995         radius_client_flush(radius, 0);
996         os_free(radius->auth_handlers);
997         os_free(radius->acct_handlers);
998         os_free(radius);
999 }
1000
1001
1002 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
1003 {
1004         struct radius_msg_list *entry, *prev, *tmp;
1005
1006         prev = NULL;
1007         entry = radius->msgs;
1008         while (entry) {
1009                 if (entry->msg_type == RADIUS_AUTH &&
1010                     os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1011                         hostapd_logger(radius->ctx, addr,
1012                                        HOSTAPD_MODULE_RADIUS,
1013                                        HOSTAPD_LEVEL_DEBUG,
1014                                        "Removing pending RADIUS authentication"
1015                                        " message for removed client");
1016
1017                         if (prev)
1018                                 prev->next = entry->next;
1019                         else
1020                                 radius->msgs = entry->next;
1021
1022                         tmp = entry;
1023                         entry = entry->next;
1024                         radius_client_msg_free(tmp);
1025                         radius->num_msgs--;
1026                         continue;
1027                 }
1028
1029                 prev = entry;
1030                 entry = entry->next;
1031         }
1032 }
1033
1034
1035 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1036                                           struct hostapd_radius_server *serv,
1037                                           struct radius_client_data *cli)
1038 {
1039         int pending = 0;
1040         struct radius_msg_list *msg;
1041         char abuf[50];
1042
1043         if (cli) {
1044                 for (msg = cli->msgs; msg; msg = msg->next) {
1045                         if (msg->msg_type == RADIUS_AUTH)
1046                                 pending++;
1047                 }
1048         }
1049
1050         return os_snprintf(buf, buflen,
1051                            "radiusAuthServerIndex=%d\n"
1052                            "radiusAuthServerAddress=%s\n"
1053                            "radiusAuthClientServerPortNumber=%d\n"
1054                            "radiusAuthClientRoundTripTime=%d\n"
1055                            "radiusAuthClientAccessRequests=%u\n"
1056                            "radiusAuthClientAccessRetransmissions=%u\n"
1057                            "radiusAuthClientAccessAccepts=%u\n"
1058                            "radiusAuthClientAccessRejects=%u\n"
1059                            "radiusAuthClientAccessChallenges=%u\n"
1060                            "radiusAuthClientMalformedAccessResponses=%u\n"
1061                            "radiusAuthClientBadAuthenticators=%u\n"
1062                            "radiusAuthClientPendingRequests=%u\n"
1063                            "radiusAuthClientTimeouts=%u\n"
1064                            "radiusAuthClientUnknownTypes=%u\n"
1065                            "radiusAuthClientPacketsDropped=%u\n",
1066                            serv->index,
1067                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1068                            serv->port,
1069                            serv->round_trip_time,
1070                            serv->requests,
1071                            serv->retransmissions,
1072                            serv->access_accepts,
1073                            serv->access_rejects,
1074                            serv->access_challenges,
1075                            serv->malformed_responses,
1076                            serv->bad_authenticators,
1077                            pending,
1078                            serv->timeouts,
1079                            serv->unknown_types,
1080                            serv->packets_dropped);
1081 }
1082
1083
1084 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1085                                           struct hostapd_radius_server *serv,
1086                                           struct radius_client_data *cli)
1087 {
1088         int pending = 0;
1089         struct radius_msg_list *msg;
1090         char abuf[50];
1091
1092         if (cli) {
1093                 for (msg = cli->msgs; msg; msg = msg->next) {
1094                         if (msg->msg_type == RADIUS_ACCT ||
1095                             msg->msg_type == RADIUS_ACCT_INTERIM)
1096                                 pending++;
1097                 }
1098         }
1099
1100         return os_snprintf(buf, buflen,
1101                            "radiusAccServerIndex=%d\n"
1102                            "radiusAccServerAddress=%s\n"
1103                            "radiusAccClientServerPortNumber=%d\n"
1104                            "radiusAccClientRoundTripTime=%d\n"
1105                            "radiusAccClientRequests=%u\n"
1106                            "radiusAccClientRetransmissions=%u\n"
1107                            "radiusAccClientResponses=%u\n"
1108                            "radiusAccClientMalformedResponses=%u\n"
1109                            "radiusAccClientBadAuthenticators=%u\n"
1110                            "radiusAccClientPendingRequests=%u\n"
1111                            "radiusAccClientTimeouts=%u\n"
1112                            "radiusAccClientUnknownTypes=%u\n"
1113                            "radiusAccClientPacketsDropped=%u\n",
1114                            serv->index,
1115                            hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1116                            serv->port,
1117                            serv->round_trip_time,
1118                            serv->requests,
1119                            serv->retransmissions,
1120                            serv->responses,
1121                            serv->malformed_responses,
1122                            serv->bad_authenticators,
1123                            pending,
1124                            serv->timeouts,
1125                            serv->unknown_types,
1126                            serv->packets_dropped);
1127 }
1128
1129
1130 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1131                           size_t buflen)
1132 {
1133         struct hostapd_radius_servers *conf = radius->conf;
1134         int i;
1135         struct hostapd_radius_server *serv;
1136         int count = 0;
1137
1138         if (conf->auth_servers) {
1139                 for (i = 0; i < conf->num_auth_servers; i++) {
1140                         serv = &conf->auth_servers[i];
1141                         count += radius_client_dump_auth_server(
1142                                 buf + count, buflen - count, serv,
1143                                 serv == conf->auth_server ?
1144                                 radius : NULL);
1145                 }
1146         }
1147
1148         if (conf->acct_servers) {
1149                 for (i = 0; i < conf->num_acct_servers; i++) {
1150                         serv = &conf->acct_servers[i];
1151                         count += radius_client_dump_acct_server(
1152                                 buf + count, buflen - count, serv,
1153                                 serv == conf->acct_server ?
1154                                 radius : NULL);
1155                 }
1156         }
1157
1158         return count;
1159 }
1160
1161
1162 static int radius_servers_diff(struct hostapd_radius_server *nserv,
1163                                struct hostapd_radius_server *oserv,
1164                                int num)
1165 {
1166         int i;
1167
1168         for (i = 0; i < num; i++) {
1169                 if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
1170                     nserv[i].port != oserv[i].port ||
1171                     nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
1172                     memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
1173                            nserv[i].shared_secret_len) != 0)
1174                         return 1;
1175         }
1176
1177         return 0;
1178 }
1179
1180
1181 struct radius_client_data *
1182 radius_client_reconfig(struct radius_client_data *old, void *ctx,
1183                        struct hostapd_radius_servers *oldconf,
1184                        struct hostapd_radius_servers *newconf)
1185 {
1186         radius_client_flush(old, 0);
1187
1188         if (newconf->retry_primary_interval !=
1189             oldconf->retry_primary_interval ||
1190             newconf->num_auth_servers != oldconf->num_auth_servers ||
1191             newconf->num_acct_servers != oldconf->num_acct_servers ||
1192             radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
1193                                 newconf->num_auth_servers) ||
1194             radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
1195                                 newconf->num_acct_servers)) {
1196                 hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
1197                                HOSTAPD_LEVEL_DEBUG,
1198                                "Reconfiguring RADIUS client");
1199                 radius_client_deinit(old);
1200                 return radius_client_init(ctx, newconf);
1201         }
1202
1203         return old;
1204 }