From b1cf2a9afe47bfd3872ccaf88b1470080fd84633 Mon Sep 17 00:00:00 2001 From: venaas Date: Tue, 22 May 2007 13:57:25 +0000 Subject: added sending of statusserver and some missing free and unlock in some error cases git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@95 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- radsecproxy.c | 129 ++++++++++++++++++++++++++++++++++++++++------------------ radsecproxy.h | 2 +- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/radsecproxy.c b/radsecproxy.c index 02cf142..a3d8ff5 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -684,7 +684,7 @@ unsigned char *attrget(unsigned char *attrs, int length, uint8_t type) { void sendrq(struct server *to, struct client *from, struct request *rq) { int i; uint8_t *attr; - + pthread_mutex_lock(&to->newrq_mutex); /* might simplify if only try nextid, might be ok */ for (i = to->nextid; i < MAX_REQUESTS; i++) @@ -696,20 +696,24 @@ void sendrq(struct server *to, struct client *from, struct request *rq) { break; if (i == to->nextid) { debug(DBG_WARN, "No room in queue, dropping request"); + free(rq->buf); pthread_mutex_unlock(&to->newrq_mutex); return; } } - to->nextid = i + 1; rq->buf[1] = (char)i; - debug(DBG_DBG, "sendrq: inserting packet with id %d in queue for %s", i, to->peer.host); attr = attrget(rq->buf + 20, RADLEN(rq->buf) - 20, RAD_Attr_Message_Authenticator); - if (attr && !createmessageauth(rq->buf, ATTRVAL(attr), to->peer.secret)) + if (attr && !createmessageauth(rq->buf, ATTRVAL(attr), to->peer.secret)) { + free(rq->buf); + pthread_mutex_unlock(&to->newrq_mutex); return; + } + debug(DBG_DBG, "sendrq: inserting packet with id %d in queue for %s", i, to->peer.host); to->requests[i] = *rq; + to->nextid = i + 1; if (!to->newrq) { to->newrq = 1; @@ -726,6 +730,7 @@ void sendreply(struct client *to, struct server *from, unsigned char *buf, struc if (replyq->count == replyq->size) { debug(DBG_WARN, "No room in queue, dropping request"); pthread_mutex_unlock(&replyq->count_mutex); + free(buf); return; } @@ -1159,14 +1164,13 @@ struct server *radsrv(struct request *rq, unsigned char *buf, struct client *fro return NULL; } - if (!RAND_bytes(newauth, 16)) { - debug(DBG_WARN, "radsrv: failed to generate random auth"); - return NULL; - } + if (!RAND_bytes(newauth, 16)) { + debug(DBG_WARN, "radsrv: failed to generate random auth"); + return NULL; + } #ifdef DEBUG printauth("auth", auth); - printauth("newauth", newauth); #endif attr = attrget(attrs, len, RAD_Attr_User_Password); @@ -1188,10 +1192,6 @@ struct server *radsrv(struct request *rq, unsigned char *buf, struct client *fro rq->origid = id; memcpy(rq->origauth, auth, 16); memcpy(auth, newauth, 16); -#ifdef DEBUG - printauth("rq->origauth", (unsigned char *)rq->origauth); - printauth("auth", auth); -#endif return to; } @@ -1227,6 +1227,7 @@ void *clientrd(void *arg) { debug(DBG_DBG, "got Access Challenge with id %d", i); break; default: + free(buf); debug(DBG_INFO, "clientrd: discarding, only accept access accept, access reject and access challenge messages"); continue; } @@ -1234,18 +1235,21 @@ void *clientrd(void *arg) { pthread_mutex_lock(&server->newrq_mutex); if (!server->requests[i].buf || !server->requests[i].tries) { pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_INFO, "clientrd: no matching request sent with this id, ignoring"); continue; } if (server->requests[i].received) { pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_INFO, "clientrd: already received, ignoring"); continue; } if (!validauth(buf, server->requests[i].buf + 4, (unsigned char *)server->peer.secret)) { pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_WARN, "clientrd: invalid auth, ignoring"); continue; } @@ -1255,6 +1259,8 @@ void *clientrd(void *arg) { attrs = buf + 20; if (!attrvalidate(attrs, len)) { + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_WARN, "clientrd: attribute validation failed, ignoring packet"); continue; } @@ -1263,18 +1269,30 @@ void *clientrd(void *arg) { messageauth = attrget(attrs, len, RAD_Attr_Message_Authenticator); if (messageauth) { if (ATTRVALLEN(messageauth) != 16) { + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_WARN, "clientrd: illegal message auth attribute length, ignoring packet"); continue; } memcpy(tmp, buf + 4, 16); memcpy(buf + 4, server->requests[i].buf + 4, 16); if (!checkmessageauth(buf, ATTRVAL(messageauth), server->peer.secret)) { + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_WARN, "clientrd: message authentication failed"); continue; } memcpy(buf + 4, tmp, 16); debug(DBG_DBG, "clientrd: message auth ok"); } + + if (*server->requests[i].buf == RAD_Status_Server) { + server->requests[i].received = 1; + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); + debug(DBG_INFO, "clientrd: got status server response"); + continue; + } /* MS MPPE */ for (attr = attrs; (attr = attrget(attr, len - (attr - attrs), RAD_Attr_Vendor_Specific)); attr += ATTRLEN(attr)) { @@ -1294,6 +1312,8 @@ void *clientrd(void *arg) { break; } if (attr) { + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); debug(DBG_WARN, "clientrd: MS attribute handling failed, ignoring packet"); continue; } @@ -1321,8 +1341,11 @@ void *clientrd(void *arg) { #endif if (messageauth) { - if (!createmessageauth(buf, ATTRVAL(messageauth), from->peer.secret)) + if (!createmessageauth(buf, ATTRVAL(messageauth), from->peer.secret)) { + pthread_mutex_unlock(&server->newrq_mutex); + free(buf); continue; + } debug(DBG_DBG, "clientrd: computed messageauthattr"); } @@ -1332,6 +1355,7 @@ void *clientrd(void *arg) { pthread_mutex_unlock(&server->newrq_mutex); if (!radsign(buf, (unsigned char *)from->peer.secret)) { + free(buf); debug(DBG_WARN, "clientrd: failed to sign message"); continue; } @@ -1351,10 +1375,22 @@ void *clientwr(void *arg) { uint8_t rnd; struct timeval now, lastsend; struct timespec timeout; + struct request statsrvrq; + unsigned char statsrvbuf[38]; - memset(&lastsend, 0, sizeof(struct timeval)); memset(&timeout, 0, sizeof(struct timespec)); - + + if (server->statusserver) { + memset(&statsrvrq, 0, sizeof(struct request)); + statsrvrq.buf = statsrvbuf; + memset(&statsrvbuf, 0, sizeof(statsrvbuf)); + statsrvbuf[0] = RAD_Status_Server; + statsrvbuf[3] = 38; + statsrvbuf[20] = RAD_Attr_Message_Authenticator; + statsrvbuf[21] = 18; + gettimeofday(&lastsend, NULL); + } + if (server->peer.type == 'U') { if ((server->sock = connecttoserver(server->peer.addrinfo)) < 0) debugx(1, DBG_ERR, "clientwr: connecttoserver failed"); @@ -1368,17 +1404,17 @@ void *clientwr(void *arg) { pthread_mutex_lock(&server->newrq_mutex); if (!server->newrq) { gettimeofday(&now, NULL); + if (server->statusserver) { + /* random 0-7 seconds */ + RAND_bytes(&rnd, 1); + rnd /= 32; + if (!timeout.tv_sec || timeout.tv_sec - now.tv_sec > lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd) + timeout.tv_sec = lastsend.tv_sec + STATUS_SERVER_PERIOD + rnd; + } if (timeout.tv_sec) { debug(DBG_DBG, "clientwr: waiting up to %ld secs for new request", timeout.tv_sec - now.tv_sec); pthread_cond_timedwait(&server->newrq_cond, &server->newrq_mutex, &timeout); timeout.tv_sec = 0; - } else if (options.statusserver) { - timeout.tv_sec = now.tv_sec + STATUS_SERVER_PERIOD; - /* add random 0-7 seconds to timeout */ - RAND_bytes(&rnd, 1); - timeout.tv_sec += rnd / 32; - pthread_cond_timedwait(&server->newrq_cond, &server->newrq_mutex, &timeout); - timeout.tv_sec = 0; } else { debug(DBG_DBG, "clientwr: waiting for new request"); pthread_cond_wait(&server->newrq_cond, &server->newrq_mutex); @@ -1403,7 +1439,8 @@ void *clientwr(void *arg) { if (rq->received) { debug(DBG_DBG, "clientwr: removing received packet from queue"); - free(rq->buf); + if (*rq->buf != RAD_Status_Server) + free(rq->buf); /* setting this to NULL means that it can be reused */ rq->buf = NULL; pthread_mutex_unlock(&server->newrq_mutex); @@ -1418,9 +1455,13 @@ void *clientwr(void *arg) { continue; } - if (rq->tries == (server->peer.type == 'T' ? 1 : REQUEST_RETRIES)) { + if (rq->tries == (*rq->buf == RAD_Status_Server || server->peer.type == 'T' + ? 1 : REQUEST_RETRIES)) { debug(DBG_DBG, "clientwr: removing expired packet from queue"); - free(rq->buf); + if (*rq->buf == RAD_Status_Server) + debug(DBG_WARN, "clientwr: no status server response, server dead?"); + else + free(rq->buf); /* setting this to NULL means that it can be reused */ rq->buf = NULL; pthread_mutex_unlock(&server->newrq_mutex); @@ -1429,7 +1470,8 @@ void *clientwr(void *arg) { pthread_mutex_unlock(&server->newrq_mutex); rq->expiry.tv_sec = now.tv_sec + - (server->peer.type == 'T' ? REQUEST_EXPIRY : REQUEST_EXPIRY / REQUEST_RETRIES); + (*rq->buf == RAD_Status_Server || server->peer.type == 'T' + ? REQUEST_EXPIRY : REQUEST_EXPIRY / REQUEST_RETRIES); if (!timeout.tv_sec || rq->expiry.tv_sec < timeout.tv_sec) timeout.tv_sec = rq->expiry.tv_sec; rq->tries++; @@ -1437,11 +1479,16 @@ void *clientwr(void *arg) { gettimeofday(&lastsend, NULL); usleep(200000); } - if (options.statusserver) { + if (server->statusserver) { gettimeofday(&now, NULL); if (now.tv_sec - lastsend.tv_sec >= STATUS_SERVER_PERIOD) { + if (!RAND_bytes(statsrvbuf + 4, 16)) { + debug(DBG_WARN, "clientwr: failed to generate random auth"); + continue; + } + debug(DBG_DBG, "clientwr: sending status server to %s", server->peer.host); lastsend.tv_sec = now.tv_sec; - debug(DBG_DBG, "clientwr: should send status to %s here", server->peer.host); + sendrq(server, NULL, &statsrvrq); } } } @@ -1494,6 +1541,7 @@ void *udpserverrd(void *arg) { buf = radudpget(udp_server_sock, &fr, NULL, &rq.fromsa); to = radsrv(&rq, buf, fr); if (!to) { + free(buf); debug(DBG_INFO, "udpserverrd: ignoring request, no place to send it"); continue; } @@ -1572,6 +1620,7 @@ void *tlsserverrd(void *arg) { memset(&rq, 0, sizeof(struct request)); to = radsrv(&rq, buf, client); if (!to) { + free(buf); debug(DBG_INFO, "tlsserverrd: ignoring request, no place to send it"); continue; } @@ -2037,12 +2086,12 @@ void getgeneralconfig(FILE *f, char *block, ...) { } void confclsrv_cb(FILE *f, char *opt, char *val) { - char *type = NULL, *secret = NULL, *port = NULL; + char *type = NULL, *secret = NULL, *port = NULL, *statusserver = NULL; char *block; struct client *client = NULL; struct server *server = NULL; struct peer *peer; - + block = malloc(strlen(opt) + strlen(val) + 2); if (!block) debugx(1, DBG_ERR, "malloc failed"); @@ -2067,6 +2116,7 @@ void confclsrv_cb(FILE *f, char *opt, char *val) { "type", CONF_STR, &type, "secret", CONF_STR, &secret, "port", CONF_STR, &port, + "StatusServer", CONF_STR, &statusserver, NULL ); server_count++; @@ -2077,6 +2127,13 @@ void confclsrv_cb(FILE *f, char *opt, char *val) { memset(server, 0, sizeof(struct server)); peer = &server->peer; peer->port = port; + if (statusserver) { + if (!strcasecmp(statusserver, "on")) + server->statusserver = 1; + else if (strcasecmp(statusserver, "off")) + debugx(1, DBG_ERR, "error in block %s, StatusServer is %s, must be on or off", block, statusserver); + free(statusserver); + } } peer->host = stringcopy(val, 0); @@ -2167,7 +2224,7 @@ void confrealm_cb(FILE *f, char *opt, char *val) { void getmainconfig(const char *configfile) { FILE *f; - char *statusserver = NULL, *loglevel = NULL; + char *loglevel = NULL; f = openconfigfile(configfile); memset(&options, 0, sizeof(options)); @@ -2180,7 +2237,6 @@ void getmainconfig(const char *configfile) { "TLSCertificateKeyPassword", CONF_STR, &options.tlscertificatekeypassword, "ListenUDP", CONF_STR, &options.listenudp, "ListenTCP", CONF_STR, &options.listentcp, - "StatusServer", CONF_STR, &statusserver, "LogLevel", CONF_STR, &loglevel, "LogDestination", CONF_STR, &options.logdestination, "Client", CONF_CBK, confclsrv_cb, @@ -2190,13 +2246,6 @@ void getmainconfig(const char *configfile) { ); fclose(f); - if (statusserver) { - if (!strcasecmp(statusserver, "on")) - options.statusserver = 1; - else if (strcasecmp(statusserver, "off")) - debugx(1, DBG_ERR, "error in %s, value of option StatusServer is %s, must be on or off", configfile, statusserver); - free(statusserver); - } if (loglevel) { if (strlen(loglevel) != 1 || *loglevel < '1' || *loglevel > '4') debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %s, must be 1, 2, 3 or 4", configfile, loglevel); diff --git a/radsecproxy.h b/radsecproxy.h index 9b1747c..b4dcfe6 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -52,7 +52,6 @@ struct options { char *listentcp; char *logdestination; uint8_t loglevel; - uint8_t statusserver; }; /* requests that our client will send */ @@ -103,6 +102,7 @@ struct server { struct timeval lastconnecttry; uint8_t connectionok; int nextid; + uint8_t statusserver; struct request *requests; uint8_t newrq; pthread_mutex_t newrq_mutex; -- cgit v1.2.3