Port "use_tunneled_reply" fix for MS-CHAP from branch_1_1
[freeradius.git] / src / main / request_list.c
1 /*
2  * request_list.c       Hide the handling of the REQUEST list from
3  *                      the main server.
4  *
5  * Version:     $Id$
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2003-2004,2006  The FreeRADIUS server project
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/autoconf.h>
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <signal.h>
32
33 #include <freeradius-devel/radiusd.h>
34 #include <freeradius-devel/rad_assert.h>
35 #include <freeradius-devel/request_list.h>
36 #include <freeradius-devel/radius_snmp.h>
37
38 struct request_list_t {
39         lrad_packet_list_t *pl;
40 };
41
42 #ifdef HAVE_PTHREAD_H
43 static pthread_mutex_t  proxy_mutex;
44 #else
45 /*
46  *      This is easier than ifdef's throughout the code.
47  */
48 #define pthread_mutex_lock(_x)
49 #define pthread_mutex_unlock(_x)
50 #endif
51
52 static lrad_packet_list_t *proxy_list = NULL;
53
54 /*
55  *      We keep the proxy FD's here.  The RADIUS Id's are marked
56  *      "allocated" per Id, via a bit per proxy FD.
57  */
58 static int              proxy_fds[32];
59 static rad_listen_t     *proxy_listeners[32];
60
61 /*
62  *      Initialize the request list.
63  */
64 request_list_t *rl_init(void)
65 {
66         request_list_t *rl = rad_malloc(sizeof(*rl));
67
68         /*
69          *      Initialize the request_list[] array.
70          */
71         memset(rl, 0, sizeof(*rl));
72
73         rl->pl = lrad_packet_list_create(0);
74         if (!rl->pl) {
75                 rad_assert("FAIL" == NULL);
76         }
77
78         return rl;
79 }
80
81 int rl_init_proxy(void)
82 {
83         /*
84          *      Hacks, so that multiple users can call rl_init,
85          *      and it won't get excited.
86          *
87          *      FIXME: Move proxy stuff to another struct entirely.
88          */
89         if (proxy_list) return 0;
90
91         /*
92          *      Create the tree for managing proxied requests and
93          *      responses.
94          */
95         proxy_list = lrad_packet_list_create(1);
96         if (!proxy_list) {
97                 rad_assert("FAIL" == NULL);
98         }
99
100 #ifdef HAVE_PTHREAD_H
101         /*
102          *      For now, always create the mutex.
103          *
104          *      Later, we can only create it if there are multiple threads.
105          */
106         if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
107                 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
108                        strerror(errno));
109                 exit(1);
110         }
111 #endif
112
113         {
114                 int i;
115                 rad_listen_t *listener;
116
117                 /*
118                  *      Mark the Fd's as unused.
119                  */
120                 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
121
122                 for (listener = mainconfig.listen;
123                      listener != NULL;
124                      listener = listener->next) {
125                         if (listener->type == RAD_LISTEN_PROXY) {
126                                 /*
127                                  *      FIXME: This works only because we
128                                  *      start off with one proxy socket.
129                                  */
130                                 proxy_fds[listener->fd & 0x1f] = listener->fd;
131                                 proxy_listeners[listener->fd & 0x1f] = listener;
132                                 lrad_packet_list_socket_add(proxy_list, listener->fd);
133                                 break;
134                         }
135                 }
136         }
137
138         return 1;
139 }
140
141 static int rl_free_entry(void *ctx, void *data)
142 {
143         ctx = ctx;              /* -Wunused */
144         REQUEST *request = lrad_packet2myptr(REQUEST, packet, data);
145
146 #ifdef HAVE_PTHREAD_H 
147         /*
148          *      If someone is processing this request, kill
149          *      them, and mark the request as not being used.
150          *
151          *      FIXME: Move the request to the "dead pool",
152          *      and don't kill the thread.
153          */
154         if (request->child_pid != NO_SUCH_CHILD_PID) {
155                 pthread_kill(request->child_pid, SIGKILL);
156                 request->child_pid = NO_SUCH_CHILD_PID;
157         }
158 #endif
159         request_free(&request);
160
161         return 0;
162 }
163
164
165 /*
166  *      Delete everything in the request list.
167  *
168  *      This should be called only when debugging the server...
169  */
170 void rl_deinit(request_list_t *rl)
171 {
172         if (!rl) return;
173
174         if (proxy_list) {
175                 lrad_packet_list_free(proxy_list);
176                 proxy_list = NULL;
177         }
178
179         /*
180          *      Delete everything in the table, too.
181          */
182         lrad_packet_list_walk(rl->pl, NULL, rl_free_entry);
183
184         lrad_packet_list_free(rl->pl);
185
186         /*
187          *      Just to ensure no one is using the memory.
188          */
189         memset(rl, 0, sizeof(*rl));
190         free(rl);
191 }
192
193
194 /*
195  *      Yank a request from the tree, without free'ing it.
196  */
197 void rl_yank(request_list_t *rl, REQUEST *request)
198 {
199 #ifdef WITH_SNMP
200         /*
201          *      Update the SNMP statistics.
202          *
203          *      Note that we do NOT do this in rad_respond(),
204          *      as that function is called from child threads.
205          *      Instead, we update the stats when a request is
206          *      deleted, because only the main server thread calls
207          *      this function...
208          */
209         if (mainconfig.do_snmp) {
210                 switch (request->reply->code) {
211                 case PW_AUTHENTICATION_ACK:
212                   rad_snmp.auth.total_responses++;
213                   rad_snmp.auth.total_access_accepts++;
214                   break;
215
216                 case PW_AUTHENTICATION_REJECT:
217                   rad_snmp.auth.total_responses++;
218                   rad_snmp.auth.total_access_rejects++;
219                   break;
220
221                 case PW_ACCESS_CHALLENGE:
222                   rad_snmp.auth.total_responses++;
223                   rad_snmp.auth.total_access_challenges++;
224                   break;
225
226                 case PW_ACCOUNTING_RESPONSE:
227                   rad_snmp.acct.total_responses++;
228                   break;
229
230                 default:
231                         break;
232                 }
233         }
234 #endif
235
236         /*
237          *      Delete the request from the list.
238          */
239         lrad_packet_list_yank(rl->pl, request->packet);
240         
241         /*
242          *      If there's a proxied packet, and we're still
243          *      waiting for a reply, then delete the packet
244          *      from the list of outstanding proxied requests.
245          */
246         if (request->proxy &&
247             (request->proxy_outstanding > 0)) {
248                 pthread_mutex_lock(&proxy_mutex);
249                 lrad_packet_list_yank(proxy_list, request->proxy);
250                 lrad_packet_list_id_free(proxy_list, request->proxy);
251                 pthread_mutex_unlock(&proxy_mutex);
252         }
253 }
254
255
256 /*
257  *      Delete a request from the tree.
258  */
259 void rl_delete(request_list_t *rl, REQUEST *request)
260 {
261         rl_yank(rl, request);
262         request_free(&request);
263 }
264
265
266 /*
267  *      Add a request to the request list.
268  */
269 int rl_add(request_list_t *rl, REQUEST *request)
270 {
271         return lrad_packet_list_insert(rl->pl, &request->packet);
272 }
273
274 /*
275  *      Look up a particular request, using:
276  *
277  *      Request ID, request code, source IP, source port,
278  *
279  *      Note that we do NOT use the request vector to look up requests.
280  *
281  *      We MUST NOT have two requests with identical (id/code/IP/port), and
282  *      different vectors.  This is a serious error!
283  */
284 REQUEST *rl_find(request_list_t *rl, RADIUS_PACKET *packet)
285 {
286         RADIUS_PACKET **packet_p;
287
288         packet_p = lrad_packet_list_find(rl->pl, packet);
289         if (!packet_p) return NULL;
290
291         return lrad_packet2myptr(REQUEST, packet, packet_p);
292 }
293
294 /*
295  *      Add an entry to the proxy tree.
296  *
297  *      This is the ONLY function in this source file which may be called
298  *      from a child thread.  It therefore needs mutexes...
299  */
300 int rl_add_proxy(REQUEST *request)
301 {
302         int i, proxy;
303         char buf[128];
304
305         request->proxy_outstanding = 1;
306         request->proxy->sockfd = -1;
307
308         pthread_mutex_lock(&proxy_mutex);
309
310         if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
311                 int found;
312                 rad_listen_t *proxy_listener;
313
314                 /*
315                  *      Allocate a new proxy Fd.  This function adds it
316                  *      into the list of listeners.
317                  */
318                 proxy_listener = proxy_new_listener();
319                 if (!proxy_listener) {
320                         pthread_mutex_unlock(&proxy_mutex);
321                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
322                         return 0;
323                 }
324
325                 /*
326                  *      Cache it locally.
327                  */
328                 found = -1;
329                 proxy = proxy_listener->fd;
330                 for (i = 0; i < 32; i++) {
331                         /*
332                          *      Found a free entry.  Save the socket,
333                          *      and remember where we saved it.
334                          */
335                         if (proxy_fds[(proxy + i) & 0x1f] == -1) {
336                                 found = (proxy + i) & 0x1f;
337                                 proxy_fds[found] = proxy;
338                                 proxy_listeners[found] = proxy_listener;
339                                 break;
340                         }
341                 }
342                 rad_assert(found >= 0);
343
344                 if (!lrad_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
345                         pthread_mutex_unlock(&proxy_mutex);
346                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
347                         return 0; /* leak proxy_listener */
348                         
349                 }
350                     
351                 if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
352                         pthread_mutex_unlock(&proxy_mutex);
353                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
354                         return 0;
355                 }
356         }
357
358         /*
359          *      FIXME: Hack until we get rid of rad_listen_t, and put
360          *      the information into the packet_list.
361          */
362         proxy = -1;
363         for (i = 0; i < 32; i++) {
364                 if (proxy_fds[i] == request->proxy->sockfd) {
365                         proxy = i;
366                         break;
367                 }
368         }
369         rad_assert(proxy >= 0);
370
371         rad_assert(proxy_fds[proxy] != -1);
372         request->proxy_listener = proxy_listeners[proxy];
373
374         if (!lrad_packet_list_insert(proxy_list, &request->proxy)) {
375                 pthread_mutex_unlock(&proxy_mutex);
376                 DEBUG2("ERROR: Failed to insert entry into proxy list");
377                 return 0;
378         }
379         
380         pthread_mutex_unlock(&proxy_mutex);
381
382         DEBUG3(" proxy: allocating destination %s port %d - Id %d",
383                inet_ntop(request->proxy->dst_ipaddr.af,
384                          &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
385                request->proxy->dst_port,
386                request->proxy->id);
387         
388         return 1;
389 }
390
391
392 /*
393  *      Look up a particular request, using:
394  *
395  *      Request Id, request code, source IP, source port,
396  *
397  *      Note that we do NOT use the request vector to look up requests.
398  *
399  *      We MUST NOT have two requests with identical (id/code/IP/port), and
400  *      different vectors.  This is a serious error!
401  */
402 REQUEST *rl_find_proxy(RADIUS_PACKET *reply)
403 {
404         RADIUS_PACKET **proxy_p;
405         REQUEST *request;
406
407         pthread_mutex_lock(&proxy_mutex);
408         proxy_p = lrad_packet_list_find_byreply(proxy_list, reply);
409
410         if (!proxy_p) {
411                 pthread_mutex_unlock(&proxy_mutex);
412                 return NULL;
413         }
414
415         request = lrad_packet2myptr(REQUEST, proxy, proxy_p);
416         rad_assert(request->proxy_outstanding > 0);
417         request->proxy_outstanding--;
418                 
419         /*
420          *      Received all of the replies we expect.
421          *      delete it from the managed list.
422          */
423         if (request->proxy_outstanding == 0) {
424                 lrad_packet_list_yank(proxy_list, request->proxy);
425                 lrad_packet_list_id_free(proxy_list, request->proxy);
426         }
427         pthread_mutex_unlock(&proxy_mutex);
428
429         return request;
430 }
431
432
433 /*
434  *      Return the number of requests in the request list.
435  */
436 int rl_num_requests(request_list_t *rl)
437 {
438         return lrad_packet_list_num_elements(rl->pl);
439 }
440
441
442 /*
443  *      See also radiusd.c
444  */
445 #define SLEEP_FOREVER (65536)
446 typedef struct rl_walk_t {
447         time_t  now;
448         int     sleep_time;
449         request_list_t *rl;
450 } rl_walk_t;
451
452
453 /*
454  *  Refresh a request, by using cleanup_delay, max_request_time, etc.
455  *
456  *  When walking over the request list, all of the per-request
457  *  magic is done here.
458  */
459 static int refresh_request(void *ctx, void *data)
460 {
461         int time_passed;
462         rl_walk_t *info = (rl_walk_t *) ctx;
463         child_pid_t child_pid;
464         request_list_t *rl = info->rl;
465         REQUEST *request = lrad_packet2myptr(REQUEST, packet, data);
466
467         rad_assert(request->magic == REQUEST_MAGIC);
468
469         time_passed = (int) (info->now - request->timestamp);
470         
471         /*
472          *      If the request is marked as a delayed reject, AND it's
473          *      time to send the reject, then do so now.
474          */
475         if (request->finished &&
476             ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0)) {
477                 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
478                 if (time_passed < mainconfig.reject_delay) {
479                         goto reject_delay;
480                 }
481
482         reject_packet:
483                 /*
484                  *      Clear the 'delayed reject' bit, so that we
485                  *      don't do this again, and fall through to
486                  *      setting cleanup delay.
487                  */
488                 request->listener->send(request->listener, request);
489                 request->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT;
490
491                 /*
492                  *      FIXME: Beware interaction with cleanup_delay,
493                  *      where we might send a reject, and immediately
494                  *      there-after clean it up!
495                  */
496         }
497
498         /*
499          *      If the request is finished, THEN
500          *      check that more than cleanup_delay seconds have passed
501          *      since it was received
502          *      OR, if this is a request which had the "don't cache"
503          *      option set, then it CANNOT have a duplicate
504          *      SO, clean it up
505          */
506         if (request->finished &&
507             ((time_passed >= mainconfig.cleanup_delay) ||
508             ((request->options & RAD_REQUEST_OPTION_DONT_CACHE) != 0))) {
509                 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
510                 /*
511                  *  Request completed, delete it, and unlink it
512                  *  from the currently 'alive' list of requests.
513                  */
514         cleanup:
515                 DEBUG2("Cleaning up request %d ID %d with timestamp %08lx",
516                                 request->number, request->packet->id,
517                                 (unsigned long) request->timestamp);
518
519                 /*
520                  *  Delete the request.
521                  */
522                 rl_delete(rl, request);
523                 return 0;
524         }
525
526         /*
527          *      If more than max_request_time has passed since
528          *      we received the request, kill it.
529          */
530         if (time_passed >= mainconfig.max_request_time) {
531                 int number;
532
533                 child_pid = request->child_pid;
534                 number = request->number;
535
536                 /*
537                  *      There MUST be a RAD_PACKET reply.
538                  */
539                 rad_assert(request->reply != NULL);
540
541                 /*
542                  *      If we've tried to proxy the request, and
543                  *      the proxy server hasn't responded, then
544                  *      we send a REJECT back to the caller.
545                  *
546                  *      For safety, we assert that there is no child
547                  *      handling the request.  If the assertion fails,
548                  *      it means that we've sent a proxied request to
549                  *      the home server, and the child thread is still
550                  *      sitting on the request!
551                  */
552                 if (request->proxy && !request->proxy_reply) {
553                         rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
554
555                         radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
556                                request->number,
557                                client_name_old(&request->packet->src_ipaddr),
558                                request->packet->src_port);
559                         request_reject(request, REQUEST_FAIL_HOME_SERVER);
560                         request->finished = TRUE;
561                         return 0;
562                 }
563
564                 if (mainconfig.kill_unresponsive_children) {
565                         if (child_pid != NO_SUCH_CHILD_PID) {
566                                 /*
567                                  *  This request seems to have hung
568                                  *   - kill it
569                                  */
570 #ifdef HAVE_PTHREAD_H
571                                 radlog(L_ERR, "Killing unresponsive thread for request %d",
572                                        request->number);
573                                 pthread_cancel(child_pid);
574 #endif
575                         } /* else no proxy reply, quietly fail */
576
577                         /*
578                          *      Maybe we haven't killed it.  In that
579                          *      case, print a warning.
580                          */
581                 } else if ((child_pid != NO_SUCH_CHILD_PID) &&
582                            ((request->options & RAD_REQUEST_OPTION_LOGGED_CHILD) == 0)) {
583                         radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d",
584                                (unsigned long)child_pid, number);
585
586                         /*
587                          *  Set the option that we've sent a log message,
588                          *  so that we don't send more than one message
589                          *  per request.
590                          */
591                         request->options |= RAD_REQUEST_OPTION_LOGGED_CHILD;
592                 }
593
594                 /*
595                  *      Send a reject message for the request, mark it
596                  *      finished, and forget about the child.
597                  */
598                 request_reject(request, REQUEST_FAIL_SERVER_TIMEOUT);
599                 
600                 request->child_pid = NO_SUCH_CHILD_PID;
601
602                 if (mainconfig.kill_unresponsive_children)
603                         request->finished = TRUE;
604                 return 0;
605         } /* else the request is still allowed to be in the queue */
606
607         /*
608          *      If the request is finished, set the cleanup delay.
609          */
610         if (request->finished) {
611                 time_passed = mainconfig.cleanup_delay - time_passed;
612                 goto setup_timeout;
613         }
614
615         /*
616          *      Accounting request.  Don't re-send them, since the NAS
617          *      will take care of doing that, and we're not a NAS.
618          *      Instead, simply clean them up once we're pretty sure
619          *      that the home server won't be responding.
620          */
621         if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
622             request->proxy && !request->proxy_reply &&
623             (request->child_pid == NO_SUCH_CHILD_PID) &&
624             ((info->now - request->proxy_start_time) > (mainconfig.proxy_retry_delay * 2))) {
625                 goto cleanup;
626         }
627
628
629         /*
630          *      Set reject delay, if appropriate.
631          */
632         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
633             (mainconfig.reject_delay > 0)) {
634         reject_delay:
635                 time_passed = mainconfig.reject_delay - time_passed;
636                 
637                 /*
638                  *      This catches a corner case, apparently.
639                  */
640                 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
641                     (time_passed == 0)) goto reject_packet;
642                 if (time_passed <= 0) time_passed = 1;
643                 goto setup_timeout;
644         }
645
646         /*
647          *      The request is still alive, wake up when it's
648          *      taken too long.
649          */
650         time_passed = mainconfig.max_request_time - time_passed;
651
652 setup_timeout:          
653         if (time_passed < 0) time_passed = 1;
654
655         if (time_passed < info->sleep_time) {
656                 info->sleep_time = time_passed;
657         }
658
659         return 0;
660 }
661
662
663 /*
664  *  Clean up the request list, every so often.
665  *
666  *  This is done by walking through ALL of the list, and
667  *  - marking any requests which are finished, and expired
668  *  - killing any processes which are NOT finished after a delay
669  *  - deleting any marked requests.
670  *
671  *      Returns the number of millisends to sleep, before processing
672  *      something.
673  */
674 int rl_clean_list(request_list_t *rl, time_t now)
675 {
676         rl_walk_t info;
677
678         info.now = now;
679         info.sleep_time = SLEEP_FOREVER;
680         info.rl = rl;
681
682         lrad_packet_list_walk(rl->pl, &info, refresh_request);
683
684         if (info.sleep_time < 0) info.sleep_time = 0;
685
686         return info.sleep_time;
687 }