📄 radiusd.c
字号:
DEBUG2("rad_lowerpair: %s now '%s'", vp->name, vp->strvalue); return 0;}/* * Remove spaces in a pair. */static int rad_rmspace_pair(REQUEST *request UNUSED, VALUE_PAIR *vp) { if (vp == NULL) { return -1; } rad_rmspace((char *)vp->strvalue); vp->length = strlen((char *)vp->strvalue); DEBUG2("rad_rmspace_pair: %s now '%s'", vp->name, vp->strvalue); return 0;}/* * Respond to a request packet. * * Maybe we reply, maybe we don't. * Maybe we proxy the request to another server, or else maybe * we replicate it to another server. */int rad_respond(REQUEST *request, RAD_REQUEST_FUNP fun){ RADIUS_PACKET *packet, *original; const char *secret; int finished = FALSE; int reprocess = 0; rad_assert(request->magic == REQUEST_MAGIC); /* * Don't decode the packet if it's an internal "fake" * request. Instead, just skip ahead to processing it. */ if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) { goto skip_decode; } /* * Put the decoded packet into it's proper place. */ if (request->proxy_reply != NULL) { packet = request->proxy_reply; secret = request->proxysecret; original = request->proxy; } else { packet = request->packet; secret = request->secret; original = NULL; } /* * Decode the packet, verifying it's signature, * and parsing the attributes into structures. * * Note that we do this CPU-intensive work in * a child thread, not the master. This helps to * spread the load a little bit. * * Internal requests (ones that never go on the * wire) have ->data==NULL (data is the wire * format) and don't need to be "decoded" */ if (packet->data && rad_decode(packet, original, secret) != 0) { radlog(L_ERR, "%s", librad_errstr); request_reject(request); goto finished_request; } /* * For proxy replies, remove non-allowed * attributes from the list of VP's. */ if (request->proxy) { int rcode; rcode = proxy_receive(request); switch (rcode) { default: /* Don't Do Anything */ break; case RLM_MODULE_FAIL: /* on error just continue with next request */ goto next_request; case RLM_MODULE_HANDLED: /* if this was a replicated request, mark it as * finished first, because it was postponed */ goto finished_request; } } else { /* * This is the initial incoming request which * we're processing. * * Some requests do NOT get cached, as they * CANNOT possibly have duplicates. Set the * magic option here. * * Status-Server messages are easy to generate, * so we toss them as soon as we see a reply. * * Accounting-Request packets WITHOUT an * Acct-Delay-Time attribute are NEVER * duplicated, as RFC 2866 Section 4.1 says that * the Acct-Delay-Time MUST be updated when the * packet is re-sent, which means the packet * changes, so it MUST have a new identifier and * Request Authenticator. */ if ((request->packet->code == PW_STATUS_SERVER) || ((request->packet->code == PW_ACCOUNTING_REQUEST) && (pairfind(request->packet->vps, PW_ACCT_DELAY_TIME) == NULL))) { request->options |= RAD_REQUEST_OPTION_DONT_CACHE; } } skip_decode: /* * We should have a User-Name attribute now. */ if (request->username == NULL) { request->username = pairfind(request->packet->vps, PW_USER_NAME); } /* * FIXME: All this lowercase/nospace junk will be moved * into a module after module failover is fully in place * * See if we have to lower user/pass before processing */ if(strcmp(mainconfig.do_lower_user, "before") == 0) rad_lowerpair(request, request->username); if(strcmp(mainconfig.do_lower_pass, "before") == 0) rad_lowerpair(request, pairfind(request->packet->vps, PW_PASSWORD)); if(strcmp(mainconfig.do_nospace_user, "before") == 0) rad_rmspace_pair(request, request->username); if(strcmp(mainconfig.do_nospace_pass, "before") == 0) rad_rmspace_pair(request, pairfind(request->packet->vps, PW_PASSWORD)); (*fun)(request); /* * If the request took too long to process, don't do * anything else. */ if (request->options & RAD_REQUEST_OPTION_REJECTED) { finished = TRUE; goto postpone_request; } /* * Reprocess if we rejected last time */ if ((fun == rad_authenticate) && (request->reply->code == PW_AUTHENTICATION_REJECT)) { /* See if we have to lower user/pass after processing */ if (strcmp(mainconfig.do_lower_user, "after") == 0) { rad_lowerpair(request, request->username); reprocess = 1; } if (strcmp(mainconfig.do_lower_pass, "after") == 0) { rad_lowerpair(request, pairfind(request->packet->vps, PW_PASSWORD)); reprocess = 1; } if (strcmp(mainconfig.do_nospace_user, "after") == 0) { rad_rmspace_pair(request, request->username); reprocess = 1; } if (strcmp(mainconfig.do_nospace_pass, "after") == 0) { rad_rmspace_pair(request, pairfind(request->packet->vps, PW_PASSWORD)); reprocess = 1; } /* * If we're re-processing the request, re-set it. */ if (reprocess) { pairfree(&request->config_items); pairfree(&request->reply->vps); request->reply->code = 0; (*fun)(request); } } /* * Status-Server requests NEVER get proxied. */ if (mainconfig.proxy_requests) { if ((request->packet->code != PW_STATUS_SERVER) && ((request->options & RAD_REQUEST_OPTION_PROXIED) == 0)) { int rcode; /* * Try to proxy this request. */ rcode = proxy_send(request); switch (rcode) { default: break; /* * There was an error trying to proxy the request. * Drop it on the floor. */ case RLM_MODULE_FAIL: DEBUG2("Error trying to proxy request %d: Rejecting it", request->number); request_reject(request); goto finished_request; break; /* * The pre-proxy module has decided to reject * the request. Do so. */ case RLM_MODULE_REJECT: DEBUG2("Request %d rejected in proxy_send.", request->number); request_reject(request); goto finished_request; break; /* * If the proxy code has handled the request, * then postpone more processing, until we get * the reply packet from the home server. */ case RLM_MODULE_HANDLED: goto postpone_request; break; } /* * Else rcode==RLM_MODULE_NOOP * and the proxy code didn't do anything, so * we continue handling the request here. */ } } else if ((request->packet->code == PW_AUTHENTICATION_REQUEST) && (request->reply->code == 0)) { /* * We're not configured to reply to the packet, * and we're not proxying, so the DEFAULT behaviour * is to REJECT the user. */ DEBUG2("There was no response configured: rejecting request %d", request->number); request_reject(request); goto finished_request; } /* * If we have a reply to send, copy the Proxy-State * attributes from the request to the tail of the reply, * and send the packet. */ rad_assert(request->magic == REQUEST_MAGIC); if (request->reply->code != 0) { VALUE_PAIR *vp = NULL; /* * Perform RFC limitations on outgoing replies. */ rfc_clean(request->reply); /* * Need to copy Proxy-State from request->packet->vps */ vp = paircopy2(request->packet->vps, PW_PROXY_STATE); if (vp) pairadd(&(request->reply->vps), vp); /* * If the request isn't an authentication reject, OR * it's a reject, but the reject_delay is zero, then * send it immediately. * * Otherwise, delay the authentication reject to shut * up DoS attacks. */ if ((request->reply->code != PW_AUTHENTICATION_REJECT) || (mainconfig.reject_delay == 0)) { /* * Send the response. IF it's a real request. */ if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) == 0) { rad_send(request->reply, request->packet, request->secret); } /* * Otherwise, it's a tunneled request. * Don't do anything. */ } else { DEBUG2("Delaying request %d for %d seconds", request->number, mainconfig.reject_delay); request->options |= RAD_REQUEST_OPTION_DELAYED_REJECT; } } /* * We're done processing the request, set the * request to be finished, clean up as necessary, * and forget about the request. */finished_request: /* * Don't decode the packet if it's an internal "fake" * request. Instead, just skip ahead to processing it. */ if ((request->options & RAD_REQUEST_OPTION_FAKE_REQUEST) != 0) { goto skip_free; } /* * We're done handling the request. Free up the linked * lists of value pairs. This might take a long time, * so it's more efficient to do it in a child thread, * instead of in the main handler when it eventually * gets around to deleting the request. * * Also, no one should be using these items after the * request is finished, and the reply is sent. Cleaning * them up here ensures that they're not being used again. * * Hmm... cleaning them up in the child thread also seems * to make the server run more efficiently! * * If we've delayed the REJECT, then do NOT clean up the request, * as we haven't created the REJECT message yet. */ if ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) == 0) { if (request->packet) { pairfree(&request->packet->vps); request->username = NULL; request->password = NULL; } /* * If we've sent a reply to the NAS, then this request is * pretty much finished, and we have no more need for any * of the value-pair's in it, including the proxy stuff. */ if (request->reply->code != 0) { pairfree(&request->reply->vps); } } pairfree(&request->config_items); if (request->proxy) { pairfree(&request->proxy->vps); } if (request->proxy_reply) { pairfree(&request->proxy_reply->vps); } skip_free: DEBUG2("Finished request %d", request->number); finished = TRUE; /* * Go to the next request, without marking * the current one as finished. * * Hmm... this may not be the brightest thing to do. */next_request: DEBUG2("Going to the next request");postpone_request:#ifdef HAVE_PTHREAD_H /* * We are finished with the child thread. The thread is detached, * so that when it exits, there's nothing more for the server * to do. * * If we're running with thread pools, then this frees up the * thread in the pool for another request. */ request->child_pid = NO_SUCH_CHILD_PID;#endif request->finished = finished; /* do as the LAST thing before exiting */ return 0;}/* * Display the syntax for starting this program. */static void usage(int status){ FILE *output = status?stderr:stdout; fprintf(output, "Usage: %s [-a acct_dir] [-d db_dir] [-l log_dir] [-i address] [-p port] [-AcfnsSvXxyz]\n", progname); fprintf(output, "Options:\n\n"); fprintf(output, " -a acct_dir use accounting directory 'acct_dir'.\n"); fprintf(output, " -A Log auth detail.\n"); fprintf(output, " -d db_dir Use database directory 'db_dir'.\n"); fprintf(output, " -f Run as a foreground process, not a daemon.\n"); fprintf(output, " -h Print this help message.\n"); fprintf(output, " -i address Listen only in the given IP address.\n"); fprintf(output, " -l log_dir Log messages to 'log_dir'. Special values are:\n"); fprintf(output, " stdout == log all messages to standard output.\n"); fprintf(output, " syslog == log all messages to the system logger.\n"); fprintf(output, " -p port Bind to 'port', and not to the radius/udp, or 1646/udp.\n"); fprintf(output, " -s Do not spawn child processes to handle requests.\n"); fprintf(output, " -S Log stripped names.\n"); fprintf(output, " -v Print server version information.\n"); fprintf(output, " -X Turn on full debugging. (Means: -sfxxyz -l stdout)\n"); fprintf(output, " -x Turn on partial debugging. (-xx gives more debugging).\n"); fprintf(output, " -y Log authentication failures, with password.\n"); fprintf(output, " -z Log authentication successes, with password.\n"); exit(status);}/* * We got a fatal signal. */static void sig_fatal(int sig){ switch(sig) { case SIGTERM: do_exit = 1; break; default: do_exit = 2; break; }}/* * We got the hangup signal. * Re-read the configuration files. *//*ARGSUSED*/static void sig_hup(int sig){ sig = sig; /* -Wunused */ reset_signal(SIGHUP, sig_hup); /* * Only do the reload if we're the main server, both * for processes, and for threads. */ if (getpid() == radius_pid) { need_reload = TRUE; }#ifdef WITH_SNMP if (mainconfig.do_snmp) { rad_snmp.smux_failures = 0; rad_snmp.smux_event = SMUX_CONNECT; }#endif}/* * Process and reply to a server-status request. * Like rad_authenticate and rad_accounting this should * live in it's own file but it's so small we don't bother. */static int rad_status_server(REQUEST *request){ char reply_msg[64]; time_t t; VALUE_PAIR *vp; /* * Reply with an ACK. We might want to add some more * interesting reply attributes, such as server uptime. */ t = request->timestamp - start_time; sprintf(reply_msg, "FreeRADIUS up %d day%s, %02d:%02d", (int)(t / 86400), (t / 86400) == 1 ? "" : "s", (int)((t / 3600) % 24), (int)(t / 60) % 60); request->reply->code = PW_AUTHENTICATION_ACK; vp = pairmake("Reply-Message", reply_msg, T_OP_SET); pairadd(&request->reply->vps, vp); /* don't need to check if !vp */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -