From e6793f425cac9a78f56f31cbe25f62c6b8fd350b Mon Sep 17 00:00:00 2001 From: venaas Date: Wed, 28 May 2008 14:08:34 +0000 Subject: rudimentary dynamic server support in place git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@262 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- radsecproxy.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++------- radsecproxy.h | 1 + 2 files changed, 129 insertions(+), 16 deletions(-) diff --git a/radsecproxy.c b/radsecproxy.c index 70985eb..5f18086 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -40,6 +40,7 @@ #endif #include #include +#include #include #include #include @@ -79,7 +80,8 @@ extern char *optarg; /* minimum required declarations to avoid reordering code */ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id); - +void dynamicconfig(struct server *server); + /* callbacks for making OpenSSL thread safe */ unsigned long ssl_thread_id() { return (unsigned long)pthread_self(); @@ -507,6 +509,7 @@ void freeserver(struct server *server, uint8_t destroymutex) { return; free(server->requests); + free(server->dynamiclookuparg); if (destroymutex) { pthread_mutex_destroy(&server->lock); pthread_cond_destroy(&server->newrq_cond); @@ -1809,6 +1812,8 @@ struct clsrvconf *choosesrvconf(struct list *srvconfs) { for (entry = list_first(srvconfs); entry; entry = list_next(entry)) { server = (struct clsrvconf *)entry->data; + if (!server->servers) + return server; if (!first) first = server; if (!server->servers->connectionok) @@ -2159,6 +2164,7 @@ void *tlsclientrd(void *arg) { } } +/* code for removing state not finished */ void *clientwr(void *arg) { struct server *server = (struct server *)arg; struct request *rq; @@ -2169,10 +2175,25 @@ void *clientwr(void *arg) { struct timespec timeout; struct request statsrvrq; unsigned char statsrvbuf[38]; + struct clsrvconf *conf; + + conf = server->conf; + + if (server->dynamiclookuparg) { + dynamicconfig(server); + conf = server->conf; + if (!conf) + goto errexit; + } + + if (!conf->addrinfo && !resolvepeer(conf, 0)) { + debug(DBG_WARN, "failed to resolve host %s port %s", conf->host ? conf->host : "(null)", conf->port ? conf->port : "(null)"); + goto errexit; + } memset(&timeout, 0, sizeof(struct timespec)); - if (server->conf->statusserver) { + if (conf->statusserver) { memset(&statsrvrq, 0, sizeof(struct request)); memset(statsrvbuf, 0, sizeof(statsrvbuf)); statsrvbuf[0] = RAD_Status_Server; @@ -2182,20 +2203,22 @@ void *clientwr(void *arg) { gettimeofday(&lastsend, NULL); } - if (server->conf->type == 'U') { + if (conf->type == 'U') { server->connectionok = 1; } else { tlsconnect(server, NULL, "new client"); server->connectionok = 1; - if (pthread_create(&tlsclientrdth, NULL, tlsclientrd, (void *)server)) - debugx(1, DBG_ERR, "clientwr: pthread_create failed"); + if (pthread_create(&tlsclientrdth, NULL, tlsclientrd, (void *)server)) { + debug(DBG_ERR, "clientwr: pthread_create failed"); + goto errexit; + } } for (;;) { pthread_mutex_lock(&server->newrq_mutex); if (!server->newrq) { gettimeofday(&now, NULL); - if (server->conf->statusserver) { + if (conf->statusserver) { /* random 0-7 seconds */ RAND_bytes(&rnd, 1); rnd /= 32; @@ -2252,7 +2275,7 @@ void *clientwr(void *arg) { ? 1 : REQUEST_RETRIES)) { debug(DBG_DBG, "clientwr: removing expired packet from queue"); if (*rq->buf == RAD_Status_Server) { - debug(DBG_WARN, "clientwr: no status server response, %s dead?", server->conf->host); + debug(DBG_WARN, "clientwr: no status server response, %s dead?", conf->host); if (server->loststatsrv < 255) server->loststatsrv++; } @@ -2265,7 +2288,7 @@ void *clientwr(void *arg) { pthread_mutex_unlock(&server->newrq_mutex); rq->expiry.tv_sec = now.tv_sec + - (*rq->buf == RAD_Status_Server || server->conf->type == 'T' + (*rq->buf == RAD_Status_Server || conf->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; @@ -2273,7 +2296,7 @@ void *clientwr(void *arg) { clientradput(server, server->requests[i].buf); gettimeofday(&lastsend, NULL); } - if (server->conf->statusserver) { + if (conf->statusserver) { gettimeofday(&now, NULL); if (now.tv_sec - lastsend.tv_sec >= STATUS_SERVER_PERIOD) { if (!RAND_bytes(statsrvbuf + 4, 16)) { @@ -2286,12 +2309,32 @@ void *clientwr(void *arg) { continue; } memcpy(statsrvrq.buf, statsrvbuf, sizeof(statsrvbuf)); - debug(DBG_DBG, "clientwr: sending status server to %s", server->conf->host); + debug(DBG_DBG, "clientwr: sending status server to %s", conf->host); lastsend.tv_sec = now.tv_sec; sendrq(server, &statsrvrq); } } } + errexit: + /* this code needs more work */ + if (server->dynamiclookuparg) { + /* remove subrealms using this server */ + /* need to free server->conf etc */ + if (conf) { + free(conf->host); + free(conf->name); + if (conf->addrinfo) { + freeaddrinfo(conf->addrinfo); + conf->addrinfo = NULL; + } + /* add this once realm removal in place + free(conf); + server->conf = NULL; + */ + } + } + freeserver(server, 1); + return NULL; } void *udpserverwr(void *arg) { @@ -2681,10 +2724,16 @@ void freerealm(struct realm *realm) { if (!realm) return; free(realm->name); - if (realm->srvconfs) + if (realm->srvconfs) { + /* emptying list without freeing data */ + while (list_shift(realm->srvconfs)); list_destroy(realm->srvconfs); - if (realm->accsrvconfs) + } + if (realm->accsrvconfs) { + /* emptying list without freeing data */ + while (list_shift(realm->accsrvconfs)); list_destroy(realm->accsrvconfs); + } free(realm); } @@ -2758,11 +2807,11 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char goto errexit; } - if (!pthread_mutex_init(&realm->subrealms_mutex, NULL)) { + if (pthread_mutex_init(&realm->subrealms_mutex, NULL)) { debug(DBG_ERR, "mutex init failed"); goto errexit; } - + if (!list_push(realmlist, realm)) { debug(DBG_ERR, "malloc failed"); pthread_mutex_destroy(&realm->subrealms_mutex); @@ -2820,6 +2869,10 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id if (!addserver(srvconf)) goto errexit; + if (!realm->subrealms) + realm->subrealms = list_create(); + if (!realm->subrealms) + goto errexit; newrealm = addrealm(realm->subrealms, realmname, NULL, NULL, NULL); if (!newrealm) goto errexit; @@ -2836,11 +2889,15 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id goto errexit; } + srvconf->servers->dynamiclookuparg = stringcopy(realmname, 0); + if (pthread_create(&srvconf->servers->clientth, NULL, clientwr, (void *)(srvconf->servers))) { debug(DBG_ERR, "pthread_create failed"); goto errexit; } + goto exit; + errexit: if (newrealm) { list_removedata(realm->subrealms, newrealm); @@ -2854,6 +2911,61 @@ void adddynamicrealmserver(struct realm *realm, struct clsrvconf *conf, char *id pthread_mutex_unlock(&realm->subrealms_mutex); } +void dynamicconfig(struct server *server) { + int n, fd[2]; + pid_t pid; + char *host, *s, line[1024]; + struct clsrvconf *conf = server->conf; + + /* for now we only learn hostname/address */ + debug(DBG_DBG, "dynamicconfig: need dynamic server config for %s", server->dynamiclookuparg); + + if (pipe(fd) > 0) { + debug(DBG_ERR, "dynamicconfig: pipe error"); + goto errexit; + } + pid = fork(); + if (pid < 0) { + debug(DBG_ERR, "dynamicconfig: fork error"); + goto errexit; + } else if (pid == 0) { + /* child */ + close(fd[0]); + if (fd[1] != STDOUT_FILENO) { + if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) + debugx(1, DBG_ERR, "dynamicconfig: dup2 error for command %s", conf->dynamiclookupcommand); + close(fd[1]); + } + if (execlp(conf->dynamiclookupcommand, conf->dynamiclookupcommand, server->dynamiclookuparg, NULL) < 0) + debugx(1, DBG_ERR, "dynamicconfig: exec error for command %s", conf->dynamiclookupcommand); + } + + close(fd[1]); + n = read(fd[0], line, 1024); + debug(DBG_DBG, "dynamicconfig: command output: %s", line); + close(fd[0]); + if (waitpid(pid, NULL, 0) < 0) { + debug(DBG_ERR, "dynamicconfig: wait error"); + goto errexit; + } + debug(DBG_DBG, "dynamicconfig: after exec"); + + for (s = line; *s && strchr(" \t\r\n", *s); s++); + for (host = s; *s && !strchr(" \t\r\n", *s); s++); + *s = '\0'; + if (!*host) { + debug(DBG_ERR, "dynamicconfig: invalid dynamic hostname/address"); + goto errexit; + } + conf->name = stringcopy(host, 0); + conf->host = stringcopy(host, 0); + return; + + errexit: + server->conf = NULL; + debug(DBG_WARN, "dynamicconfig: failed to obtain dynamic server config"); +} + int addmatchcertattr(struct clsrvconf *conf, char *matchcertattr) { char *v; regex_t **r; @@ -3426,10 +3538,10 @@ int main(int argc, char **argv) { } if (udp_client4_sock >= 0) if (pthread_create(&udpclient4rdth, NULL, udpclientrd, (void *)&udp_client4_sock)) - debugx(1, DBG_ERR, "clientwr: pthread_create failed"); + debugx(1, DBG_ERR, "pthread_create failed"); if (udp_client6_sock >= 0) if (pthread_create(&udpclient6rdth, NULL, udpclientrd, (void *)&udp_client6_sock)) - debugx(1, DBG_ERR, "clientwr: pthread_create failed"); + debugx(1, DBG_ERR, "pthread_create failed"); if (client_tls_count) return tlslistener(); diff --git a/radsecproxy.h b/radsecproxy.h index 9ad79d3..71b17bd 100644 --- a/radsecproxy.h +++ b/radsecproxy.h @@ -109,6 +109,7 @@ struct server { struct timeval lastconnecttry; uint8_t connectionok; uint8_t loststatsrv; + char *dynamiclookuparg; int nextid; struct request *requests; uint8_t newrq; -- cgit v1.2.3