* 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?
*/
}
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) {
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;
}
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, rq->buf + 4, rq->origauth))
+ if (!msmpprecrypt(ATTRVAL(attr), ATTRVALLEN(attr), oldsecret, newsecret, rq->buf + 4, rq->rqauth))
return 0;
}
return 1;
}
}
-void respondaccounting(struct request *rq) {
- struct radmsg *msg;
-
- msg = radmsg_init(RAD_Accounting_Response, rq->msg->id, rq->msg->auth);
- if (msg) {
- radmsg_free(rq->msg);
- rq->msg = msg;
- debug(DBG_DBG, "respondaccounting: responding to %s", rq->from->conf->host);
- sendreply(rq);
- } else
- debug(DBG_ERR, "respondaccounting: malloc failed");
-}
-
-void respondstatusserver(struct request *rq) {
- struct radmsg *msg;
-
- msg = radmsg_init(RAD_Access_Accept, rq->msg->id, rq->msg->auth);
- if (msg) {
- radmsg_free(rq->msg);
- rq->msg = msg;
- debug(DBG_DBG, "respondstatusserver: responding to %s", rq->from->conf->host);
- sendreply(rq);
- } else
- debug(DBG_ERR, "respondstatusserver: malloc failed");
-}
-
-void respondreject(struct request *rq, char *message) {
+void respond(struct request *rq, uint8_t code, char *message) {
struct radmsg *msg;
struct tlv *attr;
- msg = radmsg_init(RAD_Access_Reject, rq->msg->id, rq->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;
}
}
radmsg_free(rq->msg);
rq->msg = msg;
- debug(DBG_DBG, "respondreject: responding to %s", rq->from->conf->host);
+ debug(DBG_DBG, "respond: sending %s to %s", radmsgtype2string(msg->code), rq->from->conf->host);
+ rq->refcount++;
sendreply(rq);
}
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 (now.tv_sec - r->created.tv_sec < r->from->conf->dupinterval) {
-#if 0
- later
- if (r->replybuf) {
- debug(DBG_INFO, "radsrv: already sent reply to request with id %d from %s, resending", id, r->from->conf->host);
- r->refcount++;
- sendreply(r);
- } else
-#endif
- debug(DBG_INFO, "radsrv: already got request with id %d from %s, ignoring", id, r->from->conf->host);
- 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 */
struct radmsg *msg = NULL;
struct tlv *attr;
uint8_t *userascii = NULL;
- unsigned char newauth[16];
struct realm *realm = NULL;
struct server *to = NULL;
struct client *from = rq->from;
}
rq->msg = msg;
+ rq->rqid = msg->id;
+ memcpy(rq->rqauth, msg->auth, 16);
+
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");
goto exit;
}
- if (!addclientrq(rq, msg->id))
+ if (!addclientrq(rq))
goto exit;
if (msg->code == RAD_Status_Server) {
- respondstatusserver(rq);
+ respond(rq, RAD_Access_Accept, NULL);
goto exit;
}
if (!attr) {
if (msg->code == RAD_Accounting_Request) {
acclog(msg, from->conf->host);
- respondaccounting(rq);
+ respond(rq, RAD_Accounting_Response, NULL);
} else
debug(DBG_WARN, "radsrv: ignoring access request, no username attribute");
goto exit;
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(rq, realm->message);
+ respond(rq, RAD_Access_Reject, realm->message);
} else if (realm->accresp && msg->code == RAD_Accounting_Request) {
acclog(msg, from->conf->host);
- respondaccounting(rq);
+ respond(rq, RAD_Accounting_Response, NULL);
}
goto exit;
}
goto exit;
}
- if (msg->code != RAD_Accounting_Request) {
- if (!RAND_bytes(newauth, 16)) {
- debug(DBG_WARN, "radsrv: failed to generate random auth");
- goto rmclrqexit;
- }
+ 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))
+ 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))
+ if (!pwdrecrypt(attr->v, attr->l, from->conf->secret, to->conf->secret, rq->rqauth, msg->auth))
goto rmclrqexit;
}
- rq->origid = msg->id;
- memcpy(rq->origauth, msg->auth, 16);
- memcpy(msg->auth, newauth, 16);
-
if (to->conf->rewriteout && !dorewrite(msg, to->conf->rewriteout))
goto rmclrqexit;
rmclrqexit:
rmclientrq(rq, msg->id);
exit:
- free(rq);
+ freerq(rq);
free(userascii);
return 1;
}
struct rqout *rqout;
int sublen;
unsigned char *subattrs;
- uint8_t *username, *stationid;
+ uint8_t *username, *stationid, *replymsg;
struct radmsg *msg = NULL;
struct tlv *attr;
struct list_node *node;
username = radattr2ascii(radmsg_gettype(rqout->rq->msg, RAD_Attr_User_Name));
if (username) {
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);
/* 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;
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);