📄 radiusd.c
字号:
packet->src_port, packet->id, curreq->number); return NULL; } /* * The old request is finished. We now check the * authentication vectors. If the client has sent us a * request with identical code && ID, but different * vector, then they MUST have gotten our response, so we * can delete the original request, and process the new * one. * * If the vectors are the same, then it's a duplicate * request, and we can send a duplicate reply. */ if (memcmp(curreq->packet->vector, packet->vector, sizeof(packet->vector)) == 0) { RAD_SNMP_INC(rad_snmp.auth.total_dup_requests); /* * If the packet has been delayed, then silently * send a response, and clear the delayed flag. * * Note that this means if the NAS kicks us while * we're delaying a reject, then the reject may * be sent sooner than otherwise. * * This COULD be construed as a bug. Maybe what * we want to do is to ignore the duplicate * packet, and send the reject later. */ if (curreq->options & RAD_REQUEST_OPTION_DELAYED_REJECT) { curreq->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT; rad_send(curreq->reply, curreq->packet, curreq->secret); return NULL; } /* * Maybe we've saved a reply packet. If so, * re-send it. Otherwise, just complain. */ if (curreq->reply->code != 0) { DEBUG2("Sending duplicate reply " "to client %s:%d - ID: %d", client_name(packet->src_ipaddr), packet->src_port, packet->id); rad_send(curreq->reply, curreq->packet, curreq->secret); return NULL; } /* * Else we never sent a reply to the NAS, * as we decided somehow we didn't like the request. * * This shouldn't happen, in general... */ DEBUG2("Discarding duplicate request from client %s:%d - ID: %d", client_name(packet->src_ipaddr), packet->src_port, packet->id); return NULL; } /* else the vectors were different, so we discard the old request. */ /* * 'packet' has the same source IP, source port, code, * and Id as 'curreq', but a different authentication * vector. We can therefore delete 'curreq', as we were * only keeping it around to send out duplicate replies, * if the first reply got lost in the network. */ rl_delete(curreq); /* * The request is OK. We can process it... * * Don't bother checking the maximum nubmer of requests * here. we've just deleted one, so we KNOW we're under * the limit if we add one more. */ return fun;}/* * Do a proxy check of the REQUEST list when using the new proxy code. */static REQUEST *proxy_ok(RADIUS_PACKET *packet){ REALM *cl; REQUEST *oldreq; char buffer[32]; /* * Find the original request in the request list */ oldreq = rl_find_proxy(packet); /* * If we haven't found the original request which was * sent, to get this reply. Complain, and discard this * request, as there's no way for us to send it to a NAS. */ if (!oldreq) { radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s:%d - ID %d", ip_ntoa(buffer, packet->src_ipaddr), packet->src_port, packet->id); return NULL; } /* * The proxy reply has arrived too late, as the original * (old) request has timed out, been rejected, and marked * as finished. The client has already received a * response, so there is nothing that can be done. Delete * the tardy reply from the home server, and return NULL. */ if ((oldreq->reply->code != 0) || (oldreq->finished)) { radlog(L_ERR, "Reply from home server %s:%d - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'", ip_ntoa(buffer, packet->src_ipaddr), packet->src_port, packet->id, oldreq->number); return NULL; } /* * If there is already a reply, maybe this one is a * duplicate? */ if (oldreq->proxy_reply) { if (memcmp(oldreq->proxy_reply->vector, packet->vector, sizeof(oldreq->proxy_reply->vector)) == 0) { radlog(L_ERR, "Discarding duplicate reply from home server %s:%d - ID: %d for request %d", ip_ntoa(buffer, packet->src_ipaddr), packet->src_port, packet->id, oldreq->number); } else { /* * ? The home server gave us a new * * proxy reply, which doesn't match * the * old one. Delete it ! */ DEBUG2("Ignoring conflicting proxy reply"); } /* * We've already received a reply, so * we discard this one, as we don't want * to do duplicate work. */ return NULL; } /* else there wasn't a proxy reply yet, so we can process it */ /* * Refresh the old request, and update it with the proxy * reply. * * ? Can we delete the proxy request here? * Is there * any more need for it? * * FIXME: we probably shouldn't be updating the time * stamp here. */ oldreq->timestamp = time_now; oldreq->proxy_reply = packet; /* * Now that we've verified the packet IS actually * from that realm, and not forged, we can go mark the * realms for this home server as active. * * If we had done this check in the 'find realm by IP address' * function, then an attacker could force us to use a home * server which was inactive, by forging reply packets * which didn't match any request. We would think that * the reply meant the home server was active, would * re-activate the realms, and THEN bounce the packet * as garbage. */ for (cl = mainconfig.realms; cl != NULL; cl = cl->next) { if (oldreq->proxy_reply->src_ipaddr == cl->ipaddr) { if (oldreq->proxy_reply->src_port == cl->auth_port) { cl->active = TRUE; cl->last_reply = oldreq->timestamp; } else if (oldreq->proxy_reply->src_port == cl->acct_port) { cl->acct_active = TRUE; cl->last_reply = oldreq->timestamp; } } } return oldreq;}/* * Do more checks, this time on the REQUEST data structure. * * The main purpose of this code is to handle proxied requests. */static REQUEST *request_ok(RADIUS_PACKET *packet, uint8_t *secret, rad_listen_t *listener){ REQUEST *request = NULL; /* * If the request has come in on the proxy FD, then * it's a proxy reply, so pass it through the code which * tries to find the original request, which we should * process, rather than processing the reply as a "new" * request. */ if (listener->type == RAD_LISTEN_PROXY) { /* * Find the old request, based on the current * packet. */ request = proxy_ok(packet); if (!request) { return NULL; } rad_assert(request->magic == REQUEST_MAGIC); /* * We must have passed through the code below * for the original request, which adds the * reply packet to it. */ rad_assert(request->reply != NULL); } else { /* remember the new request */ /* * A unique per-request counter. */ static int request_num_counter = 0; request = request_alloc(); /* never fails */ request->packet = packet; request->number = request_num_counter++; strNcpy(request->secret, (char *)secret, sizeof(request->secret)); /* * Remember the request. */ rl_add(request); /* * ADD IN "server identifier" from "listen" * directive! */ /* * The request passes many of our sanity checks. * From here on in, if anything goes wrong, we * send a reject message, instead of dropping the * packet. * * Build the reply template from the request * template. */ rad_assert(request->reply == NULL); if ((request->reply = rad_alloc(0)) == NULL) { radlog(L_ERR, "No memory"); exit(1); } request->reply->sockfd = request->packet->sockfd; request->reply->dst_ipaddr = request->packet->src_ipaddr; request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; request->reply->id = request->packet->id; request->reply->code = 0; /* UNKNOWN code */ memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector)); request->reply->vps = NULL; request->reply->data = NULL; request->reply->data_len = 0; } return request;}/* * The main guy. */int main(int argc, char *argv[]){ REQUEST *request; RADIUS_PACKET *packet; u_char *secret; unsigned char buffer[4096]; fd_set readfds; int argval; int pid; int max_fd; int status; struct timeval *tv = NULL;#ifdef HAVE_SIGACTION struct sigaction act;#endif rad_listen_t *listener; syslog_facility = LOG_DAEMON;#ifdef OSFC2 set_auth_parameters(argc,argv);#endif if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; debug_flag = 0; spawn_flag = TRUE; radius_dir = strdup(RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&mainconfig, 0, sizeof(mainconfig));#ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_flags = 0 ; sigemptyset( &act.sa_mask ) ;#endif /* Process the options. */ while ((argval = getopt(argc, argv, "Aa:bcd:fg:hi:l:p:sSvxXyz")) != EOF) { switch(argval) { case 'A': log_auth_detail = TRUE; break; case 'a': if (radacct_dir) xfree(radacct_dir); radacct_dir = strdup(optarg); break; case 'c': /* ignore for backwards compatibility with Cistron */ break; case 'd': if (radius_dir) xfree(radius_dir); radius_dir = strdup(optarg); break; case 'f': dont_fork = TRUE; break; case 'h': usage(0); break; case 'i': if ((mainconfig.myip = ip_getaddr(optarg)) == INADDR_NONE) { fprintf(stderr, "radiusd: %s: host unknown\n", optarg); exit(1); } break; case 'l': radlog_dir = strdup(optarg); break; /* * We should also have this as a configuration * file directive. */ case 'g': syslog_facility = str2fac(optarg); break; case 'S': log_stripped_names++; break; case 'p': fprintf(stderr, "Ignoring deprecated command-line option -p"); break; case 's': /* Single process mode */ spawn_flag = FALSE; dont_fork = TRUE; break; case 'v': version(); break; /* * BIG debugging mode for users who are * TOO LAZY to type '-sfxxyz -l stdout' themselves. */ case 'X': spawn_flag = FALSE; dont_fork = TRUE; debug_flag += 2; mainconfig.log_auth = TRUE; mainconfig.log_auth_badpass = TRUE; mainconfig.log_auth_goodpass = TRUE; radlog_dir = strdup("stdout"); break; case 'x': debug_flag++; break; case 'y': mainconfig.log_auth = TRUE; mainconfig.log_auth_badpass = TRUE; break; case 'z': mainconfig.log_auth_badpass = TRUE; mainconfig.log_auth_goodpass = TRUE; break; default: usage(1); break; } } /* * Get our PID. */ radius_pid = getpid(); /* Read the configuration files, BEFORE doing anything else. */ if (read_mainconfig(0) < 0) { exit(1); } /* * If we're NOT debugging, trap fatal signals, so we can * easily clean up after ourselves. * * If we ARE debugging, don't trap them, so we can * dump core. */ if ((mainconfig.allow_core_dumps == FALSE) && (debug_flag == 0)) {#ifdef SIGSEGV#ifdef HAVE_SIGACTION act.sa_handler = sig_fatal; sigaction(SIGSEGV, &act, NULL);#else signal(SIGSEGV, sig_fatal);#endif#endif } /* Reload the modules. */ DEBUG2("radiusd: entering modules setup"); if (setup_modules() < 0) { radlog(L_ERR|L_CONS, "Errors setting up modules"); exit(1); }#ifdef HAVE_SYSLOG_H /* * If they asked for syslog, then give it to them. * Also, initialize the logging facility with the * configuration that they asked for. */ if (strcmp(radlog_dir, "syslog") == 0) { openlog(progname, LOG_PID, syslog_facility); radlog_dest = RADLOG_SYSLOG; } /* Do you want a warning if -g is used without a -l to activate it? */#endif if (strcmp(radlog_dir, "stdout") == 0) { radlog_dest = RADLOG_STDOUT; } else if (strcmp(radlog_dir, "stderr") == 0) { radlog_dest = RADLOG_STDERR; } /* Initialize the request list. */ rl_init(); /* * Register built-in compare functions. */ pair_builtincompare_init();#ifdef WITH_SNMP if (mainconfig.do_snmp) radius_snmp_init();#endif /* * Disconnect from session
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -