* copyright notice and this permission notice appear in all copies.
*/
+/* Code contributions from:
+ *
+ * Arne Schwabe <schwabe at uni-paderborn.de>
+ */
+
/* For UDP there is one server instance consisting of udpserverrd and udpserverth
* rd is responsible for init and launching wr
* For TLS there is a server instance that launches tlsserverrd for each TLS peer
*/
/* Bugs:
- * TCP accounting not yet supported
+ * Multiple outgoing connections if not enough IDs? (multiple servers per conf?)
+ * Also useful for TCP accounting which is not yet supported?
* We are not removing client requests from dynamic servers, see removeclientrqs()
+ * Reserve ID 0 for statusserver requests?
* Need to remove UDP clients when no activity for a while...
* Remove expired stuff from clients request list?
*/
void freeclsrvconf(struct clsrvconf *conf);
void freerq(struct request *rq);
void freerqoutdata(struct rqout *rqout);
+void rmclientrq(struct request *rq, uint8_t id);
static const struct protodefs protodefs[] = {
{ "udp", /* UDP, assuming RAD_UDP defined as 0 */
debug(DBG_WARN, "resolvepeer: can't resolve (null) port (null)");
return 0;
}
- for (res = addrinfo; res; res = res->ai_next) {
- switch (res->ai_family) {
- case AF_INET:
- ((struct sockaddr_in *)res->ai_addr)->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *)res->ai_addr)->sin6_port = 0;
- break;
- }
- }
+ for (res = addrinfo; res; res = res->ai_next)
+ port_set(res->ai_addr, 0);
} else {
if (slash)
hints.ai_flags |= AI_NUMERICHOST;
return;
pthread_mutex_lock(&q->mutex);
for (entry = list_first(q->entries); entry; entry = list_next(entry))
- free(((struct reply *)entry)->buf);
+ freerq((struct request *)entry);
list_destroy(q->entries);
pthread_cond_destroy(&q->cond);
pthread_mutex_unlock(&q->mutex);
}
memset(new, 0, sizeof(struct client));
- pthread_mutex_init(&new->lock, NULL);
new->conf = conf;
if (conf->pdef->addclient)
conf->pdef->addclient(new);
}
void removeclient(struct client *client) {
+ struct clsrvconf *conf;
+
if (!client)
return;
-
- pthread_mutex_lock(client->conf->lock);
- if (client->conf->clients) {
- pthread_mutex_lock(&client->lock);
+ conf = client->conf;
+ pthread_mutex_lock(conf->lock);
+ if (conf->clients) {
removequeue(client->replyq);
- list_removedata(client->conf->clients, client);
- pthread_mutex_unlock(&client->lock);
- pthread_mutex_destroy(&client->lock);
+ list_removedata(conf->clients, client);
free(client->addr);
free(client);
}
- pthread_mutex_unlock(client->conf->lock);
+ pthread_mutex_unlock(conf->lock);
}
void removeclientrqs(struct client *client) {
server = ((struct clsrvconf *)entry->data)->servers;
if (!server)
continue;
- pthread_mutex_lock(&server->newrq_mutex);
for (i = 0; i < MAX_REQUESTS; i++) {
rqout = server->requests + i;
- if (rqout->rq && rqout->rq->from == client) {
- freerq(rqout->rq);
- rqout->rq = NULL;
- }
+ pthread_mutex_lock(rqout->lock);
+ if (rqout->rq && rqout->rq->from == client)
+ freerqoutdata(rqout);
+ pthread_mutex_unlock(rqout->lock);
}
- pthread_mutex_unlock(&server->newrq_mutex);
}
}
if (server->requests) {
rqout = server->requests;
- for (end = rqout + MAX_REQUESTS; rqout < end; rqout++)
+ for (end = rqout + MAX_REQUESTS; rqout < end; rqout++) {
freerqoutdata(rqout);
+ pthread_mutex_destroy(rqout->lock);
+ free(rqout->lock);
+ }
free(server->requests);
}
if (server->rbios)
int addserver(struct clsrvconf *conf) {
struct clsrvconf *res;
uint8_t type;
+ int i;
if (conf->servers) {
debug(DBG_ERR, "addserver: currently works with just one server per conf");
debug(DBG_ERR, "malloc failed");
goto errexit;
}
+ for (i = 0; i < MAX_REQUESTS; i++) {
+ conf->servers->requests[i].lock = malloc(sizeof(pthread_mutex_t));
+ if (!conf->servers->requests[i].lock) {
+ debug(DBG_ERR, "malloc failed");
+ goto errexit;
+ }
+ if (pthread_mutex_init(conf->servers->requests[i].lock, NULL)) {
+ debug(DBG_ERR, "mutex init failed");
+ free(conf->servers->requests[i].lock);
+ conf->servers->requests[i].lock = NULL;
+ goto errexit;
+ }
+ }
if (pthread_mutex_init(&conf->servers->lock, NULL)) {
debug(DBG_ERR, "mutex init failed");
goto errexit;
return NULL;
}
-void freerqdata(struct request *rq) {
- if (!rq)
- return;
- if (rq->origusername)
- free(rq->origusername);
- if (rq->buf)
- free(rq->buf);
-}
-
void freerq(struct request *rq) {
if (!rq)
return;
debug(DBG_DBG, "freerq: called with refcount %d", rq->refcount);
if (--rq->refcount)
return;
- freerqdata(rq);
+ if (rq->origusername)
+ free(rq->origusername);
+ if (rq->buf)
+ free(rq->buf);
+ if (rq->replybuf)
+ free(rq->replybuf);
+ if (rq->msg)
+ radmsg_free(rq->msg);
free(rq);
}
void freerqoutdata(struct rqout *rqout) {
if (!rqout)
return;
- if (rqout->msg)
- radmsg_free(rqout->msg);
- if (rqout->buf)
- free(rqout->buf);
- if (rqout->rq)
+ if (rqout->rq) {
freerq(rqout->rq);
+ rqout->rq = NULL;
+ }
+ rqout->tries = 0;
+ memset(&rqout->expiry, 0, sizeof(struct timeval));
}
-void sendrq(struct server *to, struct rqout *rqout) {
+void sendrq(struct server *to, struct request *rq) {
int i;
-
+
pthread_mutex_lock(&to->newrq_mutex);
/* might simplify if only try nextid, might be ok */
- for (i = to->nextid; i < MAX_REQUESTS; i++)
- if (!to->requests[i].buf)
- break;
- if (i == MAX_REQUESTS) {
- for (i = 0; i < to->nextid; i++)
- if (!to->requests[i].buf)
+ for (i = to->nextid; i < MAX_REQUESTS; i++) {
+ if (!to->requests[i].rq) {
+ pthread_mutex_lock(to->requests[i].lock);
+ if (!to->requests[i].rq)
break;
+ pthread_mutex_unlock(to->requests[i].lock);
+ }
+ }
+ if (i == MAX_REQUESTS) {
+ for (i = 0; i < to->nextid; i++) {
+ if (!to->requests[i].rq) {
+ pthread_mutex_lock(to->requests[i].lock);
+ if (!to->requests[i].rq)
+ break;
+ pthread_mutex_unlock(to->requests[i].lock);
+ }
+ }
if (i == to->nextid) {
debug(DBG_WARN, "sendrq: no room in queue, dropping request");
- freerqoutdata(rqout);
+ rmclientrq(rq, rq->msg->id);
+ freerq(rq);
goto exit;
}
}
- rqout->msg->id = (uint8_t)i;
- rqout->buf = radmsg2buf(rqout->msg, (uint8_t *)to->conf->secret);
- if (!rqout->buf) {
+ rq->msg->id = (uint8_t)i;
+ rq->buf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret);
+ if (!rq->buf) {
+ pthread_mutex_unlock(to->requests[i].lock);
debug(DBG_ERR, "sendrq: radmsg2buf failed");
- freerqoutdata(rqout);
+ rmclientrq(rq, rq->msg->id);
+ freerq(rq);
goto exit;
}
debug(DBG_DBG, "sendrq: inserting packet with id %d in queue for %s", i, to->conf->host);
- to->requests[i] = *rqout;
+ to->requests[i].rq = rq;
+ pthread_mutex_unlock(to->requests[i].lock);
to->nextid = i + 1;
if (!to->newrq) {
pthread_mutex_unlock(&to->newrq_mutex);
}
-void sendreply(struct client *to, struct radmsg *msg, struct sockaddr_storage *tosa, int toudpsock) {
- uint8_t *buf;
- struct reply *reply;
+void sendreply(struct request *rq) {
uint8_t first;
-
- buf = radmsg2buf(msg, (uint8_t *)to->conf->secret);
- radmsg_free(msg);
- if (!buf) {
+ struct client *to = rq->from;
+
+ if (!rq->replybuf)
+ rq->replybuf = radmsg2buf(rq->msg, (uint8_t *)to->conf->secret);
+ radmsg_free(rq->msg);
+ rq->msg = NULL;
+ if (!rq->replybuf) {
+ freerq(rq);
debug(DBG_ERR, "sendreply: radmsg2buf failed");
return;
}
- reply = malloc(sizeof(struct reply));
- if (!reply) {
- free(buf);
- debug(DBG_ERR, "sendreply: malloc failed");
- return;
- }
- memset(reply, 0, sizeof(struct reply));
- reply->buf = buf;
- if (tosa)
- reply->tosa = *tosa;
- reply->toudpsock = toudpsock;
-
pthread_mutex_lock(&to->replyq->mutex);
-
first = list_first(to->replyq->entries) == NULL;
- if (!list_push(to->replyq->entries, reply)) {
+ if (!list_push(to->replyq->entries, rq)) {
pthread_mutex_unlock(&to->replyq->mutex);
- free(reply);
- free(buf);
+ freerq(rq);
debug(DBG_ERR, "sendreply: malloc failed");
return;
}
}
}
-int rqinqueue(struct server *to, struct client *from, uint8_t id, uint8_t code) {
- struct rqout *rqout = to->requests, *end;
-
- pthread_mutex_lock(&to->newrq_mutex);
- for (end = rqout + MAX_REQUESTS; rqout < end; rqout++)
- if (rqout->buf && !rqout->received && rqout->rq && rqout->rq->origid == id && rqout->rq->from == from && *rqout->buf == code)
- break;
- pthread_mutex_unlock(&to->newrq_mutex);
-
- return rqout < end;
-}
-
int attrvalidate(unsigned char *attrs, int length) {
while (length > 1) {
if (ATTRLEN(attrs) < 2) {
return 1;
}
-int msmpprecrypt(uint8_t *msmpp, uint8_t len, char *oldsecret, char *newsecret, unsigned char *oldauth, char *newauth) {
+int msmpprecrypt(uint8_t *msmpp, uint8_t len, char *oldsecret, char *newsecret, uint8_t *oldauth, uint8_t *newauth) {
if (len < 18)
return 0;
- if (!msmppdecrypt(msmpp + 2, len - 2, (unsigned char *)oldsecret, strlen(oldsecret), oldauth, msmpp)) {
+ if (!msmppdecrypt(msmpp + 2, len - 2, (uint8_t *)oldsecret, strlen(oldsecret), oldauth, msmpp)) {
debug(DBG_WARN, "msmpprecrypt: failed to decrypt msppe key");
return 0;
}
- if (!msmppencrypt(msmpp + 2, len - 2, (unsigned char *)newsecret, strlen(newsecret), (unsigned char *)newauth, msmpp)) {
+ if (!msmppencrypt(msmpp + 2, len - 2, (uint8_t *)newsecret, strlen(newsecret), newauth, msmpp)) {
debug(DBG_WARN, "msmpprecrypt: failed to encrypt msppe key");
return 0;
}
return 1;
}
-int msmppe(unsigned char *attrs, int length, uint8_t type, char *attrtxt, struct rqout *rqout,
+int msmppe(unsigned char *attrs, int length, uint8_t type, char *attrtxt, struct request *rq,
char *oldsecret, char *newsecret) {
unsigned char *attr;
for (attr = attrs; (attr = attrget(attr, length - (attr - attrs), type)); attr += ATTRLEN(attr)) {
debug(DBG_DBG, "msmppe: Got %s", attrtxt);
- if (!msmpprecrypt(ATTRVAL(attr), ATTRVALLEN(attr), oldsecret, newsecret, rqout->buf + 4, rqout->rq->origauth))
+ if (!msmpprecrypt(ATTRVAL(attr), ATTRVALLEN(attr), oldsecret, newsecret, rq->buf + 4, rq->rqauth))
return 0;
}
return 1;
return 1;
}
-int rewriteusername(struct rqout *rqout, struct tlv *attr) {
+int rewriteusername(struct request *rq, struct tlv *attr) {
char *orig = (char *)tlv2str(attr);
- if (!dorewritemodattr(attr, rqout->rq->from->conf->rewriteusername)) {
+ if (!dorewritemodattr(attr, rq->from->conf->rewriteusername)) {
free(orig);
return 0;
}
if (strlen(orig) != attr->l || memcmp(orig, attr->v, attr->l))
- rqout->rq->origusername = (char *)orig;
+ rq->origusername = (char *)orig;
else
free(orig);
return 1;
}
}
-void respondaccounting(struct rqout *rqout) {
- struct radmsg *msg;
-
- msg = radmsg_init(RAD_Accounting_Response, rqout->msg->id, rqout->msg->auth);
- if (msg) {
- debug(DBG_DBG, "respondaccounting: responding to %s", rqout->rq->from->conf->host);
- sendreply(rqout->rq->from, msg, &rqout->rq->fromsa, rqout->rq->fromudpsock);
- } else
- debug(DBG_ERR, "respondaccounting: malloc failed");
-}
-
-void respondstatusserver(struct rqout *rqout) {
- struct radmsg *msg;
-
- msg = radmsg_init(RAD_Access_Accept, rqout->msg->id, rqout->msg->auth);
- if (msg) {
- debug(DBG_DBG, "respondstatusserver: responding to %s", rqout->rq->from->conf->host);
- sendreply(rqout->rq->from, msg, &rqout->rq->fromsa, rqout->rq->fromudpsock);
- } else
- debug(DBG_ERR, "respondstatusserver: malloc failed");
-}
-
-void respondreject(struct rqout *rqout, char *message) {
+void respond(struct request *rq, uint8_t code, char *message) {
struct radmsg *msg;
struct tlv *attr;
- msg = radmsg_init(RAD_Access_Reject, rqout->msg->id, rqout->msg->auth);
+ msg = radmsg_init(code, rq->msg->id, rq->msg->auth);
if (!msg) {
- debug(DBG_ERR, "respondreject: malloc failed");
+ debug(DBG_ERR, "respond: malloc failed");
return;
}
if (message && *message) {
if (!attr || !radmsg_add(msg, attr)) {
freetlv(attr);
radmsg_free(msg);
- debug(DBG_ERR, "respondreject: malloc failed");
+ debug(DBG_ERR, "respond: malloc failed");
return;
}
}
- debug(DBG_DBG, "respondreject: responding to %s", rqout->rq->from->conf->host);
- sendreply(rqout->rq->from, msg, &rqout->rq->fromsa, rqout->rq->fromudpsock);
+ radmsg_free(rq->msg);
+ rq->msg = msg;
+ debug(DBG_DBG, "respond: sending %s to %s", radmsgtype2string(msg->code), rq->from->conf->host);
+ rq->refcount++;
+ sendreply(rq);
}
struct clsrvconf *choosesrvconf(struct list *srvconfs) {
return rq;
}
-int addclientrq(struct request *rq, uint8_t id) {
+int addclientrq(struct request *rq) {
struct request *r;
struct timeval now;
-
- pthread_mutex_lock(&rq->from->lock);
- gettimeofday(&now, NULL);
- r = rq->from->rqs[id];
+
+ r = rq->from->rqs[rq->rqid];
if (r) {
- if (r->refcount > 1 && now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) {
- pthread_mutex_unlock(&rq->from->lock);
- return 0;
+ if (rq->udpport == r->udpport && !memcmp(rq->rqauth, r->rqauth, 16)) {
+ gettimeofday(&now, NULL);
+ if (now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) {
+ if (r->replybuf) {
+ debug(DBG_INFO, "addclientrq: already sent reply to request with id %d from %s, resending", rq->rqid, addr2string(r->from->addr));
+ r->refcount++;
+ sendreply(r);
+ } else
+ debug(DBG_INFO, "addclientrq: already got request with id %d from %s, ignoring", rq->rqid, addr2string(r->from->addr));
+ return 0;
+ }
}
freerq(r);
}
rq->refcount++;
- rq->from->rqs[id] = rq;
- pthread_mutex_unlock(&rq->from->lock);
+ rq->from->rqs[rq->rqid] = rq;
return 1;
}
void rmclientrq(struct request *rq, uint8_t id) {
struct request *r;
- pthread_mutex_lock(&rq->from->lock);
r = rq->from->rqs[id];
if (r) {
freerq(r);
rq->from->rqs[id] = NULL;
}
- pthread_mutex_unlock(&rq->from->lock);
}
/* returns 0 if validation/authentication fails, else 1 */
int radsrv(struct request *rq) {
struct radmsg *msg = NULL;
- struct rqout *rqout, rqdata;
struct tlv *attr;
uint8_t *userascii = NULL;
- unsigned char newauth[16];
struct realm *realm = NULL;
struct server *to = NULL;
struct client *from = rq->from;
if (!msg) {
debug(DBG_WARN, "radsrv: message validation failed, ignoring packet");
+ freerq(rq);
return 0;
}
+
+ rq->msg = msg;
+ rq->rqid = msg->id;
+ memcpy(rq->rqauth, msg->auth, 16);
- rqout = &rqdata;
- memset(rqout, 0, sizeof(struct rqout));
- rqout->msg = msg;
debug(DBG_DBG, "radsrv: code %d, id %d", msg->code, msg->id);
-
if (msg->code != RAD_Access_Request && msg->code != RAD_Status_Server && msg->code != RAD_Accounting_Request) {
- debug(DBG_INFO, "radsrv: server currently accepts only access-requests, accounting-requests and status-server, ignoring");
- freerqoutdata(rqout);
- return 1;
- }
-
- if (!addclientrq(rq, msg->id)) {
- debug(DBG_INFO, "radsrv: already got request with id %d from %s, ignoring", msg->id, from->conf->host);
- freerqoutdata(rqout);
- return 1;
+ debug(DBG_INFO, "radsrv: server currently accepts only access-requests, accounting-requests and status-server, ignoring");
+ goto exit;
}
- rqout->rq = rq;
- rq->refcount++;
+ if (!addclientrq(rq))
+ goto exit;
+
if (msg->code == RAD_Status_Server) {
- respondstatusserver(rqout);
- goto respexit;
+ respond(rq, RAD_Access_Accept, NULL);
+ goto exit;
}
/* below: code == RAD_Access_Request || code == RAD_Accounting_Request */
if (from->conf->rewritein && !dorewrite(msg, from->conf->rewritein))
- goto exit;
+ goto rmclrqexit;
attr = radmsg_gettype(msg, RAD_Attr_User_Name);
if (!attr) {
if (msg->code == RAD_Accounting_Request) {
acclog(msg, from->conf->host);
- respondaccounting(rqout);
- goto respexit;
- }
- debug(DBG_WARN, "radsrv: ignoring access request, no username attribute");
+ respond(rq, RAD_Accounting_Response, NULL);
+ } else
+ debug(DBG_WARN, "radsrv: ignoring access request, no username attribute");
goto exit;
}
- if (from->conf->rewriteusername && !rewriteusername(rqout, attr)) {
+ if (from->conf->rewriteusername && !rewriteusername(rq, attr)) {
debug(DBG_WARN, "radsrv: username malloc failed, ignoring request");
- goto exit;
+ goto rmclrqexit;
}
userascii = radattr2ascii(attr);
if (!userascii)
- goto exit;
+ goto rmclrqexit;
debug(DBG_DBG, "%s with username: %s", radmsgtype2string(msg->code), userascii);
to = findserver(&realm, attr, msg->code == RAD_Accounting_Request);
if (!to) {
if (realm->message && msg->code == RAD_Access_Request) {
debug(DBG_INFO, "radsrv: sending reject to %s for %s", from->conf->host, userascii);
- respondreject(rqout, realm->message);
+ respond(rq, RAD_Access_Reject, realm->message);
} else if (realm->accresp && msg->code == RAD_Accounting_Request) {
acclog(msg, from->conf->host);
- respondaccounting(rqout);
+ respond(rq, RAD_Accounting_Response, NULL);
}
- goto respexit;
+ goto exit;
}
if (options.loopprevention && !strcmp(from->conf->name, to->conf->name)) {
goto exit;
}
-#if 0
- skip this now that we have rqrcv... per client?
- if (rqinqueue(to, from, msg->id, msg->code)) {
- debug(DBG_INFO, "radsrv: already got %s from host %s with id %d, ignoring",
- radmsgtype2string(msg->code), from->conf->host, msg->id);
- goto exit;
- }
-#endif
-
- if (msg->code != RAD_Accounting_Request) {
- if (!RAND_bytes(newauth, 16)) {
- debug(DBG_WARN, "radsrv: failed to generate random auth");
- goto exit;
- }
+ if (msg->code == RAD_Accounting_Request)
+ memset(msg->auth, 0, 16);
+ else if (!RAND_bytes(msg->auth, 16)) {
+ debug(DBG_WARN, "radsrv: failed to generate random auth");
+ goto rmclrqexit;
}
#ifdef DEBUG
attr = radmsg_gettype(msg, RAD_Attr_User_Password);
if (attr) {
debug(DBG_DBG, "radsrv: found userpwdattr with value length %d", attr->l);
- if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, msg->auth, newauth))
- goto exit;
+ if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
+ goto rmclrqexit;
}
attr = radmsg_gettype(msg, RAD_Attr_Tunnel_Password);
if (attr) {
debug(DBG_DBG, "radsrv: found tunnelpwdattr with value length %d", attr->l);
- if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, msg->auth, newauth))
- goto exit;
+ if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
+ goto rmclrqexit;
}
- rqout->rq->origid = msg->id;
- memcpy(rqout->rq->origauth, msg->auth, 16);
- memcpy(msg->auth, newauth, 16);
-
if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
- goto exit;
+ goto rmclrqexit;
free(userascii);
- sendrq(to, rqout);
+ sendrq(to, rq);
return 1;
- exit:
+ rmclrqexit:
rmclientrq(rq, msg->id);
+ exit:
+ freerq(rq);
free(userascii);
- freerqoutdata(rqout);
- return 1;
-
- respexit:
- free(userascii);
- freerqoutdata(rqout);
return 1;
-
}
void replyh(struct server *server, unsigned char *buf) {
struct rqout *rqout;
int sublen;
unsigned char *subattrs;
- struct sockaddr_storage fromsa;
- uint8_t *username, *stationid;
+ uint8_t *username, *stationid, *replymsg;
struct radmsg *msg = NULL;
struct tlv *attr;
struct list_node *node;
server->lostrqs = 0;
rqout = server->requests + buf[1];
- msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rqout->msg->auth);
+ pthread_mutex_lock(rqout->lock);
+ if (!rqout->tries) {
+ free(buf);
+ buf = NULL;
+ debug(DBG_INFO, "replyh: no outstanding request with this id, ignoring reply");
+ goto errunlock;
+ }
+
+ msg = buf2radmsg(buf, (uint8_t *)server->conf->secret, rqout->rq->msg->auth);
free(buf);
buf = NULL;
if (!msg) {
debug(DBG_WARN, "replyh: message validation failed, ignoring packet");
- return;
+ goto errunlock;
}
if (msg->code != RAD_Access_Accept && msg->code != RAD_Access_Reject && msg->code != RAD_Access_Challenge
&& msg->code != RAD_Accounting_Response) {
debug(DBG_INFO, "replyh: discarding message type %s, accepting only access accept, access reject, access challenge and accounting response messages", radmsgtype2string(msg->code));
- radmsg_free(msg);
- return;
- }
- debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
-
- pthread_mutex_lock(&server->newrq_mutex);
- if (!rqout->buf || !rqout->tries) {
- debug(DBG_INFO, "replyh: no matching request sent with this id, ignoring reply");
goto errunlock;
}
+ debug(DBG_DBG, "got %s message with id %d", radmsgtype2string(msg->code), msg->id);
- if (rqout->received) {
- debug(DBG_INFO, "replyh: already received, ignoring reply");
- goto errunlock;
- }
-
gettimeofday(&server->lastrcv, NULL);
- if (rqout->msg->code == RAD_Status_Server) {
- rqout->received = 1;
+ if (rqout->rq->msg->code == RAD_Status_Server) {
+ freerqoutdata(rqout);
debug(DBG_DBG, "replyh: got status server response from %s", server->conf->host);
goto errunlock;
}
gettimeofday(&server->lastreply, NULL);
-
- if (!rqout->rq) {
- debug(DBG_INFO, "replyh: client gone, ignoring reply");
- goto errunlock;
- }
from = rqout->rq->from;
if (server->conf->rewritein && !dorewrite(msg, from->conf->rewritein)) {
subattrs = attr->v + 4;
if (!attrvalidate(subattrs, sublen) ||
!msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Send_Key, "MS MPPE Send Key",
- rqout, server->conf->secret, from->conf->secret) ||
+ rqout->rq, server->conf->secret, from->conf->secret) ||
!msmppe(subattrs, sublen, RAD_VS_ATTR_MS_MPPE_Recv_Key, "MS MPPE Recv Key",
- rqout, server->conf->secret, from->conf->secret))
+ rqout->rq, server->conf->secret, from->conf->secret))
break;
}
if (node) {
}
if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Accounting_Response) {
- username = radattr2ascii(radmsg_gettype(rqout->msg, RAD_Attr_User_Name));
+ username = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_User_Name));
if (username) {
- stationid = radattr2ascii(radmsg_gettype(rqout->msg, RAD_Attr_Calling_Station_Id));
+ stationid = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_Calling_Station_Id));
+ replymsg = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Reply_Message));
if (stationid) {
- debug(DBG_INFO, "%s for user %s stationid %s from %s",
- radmsgtype2string(msg->code), username, stationid, server->conf->host);
+ if (replymsg) {
+ debug(DBG_INFO, "%s for user %s stationid %s from %s (%s)",
+ radmsgtype2string(msg->code), username, stationid, server->conf->host, replymsg);
+ free(replymsg);
+ } else
+ debug(DBG_INFO, "%s for user %s stationid %s from %s",
+ radmsgtype2string(msg->code), username, stationid, server->conf->host);
free(stationid);
- } else
- debug(DBG_INFO, "%s for user %s from %s", radmsgtype2string(msg->code), username, server->conf->host);
+ } else {
+ if (replymsg) {
+ debug(DBG_INFO, "%s for user %s from %s (%s)",
+ radmsgtype2string(msg->code), username, server->conf->host, replymsg);
+ free(replymsg);
+ } else
+ debug(DBG_INFO, "%s for user %s from %s",
+ radmsgtype2string(msg->code), username, server->conf->host);
+ }
free(username);
}
}
- msg->id = (char)rqout->rq->origid;
- memcpy(msg->auth, rqout->rq->origauth, 16);
+ msg->id = (char)rqout->rq->rqid;
+ memcpy(msg->auth, rqout->rq->rqauth, 16);
#ifdef DEBUG
printfchars(NULL, "origauth/buf+4", "%02x ", buf + 4, 16);
goto errunlock;
}
- fromsa = rqout->rq->fromsa; /* only needed for UDP */
- /* once we set received = 1, rq may be reused */
- rqout->received = 1;
-
debug(DBG_INFO, "replyh: passing reply to client %s", from->conf->name);
- sendreply(from, msg, &fromsa, rqout->rq->fromudpsock);
- pthread_mutex_unlock(&server->newrq_mutex);
+ radmsg_free(rqout->rq->msg);
+ rqout->rq->msg = msg;
+ rqout->rq->refcount++;
+ sendreply(rqout->rq);
+ freerqoutdata(rqout);
+ pthread_mutex_unlock(rqout->lock);
return;
errunlock:
radmsg_free(msg);
- pthread_mutex_unlock(&server->newrq_mutex);
+ pthread_mutex_unlock(rqout->lock);
return;
}
-struct radmsg *createstatsrvmsg() {
- struct radmsg *msg;
+struct request *createstatsrvrq() {
+ struct request *rq;
struct tlv *attr;
- msg = radmsg_init(RAD_Status_Server, 0, NULL);
- if (!msg)
+ rq = newrequest();
+ if (!rq)
return NULL;
-
+ rq->msg = radmsg_init(RAD_Status_Server, 0, NULL);
+ if (!rq->msg)
+ goto exit;
attr = maketlv(RAD_Attr_Message_Authenticator, 16, NULL);
- if (!attr) {
- radmsg_free(msg);
- return NULL;
- }
- if (!radmsg_add(msg, attr)) {
+ if (!attr)
+ goto exit;
+ if (!radmsg_add(rq->msg, attr)) {
freetlv(attr);
- radmsg_free(msg);
- return NULL;
+ goto exit;
}
- return msg;
+ return rq;
+
+ exit:
+ freerq(rq);
+ return NULL;
}
/* code for removing state not finished */
void *clientwr(void *arg) {
struct server *server = (struct server *)arg;
- struct rqout *rqout;
+ struct rqout *rqout = NULL;
pthread_t clientrdth;
int i, secs, dynconffail = 0;
uint8_t rnd;
struct timeval now, laststatsrv;
struct timespec timeout;
- struct rqout statsrvrq;
+ struct request *statsrvrq;
struct clsrvconf *conf;
conf = server->conf;
pthread_join(clientrdth, NULL);
goto errexit;
}
- pthread_mutex_lock(&server->newrq_mutex);
- while (i < MAX_REQUESTS && !server->requests[i].buf)
- i++;
- if (i == MAX_REQUESTS) {
- pthread_mutex_unlock(&server->newrq_mutex);
- break;
- }
- rqout = server->requests + i;
- if (rqout->received) {
- debug(DBG_DBG, "clientwr: packet %d in queue is marked as received", i);
- if (rqout->buf) {
- debug(DBG_DBG, "clientwr: freeing received packet %d from queue", i);
- freerqoutdata(rqout);
- /* setting this to NULL means that it can be reused */
- rqout->buf = NULL;
+ for (; i < MAX_REQUESTS; i++) {
+ rqout = server->requests + i;
+ if (rqout->rq) {
+ pthread_mutex_lock(rqout->lock);
+ if (rqout->rq)
+ break;
+ pthread_mutex_unlock(rqout->lock);
}
- pthread_mutex_unlock(&server->newrq_mutex);
- continue;
- }
-
+ }
+
+ if (i == MAX_REQUESTS)
+ break;
+
gettimeofday(&now, NULL);
if (now.tv_sec < rqout->expiry.tv_sec) {
if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
timeout.tv_sec = rqout->expiry.tv_sec;
- pthread_mutex_unlock(&server->newrq_mutex);
+ pthread_mutex_unlock(rqout->lock);
continue;
}
- if (rqout->tries == (*rqout->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) {
+ if (rqout->tries == (*rqout->rq->buf == RAD_Status_Server ? 1 : conf->retrycount + 1)) {
debug(DBG_DBG, "clientwr: removing expired packet from queue");
if (conf->statusserver) {
- if (*rqout->buf == RAD_Status_Server) {
+ if (*rqout->rq->buf == RAD_Status_Server) {
debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->host);
if (server->lostrqs < 255)
server->lostrqs++;
server->lostrqs++;
}
freerqoutdata(rqout);
- /* setting this to NULL means that it can be reused */
- rqout->buf = NULL;
- pthread_mutex_unlock(&server->newrq_mutex);
+ pthread_mutex_unlock(rqout->lock);
continue;
}
- pthread_mutex_unlock(&server->newrq_mutex);
rqout->expiry.tv_sec = now.tv_sec + conf->retryinterval;
if (!timeout.tv_sec || rqout->expiry.tv_sec < timeout.tv_sec)
timeout.tv_sec = rqout->expiry.tv_sec;
rqout->tries++;
- conf->pdef->clientradput(server, server->requests[i].buf);
+ conf->pdef->clientradput(server, rqout->rq->buf);
+ pthread_mutex_unlock(rqout->lock);
}
if (conf->statusserver) {
secs = server->lastrcv.tv_sec > laststatsrv.tv_sec ? server->lastrcv.tv_sec : laststatsrv.tv_sec;
gettimeofday(&now, NULL);
if (now.tv_sec - secs > STATUS_SERVER_PERIOD) {
laststatsrv = now;
- memset(&statsrvrq, 0, sizeof(struct rqout));
- statsrvrq.msg = createstatsrvmsg();
- if (statsrvrq.msg) {
+ statsrvrq = createstatsrvrq();
+ if (statsrvrq) {
debug(DBG_DBG, "clientwr: sending status server to %s", conf->host);
- sendrq(server, &statsrvrq);
+ sendrq(server, statsrvrq);
}
}
}
if (!foreground && (daemon(0, 0) < 0))
debugx(1, DBG_ERR, "daemon() failed: %s", strerror(errno));
+ debug_timestamp_on();
debug(DBG_INFO, "radsecproxy revision $Rev$ starting");
sigemptyset(&sigset);