Cleaned up proxy handling, trying to get away from potential
[freeradius.git] / src / main / event.c
1 /*
2  * event.c      Server event handling
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007  The FreeRADIUS server project
21  * Copyright 2007  Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/modules.h>
30 #include <freeradius-devel/event.h>
31 #include <freeradius-devel/radius_snmp.h>
32
33 #include <freeradius-devel/rad_assert.h>
34
35 #define USEC (1000000)
36
37 /*
38  *      Ridiculous amounts of local state.
39  */
40 static lrad_event_list_t        *el = NULL;
41 static lrad_packet_list_t       *pl = NULL;
42 static int                      request_num_counter = 0;
43 static struct timeval           now;
44 static time_t                   start_time;
45 static int                      have_children;
46
47 #ifdef HAVE_PTHREAD_H
48 static pthread_mutex_t  proxy_mutex;
49
50 #define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
51 #define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
52 #else
53 /*
54  *      This is easier than ifdef's throughout the code.
55  */
56 #define PTHREAD_MUTEX_LOCK(_x)
57 #define PTHREAD_MUTEX_UNLOCK(_x)
58 #endif
59
60 #define INSERT_EVENT(_function, _ctx) if (!lrad_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
61
62 static lrad_packet_list_t *proxy_list = NULL;
63
64 /*
65  *      We keep the proxy FD's here.  The RADIUS Id's are marked
66  *      "allocated" per Id, via a bit per proxy FD.
67  */
68 static int              proxy_fds[32];
69 static rad_listen_t     *proxy_listeners[32];
70
71 static void request_post_handler(REQUEST *request);
72 static void wait_a_bit(void *ctx);
73
74 static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,
75                                     const char *msg)
76 {
77         radlog(L_ERR, "]%s:%d] %s", file, line, msg);
78         _exit(1);
79 }
80
81 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
82
83
84 static void tv_add(struct timeval *tv, int usec_delay)
85 {
86         if (usec_delay > USEC) {
87                 tv->tv_sec += usec_delay / USEC;
88                 usec_delay %= USEC;
89         }
90         tv->tv_usec += usec_delay;
91
92         if (tv->tv_usec > USEC) {
93                 tv->tv_usec -= USEC;
94                 tv->tv_sec++;
95         }
96 }
97
98 static VALUE_PAIR * radius_pairmake(REQUEST *request, VALUE_PAIR **vps,
99                                    const char *attribute, const char *value)
100 {
101         VALUE_PAIR *vp;
102
103         request = request;      /* -Wunused */
104
105         vp = pairmake(attribute, value, T_OP_SET);
106         if (!vp) {
107                 radlog(L_ERR, "No memory!");
108                 rad_assert("No memory" == NULL);
109                 _exit(1);
110         }
111
112         pairadd(vps, vp);
113
114         return vp;
115 }
116
117 #ifdef WITH_SNMP
118 static void snmp_inc_counters(REQUEST *request)
119 {
120         if (!mainconfig.do_snmp) return;
121
122         if (request->master_state == REQUEST_COUNTED) return;
123
124         if ((request->listener->type != RAD_LISTEN_AUTH) &&
125             (request->listener->type != RAD_LISTEN_ACCT)) return;
126
127         /*
128          *      Update the SNMP statistics.
129          *
130          *      Note that we do NOT do this in a child thread.
131          *      Instead, we update the stats when a request is
132          *      deleted, because only the main server thread calls
133          *      this function, which makes it thread-safe.
134          */
135         switch (request->reply->code) {
136         case PW_AUTHENTICATION_ACK:
137                 rad_snmp.auth.total_responses++;
138                 rad_snmp.auth.total_access_accepts++;
139                 if (request->client) request->client->auth->accepts++;
140                 break;
141
142         case PW_AUTHENTICATION_REJECT:
143                 rad_snmp.auth.total_responses++;
144                 rad_snmp.auth.total_access_rejects++;
145                 if (request->client) request->client->auth->rejects++;
146                 break;
147
148         case PW_ACCESS_CHALLENGE:
149                 rad_snmp.auth.total_responses++;
150                 rad_snmp.auth.total_access_challenges++;
151                 if (request->client) request->client->auth->challenges++;
152                 break;
153
154         case PW_ACCOUNTING_RESPONSE:
155                 rad_snmp.acct.total_responses++;
156                 if (request->client) request->client->auth->responses++;
157                 break;
158
159                 /*
160                  *      No response, it must have been a bad
161                  *      authenticator.
162                  */
163         case 0:
164                 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
165                         rad_snmp.auth.total_bad_authenticators++;
166                         if (request->client) request->client->auth->bad_authenticators++;
167                 }
168                 break;
169
170         default:
171                 break;
172         }
173
174         request->master_state = REQUEST_COUNTED;
175 }
176 #else
177 #define snmp_inc_counters(_x)
178 #endif
179
180
181 static void remove_from_request_hash(REQUEST *request)
182 {
183         if (!request->in_request_hash) return;
184
185         lrad_packet_list_yank(pl, request->packet);
186         request->in_request_hash = FALSE;
187
188         snmp_inc_counters(request);
189 }
190
191
192 static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
193 {
194         RADIUS_PACKET **proxy_p;
195         REQUEST *request;
196
197         PTHREAD_MUTEX_LOCK(&proxy_mutex);
198         proxy_p = lrad_packet_list_find_byreply(proxy_list, reply);
199
200         if (!proxy_p) {
201                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
202                 return NULL;
203         }
204
205         request = lrad_packet2myptr(REQUEST, proxy, proxy_p);
206
207         if (!request) {
208                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
209                 return NULL;
210         }
211
212         request->num_proxied_responses++;
213
214         /*
215          *      Catch the most common case of everything working
216          *      correctly.
217          */
218         if (request->num_proxied_requests == request->num_proxied_responses) {
219                 lrad_packet_list_yank(proxy_list, request->proxy);
220                 lrad_packet_list_id_free(proxy_list, request->proxy);
221                 request->in_proxy_hash = FALSE;
222         }
223
224         /*
225          *      On the FIRST reply, decrement the count of outstanding
226          *      requests.  Note that this is NOT the count of sent
227          *      packets, but whether or not the home server has
228          *      responded at all.
229          */
230         if (!request->proxy_reply &&
231             request->home_server->currently_outstanding) {
232                 request->home_server->currently_outstanding--;
233         }
234
235         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
236
237         return request;
238 }
239
240
241 static void remove_from_proxy_hash(REQUEST *request)
242 {
243         if (!request->in_proxy_hash) return;
244
245         PTHREAD_MUTEX_LOCK(&proxy_mutex);
246         lrad_packet_list_yank(proxy_list, request->proxy);
247         lrad_packet_list_id_free(proxy_list, request->proxy);
248
249         /*
250          *      The home server hasn't replied, but we've given up on
251          *      this request.  Don't count this request against the
252          *      home server.
253          */
254         if (!request->proxy_reply &&
255             request->home_server->currently_outstanding) {
256                 request->home_server->currently_outstanding--;
257         }
258
259         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
260
261         request->in_proxy_hash = FALSE;
262 }
263
264
265 static int insert_into_proxy_hash(REQUEST *request)
266 {
267         int i, proxy;
268         char buf[128];
269
270         rad_assert(request->proxy != NULL);
271         rad_assert(proxy_list != NULL);
272
273         request->proxy->sockfd = -1;
274
275         PTHREAD_MUTEX_LOCK(&proxy_mutex);
276
277         request->home_server->currently_outstanding++;
278         request->home_server->total_requests_sent++;
279
280         /*
281          *      On overflow, back up to ~0.
282          */
283         if (!request->home_server->total_requests_sent) {
284                 request->home_server->total_requests_sent--;
285         }
286
287         if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
288                 int found;
289                 rad_listen_t *proxy_listener;
290
291                 /*
292                  *      Allocate a new proxy fd.  This function adds it
293                  *      into the list of listeners.
294                  */
295                 proxy_listener = proxy_new_listener();
296                 if (!proxy_listener) {
297                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
298                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
299                         return 0;
300                 }
301
302                 /*
303                  *      Cache it locally.
304                  */
305                 found = -1;
306                 proxy = proxy_listener->fd;
307                 for (i = 0; i < 32; i++) {
308                         DEBUG2("PROXY %d %d", i, proxy_fds[(proxy + i) & 0x1f]);
309
310                         /*
311                          *      Found a free entry.  Save the socket,
312                          *      and remember where we saved it.
313                          */
314                         if (proxy_fds[(proxy + i) & 0x1f] == -1) {
315                                 found = (proxy + i) & 0x1f;
316                                 proxy_fds[found] = proxy;
317                                 proxy_listeners[found] = proxy_listener;
318                                 break;
319                         }
320                 }
321                 rad_assert(found >= 0);
322
323                 if (!lrad_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
324                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
325                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
326                         return 0; /* leak proxy_listener */
327
328                 }
329
330                 if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
331                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
332                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
333                         return 0;
334                 }
335         }
336         rad_assert(request->proxy->sockfd >= 0);
337
338         /*
339          *      FIXME: Hack until we get rid of rad_listen_t, and put
340          *      the information into the packet_list.
341          */
342         proxy = -1;
343         for (i = 0; i < 32; i++) {
344                 if (proxy_fds[i] == request->proxy->sockfd) {
345                         proxy = i;
346                         break;
347                 }
348         }
349
350         if (proxy < 0) {
351                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
352                 DEBUG2("ERROR: All sockets are full.");
353                 return 0;
354         }
355
356         rad_assert(proxy_fds[proxy] != -1);
357         rad_assert(proxy_listeners[proxy] != NULL);
358         request->proxy_listener = proxy_listeners[proxy];
359
360         if (!lrad_packet_list_insert(proxy_list, &request->proxy)) {
361                 lrad_packet_list_id_free(proxy_list, request->proxy);
362                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
363                 DEBUG2("ERROR: Failed to insert entry into proxy list");
364                 return 0;
365         }
366
367         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
368
369         DEBUG3(" proxy: allocating destination %s port %d - Id %d",
370                inet_ntop(request->proxy->dst_ipaddr.af,
371                          &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
372                request->proxy->dst_port,
373                request->proxy->id);
374
375         request->in_proxy_hash = TRUE;
376
377         return 1;
378 }
379
380
381 /*
382  *      Called as BOTH an event, and in-line from other functions.
383  */
384 static void wait_for_proxy_id_to_expire(void *ctx)
385 {
386         REQUEST *request = ctx;
387         home_server *home = request->home_server;
388
389         rad_assert(request->magic == REQUEST_MAGIC);
390         rad_assert(request->proxy != NULL);
391
392         request->when = request->proxy_when;
393         request->when.tv_sec += home->response_window;
394
395         if ((request->num_proxied_requests == request->num_proxied_responses) ||
396             timercmp(&now, &request->when, >)) {
397                 if (request->packet) {
398                         DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
399                                request->number, request->packet->id,
400                                (unsigned int) (request->timestamp - start_time));
401                 } else {
402                         DEBUG2("Cleaning up request %d with timestamp +%d",
403                                request->number,
404                                (unsigned int) (request->timestamp - start_time));
405                 }
406                 lrad_event_delete(el, &request->ev);
407                 remove_from_proxy_hash(request);
408                 remove_from_request_hash(request);
409                 request_free(&request);
410                 return;
411         }
412
413         INSERT_EVENT(wait_for_proxy_id_to_expire, request);
414 }
415
416
417 static void wait_for_child_to_die(void *ctx)
418 {
419         REQUEST *request = ctx;
420
421         rad_assert(request->magic == REQUEST_MAGIC);
422
423         if ((request->child_state == REQUEST_QUEUED) |
424             (request->child_state == REQUEST_RUNNING)) {
425                 request->delay += (request->delay >> 1);
426                 tv_add(&request->when, request->delay);
427
428                 DEBUG2("Child is still stuck for request %d", request->number);
429
430                 INSERT_EVENT(wait_for_child_to_die, request);
431                 return;
432         }
433
434         DEBUG2("Child is finally responsive for request %d", request->number);
435         remove_from_request_hash(request);
436
437         if (request->proxy) {
438                 wait_for_proxy_id_to_expire(request);
439                 return;
440         }
441
442         request_free(&request);
443 }
444
445
446 static void cleanup_delay(void *ctx)
447 {
448         REQUEST *request = ctx;
449
450         rad_assert(request->magic == REQUEST_MAGIC);
451         rad_assert((request->child_state == REQUEST_CLEANUP_DELAY) ||
452                    (request->child_state == REQUEST_DONE));
453
454         remove_from_request_hash(request);
455
456         if (request->proxy && request->in_proxy_hash) {
457                 wait_for_proxy_id_to_expire(request);
458                 return;
459         }
460
461         DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
462                request->number, request->packet->id,
463                (unsigned int) (request->timestamp - start_time));
464
465         lrad_event_delete(el, &request->ev);
466         request_free(&request);
467 }
468
469
470 static void reject_delay(void *ctx)
471 {
472         REQUEST *request = ctx;
473
474         rad_assert(request->magic == REQUEST_MAGIC);
475         rad_assert(request->child_state == REQUEST_REJECT_DELAY);
476
477         DEBUG2("Sending delayed reject for request %d", request->number);
478
479         request->listener->send(request->listener, request);
480
481         request->when.tv_sec += mainconfig.cleanup_delay;
482         request->child_state = REQUEST_CLEANUP_DELAY;
483
484         INSERT_EVENT(cleanup_delay, request);
485 }
486
487
488 static void revive_home_server(void *ctx)
489 {
490         home_server *home = ctx;
491
492         home->state = HOME_STATE_ALIVE;
493         DEBUG2("Marking home server alive again... we have no idea if it really is alive or not.");
494         home->currently_outstanding = 0;
495 }
496
497
498 static void no_response_to_ping(void *ctx)
499 {
500         REQUEST *request = ctx;
501         home_server *home = request->home_server;
502         char buffer[128];
503
504         home->num_received_pings = 0;
505
506         DEBUG2("No response to status check %d from home server %s port %d",
507                request->number,
508                inet_ntop(request->proxy->dst_ipaddr.af,
509                          &request->proxy->dst_ipaddr.ipaddr,
510                          buffer, sizeof(buffer)),
511                request->proxy->dst_port);
512
513         wait_for_proxy_id_to_expire(request);
514 }
515
516
517 static void received_response_to_ping(REQUEST *request)
518 {
519         home_server *home = request->home_server;
520         char buffer[128];
521
522         home->num_received_pings++;
523
524         DEBUG2("Received response to status check %d (%d in current sequence)",
525                request->number, home->num_received_pings);
526
527         if (home->num_received_pings < home->num_pings_to_alive) {
528                 wait_for_proxy_id_to_expire(request);
529                 return;
530         }
531
532         DEBUG2("Marking home server %s port %d alive",
533                inet_ntop(request->proxy->dst_ipaddr.af,
534                          &request->proxy->dst_ipaddr.ipaddr,
535                          buffer, sizeof(buffer)),
536                request->proxy->dst_port);
537
538         if (!lrad_event_delete(el, &home->ev)) {
539                 DEBUG2("Hmm... no event for home server, WTF?");
540         }
541
542         if (!lrad_event_delete(el, &request->ev)) {
543                 DEBUG2("Hmm... no event for request, WTF?");
544         }
545
546         wait_for_proxy_id_to_expire(request);
547
548         home->state = HOME_STATE_ALIVE;
549         home->currently_outstanding = 0;
550 }
551
552
553 static void ping_home_server(void *ctx)
554 {
555         uint32_t jitter;
556         home_server *home = ctx;
557         REQUEST *request;
558         VALUE_PAIR *vp;
559
560         if (home->state == HOME_STATE_ALIVE) {
561                 radlog(L_INFO, "Suspicious proxy state... continuing");
562                 return;
563         }
564
565         request = request_alloc();
566         request->number = request_num_counter++;
567
568         request->proxy = rad_alloc(1);
569         rad_assert(request->proxy != NULL);
570
571         gettimeofday(&request->when, NULL);
572         home->when = request->when;
573
574         if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
575                 request->proxy->code = PW_STATUS_SERVER;
576
577                 radius_pairmake(request, &request->proxy->vps,
578                                 "Message-Authenticator", "0x00");
579
580         } else if (home->type == HOME_TYPE_AUTH) {
581                 request->proxy->code = PW_AUTHENTICATION_REQUEST;
582
583                 radius_pairmake(request, &request->proxy->vps,
584                                 "User-Name", home->ping_user_name);
585                 radius_pairmake(request, &request->proxy->vps,
586                                 "User-Password", home->ping_user_password);
587                 radius_pairmake(request, &request->proxy->vps,
588                                 "Service-Type", "Authenticate-Only");
589                 radius_pairmake(request, &request->proxy->vps,
590                                 "Message-Authenticator", "0x00");
591
592         } else {
593                 request->proxy->code = PW_ACCOUNTING_REQUEST;
594                 
595                 radius_pairmake(request, &request->proxy->vps,
596                                 "User-Name", home->ping_user_name);
597                 radius_pairmake(request, &request->proxy->vps,
598                                 "Acct-Status-Type", "Stop");
599                 radius_pairmake(request, &request->proxy->vps,
600                                 "Acct-Session-Id", "00000000");
601                 vp = radius_pairmake(request, &request->proxy->vps,
602                                      "Event-Timestamp", "0");
603                 vp->vp_date = now.tv_sec;
604         }
605
606         radius_pairmake(request, &request->proxy->vps,
607                         "NAS-Identifier", "Status Check. Are you alive?");
608
609         request->proxy->dst_ipaddr = home->ipaddr;
610         request->proxy->dst_port = home->port;
611         request->home_server = home;
612
613         rad_assert(request->proxy_listener == NULL);
614
615         if (!insert_into_proxy_hash(request)) {
616                 DEBUG2("Failed inserting status check %d into proxy hash.  Discarding it.",
617                        request->number);
618                 request_free(&request);
619                 return;
620         }
621         rad_assert(request->proxy_listener != NULL);
622         request->proxy_listener->send(request->proxy_listener,
623                                       request);
624
625         request->next_callback = NULL;
626         request->child_state = REQUEST_PROXIED;
627         request->when.tv_sec += home->ping_timeout;;
628
629         INSERT_EVENT(no_response_to_ping, request);
630
631         /*
632          *      Add +/- 2s of jitter, as suggested in RFC 3539
633          *      and in the Issues and Fixes draft.
634          */
635         home->when.tv_sec += home->ping_interval - 2;
636
637         jitter = lrad_rand();
638         jitter ^= (jitter >> 10);
639         jitter &= ((1 << 23) - 1); /* 22 bits of 1 */
640
641         tv_add(&home->when, jitter);
642
643
644         INSERT_EVENT(ping_home_server, home);
645 }
646
647
648 static void check_for_zombie_home_server(REQUEST *request)
649 {
650         home_server *home;
651         struct timeval when;
652         char buffer[128];
653
654         home = request->home_server;
655
656         if (home->state != HOME_STATE_ZOMBIE) return;
657
658         when = home->zombie_period_start;
659         when.tv_sec += home->zombie_period;
660
661         if (timercmp(&now, &when, <)) {
662                 return;
663         }
664
665         /*
666          *      It's been a zombie for too long, mark it as
667          *      dead.
668          */
669         DEBUG2("FAILURE: Marking home server %s port %d as dead.",
670                inet_ntop(request->proxy->dst_ipaddr.af,
671                          &request->proxy->dst_ipaddr.ipaddr,
672                          buffer, sizeof(buffer)),
673                request->proxy->dst_port);
674         home->state = HOME_STATE_IS_DEAD;
675         home->num_received_pings = 0;
676         home->when = request->when;
677
678         if (home->ping_check != HOME_PING_CHECK_NONE) {
679                 rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||
680                            (home->ping_user_name != NULL));
681                 home->when.tv_sec += home->ping_interval;
682
683                 INSERT_EVENT(ping_home_server, home);
684         } else {
685                 home->when.tv_sec += home->revive_interval;
686
687                 INSERT_EVENT(revive_home_server, home);
688         }
689 }
690
691
692 static int setup_post_proxy_fail(REQUEST *request)
693 {
694         DICT_VALUE *dval = NULL;
695         VALUE_PAIR *vp;
696
697         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
698                 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication");
699
700         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
701                 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting");
702
703         } else {
704                 return 0;
705         }
706
707         if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail");
708
709         if (!dval) {
710                 pairdelete(&request->config_items, PW_POST_PROXY_TYPE);
711                 return 0;
712         }
713
714         vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
715         if (!vp) vp = radius_paircreate(request, &request->config_items,
716                                         PW_POST_PROXY_TYPE, PW_TYPE_INTEGER);
717         vp->vp_integer = dval->value;
718
719         rad_assert(request->proxy_reply == NULL);
720
721         return 1;
722 }
723
724
725 static int null_handler(UNUSED REQUEST *request)
726 {
727         return 0;
728 }
729
730 static void post_proxy_fail_handler(REQUEST *request)
731 {
732         /*
733          *      Not set up to run Post-Proxy-Type = Fail.
734          *
735          *      Mark the request as still running, and figure out what
736          *      to do next.
737          */
738         if (!setup_post_proxy_fail(request)) {
739                 request->child_state = REQUEST_RUNNING;
740                 request_post_handler(request);
741                 wait_a_bit(request);
742
743         } else {
744                 /*
745                  *      Re-queue the request.
746                  */
747                 request->child_state = REQUEST_QUEUED;
748
749                 wait_a_bit(request);
750
751                 /*
752                  *      There is a post-proxy-type of fail.  We run
753                  *      the request through the pre/post proxy
754                  *      handlers, just like it was a real proxied
755                  *      request.  However, we set the per-request
756                  *      handler to NULL, as we don't want to do
757                  *      anything else.
758                  */
759                 request->priority = 0;
760                 rad_assert(request->proxy != NULL);
761                 thread_pool_addrequest(request, null_handler);
762         }
763 }
764
765
766 /* maybe check this against wait_for_proxy_id_to_expire? */
767 static void no_response_to_proxied_request(void *ctx)
768 {
769         REQUEST *request = ctx;
770         home_server *home;
771         char buffer[128];
772
773         rad_assert(request->magic == REQUEST_MAGIC);
774         rad_assert(request->child_state == REQUEST_PROXIED);
775
776         radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
777                request->number,
778                inet_ntop(request->proxy->dst_ipaddr.af,
779                          &request->proxy->dst_ipaddr.ipaddr,
780                          buffer, sizeof(buffer)),
781                request->proxy->dst_port);
782
783         check_for_zombie_home_server(request);
784
785         home = request->home_server;
786
787         post_proxy_fail_handler(request);
788
789         /*
790          *      Don't touch request due to race conditions
791          */
792         if (home->state == HOME_STATE_IS_DEAD) {
793                 rad_assert(home->ev != NULL); /* or it will never wake up */
794                 return;
795         }
796
797         /*
798          *      Enable the zombie period when we notice that the home
799          *      server hasn't responded.  We also back-date the start
800          *      of the zombie period to when the proxied request was
801          *      sent.
802          */
803         if (home->state == HOME_STATE_ALIVE) {
804                 DEBUG2("WARNING: Marking home server %s port %d as zombie (it looks like it is dead).",
805                        inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
806                                  buffer, sizeof(buffer)),
807                        home->port);
808                 home->state = HOME_STATE_ZOMBIE;
809                 home->zombie_period_start = now;
810                 home->zombie_period_start.tv_sec -= home->response_window;
811                 return;
812         }
813 }
814
815
816 static void wait_a_bit(void *ctx)
817 {
818         struct timeval when;
819         REQUEST *request = ctx;
820         lrad_event_callback_t callback = NULL;
821
822         rad_assert(request->magic == REQUEST_MAGIC);
823
824         switch (request->child_state) {
825         case REQUEST_QUEUED:
826         case REQUEST_RUNNING:
827                 when = request->received;
828                 when.tv_sec += mainconfig.max_request_time;
829
830                 if (timercmp(&now, &when, <)) {
831                         callback = wait_a_bit;
832                 } else {
833                         /* FIXME: kill unresponsive children? */
834                         radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",
835                                (unsigned long)request->child_pid, request->number,
836                                request->module ? request->module : "<server core>",
837                                request->component ? request->component : "<server core>");
838
839                         request->master_state = REQUEST_STOP_PROCESSING;
840
841                         request->delay = USEC / 2;
842                         tv_add(&request->when, request->delay);
843                         callback = wait_for_child_to_die;
844                 }
845                 request->delay += request->delay >> 1;
846                 break;
847
848         case REQUEST_REJECT_DELAY:
849         case REQUEST_CLEANUP_DELAY:
850                 request->child_pid = NO_SUCH_CHILD_PID;
851                 snmp_inc_counters(request);
852
853         case REQUEST_PROXIED:
854                 rad_assert(request->next_callback != NULL);
855                 rad_assert(request->next_callback != wait_a_bit);
856
857                 request->when = request->next_when;
858                 callback = request->next_callback;
859                 request->next_callback = NULL;
860                 break;
861
862                 /*
863                  *      Mark the request as no longer running,
864                  *      and clean it up.
865                  */
866         case REQUEST_DONE:
867                 request->child_pid = NO_SUCH_CHILD_PID;
868                 snmp_inc_counters(request);
869                 cleanup_delay(request);
870                 return;
871
872         default:
873                 rad_panic("Internal sanity check failure");
874                 return;
875         }
876
877         INSERT_EVENT(callback, request);
878 }
879
880
881 static int request_pre_handler(REQUEST *request)
882 {
883         int rcode;
884
885         rad_assert(request->magic == REQUEST_MAGIC);
886         rad_assert(request->packet != NULL);
887         rad_assert(request->packet->dst_port != 0);
888
889         request->child_state = REQUEST_RUNNING;
890
891         /*
892          *      Don't decode the packet if it's an internal "fake"
893          *      request.  Instead, just return so that the caller can
894          *      process it.
895          */
896         if (request->packet->dst_port == 0) {
897                 request->username = pairfind(request->packet->vps,
898                                              PW_USER_NAME);
899                 request->password = pairfind(request->packet->vps,
900                                              PW_USER_PASSWORD);
901                 return 1;
902         }
903
904         /*
905          *      Put the decoded packet into it's proper place.
906          */
907         if (request->proxy_reply != NULL) {
908                 rcode = request->proxy_listener->decode(request->proxy_listener,
909                                                         request);
910         } else if (request->packet->vps == NULL) {
911                 rcode = request->listener->decode(request->listener, request);
912
913         } else {
914                 rcode = 0;
915         }
916
917         if (rcode < 0) {
918                 radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);
919                 request->child_state = REQUEST_DONE;
920                 return 0;
921         }
922
923         if (!request->proxy) {
924                 request->username = pairfind(request->packet->vps,
925                                              PW_USER_NAME);
926
927         } else {
928                 int post_proxy_type = 0;
929                 VALUE_PAIR *vp;
930
931                 /*
932                  *      Delete any reply we had accumulated until now.
933                  */
934                 pairfree(&request->reply->vps);
935
936                 /*
937                  *      Run the packet through the post-proxy stage,
938                  *      BEFORE playing games with the attributes.
939                  */
940                 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
941                 if (vp) {
942                         DEBUG2("  Found Post-Proxy-Type %s", vp->vp_strvalue);
943                         post_proxy_type = vp->vp_integer;
944                 }
945                 rcode = module_post_proxy(post_proxy_type, request);
946
947                 /*
948                  *      There may NOT be a proxy reply, as we may be
949                  *      running Post-Proxy-Type = Fail.
950                  */
951                 if (request->proxy_reply) {
952                         /*
953                          *      Delete the Proxy-State Attributes from
954                          *      the reply.  These include Proxy-State
955                          *      attributes from us and remote server.
956                          */
957                         pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
958
959                         /*
960                          *      Add the attributes left in the proxy
961                          *      reply to the reply list.
962                          */
963                         pairadd(&request->reply->vps, request->proxy_reply->vps);
964                         request->proxy_reply->vps = NULL;
965
966                         /*
967                          *      Free proxy request pairs.
968                          */
969                         pairfree(&request->proxy->vps);
970                 }
971
972                 switch (rcode) {
973                 default:  /* Don't do anything */
974                         break;
975                 case RLM_MODULE_FAIL:
976                         /* FIXME: debug print stuff */
977                         request->child_state = REQUEST_DONE;
978                         return 0;
979
980                 case RLM_MODULE_HANDLED:
981                         /* FIXME: debug print stuff */
982                         request->child_state = REQUEST_DONE;
983                         return 0;
984                 }
985         }
986
987         return 1;
988 }
989
990
991 /*
992  *      Do state handling when we proxy a request.
993  */
994 static int proxy_request(REQUEST *request)
995 {
996         struct timeval when;
997         char buffer[128];
998
999         if (!insert_into_proxy_hash(request)) {
1000                 DEBUG("Error: Failed inserting request into proxy hash.");
1001                 return 0;
1002         }
1003
1004         request->proxy_listener->encode(request->proxy_listener, request);
1005
1006         when = request->received;
1007         when.tv_sec += mainconfig.max_request_time;
1008
1009         gettimeofday(&request->proxy_when, NULL);
1010
1011         request->next_when = request->proxy_when;
1012         request->next_when.tv_sec += request->home_server->response_window;
1013
1014         rad_assert(request->home_server->response_window > 0);
1015
1016         if (timercmp(&when, &request->next_when, <)) {
1017                 request->next_when = when;
1018         }
1019         request->next_callback = no_response_to_proxied_request;
1020
1021         DEBUG2("Proxying request %d to home server %s port %d",
1022                request->number,
1023                inet_ntop(request->proxy->dst_ipaddr.af,
1024                          &request->proxy->dst_ipaddr.ipaddr,
1025                          buffer, sizeof(buffer)),
1026                request->proxy->dst_port);
1027
1028         /*
1029          *      Note that we set proxied BEFORE sending the packet.
1030          *
1031          *      Once we send it, the request is tainted, as
1032          *      another thread may have picked it up.  Don't
1033          *      touch it!
1034          */
1035         request->num_proxied_requests = 1;
1036         request->num_proxied_responses = 0;
1037         request->child_pid = NO_SUCH_CHILD_PID;
1038         request->child_state = REQUEST_PROXIED;
1039         request->proxy_listener->send(request->proxy_listener,
1040                                       request);
1041         return 1;
1042 }
1043
1044 /*
1045  *      Return 1 if we did proxy it, or the proxy attempt failed
1046  *      completely.  Either way, the caller doesn't touch the request
1047  *      any more if we return 1.
1048  */
1049 static int successfully_proxied_request(REQUEST *request)
1050 {
1051         int rcode;
1052         int pre_proxy_type = 0;
1053         VALUE_PAIR *realmpair;
1054         VALUE_PAIR *strippedname;
1055         VALUE_PAIR *vp;
1056         char *realmname;
1057         home_server *home;
1058         REALM *realm = NULL;
1059         home_pool_t *pool;
1060
1061         realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
1062         if (!realmpair || (realmpair->length == 0)) {
1063                 return 0;
1064         }
1065
1066         realmname = (char *) realmpair->vp_strvalue;
1067
1068         realm = realm_find(realmname);
1069         if (!realm) {
1070                 DEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname);
1071                 return 0;
1072         }
1073
1074         /*
1075          *      Figure out which pool to use.
1076          */
1077         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1078                 pool = realm->auth_pool;
1079
1080         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1081                 pool = realm->acct_pool;
1082
1083         } else {
1084                 rad_panic("Internal sanity check failed");
1085         }
1086
1087         if (!pool) {
1088                 DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
1089                        realmname);
1090                 return 0;
1091         }
1092
1093         home = home_server_ldb(realmname, pool, request);
1094         if (!home) {
1095                 DEBUG2("ERROR: Failed to find live home server for realm %s",
1096                        realmname);
1097                 return -1;
1098         }
1099         request->home_pool = pool;
1100
1101         /*
1102          *      Remember that we sent the request to a Realm.
1103          */
1104         pairadd(&request->packet->vps,
1105                 pairmake("Realm", realmname, T_OP_EQ));
1106
1107         /*
1108          *      We read the packet from a detail file, AND it came from
1109          *      the server we're about to send it to.  Don't do that.
1110          */
1111         if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
1112             (request->listener->type == RAD_LISTEN_DETAIL) &&
1113             (home->ipaddr.af == AF_INET) &&
1114             (request->packet->src_ipaddr.af == AF_INET) &&
1115             (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
1116                 DEBUG2("    rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
1117                 return 0;
1118         }
1119
1120         /*
1121          *      Allocate the proxy packet, only if it wasn't already
1122          *      allocated by a module.  This check is mainly to support
1123          *      the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
1124          *
1125          *      In those cases, the EAP module creates a "fake"
1126          *      request, and recursively passes it through the
1127          *      authentication stage of the server.  The module then
1128          *      checks if the request was supposed to be proxied, and
1129          *      if so, creates a proxy packet from the TUNNELED request,
1130          *      and not from the EAP request outside of the tunnel.
1131          *
1132          *      The proxy then works like normal, except that the response
1133          *      packet is "eaten" by the EAP module, and encapsulated into
1134          *      an EAP packet.
1135          */
1136         if (!request->proxy) {
1137                 if ((request->proxy = rad_alloc(TRUE)) == NULL) {
1138                         radlog(L_ERR|L_CONS, "no memory");
1139                         exit(1);
1140                 }
1141
1142                 /*
1143                  *      Copy the request, then look up name and
1144                  *      plain-text password in the copy.
1145                  *
1146                  *      Note that the User-Name attribute is the
1147                  *      *original* as sent over by the client.  The
1148                  *      Stripped-User-Name attribute is the one hacked
1149                  *      through the 'hints' file.
1150                  */
1151                 request->proxy->vps =  paircopy(request->packet->vps);
1152         }
1153
1154         /*
1155          *      Strip the name, if told to.
1156          *
1157          *      Doing it here catches the case of proxied tunneled
1158          *      requests.
1159          */
1160         if (realm->striprealm == TRUE &&
1161            (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
1162                 /*
1163                  *      If there's a Stripped-User-Name attribute in
1164                  *      the request, then use THAT as the User-Name
1165                  *      for the proxied request, instead of the
1166                  *      original name.
1167                  *
1168                  *      This is done by making a copy of the
1169                  *      Stripped-User-Name attribute, turning it into
1170                  *      a User-Name attribute, deleting the
1171                  *      Stripped-User-Name and User-Name attributes
1172                  *      from the vps list, and making the new
1173                  *      User-Name the head of the vps list.
1174                  */
1175                 vp = pairfind(request->proxy->vps, PW_USER_NAME);
1176                 if (!vp) {
1177                         vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
1178                         if (!vp) {
1179                                 radlog(L_ERR|L_CONS, "no memory");
1180                                 exit(1);
1181                         }
1182                         /* Insert at the START of the list */
1183                         vp->next = request->proxy->vps;
1184                         request->proxy->vps = vp;
1185                 }
1186                 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
1187                        sizeof(vp->vp_strvalue));
1188                 vp->length = strippedname->length;
1189
1190                 /*
1191                  *      Do NOT delete Stripped-User-Name.
1192                  */
1193         }
1194
1195         /*
1196          *      If there is no PW_CHAP_CHALLENGE attribute but
1197          *      there is a PW_CHAP_PASSWORD we need to add it
1198          *      since we can't use the request authenticator
1199          *      anymore - we changed it.
1200          */
1201         if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
1202             pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
1203                 vp = radius_paircreate(request, &request->proxy->vps,
1204                                        PW_CHAP_CHALLENGE, PW_TYPE_OCTETS);
1205                 vp->length = AUTH_VECTOR_LEN;
1206                 memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN);
1207         }
1208
1209         /*
1210          *      The RFC's say we have to do this, but FreeRADIUS
1211          *      doesn't need it.
1212          */
1213         vp = radius_paircreate(request, &request->proxy->vps,
1214                                PW_PROXY_STATE, PW_TYPE_OCTETS);
1215         sprintf(vp->vp_strvalue, "%d", request->packet->id);
1216         vp->length = strlen(vp->vp_strvalue);
1217
1218         /*
1219          *      Should be done BEFORE inserting into proxy hash, as
1220          *      pre-proxy may use this information, or change it.
1221          */
1222         request->proxy->code = request->packet->code;
1223         request->proxy->dst_ipaddr = home->ipaddr;
1224         request->proxy->dst_port = home->port;
1225         request->home_server = home;
1226
1227         /*
1228          *      Call the pre-proxy routines.
1229          */
1230         vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1231         if (vp) {
1232                 DEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
1233                 pre_proxy_type = vp->vp_integer;
1234         }
1235         rcode = module_pre_proxy(pre_proxy_type, request);
1236         switch (rcode) {
1237         case RLM_MODULE_FAIL:
1238         case RLM_MODULE_INVALID:
1239         case RLM_MODULE_NOTFOUND:
1240         case RLM_MODULE_USERLOCK:
1241         default:
1242                 /* FIXME: debug print failed stuff */
1243                 return -1;
1244
1245         case RLM_MODULE_REJECT:
1246         case RLM_MODULE_HANDLED:
1247                 return 0;
1248
1249         /*
1250          *      Only proxy the packet if the pre-proxy code succeeded.
1251          */
1252         case RLM_MODULE_NOOP:
1253         case RLM_MODULE_OK:
1254         case RLM_MODULE_UPDATED:
1255                 break;
1256         }
1257
1258         /*
1259          *      If it's a fake request, don't send the proxy
1260          *      packet.  The outer tunnel session will take
1261          *      care of doing that.
1262          */
1263         if (request->packet->dst_port == 0) {
1264                 request->home_server = NULL;
1265                 return 1;
1266         }
1267
1268         if (!proxy_request(request)) {
1269                 DEBUG("ERROR: Failed to proxy request %d", request->number);
1270                 return -1;
1271         }
1272         
1273         return 1;
1274 }
1275
1276
1277 static void request_post_handler(REQUEST *request)
1278 {
1279         int child_state = -1;
1280         struct timeval when;
1281         VALUE_PAIR *vp;
1282
1283         if ((request->master_state == REQUEST_STOP_PROCESSING) ||
1284             (request->parent &&
1285              (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
1286                 DEBUG2("Request %d was cancelled.", request->number);
1287                 request->child_pid = NO_SUCH_CHILD_PID;
1288                 request->child_state = REQUEST_DONE;
1289                 return;
1290         }
1291
1292         if (request->child_state != REQUEST_RUNNING) {
1293                 rad_panic("Internal sanity check failed");
1294         }
1295
1296         if ((request->reply->code == 0) &&
1297             ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
1298             (vp->vp_integer == PW_AUTHTYPE_REJECT)) {
1299                 request->reply->code = PW_AUTHENTICATION_REJECT;
1300         }
1301
1302         if (mainconfig.proxy_requests &&
1303             !request->proxy &&
1304             (request->reply->code == 0) &&
1305             (request->packet->code != PW_STATUS_SERVER)) {
1306                 int rcode = successfully_proxied_request(request);
1307
1308                 if (rcode == 1) return;
1309
1310                 /*
1311                  *      Failed proxying it (dead home servers, etc.)
1312                  *      Run it through Post-Proxy-Type = Fail, and
1313                  *      respond to the request.
1314                  *
1315                  *      Note that we're in a child thread here, so we
1316                  *      do NOT re-schedule the request.  Instead, we
1317                  *      do what we would have done, which is run the
1318                  *      pre-handler, a NULL request handler, and then
1319                  *      the post handler.
1320                  */
1321                 if ((rcode < 0) && setup_post_proxy_fail(request)) {
1322                         request_pre_handler(request);
1323                 }
1324
1325                 /*
1326                  *      Else we weren't supposed to proxy it.
1327                  */
1328         }
1329
1330         /*
1331          *      Fake requests don't get encoded or signed.  The caller
1332          *      also requires the reply VP's, so we don't free them
1333          *      here!
1334          */
1335         if (request->packet->dst_port == 0) {
1336                 /* FIXME: DEBUG going to the next request */
1337                 request->child_pid = NO_SUCH_CHILD_PID;
1338                 request->child_state = REQUEST_DONE;
1339                 return;
1340         }
1341
1342         /*
1343          *      Copy Proxy-State from the request to the reply.
1344          */
1345         vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
1346         if (vp) pairadd(&request->reply->vps, vp);
1347
1348         /*
1349          *      Access-Requests get delayed or cached.
1350          */
1351         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1352                 gettimeofday(&request->next_when, NULL);
1353
1354                 if (request->reply->code == 0) {
1355                         /*
1356                          *      Check if the lack of response is intentional.
1357                          */
1358                         vp = pairfind(request->config_items,
1359                                       PW_RESPONSE_PACKET_TYPE);
1360                         if (!vp || (vp->vp_integer != 256)) {
1361                                 DEBUG2("There was no response configured: rejecting request %d",
1362                                        request->number);
1363                                 request->reply->code = PW_AUTHENTICATION_REJECT;
1364                         } else {
1365                                 DEBUG2("Not responding to request %d",
1366                                        request->number);
1367                         }
1368                 }
1369
1370                 /*
1371                  *      Run rejected packets through
1372                  *
1373                  *      Post-Auth-Type = Reject
1374                  */
1375                 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
1376                         vp = pairmake("Post-Auth-Type", "Reject", T_OP_SET);
1377                         if (vp) {
1378                                 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
1379                                 pairadd(&request->config_items, vp);
1380                                 rad_postauth(request);
1381                         } /* else no Reject section defined */
1382
1383                         /*
1384                          *      If configured, delay Access-Reject packets.
1385                          *
1386                          *      If mainconfig.reject_delay = 0, we discover
1387                          *      that we have to send the packet now.
1388                          */
1389                         when = request->received;
1390                         when.tv_sec += mainconfig.reject_delay;
1391
1392                         if (timercmp(&when, &request->next_when, >)) {
1393                                 DEBUG2("Delaying reject of request %d for %d seconds",
1394                                        request->number,
1395                                        mainconfig.reject_delay);
1396                                 request->next_when = when;
1397                                 request->next_callback = reject_delay;
1398                                 request->child_pid = NO_SUCH_CHILD_PID;
1399                                 request->child_state = REQUEST_REJECT_DELAY;
1400                                 return;
1401                         }
1402                 }
1403
1404                 request->next_when.tv_sec += mainconfig.cleanup_delay;
1405                 request->next_callback = cleanup_delay;
1406                 child_state = REQUEST_CLEANUP_DELAY;
1407
1408         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1409                 request->next_callback = NULL; /* just to be safe */
1410                 child_state = REQUEST_DONE;
1411
1412                 /*
1413                  *      FIXME: Status-Server should probably not be
1414                  *      handled here...
1415                  */
1416         } else if (request->packet->code == PW_STATUS_SERVER) {
1417                 request->next_callback = NULL;
1418                 child_state = REQUEST_DONE;
1419
1420         } else {
1421                 rad_panic("Unknown packet type");
1422         }
1423
1424         /*
1425          *      Suppress "no reply" packets here, unless we're reading
1426          *      from the "detail" file.  In that case, we've got to
1427          *      tell the detail file handler that the request is dead,
1428          *      and it should re-send it.
1429          *      If configured, encode, sign, and send.
1430          */
1431         if ((request->reply->code != 0) ||
1432             (request->listener->type == RAD_LISTEN_DETAIL)) {
1433                 request->listener->send(request->listener, request);
1434         }
1435
1436         /*
1437          *      Clean up.  These are no longer needed.
1438          */
1439         pairfree(&request->config_items);
1440
1441         pairfree(&request->packet->vps);
1442         request->username = NULL;
1443         request->password = NULL;
1444
1445         pairfree(&request->reply->vps);
1446
1447         if (request->proxy) {
1448                 pairfree(&request->proxy->vps);
1449
1450                 if (request->proxy_reply) {
1451                         pairfree(&request->proxy_reply->vps);
1452                 }
1453
1454                 /*
1455                  *      We're not tracking responses from the home
1456                  *      server, we can therefore free this memory in
1457                  *      the child thread.
1458                  */
1459                 if (!request->in_proxy_hash) {
1460                         rad_free(&request->proxy);
1461                         rad_free(&request->proxy_reply);
1462                         request->home_server = NULL;
1463                 }
1464         }
1465
1466         DEBUG2("Finished request %d state %d", request->number, child_state);
1467
1468         request->child_state = child_state;
1469 }
1470
1471
1472 static void received_retransmit(REQUEST *request, const RADCLIENT *client)
1473 {
1474         char buffer[128];
1475
1476         RAD_SNMP_TYPE_INC(request->listener, total_dup_requests);
1477         RAD_SNMP_CLIENT_INC(request->listener, client, dup_requests);
1478
1479         switch (request->child_state) {
1480         case REQUEST_QUEUED:
1481         case REQUEST_RUNNING:
1482         discard:
1483                 radlog(L_ERR, "Discarding duplicate request from "
1484                        "client %s port %d - ID: %d due to unfinished request %d",
1485                        client->shortname,
1486                        request->packet->src_port,request->packet->id,
1487                        request->number);
1488                 break;
1489
1490         case REQUEST_PROXIED:
1491                 /*
1492                  *      We're not supposed to have duplicate
1493                  *      accounting packets.  The other states handle
1494                  *      duplicates fine (discard, or send duplicate
1495                  *      reply).  But we do NOT want to retransmit an
1496                  *      accounting request here, because that would
1497                  *      involve updating the Acct-Delay-Time, and
1498                  *      therefore changing the packet Id, etc.
1499                  *
1500                  *      Instead, we just discard the packet.  We may
1501                  *      eventually respond, or the client will send a
1502                  *      new accounting packet.
1503                  */
1504                 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1505                         goto discard;
1506                 }
1507
1508                 check_for_zombie_home_server(request);
1509
1510                 /*
1511                  *      If we've just discovered that the home server is
1512                  *      dead, send the packet to another one.
1513                  */
1514                 if ((request->packet->dst_port != 0) &&
1515                     (request->home_server->state == HOME_STATE_IS_DEAD)) {
1516                         home_server *home;
1517
1518                         remove_from_proxy_hash(request);
1519
1520                         home = home_server_ldb(NULL, request->home_pool, request);
1521                         if (!home) {
1522                                 DEBUG2("Failed to find live home server for request %d", request->number);
1523                         no_home_servers:
1524                                 /*
1525                                  *      Do post-request processing,
1526                                  *      and any insertion of necessary
1527                                  *      events.
1528                                  */
1529                                 post_proxy_fail_handler(request);
1530                                 return;
1531                         }
1532
1533                         request->proxy->code = request->packet->code;
1534                         request->proxy->dst_ipaddr = home->ipaddr;
1535                         request->proxy->dst_port = home->port;
1536                         request->home_server = home;
1537
1538                         /*
1539                          *      Free the old packet, to force re-encoding
1540                          */
1541                         free(request->proxy->data);
1542                         request->proxy->data = NULL;
1543                         request->proxy->data_len = 0;
1544
1545                         /*
1546                          *      Try to proxy the request.
1547                          */
1548                         if (!proxy_request(request)) {
1549                                 DEBUG("ERROR: Failed to re-proxy request %d", request->number);
1550                                 goto no_home_servers;
1551                         }
1552
1553                         /*
1554                          *      This code executes in the main server
1555                          *      thread, so there's no need for locking.
1556                          */
1557                         rad_assert(request->next_callback != NULL);
1558                         INSERT_EVENT(request->next_callback, request);
1559                         request->next_callback = NULL;
1560                         return;
1561                 } /* else the home server is still alive */
1562
1563                 DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
1564                        inet_ntop(request->proxy->dst_ipaddr.af,
1565                                  &request->proxy->dst_ipaddr.ipaddr,
1566                                  buffer, sizeof(buffer)),
1567                        request->proxy->dst_port,
1568                        request->proxy->id);
1569                 request->num_proxied_requests++;
1570                 request->proxy_listener->send(request->proxy_listener,
1571                                               request);
1572                 break;
1573
1574         case REQUEST_REJECT_DELAY:
1575                 DEBUG2("Waiting to send Access-Reject "
1576                        "to client %s port %d - ID: %d",
1577                        client->shortname,
1578                        request->packet->src_port, request->packet->id);
1579                 break;
1580
1581         case REQUEST_CLEANUP_DELAY:
1582         case REQUEST_DONE:
1583                 DEBUG2("Sending duplicate reply "
1584                        "to client %s port %d - ID: %d",
1585                        client->shortname,
1586                        request->packet->src_port, request->packet->id);
1587                 request->listener->send(request->listener, request);
1588                 break;
1589         }
1590 }
1591
1592
1593 static void received_conflicting_request(REQUEST *request,
1594                                          const RADCLIENT *client)
1595 {
1596         radlog(L_ERR, "Received conflicting packet from "
1597                "client %s port %d - ID: %d due to unfinished request %d.  Giving up on old request.",
1598                client->shortname,
1599                request->packet->src_port, request->packet->id,
1600                request->number);
1601
1602         /*
1603          *      Nuke it from the request hash, so we can receive new
1604          *      packets.
1605          */
1606         remove_from_request_hash(request);
1607
1608         switch (request->child_state) {
1609                 /*
1610                  *      It's queued or running.  Tell it to stop, and
1611                  *      wait for it to do so.
1612                  */
1613         case REQUEST_QUEUED:
1614         case REQUEST_RUNNING:
1615                 request->master_state = REQUEST_STOP_PROCESSING;
1616                 request->delay += request->delay >> 1;
1617
1618                 tv_add(&request->when, request->delay);
1619
1620                 INSERT_EVENT(wait_for_child_to_die, request);
1621                 return;
1622
1623                 /*
1624                  *      It's in some other state, and therefore also
1625                  *      in the event queue.  At some point, the
1626                  *      child will notice, and we can then delete it.
1627                  */
1628         default:
1629                 rad_assert(request->ev != NULL);
1630                 break;
1631         }
1632 }
1633
1634
1635 static int can_handle_new_request(RADIUS_PACKET *packet,
1636                                   RADCLIENT *client)
1637 {
1638         /*
1639          *      Count the total number of requests, to see if
1640          *      there are too many.  If so, return with an
1641          *      error.
1642          */
1643         if (mainconfig.max_requests) {
1644                 int request_count = lrad_packet_list_num_elements(pl);
1645
1646                 /*
1647                  *      This is a new request.  Let's see if
1648                  *      it makes us go over our configured
1649                  *      bounds.
1650                  */
1651                 if (request_count > mainconfig.max_requests) {
1652                         radlog(L_ERR, "Dropping request (%d is too many): "
1653                                "from client %s port %d - ID: %d", request_count,
1654                                client->shortname,
1655                                packet->src_port, packet->id);
1656                         radlog(L_INFO, "WARNING: Please check the %s file.\n"
1657                                "\tThe value for 'max_requests' is probably set too low.\n", mainconfig.radiusd_conf);
1658                         return 0;
1659                 } /* else there were a small number of requests */
1660         } /* else there was no configured limit for requests */
1661
1662         /*
1663          *      FIXME: Add per-client checks.  If one client is sending
1664          *      too many packets, start discarding them.
1665          *
1666          *      We increment the counters here, and decrement them
1667          *      when the response is sent... somewhere in this file.
1668          */
1669
1670         /*
1671          *      FUTURE: Add checks for system load.  If the system is
1672          *      busy, start dropping requests...
1673          *
1674          *      We can probably keep some statistics ourselves...  if
1675          *      there are more requests coming in than we can handle,
1676          *      start dropping some.
1677          */
1678
1679         return 1;
1680 }
1681
1682
1683 int received_request(rad_listen_t *listener,
1684                      RADIUS_PACKET *packet, REQUEST **prequest,
1685                      RADCLIENT *client)
1686 {
1687         RADIUS_PACKET **packet_p;
1688         REQUEST *request = NULL;
1689
1690         packet_p = lrad_packet_list_find(pl, packet);
1691         if (packet_p) {
1692                 request = lrad_packet2myptr(REQUEST, packet, packet_p);
1693                 rad_assert(request->in_request_hash);
1694
1695                 if ((request->packet->data_len == packet->data_len) &&
1696                     (memcmp(request->packet->vector, packet->vector,
1697                             sizeof(packet->vector)) == 0)) {
1698                         received_retransmit(request, client);
1699                         return 0;
1700                 }
1701
1702                 /*
1703                  *      The new request is different from the old one,
1704                  *      but maybe the old is finished.  If so, delete
1705                  *      the old one.
1706                  */
1707                 switch (request->child_state) {
1708                         struct timeval when;
1709
1710                 default:
1711                         gettimeofday(&when, NULL);
1712                         when.tv_sec -= 1;
1713
1714                         /*
1715                          *      If the cached request was received
1716                          *      within the last second, then we
1717                          *      discard the NEW request instead of the
1718                          *      old one.  This will happen ONLY when
1719                          *      the client is severely broken, and is
1720                          *      sending conflicting packets very
1721                          *      quickly.
1722                          */
1723                         if (timercmp(&when, &request->received, <)) {
1724                                 radlog(L_ERR, "Discarding conflicting packet from "
1725                                        "client %s port %d - ID: %d due to recent request %d.",
1726                                        client->shortname,
1727                                        packet->src_port, packet->id,
1728                                        request->number);
1729                                 return 0;
1730                         }
1731
1732                         received_conflicting_request(request, client);
1733                         request = NULL;
1734                         break;
1735
1736                 case REQUEST_REJECT_DELAY:
1737                 case REQUEST_CLEANUP_DELAY:
1738                         request->child_state = REQUEST_DONE;
1739                 case REQUEST_DONE:
1740                         cleanup_delay(request);
1741                         request = NULL;
1742                         break;
1743                 }
1744
1745
1746         }
1747
1748         /*
1749          *      We may want to quench the new request.
1750          */
1751         if (!can_handle_new_request(packet, client)) {
1752                 return 0;
1753         }
1754
1755         /*
1756          *      Create and initialize the new request.
1757          */
1758         request = request_alloc(); /* never fails */
1759
1760         if ((request->reply = rad_alloc(0)) == NULL) {
1761                 radlog(L_ERR, "No memory");
1762                 exit(1);
1763         }
1764
1765         request->listener = listener;
1766         request->client = client;
1767         request->packet = packet;
1768         request->packet->timestamp = request->timestamp;
1769         request->number = request_num_counter++;
1770         request->priority = listener->type;
1771
1772         /*
1773          *      Set virtual server identity
1774          */
1775         if (client->server) {
1776                 request->server = client->server;
1777         } else if (listener->server) {
1778                 request->server = listener->server;
1779         } else {
1780                 request->server = NULL;
1781         }
1782
1783         /*
1784          *      Remember the request in the list.
1785          */
1786         if (!lrad_packet_list_insert(pl, &request->packet)) {
1787                 radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number);
1788                 request_free(&request);
1789                 return 0;
1790         }
1791         request->in_request_hash = TRUE;
1792
1793         /*
1794          *      The request passes many of our sanity checks.
1795          *      From here on in, if anything goes wrong, we
1796          *      send a reject message, instead of dropping the
1797          *      packet.
1798          */
1799
1800         /*
1801          *      Build the reply template from the request.
1802          */
1803
1804         request->reply->sockfd = request->packet->sockfd;
1805         request->reply->dst_ipaddr = request->packet->src_ipaddr;
1806         request->reply->src_ipaddr = request->packet->dst_ipaddr;
1807         request->reply->dst_port = request->packet->src_port;
1808         request->reply->src_port = request->packet->dst_port;
1809         request->reply->id = request->packet->id;
1810         request->reply->code = 0; /* UNKNOWN code */
1811         memcpy(request->reply->vector, request->packet->vector,
1812                sizeof(request->reply->vector));
1813         request->reply->vps = NULL;
1814         request->reply->data = NULL;
1815         request->reply->data_len = 0;
1816
1817         request->master_state = REQUEST_ACTIVE;
1818         request->child_state = REQUEST_QUEUED;
1819         request->next_callback = NULL;
1820
1821         gettimeofday(&request->received, NULL);
1822         request->timestamp = request->received.tv_sec;
1823         request->when = request->received;
1824
1825         request->delay = USEC / 10;
1826
1827         tv_add(&request->when, request->delay);
1828
1829         INSERT_EVENT(wait_a_bit, request);
1830
1831         *prequest = request;
1832         return 1;
1833 }
1834
1835
1836 REQUEST *received_proxy_response(RADIUS_PACKET *packet)
1837 {
1838         char            buffer[128];
1839         home_server     *home;
1840         REQUEST         *request;
1841
1842         if (!home_server_find(&packet->src_ipaddr, packet->src_port)) {
1843                 radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
1844                        inet_ntop(packet->src_ipaddr.af,
1845                                  &packet->src_ipaddr.ipaddr,
1846                                  buffer, sizeof(buffer)),
1847                                packet->src_port);
1848                 rad_free(&packet);
1849                 return NULL;
1850         }
1851
1852         /*
1853          *      Also removes from the proxy hash if responses == requests
1854          */
1855         request = lookup_in_proxy_hash(packet);
1856
1857         if (!request) {
1858                 radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
1859                        inet_ntop(packet->src_ipaddr.af,
1860                                  &packet->src_ipaddr.ipaddr,
1861                                  buffer, sizeof(buffer)),
1862                        packet->src_port, packet->id);
1863                 rad_free(&packet);
1864                 return NULL;
1865         }
1866
1867         home = request->home_server;
1868
1869         gettimeofday(&now, NULL);
1870         home->state = HOME_STATE_ALIVE;
1871
1872         if (request->reply && request->reply->code != 0) {
1873                 DEBUG2("We already replied to this request.  Discarding response from home server.");
1874                 rad_free(&packet);
1875                 return NULL;
1876         }
1877
1878         /*
1879          *      We had previously received a reply, so we don't need
1880          *      to do anything here.
1881          */
1882         if (request->proxy_reply) {
1883                 if (memcmp(request->proxy_reply->vector,
1884                            packet->vector,
1885                            sizeof(request->proxy_reply->vector)) == 0) {
1886                         DEBUG2("Discarding duplicate reply from home server %s port %d  - ID: %d for request %d",
1887                                inet_ntop(packet->src_ipaddr.af,
1888                                          &packet->src_ipaddr.ipaddr,
1889                                          buffer, sizeof(buffer)),
1890                                packet->src_port, packet->id,
1891                                request->number);
1892                 } else {
1893                         /*
1894                          *      ? The home server gave us a new proxy
1895                          *      reply, which doesn't match the old
1896                          *      one.  Delete it.
1897                          */
1898                         DEBUG2("Ignoring conflicting proxy reply");
1899                 }
1900
1901                 /* assert that there's an event queued for request? */
1902                 rad_free(&packet);
1903                 return NULL;
1904         }
1905
1906         switch (request->child_state) {
1907         case REQUEST_QUEUED:
1908         case REQUEST_RUNNING:
1909                 rad_panic("Internal sanity check failed for child state");
1910                 break;
1911
1912         case REQUEST_REJECT_DELAY:
1913         case REQUEST_CLEANUP_DELAY:
1914         case REQUEST_DONE:
1915                 radlog(L_ERR, "Reply from home server %s port %d  - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'",
1916                        inet_ntop(packet->src_ipaddr.af,
1917                                  &packet->src_ipaddr.ipaddr,
1918                                  buffer, sizeof(buffer)),
1919                        packet->src_port, packet->id,
1920                        request->number);
1921                 /* assert that there's an event queued for request? */
1922                 rad_free(&packet);
1923                 return NULL;
1924
1925         case REQUEST_PROXIED:
1926                 break;
1927         }
1928
1929         request->proxy_reply = packet;
1930
1931 #if 0
1932         /*
1933          *      Perform RTT calculations, as per RFC 2988 (for TCP).
1934          *      Note that we do so only if we sent one request, and
1935          *      received one response.  If we sent two requests, we
1936          *      have no idea if the response is for the first, or for
1937          *      the second request/
1938          */
1939         if (request->num_proxied_requests == 1) {
1940                 int rtt;
1941                 home_server *home = request->home_server;
1942
1943                 rtt = now.tv_sec - request->proxy_when.tv_sec;
1944                 rtt *= USEC;
1945                 rtt += now.tv_usec;
1946                 rtt -= request->proxy_when.tv_usec;
1947
1948                 if (!home->has_rtt) {
1949                         home->has_rtt = TRUE;
1950
1951                         home->srtt = rtt;
1952                         home->rttvar = rtt / 2;
1953
1954                 } else {
1955                         home->rttvar -= home->rttvar >> 2;
1956                         home->rttvar += (home->srtt - rtt);
1957                         home->srtt -= home->srtt >> 3;
1958                         home->srtt += rtt >> 3;
1959                 }
1960
1961                 home->rto = home->srtt;
1962                 if (home->rttvar > (USEC / 4)) {
1963                         home->rto += home->rttvar * 4;
1964                 } else {
1965                         home->rto += USEC;
1966                 }
1967         }
1968 #endif
1969
1970         /*
1971          *      There's no incoming request, so it's a proxied packet
1972          *      we originated.
1973          */
1974         if (!request->packet) {
1975                 received_response_to_ping(request);
1976                 return NULL;
1977         }
1978
1979         request->child_state = REQUEST_QUEUED;
1980         request->when = now;
1981         request->delay = USEC / 10;
1982         request->priority = RAD_LISTEN_PROXY;
1983         tv_add(&request->when, request->delay);
1984
1985         /*
1986          *      Wait a bit will take care of max_request_time
1987          */
1988         INSERT_EVENT(wait_a_bit, request);
1989
1990         return request;
1991 }
1992
1993
1994 /*
1995  *      Externally-visibly functions.
1996  */
1997 int radius_event_init(int spawn_flag)
1998 {
1999         if (el) return 0;
2000
2001         time(&start_time);
2002
2003         el = lrad_event_list_create();
2004         if (!el) return 0;
2005
2006         pl = lrad_packet_list_create(0);
2007         if (!el) return 0;
2008
2009         request_num_counter = 0;
2010
2011         /*
2012          *      Move all of the thread calls to this file?
2013          *
2014          *      It may be best for the mutexes to be in this file...
2015          */
2016         have_children = spawn_flag;
2017
2018         if (mainconfig.proxy_requests) {
2019                 int i;
2020                 rad_listen_t *listener;
2021
2022                 /*
2023                  *      Create the tree for managing proxied requests and
2024                  *      responses.
2025                  */
2026                 proxy_list = lrad_packet_list_create(1);
2027                 if (!proxy_list) return 0;
2028
2029 #ifdef HAVE_PTHREAD_H
2030                 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
2031                         radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
2032                                strerror(errno));
2033                         exit(1);
2034                 }
2035 #endif
2036
2037                 /*
2038                  *      Mark the Fd's as unused.
2039                  */
2040                 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
2041
2042                 i = -1;
2043
2044                 for (listener = mainconfig.listen;
2045                      listener != NULL;
2046                      listener = listener->next) {
2047                         if (listener->type == RAD_LISTEN_PROXY) {
2048                                 /*
2049                                  *      FIXME: This works only because we
2050                                  *      start off with one proxy socket.
2051                                  */
2052                                 rad_assert(proxy_fds[listener->fd & 0x1f] == -1);
2053                                 rad_assert(proxy_listeners[listener->fd & 0x1f] == NULL);
2054
2055                                 proxy_fds[listener->fd & 0x1f] = listener->fd;
2056                                 proxy_listeners[listener->fd & 0x1f] = listener;
2057                                 if (!lrad_packet_list_socket_add(proxy_list, listener->fd)) {
2058                                         rad_assert(0 == 1);
2059                                 }
2060                                 i = listener->fd;
2061                         }
2062                 }
2063
2064                 if (mainconfig.proxy_requests) rad_assert(i >= 0);
2065         }
2066
2067         if (thread_pool_init(spawn_flag) < 0) {
2068                 exit(1);
2069         }
2070
2071         return 1;
2072 }
2073
2074
2075 static int request_hash_cb(void *ctx, void *data)
2076 {
2077         ctx = ctx;              /* -Wunused */
2078         REQUEST *request = lrad_packet2myptr(REQUEST, packet, data);
2079
2080         rad_assert(request->in_proxy_hash == FALSE);
2081
2082         lrad_event_delete(el, &request->ev);
2083         remove_from_request_hash(request);
2084         request_free(&request);
2085
2086         return 0;
2087 }
2088
2089
2090 static int proxy_hash_cb(void *ctx, void *data)
2091 {
2092         ctx = ctx;              /* -Wunused */
2093         REQUEST *request = lrad_packet2myptr(REQUEST, proxy, data);
2094
2095         lrad_packet_list_yank(proxy_list, request->proxy);
2096         request->in_proxy_hash = FALSE;
2097
2098         if (!request->in_request_hash) {
2099                 lrad_event_delete(el, &request->ev);
2100                 request_free(&request);
2101         }
2102
2103         return 0;
2104 }
2105
2106
2107 void radius_event_free(void)
2108 {
2109         /*
2110          *      FIXME: Stop all threads, or at least check that
2111          *      they're all waiting on the semaphore, and the queues
2112          *      are empty.
2113          */
2114
2115         /*
2116          *      There are requests in the proxy hash that aren't
2117          *      referenced from anywhere else.  Remove them first.
2118          */
2119         if (proxy_list) {
2120                 PTHREAD_MUTEX_LOCK(&proxy_mutex);
2121                 lrad_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
2122                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
2123                 lrad_packet_list_free(proxy_list);
2124                 proxy_list = NULL;
2125         }
2126
2127         lrad_packet_list_walk(pl, NULL, request_hash_cb);
2128
2129         lrad_packet_list_free(pl);
2130         pl = NULL;
2131
2132         lrad_event_list_free(el);
2133 }
2134
2135 int radius_event_process(struct timeval **pptv)
2136 {
2137         int rcode;
2138         struct timeval when;
2139
2140         if (!el) return 0;
2141
2142         if (lrad_event_list_num_elements(el) == 0) {
2143                 *pptv = NULL;
2144                 return 1;
2145         }
2146
2147         gettimeofday(&now, NULL);
2148         when = now;
2149
2150         do {
2151                 rcode = lrad_event_run(el, &when);
2152         } while (rcode == 1);
2153
2154         gettimeofday(&now, NULL);
2155
2156         if ((when.tv_sec == 0) && (when.tv_usec == 0)) {
2157                 if (lrad_event_list_num_elements(el) == 0) {
2158                         *pptv = NULL;
2159                         return 1;
2160                 }
2161                 rad_panic("Internal sanity check failed");
2162
2163         } else if (timercmp(&now, &when, >)) {
2164                 DEBUG3("Event in the past... compensating");
2165                 when.tv_sec = 0;
2166                 when.tv_usec = 1;
2167
2168         } else {
2169                 when.tv_sec -= now.tv_sec;
2170                 when.tv_usec -= now.tv_usec;
2171                 if (when.tv_usec < 0) {
2172                         when.tv_sec--;
2173                         when.tv_usec += USEC;
2174                 }
2175         }
2176         **pptv = when;
2177
2178         return 1;
2179 }
2180
2181 void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
2182 {
2183         if (request_pre_handler(request)) {
2184                 rad_assert(fun != NULL);
2185                 rad_assert(request != NULL);
2186                 
2187                 if (request->server) DEBUG("server %s {",
2188                                              request->server); 
2189                 fun(request);
2190
2191                 if (request->server) DEBUG("} # server %s",
2192                                              request->server);
2193
2194                 request_post_handler(request);
2195         }
2196
2197         DEBUG2("Going to the next request");
2198         return;
2199 }