#include "radiusd.h"
-static int proxy_id = 1;
-static REQUEST *proxy_requests;
+static uint32_t proxy_id = 1;
+static REQUEST *proxy_requests = NULL;
+
+#ifdef WITH_OLD_PROXY
static int allowed [] = {
PW_SERVICE_TYPE,
PW_FRAMED_PROTOCOL,
last = a;
}
}
+#endif
/*
* Add a proxy-pair to the end of the request.
pairadd(&rp->vps, proxy_pair);
}
+#ifdef WITH_OLD_PROXY
+
/*
* Add the request to the list.
*/
}
request->next = NULL;
- request->child_pid = -1;
+ request->child_pid = NO_SUCH_CHILD_PID;
request->timestamp = time(NULL);
request->next = proxy_requests;
return id;
}
+#endif
/*
char *realmname;
int replicating;
+#ifdef WITH_OLD_PROXY
/*
* First cleanup old outstanding requests.
*/
proxy_cleanup();
+#else
+ request->timestamp += 5;
+#endif
/* Look for proxy/replicate signs */
/* FIXME - What to do if multiple Proxy-To/Replicate-To attrs are
* OTOH the remote radius server should be smart enough to
* compare _both_ ID and vector. Right ?
*/
- if ((request->proxy = rad_alloc(0)) == NULL) {
+ if ((request->proxy = rad_alloc(TRUE)) == NULL) {
log(L_ERR|L_CONS, "no memory");
exit(1);
}
request->proxy->dst_port = realm->acct_port;
request->proxy->vps = vps;
- printf("Destination port: %d, server %s (%d/%d)\n",
- request->proxy->dst_port, realm->server,
- realm->auth_port, realm->acct_port);
-
+#ifdef WITH_OLD_PROXY
/*
* XXX: we re-use the vector from the original request
* here, since that's easy for retransmits ...
*/
memcpy(request->proxy->vector, request->packet->vector,
AUTH_VECTOR_LEN);
+#endif
/*
* Add the request to the list of outstanding requests.
* while rad_send sends only the 8 least significant
* bits of that same value.
*/
+#ifdef WITH_OLD_PROXY
request->proxy->id = proxy_addrequest(request, &proxy_id);
+#else
+ request->proxy->id = (proxy_id++) & 0xff;
+#endif
/*
* Add PROXY_STATE attribute.
return replicating?2:1;
}
-
+#ifdef WITH_OLD_PROXY
/*
* We received a response from a remote radius server.
* Find the original request, then return.
VALUE_PAIR *realmpair;
int replicating;
REALM *realm;
- char *realmname;
/*
* First cleanup old outstanding requests.
*/
/*
+ * This isn't really necessary. If it comes into
+ * our proxy FD from the right client with the right
+ * code, ID, and md5 checksum, then the Proxy-State
+ * attribute is unimportant.
+ */
+ /*
* Find the last PROXY_STATE attribute.
*/
oldreq = NULL;
log(L_PROXY, "Proxy reply to packet with no Realm");
return -1;
}
- realmname=realmpair->strvalue;
- /* FIXME - this "NULL" realm is probably broken now. Does anyone
- * still need it? */
- realm = realm_find(realmname ? realmname : "NULL");
+ realm = realm_find(realmpair->strvalue);
/* FIXME - do we want to use the trusted/allowed filters on replicate
* replies, which are not going to be used for anything except maybe
return replicating?1:0;
}
+#endif
/*
* FIXME: Maybe keeping the proxy_requests list sorted by
static int request_list_busy = FALSE;
static int authfd;
static int acctfd;
-int proxyfd;
-static int spawn_flag = FALSE;
+int proxyfd;
+static int spawn_flag = TRUE;
static int radius_pid;
static int need_reload = FALSE;
static struct rlimit core_limits;
static void sig_fatal (int);
static void sig_hup (int);
-static int rad_process (REQUEST *);
+static int rad_process (REQUEST *, int);
static void rad_clean_list(void);
static REQUEST *rad_check_list(REQUEST *);
#ifndef WITH_THREAD_POOL
-static int rad_respond (REQUEST *);
static void rad_spawn_child(REQUEST *, RAD_REQUEST_FUNP);
#else
extern void rad_spawn_child(REQUEST *, RAD_REQUEST_FUNP);
* TOO LAZY to type '-sfxxyz -l stdout' themselves.
*/
case 'X':
+#ifndef WITH_THREAD_POOL
spawn_flag = FALSE;
+#endif
dont_fork = TRUE;
debug_flag = 2;
librad_debug = 2;
request->packet = packet;
request->proxy = NULL;
request->reply = NULL;
+ request->proxy_reply = NULL;
request->config_items = NULL;
request->username = pairfind(request->packet->vps, PW_USER_NAME);
request->password = NULL;
request->prev = NULL;
request->next = NULL;
strcpy(request->secret, cl->secret);
- rad_process(request);
+ rad_process(request, spawn_flag);
/*
* After processing the current request,
* Relay reply back to original NAS.
*
*/
-int rad_process(REQUEST *request)
+int rad_process(REQUEST *request, int dospawn)
{
- int dospawn;
RAD_REQUEST_FUNP fun;
int replicating = 0;
- dospawn = FALSE;
fun = NULL;
switch(request->packet->code) {
case PW_AUTHENTICATION_REQUEST:
+ /*
+ * Check for requests sent to the wrongport,
+ * and ignore them, if so.
+ */
+ if (request->packet->sockfd != authfd) {
+ log(L_ERR, "Request packet code %d sent to authentication port from "
+ "client %s - ID %d : IGNORED",
+ request->packet->code,
+ client_name(request->packet->src_ipaddr),
+ request->packet->id);
+ request_free(request);
+ return -1;
+ }
+ break;
+
case PW_ACCOUNTING_REQUEST:
/*
- * Check for requests sent to the proxy port,
+ * Check for requests sent to the wrong port,
* and ignore them, if so.
*/
- if (request->packet->sockfd == proxyfd) {
- log(L_ERR, "Request packet code %d sent to proxy port from "
+ if (request->packet->sockfd != acctfd) {
+ log(L_ERR, "Request packet code %d sent to accounting port from "
"client %s - ID %d : IGNORED",
request->packet->code,
client_name(request->packet->src_ipaddr),
* an error message logged, and the packet is dropped.
*/
if (request->packet->sockfd == proxyfd) {
+#ifdef WITH_OLD_PROXY
int recvd = proxy_receive(request);
if (recvd < 0) {
return -1;
}
replicating = recvd;
+#endif
break;
}
/* NOT proxyfd: fall through to error message */
switch(request->packet->code) {
case PW_AUTHENTICATION_REQUEST:
- dospawn = spawn_flag;
+ DEBUG2("Calling rad_authenticate");
fun = rad_authenticate;
break;
case PW_ACCOUNTING_REQUEST:
+ DEBUG2("Calling rad_accounting");
fun = rad_accounting;
break;
return -1;
break;
+#ifndef WITH_OLD_PROXY
+ case PW_AUTHENTICATION_ACK:
+ case PW_AUTHENTICATION_REJECT:
+ case PW_ACCOUNTING_RESPONSE:
+ DEBUG2("Calling proxy_receive");
+ fun = proxy_receive;
+ break;
+#endif
default:
log(L_ERR, "Unknown packet type %d from client %s "
*/
request = rad_check_list(request);
if (request == NULL) {
+ DEBUG2("Dropped duplicate");
return 0;
}
return 0;
}
-/*
- * This define is here only for debugging the thread pool.
- * Normally, when in NON-spawning mode, there should be NO
- * child threads.
- */
-#ifndef WITH_THREAD_POOL
/*
* We're the one who's supposed to handle the request,
* as everyone else gave up on it. Let's do so.
*/
(*fun)(request);
-
- /*
- * If we don't already have a proxy
- * packet for this request, we MIGHT have
- * to go proxy it.
- */
- if (!request->proxy) {
- int sent;
- sent = proxy_send(request);
- if (sent == 0 || sent == 2)
- rad_respond(request);
- } else {
- if (replicating == 0) {
-
- rad_respond(request);
- }
- }
-#else
- /*
- * Temporary thread pools: always spawn, even if debugging.
- */
- rad_spawn_child(request, fun);
-#endif
+ rad_respond(request);
return 0;
}
-#ifndef WITH_THREAD_POOL
/*
* Respond to a request packet.
*
* Maybe we proxy the request to another server, or else maybe
* we replicate it to another server.
*/
-static int rad_respond(REQUEST *request)
+int rad_respond(REQUEST *request)
{
- if (request->reply)
- rad_send(request->reply, request->secret);
+ /*
+ * If we don't already have a proxy
+ * packet for this request, we MIGHT have
+ * to go proxy it.
+ */
+ if (request->proxy == NULL) {
+ int sent;
+ sent = proxy_send(request);
- request->finished = TRUE;
- return 0;
-}
+ /*
+ * sent==1 means it's been proxied. The child
+ * is done handling the request, but the request
+ * is NOT finished!
+ */
+ if (sent != 0 || sent != 2) {
+#ifdef WITH_THREAD_POOL
+ request->child_pid = NO_SUCH_CHILD_PID;
+#endif
+ return 0;
+ }
+
+#if 0
+ } else {
+ if (replicating != 0) {
+ /* ??? */
+ }
+#endif
+ }
+
+ if (request->reply)
+ rad_send(request->reply, request->secret);
+
+#ifdef WITH_THREAD_POOL
+ request->child_pid = NO_SUCH_CHILD_PID;
#endif
+ request->finished = TRUE;
+ return 0;
+}
/*
* Clean up the request list, every so often.
* Maybe the child process handling the request
* has hung: kill it, and continue.
*/
- if (!curreq->finished &&
- (curreq->timestamp + max_request_time) <= curtime &&
- curreq->child_pid != NO_SUCH_CHILD_PID) {
- /*
- * This request seems to have hung
- * - kill it
- */
- child_pid = curreq->child_pid;
- log(L_ERR, "Killing unresponsive child %d",
- child_pid);
- child_kill(child_pid, SIGTERM);
-
+ if (!curreq->finished &&
+ (curreq->timestamp + max_request_time) <= curtime) {
+ if (curreq->child_pid != NO_SUCH_CHILD_PID) {
+ /*
+ * This request seems to have hung
+ * - kill it
+ */
+ child_pid = curreq->child_pid;
+ log(L_ERR, "Killing unresponsive child %d",
+ child_pid);
+ child_kill(child_pid, SIGTERM);
+ } /* else no proxy reply, quietly fail */
+
/*
* Mark the request as unsalvagable.
*/
* requests, and verifing that there is only one process
* responding to each request (duplicate requests are filtered
* out).
+ *
+ * Also, check if the request is a reply from a request proxied to
+ * a remote server. If so, play games with the request, and return
+ * the old one.
*/
static REQUEST *rad_check_list(REQUEST *request)
{
REQUEST_LIST *request_list_entry;
int i;
+#ifndef WITH_OLD_PROXY
+ /*
+ * If it's a proxy reply, then it can't be a duplicate
+ * request from one of our clients.
+ *
+ * If the request already has a proxy packet, then it's
+ * obviously not a new one, either.
+ */
+ if ((request->packet->sockfd == proxyfd) ||
+ (request->proxy != NULL)) {
+ return request;
+ }
+#endif
+
request_list_entry = &request_list[request->packet->id];
curreq = request_list_entry->first_request;
prevreq = NULL;
* We do this be checking the src IP, (NOT port)
* the packet code, and ID.
*/
- if (request &&
- (curreq->packet->src_ipaddr == pkt->src_ipaddr) &&
+ if ((curreq->packet->src_ipaddr == pkt->src_ipaddr) &&
(curreq->packet->code == pkt->code) &&
(curreq->packet->id == pkt->id)) {
client_name(request->packet->src_ipaddr),
request->packet->id);
rad_send(curreq->reply, curreq->secret);
+#ifndef WITH_OLD_PROXY
+ /*
+ * There's no reply, but maybe there's
+ * an outstanding proxy request.
+ */
+ } else if (curreq->proxy != NULL) {
+ /* FIXME: kick the remote server again ? */
+#endif
} else {
log(L_ERR,
"Dropping duplicate authentication packet"
*/
request_free(request);
request = NULL;
+ break;
} else {
/*
* The packet vectors are different, so
- * we can make the old request to be
+ * we can mark the old request to be
* deleted from the list.
*/
if (curreq->finished) {
curreq->timestamp = 0;
+ break;
}
}
} /* checks for duplicate packets */
+
prevreq = curreq;
curreq = curreq->next;
} /* end of walking the request list */
return NULL;
}
+
+#ifndef WITH_OLD_PROXY
+ /*
+ * Maybe we've received a proxy reply for a packet
+ * we've handled and forgotten. If so, ignore it.
+ */
+ if (pkt->sockfd == proxyfd) {
+ DEBUG2("Unrecognized proxy reply from server %s - ID %d",
+ client_name(request->packet->src_ipaddr),
+ request->packet->id);
+ request_free(request);
+ request_list_busy = FALSE;
+ return NULL;
+ }
+#endif
+
/*
* Count the total number of requests, to see if there
* are too many. If so, stop counting immediately,
return request;
}
-/* Remove a request from the pending list without looking at it or freeing
- * it. Called from proxy code when it wants to take over */
-void remove_from_request_list(REQUEST *request)
-{
- REQUEST *prevreq;
- REQUEST *curreq;
-
- prevreq = NULL;
- for (curreq = request_list[request->packet->id].first_request; curreq; curreq = curreq->next) {
- if (curreq == request) {
- if (prevreq) {
- prevreq->next = request->next;
- } else {
- request_list[request->packet->id].first_request = request->next;
- }
- request_list[request->packet->id].request_count--;
- return;
- }
- }
-}
-
#ifndef WITH_THREAD_POOL
#ifdef HAVE_PTHREAD_H
typedef struct spawn_thread_t {
spawn_thread_t *data = (spawn_thread_t *)arg;
signal(SIGTERM, sig_term);
- (*data->fun)(data->request);
+ (*(data->fun))(data->request);
rad_respond(data->request);
return NULL;
}
reset_signal(SIGHUP, sig_hup);
need_reload = TRUE;
}
+
+#ifndef WITH_OLD_PROXY
+/*
+ * Do a proxy receive of a packet, when using thread pools.
+ *
+ * This function is here because it has to access the REQUEST_LIST
+ * structure, which is 'static' to this C file.
+ */
+int proxy_receive(REQUEST *request)
+{
+ int id;
+ REQUEST *oldreq;
+ RADIUS_PACKET *pkt;
+
+ /*
+ * Find the original request in the request list
+ */
+ oldreq = NULL;
+ pkt = request->packet;
+
+ for (id = 0; (id < 256) && (oldreq == NULL); id++) {
+ for (oldreq = request_list[id].first_request ;
+ oldreq != NULL ;
+ oldreq = oldreq->next) {
+ if (oldreq->proxy &&
+ (oldreq->proxy->dst_ipaddr == pkt->src_ipaddr) &&
+ (oldreq->proxy->dst_port == pkt->src_port) &&
+ (oldreq->proxy->id == pkt->id)) {
+ break;
+ }
+ }
+ }
+
+ /*
+ * If we haven't found the old request, complain.
+ */
+ if (oldreq == NULL) {
+ log(L_PROXY, "Unrecognized proxy reply from server %s - ID %d",
+ client_name(request->packet->src_ipaddr),
+ request->packet->id);
+ return -1;
+ }
+
+ /*
+ * Refresh the old request,. and update it.
+ */
+ oldreq->timestamp += 5;
+ oldreq->child_pid = request->child_pid;
+ oldreq->proxy_reply = request->packet;
+ request->packet = NULL;
+
+ request->child_pid = NO_SUCH_CHILD_PID;
+ request->finished = TRUE;
+ request->timestamp = 0;
+
+ /*
+ * Process the request as if it came in
+ * from a NAS, but don't spawn a child thread to handle it.
+ */
+ rad_process(oldreq, FALSE);
+
+ return 0;
+}
+#endif
/*
+ * Proxy file descriptor. Yes, global variables are ugly.
+ */
+extern int proxyfd;
+
+
+/*
* A data structure which contains the information about
* the current thread.
*
static void *request_handler_thread(void *arg)
{
THREAD_HANDLE *self;
+ REQUEST *request;
self = (THREAD_HANDLE *) arg;
DEBUG2("Thread %d handling request %08x, number %d",
self->child_pid, self->request, self->request_count);
+
+ request = self->request;
+
/*
* Decode the packet, verifying it's signature,
* and parsing the attributes into structures.
* a child thread, not the master. This helps to
* spread the load a little bit.
*/
- if (rad_decode(self->request->packet, self->request->secret) != 0) {
+ if (rad_decode(request->packet, request->secret) != 0) {
log(L_ERR, "%s", librad_errstr);
+ request->child_pid = NO_SUCH_CHILD_PID;
+ request->finished = TRUE;
goto next_request;
}
/*
* We have a User-Name attribute now, presumably.
*/
- self->request->username = pairfind(self->request->packet->vps,
+ request->username = pairfind(request->packet->vps,
PW_USER_NAME);
/*
* We have the semaphore, and have decoded the packet.
* Let's process the request.
*/
- (*(self->fun))(self->request);
+ (*(self->fun))(request);
/*
- * If there's a reply, go send it.
+ * Respond to the request, including any
+ * proxy or replicate commands.
*/
- if (self->request->reply)
- rad_send(self->request->reply, self->request->secret);
-
+ rad_respond(request);
+
/*
* We're done processing the request, set the request
* to be finished, and forget about the request.
*/
next_request:
- self->request->child_pid = NO_SUCH_CHILD_PID;
- self->request->finished = TRUE;
self->request = NULL;
/*
* The semaphore's value is zero, because we've
- * locked it. We no go back to the top of the loop,
+ * locked it. We now go back to the top of the loop,
* where we wait for it's value to become non-zero.
*/
}