2 * event.c Server event handling
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.
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.
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
20 * Copyright 2007 The FreeRADIUS server project
21 * Copyright 2007 Alan DeKok <aland@deployingradius.com>
24 #include <freeradius-devel/ident.h>
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>
33 #include <freeradius-devel/rad_assert.h>
39 #define USEC (1000000)
42 * Ridiculous amounts of local state.
44 static lrad_event_list_t *el = NULL;
45 static lrad_packet_list_t *pl = NULL;
46 static int request_num_counter = 0;
47 static struct timeval now;
48 static time_t start_time;
49 static int have_children;
52 static pthread_mutex_t proxy_mutex;
54 #define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
55 #define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
58 * This is easier than ifdef's throughout the code.
60 #define PTHREAD_MUTEX_LOCK(_x)
61 #define PTHREAD_MUTEX_UNLOCK(_x)
64 static lrad_packet_list_t *proxy_list = NULL;
67 * We keep the proxy FD's here. The RADIUS Id's are marked
68 * "allocated" per Id, via a bit per proxy FD.
70 static int proxy_fds[32];
71 static rad_listen_t *proxy_listeners[32];
74 static void _rad_panic(const char *file, unsigned int line, const char *msg)
76 radlog(L_ERR, "]%s:%d] %s", file, line, msg);
80 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
84 * FIXME FIXME: Do SNMP, but smarter... have an array[code].foo,
85 * so we increment counters by just using code as an offset. The
86 * array should be the union of the server && client SNMP
87 * variables, which should simplify it a lot.
90 static void tv_add(struct timeval *tv, int usec_delay)
92 if (usec_delay > USEC) {
93 tv->tv_sec += usec_delay / USEC;
96 tv->tv_usec += usec_delay;
98 if (tv->tv_usec > USEC) {
105 static void remove_from_request_hash(REQUEST *request)
109 * Update the SNMP statistics.
111 * Note that we do NOT do this in a child thread.
112 * Instead, we update the stats when a request is
113 * deleted, because only the main server thread calls
116 if (mainconfig.do_snmp) {
117 switch (request->reply->code) {
118 case PW_AUTHENTICATION_ACK:
119 rad_snmp.auth.total_responses++;
120 rad_snmp.auth.total_access_accepts++;
123 case PW_AUTHENTICATION_REJECT:
124 rad_snmp.auth.total_responses++;
125 rad_snmp.auth.total_access_rejects++;
128 case PW_ACCESS_CHALLENGE:
129 rad_snmp.auth.total_responses++;
130 rad_snmp.auth.total_access_challenges++;
133 case PW_ACCOUNTING_RESPONSE:
134 rad_snmp.acct.total_responses++;
143 if (!request->in_request_hash) return;
145 lrad_packet_list_yank(pl, request->packet);
146 request->in_request_hash = FALSE;
150 static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
152 RADIUS_PACKET **proxy_p;
155 PTHREAD_MUTEX_LOCK(&proxy_mutex);
156 proxy_p = lrad_packet_list_find_byreply(proxy_list, reply);
159 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
163 request = lrad_packet2myptr(REQUEST, proxy, proxy_p);
166 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
170 request->num_proxied_responses++;
173 * Catch the most common case of everything working
176 if (request->num_proxied_requests == request->num_proxied_responses) {
178 * FIXME: remove from the event list, too?
180 lrad_packet_list_yank(proxy_list, request->proxy);
181 lrad_packet_list_id_free(proxy_list, request->proxy);
182 request->in_proxy_hash = FALSE;
185 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
191 static void remove_from_proxy_hash(REQUEST *request)
193 if (!request->in_proxy_hash) return;
195 PTHREAD_MUTEX_LOCK(&proxy_mutex);
196 request->home_server->currently_outstanding--;
197 lrad_packet_list_yank(proxy_list, request->proxy);
198 lrad_packet_list_id_free(proxy_list, request->proxy);
199 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
201 request->in_proxy_hash = FALSE;
205 static int insert_into_proxy_hash(REQUEST *request)
210 rad_assert(request->proxy != NULL);
211 rad_assert(proxy_list != NULL);
213 request->proxy->sockfd = -1;
215 PTHREAD_MUTEX_LOCK(&proxy_mutex);
217 request->home_server->currently_outstanding++;
219 if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
221 rad_listen_t *proxy_listener;
224 * Allocate a new proxy fd. This function adds it
225 * into the list of listeners.
227 proxy_listener = proxy_new_listener();
228 if (!proxy_listener) {
229 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
230 DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
238 proxy = proxy_listener->fd;
239 for (i = 0; i < 32; i++) {
240 DEBUG2("PROXY %d %d", i, proxy_fds[(proxy + i) & 0x1f]);
243 * Found a free entry. Save the socket,
244 * and remember where we saved it.
246 if (proxy_fds[(proxy + i) & 0x1f] == -1) {
247 found = (proxy + i) & 0x1f;
248 proxy_fds[found] = proxy;
249 proxy_listeners[found] = proxy_listener;
253 rad_assert(found >= 0);
255 if (!lrad_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
256 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
257 DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
258 return 0; /* leak proxy_listener */
262 if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
263 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
264 DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
268 rad_assert(request->proxy->sockfd >= 0);
271 * FIXME: Hack until we get rid of rad_listen_t, and put
272 * the information into the packet_list.
275 for (i = 0; i < 32; i++) {
276 if (proxy_fds[i] == request->proxy->sockfd) {
283 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
284 DEBUG2("ERROR: All sockets are full.");
288 rad_assert(proxy_fds[proxy] != -1);
289 rad_assert(proxy_listeners[proxy] != NULL);
290 request->proxy_listener = proxy_listeners[proxy];
292 if (!lrad_packet_list_insert(proxy_list, &request->proxy)) {
293 /* FIXME: free id? */
294 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
295 DEBUG2("ERROR: Failed to insert entry into proxy list");
299 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
301 DEBUG3(" proxy: allocating destination %s port %d - Id %d",
302 inet_ntop(request->proxy->dst_ipaddr.af,
303 &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
304 request->proxy->dst_port,
307 request->in_proxy_hash = TRUE;
314 * Called as BOTH an event, and in-line from other functions.
316 static void wait_for_proxy_id_to_expire(void *ctx)
318 REQUEST *request = ctx;
319 home_server *home = request->home_server;
321 rad_assert(request->magic == REQUEST_MAGIC);
322 rad_assert(request->proxy != NULL);
324 request->when = request->proxy_when;
325 request->when.tv_sec += home->response_window;
327 if ((request->num_proxied_requests == request->num_proxied_responses) ||
328 timercmp(&now, &request->when, >)) {
329 if (request->packet) {
330 DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
331 request->number, request->packet->id,
332 (unsigned int) (request->timestamp - start_time));
334 DEBUG2("Cleaning up request %d with timestamp +%d",
336 (unsigned int) (request->timestamp - start_time));
338 lrad_event_delete(el, request);
339 remove_from_proxy_hash(request);
340 remove_from_request_hash(request);
341 request_free(&request);
345 if (!lrad_event_insert(el, wait_for_proxy_id_to_expire,
346 request, &request->when)) {
347 rad_panic("Failed to insert event");
352 static void wait_for_child_to_die(void *ctx)
354 REQUEST *request = ctx;
356 rad_assert(request->magic == REQUEST_MAGIC);
358 if ((request->child_state == REQUEST_QUEUED) |
359 (request->child_state == REQUEST_RUNNING)) {
360 request->delay += (request->delay >> 1);
361 tv_add(&request->when, request->delay);
363 DEBUG2("Child is still stuck for request %d", request->number);
364 if (!lrad_event_insert(el, wait_for_child_to_die,
365 request, &request->when)) {
366 rad_panic("Failed to insert event");
371 DEBUG2("Child is finally responsive for request %d", request->number);
372 remove_from_request_hash(request);
374 if (request->proxy) {
375 return wait_for_proxy_id_to_expire(request);
378 request_free(&request);
382 static void cleanup_delay(void *ctx)
384 REQUEST *request = ctx;
386 rad_assert(request->magic == REQUEST_MAGIC);
387 rad_assert(request->child_state == REQUEST_CLEANUP_DELAY);
389 remove_from_request_hash(request);
391 if (request->proxy) {
392 return wait_for_proxy_id_to_expire(request);
395 DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
396 request->number, request->packet->id,
397 (unsigned int) (request->timestamp - start_time));
399 request_free(&request);
403 static void reject_delay(void *ctx)
405 REQUEST *request = ctx;
407 rad_assert(request->magic == REQUEST_MAGIC);
408 rad_assert(request->child_state == REQUEST_REJECT_DELAY);
410 DEBUG2("Sending delayed reject for request %d", request->number);
412 request->listener->send(request->listener, request);
414 request->when.tv_sec += mainconfig.cleanup_delay;
415 request->child_state = REQUEST_CLEANUP_DELAY;
417 if (!lrad_event_insert(el, cleanup_delay,
418 request, &request->when)) {
419 rad_panic("Failed to insert event");
424 static void revive_home_server(void *ctx)
426 home_server *home = ctx;
428 home->state = HOME_STATE_ALIVE;
429 DEBUG2("Marking home server alive again... we have no idea if it really is alive or not.");
433 static void no_response_to_ping(void *ctx)
435 REQUEST *request = ctx;
436 home_server *home = request->home_server;
439 home->num_received_pings = 0;
441 DEBUG2("No response to ping %d from home server %s port %d",
443 inet_ntop(request->proxy->dst_ipaddr.af,
444 &request->proxy->dst_ipaddr.ipaddr,
445 buffer, sizeof(buffer)),
446 request->proxy->dst_port);
448 wait_for_proxy_id_to_expire(request);
452 static void received_response_to_ping(REQUEST *request)
454 home_server *home = request->home_server;
457 home->num_received_pings++;
459 DEBUG2("Received response to ping %d (%d in current sequence)",
460 request->number, home->num_received_pings);
462 if (home->num_received_pings < home->num_pings_to_alive) {
463 wait_for_proxy_id_to_expire(request);
467 DEBUG2("Marking home server %s port %d alive",
468 inet_ntop(request->proxy->dst_ipaddr.af,
469 &request->proxy->dst_ipaddr.ipaddr,
470 buffer, sizeof(buffer)),
471 request->proxy->dst_port);
473 if (!lrad_event_delete(el, home)) {
474 DEBUG2("Hmm... no event for home server, WTF?");
477 if (!lrad_event_delete(el, request)) {
478 DEBUG2("Hmm... no event for request, WTF?");
481 wait_for_proxy_id_to_expire(request);
483 home->state = HOME_STATE_ALIVE;
487 static void ping_home_server(void *ctx)
490 home_server *home = ctx;
494 if (home->state == HOME_STATE_ALIVE) {
495 radlog(L_INFO, "Suspicious proxy state... continuing");
499 request = request_alloc();
500 request->number = request_num_counter++;
502 request->proxy = rad_alloc(1);
503 rad_assert(request->proxy != NULL);
505 gettimeofday(&request->when, NULL);
506 home->when = request->when;
508 if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
509 request->proxy->code = PW_STATUS_SERVER;
511 vp = pairmake("Message-Authenticator", "0x00", T_OP_SET);
512 if (!vp) rad_panic("Out of memory");
513 pairadd(&request->proxy->vps, vp);
515 } else if (home->type == HOME_TYPE_AUTH) {
516 request->proxy->code = PW_AUTHENTICATION_REQUEST;
518 vp = pairmake("User-Name", home->ping_user_name, T_OP_SET);
519 if (!vp) rad_panic("Out of memory");
520 pairadd(&request->proxy->vps, vp);
522 vp = pairmake("User-Password", home->ping_user_password, T_OP_SET);
523 if (!vp) rad_panic("Out of memory");
524 pairadd(&request->proxy->vps, vp);
526 vp = pairmake("Service-Type", "Authenticate-Only", T_OP_SET);
527 if (!vp) rad_panic("Out of memory");
528 pairadd(&request->proxy->vps, vp);
530 vp = pairmake("Message-Authenticator", "0x00", T_OP_SET);
531 if (!vp) rad_panic("Out of memory");
532 pairadd(&request->proxy->vps, vp);
535 request->proxy->code = PW_ACCOUNTING_REQUEST;
537 vp = pairmake("User-Name", home->ping_user_name, T_OP_SET);
538 if (!vp) rad_panic("Out of memory");
539 pairadd(&request->proxy->vps, vp);
541 vp = pairmake("Acct-Status-Type", "Stop", T_OP_SET);
542 if (!vp) rad_panic("Out of memory");
543 pairadd(&request->proxy->vps, vp);
545 vp = pairmake("Acct-Session-Id", "00000000", T_OP_SET);
546 if (!vp) rad_panic("Out of memory");
547 pairadd(&request->proxy->vps, vp);
549 vp = pairmake("Event-Timestamp", "0", T_OP_SET);
550 if (!vp) rad_panic("Out of memory");
551 vp->vp_date = now.tv_sec;
552 pairadd(&request->proxy->vps, vp);
555 vp = pairmake("NAS-Identifier", "Ping! Are you alive?", T_OP_SET);
556 if (!vp) rad_panic("Out of memory");
557 pairadd(&request->proxy->vps, vp);
559 request->proxy->dst_ipaddr = home->ipaddr;
560 request->proxy->dst_port = home->port;
561 request->home_server = home;
563 rad_assert(request->proxy_listener == NULL);
565 if (!insert_into_proxy_hash(request)) {
566 DEBUG2("Failed inserting ping %d into proxy hash. Discarding it.",
568 request_free(&request);
571 rad_assert(request->proxy_listener != NULL);
572 request->proxy_listener->send(request->proxy_listener,
576 * FIXME: add a separate timeout for ping packets!
578 request->child_state = REQUEST_PROXIED;
579 request->when.tv_sec += mainconfig.cleanup_delay;
581 if (!lrad_event_insert(el, no_response_to_ping,
582 request, &request->when)) {
583 rad_panic("Failed to insert event");
587 * Add +/- 2s of jitter, as suggested in RFC 3539
588 * and in the Issues and Fixes draft.
590 home->when.tv_sec += home->ping_interval - 2;
592 jitter = lrad_rand();
593 jitter ^= (jitter >> 10);
594 jitter &= ((1 << 23) - 1); /* 22 bits of 1 */
596 tv_add(&home->when, jitter);
598 if (!lrad_event_insert(el, ping_home_server,
599 home, &home->when)) {
600 rad_panic("Failed to insert event");
605 /* maybe check this against wait_for_proxy_id_to_expire? */
606 static void no_response_to_proxied_request(void *ctx)
608 REQUEST *request = ctx;
613 rad_assert(request->magic == REQUEST_MAGIC);
614 rad_assert(request->child_state == REQUEST_PROXIED);
616 radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
618 inet_ntop(request->proxy->dst_ipaddr.af,
619 &request->proxy->dst_ipaddr.ipaddr,
620 buffer, sizeof(buffer)),
621 request->proxy->dst_port);
623 if ((request->proxy->code == PW_ACCOUNTING_REQUEST) ||
624 (request->proxy->code == PW_STATUS_SERVER)) {
625 remove_from_request_hash(request);
626 wait_for_proxy_id_to_expire(request);
629 /* FIXME: run it through post-auth reject section? */
631 request->reply->code = PW_AUTHENTICATION_REJECT;
633 request->listener->send(request->listener, request);
635 request->child_state = REQUEST_CLEANUP_DELAY;
636 request->when.tv_sec += mainconfig.cleanup_delay;
638 /* cleanup_delay calls wait_for_proxy_id_to_expire */
639 if (!lrad_event_insert(el, cleanup_delay,
640 request, &request->when)) {
641 rad_panic("Failed to insert event");
645 home = request->home_server;
646 if (home->state == HOME_STATE_IS_DEAD) {
647 /* FIXME: assert that some event is set for the home server */
652 * Enable the zombie period when we notice that the home
653 * server hasn't responded. We also back-date the start
654 * of the zombie period to when the proxied request was
657 if (home->state == HOME_STATE_ALIVE) {
658 DEBUG2("WARNING: Home server %s port %d may be dead.",
659 inet_ntop(request->proxy->dst_ipaddr.af,
660 &request->proxy->dst_ipaddr.ipaddr,
661 buffer, sizeof(buffer)),
662 request->proxy->dst_port);
663 home->state = HOME_STATE_ZOMBIE;
664 home->zombie_period_start = now;
665 home->zombie_period_start.tv_sec -= home->response_window;
669 when = home->zombie_period_start;
670 when.tv_sec += home->zombie_period;
672 if (timercmp(&now, &when, <)) {
677 * It's been a zombie for too long, mark it as
680 home->state = HOME_STATE_IS_DEAD;
681 home->num_received_pings = 0;
682 home->when = request->when;
684 if (home->ping_check != HOME_PING_CHECK_NONE) {
685 rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||
686 (home->ping_user_name != NULL));
687 home->when.tv_sec += home->ping_interval;
688 if (!lrad_event_insert(el, ping_home_server,
689 home, &home->when)) {
690 rad_panic("Failed to insert event");
693 home->when.tv_sec += home->revive_interval;
694 if (!lrad_event_insert(el, revive_home_server,
695 home, &home->when)) {
696 rad_panic("Failed to insert event");
702 static void wait_a_bit(void *ctx)
705 REQUEST *request = ctx;
706 lrad_event_callback_t callback = NULL;
708 rad_assert(request->magic == REQUEST_MAGIC);
710 switch (request->child_state) {
712 case REQUEST_RUNNING:
713 when = request->received;
714 when.tv_sec += mainconfig.max_request_time;
716 if (timercmp(&now, &when, <)) {
717 callback = wait_a_bit;
719 /* FIXME: kill unresponsive children? */
720 radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",
721 (unsigned long)request->child_pid, request->number,
722 request->module ? request->module : "<server core>",
723 request->component ? request->component : "<server core>");
725 request->master_state = REQUEST_STOP_PROCESSING;
727 request->delay = 500000;
728 tv_add(&request->when, request->delay);
729 callback = wait_for_child_to_die;
731 request->delay += request->delay >> 1;
734 case REQUEST_PROXIED:
735 case REQUEST_REJECT_DELAY:
736 case REQUEST_CLEANUP_DELAY:
737 rad_assert(request->next_callback != NULL);
739 request->when = request->next_when;
740 callback = request->next_callback;
741 request->next_callback = NULL;
745 request->child_pid = NO_SUCH_CHILD_PID;
746 if (request->proxy) {
747 return wait_for_proxy_id_to_expire(request);
752 rad_panic("Internal sanity check failure");
758 * FIXME: Print time as "+%d.%06d", as that's more
759 * understandable than 32-bit numbers.
761 DEBUG2("Inserting event for request %d at time %d.%06d",
763 (int) request->when.tv_sec, (int) request->when.tv_usec);
766 if (!lrad_event_insert(el, callback,
767 request, &request->when)) {
768 rad_panic("Failed to insert event");
773 static int request_pre_handler(REQUEST *request)
777 rad_assert(request->magic == REQUEST_MAGIC);
778 rad_assert(request->packet != NULL);
779 rad_assert(request->packet->dst_port != 0);
781 request->child_state = REQUEST_RUNNING;
784 * Don't decode the packet if it's an internal "fake"
785 * request. Instead, just return so that the caller can
788 if (request->packet->dst_port == 0) {
789 request->username = pairfind(request->packet->vps,
791 request->password = pairfind(request->packet->vps,
797 * Put the decoded packet into it's proper place.
799 if (request->proxy_reply != NULL) {
800 rcode = request->proxy_listener->decode(request->proxy_listener,
803 rcode = request->listener->decode(request->listener, request);
807 radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);
808 request->child_state = REQUEST_DONE;
812 if (!request->proxy) {
813 request->username = pairfind(request->packet->vps,
816 int post_proxy_type = 0;
820 * Delete any reply we had accumulated until now.
822 pairfree(&request->reply->vps);
825 * Run the packet through the post-proxy stage,
826 * BEFORE playing games with the attributes.
828 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
830 DEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue);
831 post_proxy_type = vp->lvalue;
833 rcode = module_post_proxy(post_proxy_type, request);
836 * Delete the Proxy-State Attributes from the reply.
837 * These include Proxy-State attributes from us and
840 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
843 * Add the attributes left in the proxy reply to
846 pairadd(&request->reply->vps, request->proxy_reply->vps);
847 request->proxy_reply->vps = NULL;
850 * Free proxy request pairs.
852 pairfree(&request->proxy->vps);
855 * FIXME: If the packet is an Access-Challenge,
856 * THEN add it to a cache, which does:
858 * (src IP, State) -> (home server ip/port)
860 * This allows the load-balancing code to
863 * Alternately, we can delete the State from the home
864 * server, and use our own.. that might be better.
868 default: /* Don't Do Anything */
870 case RLM_MODULE_FAIL:
871 /* FIXME: debug print stuff */
872 request->child_state = REQUEST_DONE;
875 case RLM_MODULE_HANDLED:
876 /* FIXME: debug print stuff */
877 request->child_state = REQUEST_DONE;
887 * Return 1 if we did proxy it, or the proxy attempt failed
888 * completely. Either way, the caller doesn't touch the request
889 * any more if we return 1.
891 static int successfully_proxied_request(REQUEST *request)
894 int pre_proxy_type = 0;
895 VALUE_PAIR *realmpair;
896 VALUE_PAIR *strippedname;
904 realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
906 (realmpair->length == 0)) {
910 realmname = (char *) realmpair->vp_strvalue;
912 realm = realm_find(realmname);
914 DEBUG2("ERROR: Cannot proxy to unknown realm %s",
918 * Failed proxying means silently discard
919 * accounting responses.
921 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
922 request->child_state = REQUEST_DONE;
926 rad_assert(request->packet->code == PW_AUTHENTICATION_REQUEST);
928 request->reply->code = PW_AUTHENTICATION_REJECT;
933 if (((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
934 !realm->auth_pool) ||
935 ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
936 !realm->acct_pool)) {
937 DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
942 home = home_server_ldb(realm, request->packet->code);
944 DEBUG2("ERROR: Failed to find live home server for realm %s",
950 * Remember that we sent the request to a Realm.
952 pairadd(&request->packet->vps,
953 pairmake("Realm", realmname, T_OP_EQ));
956 * We read the packet from a detail file, AND it came from
957 * the server we're about to send it to. Don't do that.
959 if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
960 (request->listener->type == RAD_LISTEN_DETAIL) &&
961 (home->ipaddr.af == AF_INET) &&
962 (request->packet->src_ipaddr.af == AF_INET) &&
963 (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
964 DEBUG2(" rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
969 * Allocate the proxy packet, only if it wasn't already
970 * allocated by a module. This check is mainly to support
971 * the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
973 * In those cases, the EAP module creates a "fake"
974 * request, and recursively passes it through the
975 * authentication stage of the server. The module then
976 * checks if the request was supposed to be proxied, and
977 * if so, creates a proxy packet from the TUNNELED request,
978 * and not from the EAP request outside of the tunnel.
980 * The proxy then works like normal, except that the response
981 * packet is "eaten" by the EAP module, and encapsulated into
984 if (!request->proxy) {
985 if ((request->proxy = rad_alloc(TRUE)) == NULL) {
986 radlog(L_ERR|L_CONS, "no memory");
991 * Copy the request, then look up name and
992 * plain-text password in the copy.
994 * Note that the User-Name attribute is the
995 * *original* as sent over by the client. The
996 * Stripped-User-Name attribute is the one hacked
997 * through the 'hints' file.
999 request->proxy->vps = paircopy(request->packet->vps);
1003 * Strip the name, if told to.
1005 * Doing it here catches the case of proxied tunneled
1008 if (realm->striprealm == TRUE &&
1009 (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
1011 * If there's a Stripped-User-Name attribute in
1012 * the request, then use THAT as the User-Name
1013 * for the proxied request, instead of the
1016 * This is done by making a copy of the
1017 * Stripped-User-Name attribute, turning it into
1018 * a User-Name attribute, deleting the
1019 * Stripped-User-Name and User-Name attributes
1020 * from the vps list, and making the new
1021 * User-Name the head of the vps list.
1023 vp = pairfind(request->proxy->vps, PW_USER_NAME);
1025 vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
1027 radlog(L_ERR|L_CONS, "no memory");
1030 vp->next = request->proxy->vps;
1031 request->proxy->vps = vp;
1033 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
1034 sizeof(vp->vp_strvalue));
1035 vp->length = strippedname->length;
1038 * Do NOT delete Stripped-User-Name.
1043 * If there is no PW_CHAP_CHALLENGE attribute but
1044 * there is a PW_CHAP_PASSWORD we need to add it
1045 * since we can't use the request authenticator
1046 * anymore - we changed it.
1048 if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
1049 pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
1050 vp = paircreate(PW_CHAP_CHALLENGE, PW_TYPE_STRING);
1052 radlog(L_ERR|L_CONS, "no memory");
1055 vp->length = AUTH_VECTOR_LEN;
1056 memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN);
1057 pairadd(&(request->proxy->vps), vp);
1061 * The RFC's say we have to do this, but FreeRADIUS
1064 vp = paircreate(PW_PROXY_STATE, PW_TYPE_STRING);
1066 radlog(L_ERR|L_CONS, "no memory");
1069 sprintf(vp->vp_strvalue, "%d", request->packet->id);
1070 vp->length = strlen(vp->vp_strvalue);
1072 pairadd(&request->proxy->vps, vp);
1074 request->proxy->code = request->packet->code;
1075 request->proxy->dst_ipaddr = home->ipaddr;
1076 request->proxy->dst_port = home->port;
1077 request->home_server = home;
1080 * Call the pre-proxy routines.
1082 vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1084 DEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
1085 pre_proxy_type = vp->lvalue;
1087 rcode = module_pre_proxy(pre_proxy_type, request);
1089 case RLM_MODULE_FAIL:
1090 case RLM_MODULE_INVALID:
1091 case RLM_MODULE_NOTFOUND:
1092 case RLM_MODULE_REJECT:
1093 case RLM_MODULE_USERLOCK:
1095 /* FIXME: debug print failed stuff */
1096 goto reject_request;
1098 case RLM_MODULE_HANDLED:
1102 * Only proxy the packet if the pre-proxy code succeeded.
1104 case RLM_MODULE_NOOP:
1106 case RLM_MODULE_UPDATED:
1111 * If it's a fake request, don't send the proxy
1112 * packet. The outer tunnel session will take
1113 * care of doing that.
1115 if (request->packet->dst_port == 0) {
1119 if (!insert_into_proxy_hash(request)) {
1120 DEBUG("ERROR: Failed to proxy request %d", request->number);
1121 goto reject_request;
1124 request->proxy_listener->encode(request->proxy_listener, request);
1126 when = request->received;
1127 when.tv_sec += mainconfig.max_request_time;
1129 gettimeofday(&request->proxy_when, NULL);
1131 request->next_when = request->proxy_when;
1132 request->next_when.tv_sec += home->response_window;
1134 rad_assert(home->response_window > 0);
1136 if (timercmp(&when, &request->next_when, <)) {
1137 request->next_when = when;
1139 request->next_callback = no_response_to_proxied_request;
1141 DEBUG2("Proxying request %d to realm %s, home server %s port %d",
1142 request->number, realmname,
1143 inet_ntop(request->proxy->dst_ipaddr.af,
1144 &request->proxy->dst_ipaddr.ipaddr,
1145 buffer, sizeof(buffer)),
1146 request->proxy->dst_port);
1149 * Note that we set proxied AFTER creating the packet,
1150 * but BEFORE actually sending it.
1152 * Once we send it, the request is tainted, as
1153 * another thread may have picked it up. Don't
1156 request->num_proxied_requests = 1;
1157 request->num_proxied_responses = 0;
1158 request->child_state = REQUEST_PROXIED;
1159 request->proxy_listener->send(request->proxy_listener,
1165 static void request_post_handler(REQUEST *request)
1167 int child_state = -1;
1168 struct timeval when;
1171 if (request->master_state == REQUEST_STOP_PROCESSING) {
1172 DEBUG2("Request %d was cancelled.", request->number);
1173 request->child_state = REQUEST_DONE;
1177 if (request->child_state != REQUEST_RUNNING) {
1178 rad_panic("Internal sanity check failed");
1182 * FIXME: check for Auth-Type = Reject, and reject it if so?
1183 * this means don't proxy it.
1185 * FIXME: check if we can't proxy it because all of the
1186 * home servers are dead or busy, and set post-auth-type
1187 * "proxy fail", or something like that.
1190 if (mainconfig.proxy_requests &&
1191 (request->packet->code != PW_STATUS_SERVER) &&
1192 (request->reply->code == 0) &&
1194 successfully_proxied_request(request)) {
1199 * Fake requests don't get encoded or signed. The caller
1200 * also requires the reply VP's, so we don't free them
1203 if (request->packet->dst_port == 0) {
1204 /* FIXME: DEBUG going to the next request */
1205 request->child_state = REQUEST_DONE;
1210 * Copy Proxy-State from the request to the reply.
1212 vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
1213 if (vp) pairadd(&request->reply->vps, vp);
1216 * Access-Requests get delayed or cached.
1218 if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1219 gettimeofday(&request->next_when, NULL);
1221 if (request->reply->code == 0) {
1222 DEBUG2("There was no response configured: rejecting request %d",
1224 request->reply->code = PW_AUTHENTICATION_REJECT;
1228 * If configured, delay Access-Reject packets.
1230 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
1231 (mainconfig.reject_delay > 0)) {
1232 when = request->received;
1233 when.tv_sec += mainconfig.reject_delay;
1235 if (timercmp(&when, &request->next_when, >)) {
1236 DEBUG2("Delaying reject of request %d for %d seconds",
1238 mainconfig.reject_delay);
1239 request->next_when = when;
1240 request->next_callback = reject_delay;
1241 request->child_state = REQUEST_REJECT_DELAY;
1246 request->next_when.tv_sec += mainconfig.cleanup_delay;
1247 request->next_callback = cleanup_delay;
1248 child_state = REQUEST_CLEANUP_DELAY;
1250 } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1251 request->next_callback = NULL; /* just to be safe */
1252 child_state = REQUEST_DONE;
1255 * FIXME: Status-Server should probably not be
1258 } else if (request->packet->code == PW_STATUS_SERVER) {
1259 request->next_callback = NULL;
1260 child_state = REQUEST_DONE;
1263 rad_panic("Unknown packet type");
1267 * Encode, sign, and send. The accounting request
1268 * handler takes care of suppressing responses when
1269 * request->reply->code == 0.
1271 request->listener->send(request->listener, request);
1274 * Clean up. These are no longer needed.
1276 pairfree(&request->config_items);
1278 pairfree(&request->packet->vps);
1279 request->username = NULL;
1280 request->password = NULL;
1282 pairfree(&request->reply->vps);
1284 if (request->proxy) {
1285 pairfree(&request->proxy->vps);
1287 if (request->proxy_reply) {
1288 pairfree(&request->proxy_reply->vps);
1291 DEBUG2("Finished request %d state %d", request->number, child_state);
1293 request->child_state = child_state;
1297 static void received_retransmit(REQUEST *request, const RADCLIENT *client)
1301 switch (request->child_state) {
1302 case REQUEST_QUEUED:
1303 case REQUEST_RUNNING:
1304 radlog(L_ERR, "Discarding duplicate request from "
1305 "client %s port %d - ID: %d due to unfinished request %d",
1307 request->packet->src_port,request->packet->id,
1311 case REQUEST_PROXIED:
1312 DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
1313 inet_ntop(request->proxy->dst_ipaddr.af,
1314 &request->proxy->dst_ipaddr.ipaddr,
1315 buffer, sizeof(buffer)),
1316 request->proxy->dst_port,
1317 request->proxy->id);
1318 request->num_proxied_requests++;
1319 request->proxy_listener->send(request->proxy_listener,
1323 case REQUEST_REJECT_DELAY:
1324 DEBUG2("Waiting to send Access-Reject "
1325 "to client %s port %d - ID: %d",
1327 request->packet->src_port, request->packet->id);
1330 case REQUEST_CLEANUP_DELAY:
1332 DEBUG2("Sending duplicate reply "
1333 "to client %s port %d - ID: %d",
1335 request->packet->src_port, request->packet->id);
1336 request->listener->send(request->listener, request);
1342 static void received_conflicting_request(REQUEST *request,
1343 const RADCLIENT *client)
1345 radlog(L_ERR, "Received conflicting packet from "
1346 "client %s port %d - ID: %d due to unfinished request %d. Giving up on old request.",
1348 request->packet->src_port, request->packet->id,
1351 switch (request->child_state) {
1352 case REQUEST_QUEUED:
1353 case REQUEST_RUNNING:
1354 request->master_state = REQUEST_STOP_PROCESSING;
1355 request->delay += request->delay >> 1;
1357 tv_add(&request->when, request->delay);
1359 if (!lrad_event_insert(el,
1360 wait_for_child_to_die,
1361 request, &request->when)) {
1362 rad_panic("Failed to insert event");
1370 remove_from_request_hash(request);
1373 * The request stays in the event queue. At some point,
1374 * the child will notice, and we can then delete it.
1379 static int can_handle_new_request(RADIUS_PACKET *packet,
1380 const RADCLIENT *client)
1383 * Count the total number of requests, to see if
1384 * there are too many. If so, return with an
1387 if (mainconfig.max_requests) {
1388 int request_count = lrad_packet_list_num_elements(pl);
1391 * This is a new request. Let's see if
1392 * it makes us go over our configured
1395 if (request_count > mainconfig.max_requests) {
1396 radlog(L_ERR, "Dropping request (%d is too many): "
1397 "from client %s port %d - ID: %d", request_count,
1399 packet->src_port, packet->id);
1400 radlog(L_INFO, "WARNING: Please check the %s file.\n"
1401 "\tThe value for 'max_requests' is probably set too low.\n", mainconfig.radiusd_conf);
1403 } /* else there were a small number of requests */
1404 } /* else there was no configured limit for requests */
1407 * FIXME: Add per-client checks. If one client is sending
1408 * too many packets, start discarding them.
1410 * We increment the counters here, and decrement them
1411 * when the response is sent... somewhere in this file.
1415 * FUTURE: Add checks for system load. If the system is
1416 * busy, start dropping requests...
1418 * We can probably keep some statistics ourselves... if
1419 * there are more requests coming in than we can handle,
1420 * start dropping some.
1427 int received_request(rad_listen_t *listener,
1428 RADIUS_PACKET *packet, REQUEST **prequest,
1429 const RADCLIENT *client)
1431 RADIUS_PACKET **packet_p;
1432 REQUEST *request = NULL;
1434 packet_p = lrad_packet_list_find(pl, packet);
1436 request = lrad_packet2myptr(REQUEST, packet, packet_p);
1438 if (memcmp(request->packet->vector, packet->vector,
1439 sizeof(packet->vector)) == 0) {
1440 received_retransmit(request, client);
1443 received_conflicting_request(request, client);
1446 } else if (!can_handle_new_request(packet, client)) {
1451 * Create and initialize the new request.
1453 request = request_alloc(); /* never fails */
1455 if ((request->reply = rad_alloc(0)) == NULL) {
1456 radlog(L_ERR, "No memory");
1460 request->listener = listener;
1461 request->packet = packet;
1462 request->packet->timestamp = request->timestamp;
1463 request->number = request_num_counter++;
1464 strlcpy(request->secret, client->secret, sizeof(request->secret));
1467 * Remember the request in the list.
1469 if (!lrad_packet_list_insert(pl, &request->packet)) {
1470 radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number);
1471 request_free(&request);
1474 request->in_request_hash = TRUE;
1477 * The request passes many of our sanity checks.
1478 * From here on in, if anything goes wrong, we
1479 * send a reject message, instead of dropping the
1484 * Build the reply template from the request.
1487 request->reply->sockfd = request->packet->sockfd;
1488 request->reply->dst_ipaddr = request->packet->src_ipaddr;
1489 request->reply->src_ipaddr = request->packet->dst_ipaddr;
1490 request->reply->dst_port = request->packet->src_port;
1491 request->reply->src_port = request->packet->dst_port;
1492 request->reply->id = request->packet->id;
1493 request->reply->code = 0; /* UNKNOWN code */
1494 memcpy(request->reply->vector, request->packet->vector,
1495 sizeof(request->reply->vector));
1496 request->reply->vps = NULL;
1497 request->reply->data = NULL;
1498 request->reply->data_len = 0;
1500 request->master_state = REQUEST_ACTIVE;
1501 request->child_state = REQUEST_QUEUED;
1502 request->next_callback = NULL;
1504 gettimeofday(&request->received, NULL);
1505 request->when = request->received;
1506 request->delay = USEC / 10;
1508 tv_add(&request->when, request->delay);
1510 if (!lrad_event_insert(el, wait_a_bit,
1511 request, &request->when)) {
1512 rad_panic("Failed to insert event");
1515 *prequest = request;
1520 REQUEST *received_proxy_response(RADIUS_PACKET *packet)
1526 if (!home_server_find(&packet->src_ipaddr, packet->src_port)) {
1527 radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
1528 inet_ntop(packet->src_ipaddr.af,
1529 &packet->src_ipaddr.ipaddr,
1530 buffer, sizeof(buffer)),
1537 * Also removes from the proxy hash if responses == requests
1539 request = lookup_in_proxy_hash(packet);
1542 radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
1543 inet_ntop(packet->src_ipaddr.af,
1544 &packet->src_ipaddr.ipaddr,
1545 buffer, sizeof(buffer)),
1546 packet->src_port, packet->id);
1551 home = request->home_server;
1553 gettimeofday(&now, NULL);
1554 home->state = HOME_STATE_ALIVE;
1556 if (request->reply && request->reply->code != 0) {
1557 DEBUG2("We already replied to this request. Discarding response from home server.");
1563 * We had previously received a reply, so we don't need
1564 * to do anything here.
1566 if (request->proxy_reply) {
1567 if (memcmp(request->proxy_reply->vector,
1569 sizeof(request->proxy_reply->vector)) == 0) {
1570 DEBUG2("Discarding duplicate reply from home server %s port %d - ID: %d for request %d",
1571 inet_ntop(packet->src_ipaddr.af,
1572 &packet->src_ipaddr.ipaddr,
1573 buffer, sizeof(buffer)),
1574 packet->src_port, packet->id,
1578 * ? The home server gave us a new proxy
1579 * reply, which doesn't match the old
1582 DEBUG2("Ignoring conflicting proxy reply");
1585 /* assert that there's an event queued for request? */
1590 switch (request->child_state) {
1591 case REQUEST_QUEUED:
1592 case REQUEST_RUNNING:
1593 rad_panic("Internal sanity check failed for child state");
1596 case REQUEST_REJECT_DELAY:
1597 case REQUEST_CLEANUP_DELAY:
1599 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'",
1600 inet_ntop(packet->src_ipaddr.af,
1601 &packet->src_ipaddr.ipaddr,
1602 buffer, sizeof(buffer)),
1603 packet->src_port, packet->id,
1605 /* assert that there's an event queued for request? */
1609 case REQUEST_PROXIED:
1613 request->proxy_reply = packet;
1616 * There's no incoming request, so it's a proxied packet
1619 if (!request->packet) {
1620 received_response_to_ping(request);
1624 request->child_state = REQUEST_QUEUED;
1625 request->when = now;
1626 request->delay = USEC / 10;
1627 tv_add(&request->when, request->delay);
1630 * Wait a bit will take care of max_request_time
1632 if (!lrad_event_insert(el, wait_a_bit,
1633 request, &request->when)) {
1634 rad_panic("Failed to insert event");
1642 * Externally-visibly functions.
1644 int radius_event_init(int spawn_flag)
1650 el = lrad_event_list_create();
1653 pl = lrad_packet_list_create(0);
1656 request_num_counter = 0;
1659 * Move all of the thread calls to this file?
1661 * It may be best for the mutexes to be in this file...
1663 have_children = spawn_flag;
1665 if (mainconfig.proxy_requests) {
1667 rad_listen_t *listener;
1670 * Create the tree for managing proxied requests and
1673 proxy_list = lrad_packet_list_create(1);
1674 if (!proxy_list) return 0;
1676 #ifdef HAVE_PTHREAD_H
1677 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
1678 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
1685 * Mark the Fd's as unused.
1687 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
1691 for (listener = mainconfig.listen;
1693 listener = listener->next) {
1694 if (listener->type == RAD_LISTEN_PROXY) {
1696 * FIXME: This works only because we
1697 * start off with one proxy socket.
1699 rad_assert(proxy_fds[listener->fd & 0x1f] == -1);
1700 rad_assert(proxy_listeners[listener->fd & 0x1f] == NULL);
1702 proxy_fds[listener->fd & 0x1f] = listener->fd;
1703 proxy_listeners[listener->fd & 0x1f] = listener;
1704 if (!lrad_packet_list_socket_add(proxy_list, listener->fd)) {
1711 if (mainconfig.proxy_requests) rad_assert(i >= 0);
1714 thread_pool_init(spawn_flag);
1720 static int request_hash_cb(void *ctx, void *data)
1722 ctx = ctx; /* -Wunused */
1723 REQUEST *request = lrad_packet2myptr(REQUEST, packet, data);
1725 rad_assert(request->in_proxy_hash == FALSE);
1727 lrad_event_delete(el, request);
1728 remove_from_request_hash(request);
1729 request_free(&request);
1735 static int proxy_hash_cb(void *ctx, void *data)
1737 ctx = ctx; /* -Wunused */
1738 REQUEST *request = lrad_packet2myptr(REQUEST, proxy, data);
1740 lrad_packet_list_yank(proxy_list, request->proxy);
1741 request->in_proxy_hash = FALSE;
1743 if (!request->in_request_hash) {
1744 lrad_event_delete(el, request);
1745 request_free(&request);
1752 void radius_event_free(void)
1755 * FIXME: Stop all threads, or at least check that
1756 * they're all waiting on the semaphore, and the queues
1761 * There are requests in the proxy hash that aren't
1762 * referenced from anywhere else. Remove them first.
1765 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1766 lrad_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
1767 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1768 lrad_packet_list_free(proxy_list);
1772 lrad_packet_list_walk(pl, NULL, request_hash_cb);
1774 lrad_packet_list_free(pl);
1777 lrad_event_list_free(el);
1780 int radius_event_process(struct timeval **pptv)
1783 struct timeval when;
1787 if (lrad_event_list_num_elements(el) == 0) {
1792 gettimeofday(&now, NULL);
1796 rcode = lrad_event_run(el, &when);
1797 } while (rcode == 1);
1799 gettimeofday(&now, NULL);
1801 if ((when.tv_sec == 0) && (when.tv_usec == 0)) {
1802 if (lrad_event_list_num_elements(el) == 0) {
1806 rad_panic("Internal sanity check failed");
1808 } else if (timercmp(&now, &when, >)) {
1814 when.tv_sec -= now.tv_sec;
1815 when.tv_usec -= now.tv_usec;
1816 if (when.tv_usec < 0) {
1818 when.tv_usec += USEC;
1826 void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
1828 if (!request_pre_handler(request)) {
1829 DEBUG2("Going to the next request at X");
1833 rad_assert(fun != NULL);
1834 rad_assert(request != NULL);
1838 request_post_handler(request);
1839 DEBUG2("Going to the next request");