X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=radsecproxy.c;h=b7b206349b7e8d8053178d1c34ccb7c7cdedfe8c;hb=refs%2Fheads%2Fmaint-1.6;hp=36ac6c417bbbec8c29c11594e83372e4103b880b;hpb=2232f96d22b5171c5f9569e2e0d3255e137d313b;p=libradsec.git diff --git a/radsecproxy.c b/radsecproxy.c index 36ac6c4..b7b2063 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2006-2009 Stig Venaas + * Copyright (C) 2010,2011,2012 NORDUnet A/S * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,6 +52,9 @@ #include #include #include +#if defined(HAVE_MALLOPT) +#include +#endif #ifdef SYS_SOLARIS9 #include #endif @@ -63,12 +67,12 @@ #include #include #include +#include #include #include #include #include #include "debug.h" -#include "list.h" #include "hash.h" #include "util.h" #include "hostport.h" @@ -77,6 +81,9 @@ #include "tcp.h" #include "tls.h" #include "dtls.h" +#if defined(WANT_FTICKS) +#include "fticks.h" +#endif static struct options options; static struct list *clconfs, *srvconfs; @@ -323,8 +330,13 @@ void freeserver(struct server *server, uint8_t destroymutex) { if (server->rbios) freebios(server->rbios); free(server->dynamiclookuparg); - if (server->ssl) - SSL_free(server->ssl); + if (server->ssl) { +#if defined ENABLE_EXPERIMENTAL_DYNDISC + if (server->sock >= 0) + close(server->sock); +#endif + SSL_free(server->ssl); + } if (destroymutex) { pthread_mutex_destroy(&server->lock); pthread_cond_destroy(&server->newrq_cond); @@ -764,7 +776,12 @@ int hasdynamicserver(struct list *srvconfs) { struct list_node *entry; for (entry = list_first(srvconfs); entry; entry = list_next(entry)) - if (((struct clsrvconf *)entry->data)->dynamiclookupcommand) +#if defined ENABLE_EXPERIMENTAL_DYNDISC + if (((struct clsrvconf *)entry->data)->dynamiclookupcommand + || ((struct clsrvconf *)entry->data)->servers->in_use) +#else + if (((struct clsrvconf *)entry->data)->dynamiclookupcommand) +#endif return 1; return 0; } @@ -1270,7 +1287,9 @@ void acclog(struct radmsg *msg, struct client *from) { } } -void respond(struct request *rq, uint8_t code, char *message) { +void respond(struct request *rq, uint8_t code, char *message, + int copy_proxystate_flag) +{ struct radmsg *msg; struct tlv *attr; @@ -1288,6 +1307,12 @@ void respond(struct request *rq, uint8_t code, char *message) { return; } } + if (copy_proxystate_flag) { + if (radmsg_copy_attrs(msg, rq->msg, RAD_Proxy_State) < 0) { + debug(DBG_ERR, "%s: unable to copy all Proxy-State attributes", + __func__); + } + } radmsg_free(rq->msg); rq->msg = msg; @@ -1303,6 +1328,8 @@ struct clsrvconf *choosesrvconf(struct list *srvconfs) { server = (struct clsrvconf *)entry->data; if (!server->servers) return server; + if (server->servers->dynfailing) + continue; if (!first) first = server; if (!server->servers->connectionok && !server->servers->dynstartup) @@ -1341,11 +1368,15 @@ struct server *findserver(struct realm **realm, struct tlv *username, uint8_t ac pthread_mutex_unlock(&(*realm)->mutex); freerealm(*realm); *realm = subrealm; + debug(DBG_DBG, "added realm: %s", (*realm)->name); srvconf = choosesrvconf(acc ? (*realm)->accsrvconfs : (*realm)->srvconfs); + debug(DBG_DBG, "found conf for new realm: %s", srvconf->name); } } - if (srvconf) + if (srvconf) { + debug(DBG_DBG, "found matching conf: %s", srvconf->name); server = srvconf->servers; + } exit: free(id); @@ -1367,6 +1398,22 @@ struct request *newrequest() { return rq; } +static void +purgedupcache(struct client *client) { + struct request *r; + struct timeval now; + int i; + + gettimeofday(&now, NULL); + for (i = 0; i < MAX_REQUESTS; i++) { + r = client->rqs[i]; + if (r && now.tv_sec - r->created.tv_sec > r->from->conf->dupinterval) { + freerq(r); + client->rqs[i] = NULL; + } + } +} + int addclientrq(struct request *rq) { struct request *r; struct timeval now; @@ -1430,11 +1477,12 @@ int radsrv(struct request *rq) { goto exit; } + purgedupcache(from); if (!addclientrq(rq)) goto exit; if (msg->code == RAD_Status_Server) { - respond(rq, RAD_Access_Accept, NULL); + respond(rq, RAD_Access_Accept, NULL, 0); goto exit; } @@ -1453,7 +1501,7 @@ int radsrv(struct request *rq) { if (!attr) { if (msg->code == RAD_Accounting_Request) { acclog(msg, from); - respond(rq, RAD_Accounting_Response, NULL); + respond(rq, RAD_Accounting_Response, NULL, 1); } else debug(DBG_INFO, "radsrv: ignoring access request, no username attribute"); goto exit; @@ -1479,10 +1527,10 @@ int radsrv(struct request *rq) { if (!to) { if (realm->message && msg->code == RAD_Access_Request) { debug(DBG_INFO, "radsrv: sending reject to %s (%s) for %s", from->conf->name, addr2string(from->addr), userascii); - respond(rq, RAD_Access_Reject, realm->message); + respond(rq, RAD_Access_Reject, realm->message, 1); } else if (realm->accresp && msg->code == RAD_Accounting_Request) { acclog(msg, from); - respond(rq, RAD_Accounting_Response, NULL); + respond(rq, RAD_Accounting_Response, NULL, 1); } goto exit; } @@ -1634,26 +1682,42 @@ void replyh(struct server *server, unsigned char *buf) { replymsg = radattr2ascii(radmsg_gettype(msg, RAD_Attr_Reply_Message)); if (stationid) { if (replymsg) { - debug(DBG_WARN, "%s for user %s stationid %s from %s (%s) to %s (%s)", - radmsgtype2string(msg->code), username, stationid, server->conf->name, replymsg, from->conf->name, addr2string(from->addr)); + debug(DBG_NOTICE, + "%s for user %s stationid %s from %s (%s) to %s (%s)", + radmsgtype2string(msg->code), username, stationid, + server->conf->name, replymsg, from->conf->name, + addr2string(from->addr)); free(replymsg); } else - debug(DBG_WARN, "%s for user %s stationid %s from %s to %s (%s)", - radmsgtype2string(msg->code), username, stationid, server->conf->name, from->conf->name, addr2string(from->addr)); + debug(DBG_NOTICE, + "%s for user %s stationid %s from %s to %s (%s)", + radmsgtype2string(msg->code), username, stationid, + server->conf->name, from->conf->name, + addr2string(from->addr)); free(stationid); } else { if (replymsg) { - debug(DBG_WARN, "%s for user %s from %s (%s) to %s (%s)", - radmsgtype2string(msg->code), username, server->conf->name, replymsg, from->conf->name, addr2string(from->addr)); + debug(DBG_NOTICE, "%s for user %s from %s (%s) to %s (%s)", + radmsgtype2string(msg->code), username, + server->conf->name, replymsg, from->conf->name, + addr2string(from->addr)); free(replymsg); } else - debug(DBG_WARN, "%s for user %s from %s to %s (%s)", - radmsgtype2string(msg->code), username, server->conf->name, from->conf->name, addr2string(from->addr)); + debug(DBG_NOTICE, "%s for user %s from %s to %s (%s)", + radmsgtype2string(msg->code), username, + server->conf->name, from->conf->name, + addr2string(from->addr)); } free(username); } } +#if defined(WANT_FTICKS) + if (msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject) + if (options.fticks_reporting && from->conf->fticks_viscountry != NULL) + fticks_log(&options, from, msg, rqout); +#endif + msg->id = (char)rqout->rq->rqid; memcpy(msg->auth, rqout->rq->rqauth, 16); @@ -1732,18 +1796,30 @@ void *clientwr(void *arg) { conf = server->conf; +#define ZZZ 900 + if (server->dynamiclookuparg && !dynamicconfig(server)) { dynconffail = 1; server->dynstartup = 0; - sleep(900); + server->dynfailing = 1; +#if defined ENABLE_EXPERIMENTAL_DYNDISC + pthread_mutex_unlock(&server->lock); +#endif + debug(DBG_WARN, "%s: dynamicconfig(%s: %s) failed, sleeping %ds", + __func__, server->conf->name, server->dynamiclookuparg, ZZZ); + sleep(ZZZ); goto errexit; } - - if (!resolvehostports(conf->hostports, conf->pdef->socktype)) { - debug(DBG_WARN, "clientwr: resolve failed"); - server->dynstartup = 0; - sleep(900); - goto errexit; +#if defined ENABLE_EXPERIMENTAL_DYNDISC + pthread_mutex_unlock(&server->lock); +#endif + /* FIXME: Is resolving not always done by compileserverconfig(), + * either as part of static configuration setup or by + * dynamicconfig() above? */ + if (!resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) { + debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ); + sleep(ZZZ); + goto errexit; } memset(&timeout, 0, sizeof(struct timespec)); @@ -1756,13 +1832,19 @@ void *clientwr(void *arg) { if (conf->pdef->connecter) { if (!conf->pdef->connecter(server, NULL, server->dynamiclookuparg ? 5 : 0, "clientwr")) { if (server->dynamiclookuparg) { - server->dynstartup = 0; - sleep(900); + server->dynstartup = 0; + server->dynfailing = 1; + debug(DBG_WARN, "%s: connect failed, sleeping %ds", + __func__, ZZZ); + sleep(ZZZ); } goto errexit; } server->connectionok = 1; - if (pthread_create(&clientrdth, NULL, conf->pdef->clientconnreader, (void *)server)) { +#if defined ENABLE_EXPERIMENTAL_DYNDISC + server->in_use = 1; +#endif + if (pthread_create(&clientrdth, &pthread_attr, conf->pdef->clientconnreader, (void *)server)) { debugerrno(errno, DBG_ERR, "clientwr: pthread_create failed"); goto errexit; } @@ -1871,6 +1953,9 @@ void *clientwr(void *arg) { } } errexit: +#if defined ENABLE_EXPERIMENTAL_DYNDISC + server->in_use = 0; +#endif conf->servers = NULL; if (server->dynamiclookuparg) { removeserversubrealms(realms, conf); @@ -1890,7 +1975,7 @@ void createlistener(uint8_t type, char *arg) { int s = -1, on = 1, *sp = NULL; struct hostportres *hp = newhostport(arg, protodefs[type]->portdefault, 0); - if (!hp || !resolvehostport(hp, protodefs[type]->socktype, 1)) + if (!hp || !resolvehostport(hp, AF_UNSPEC, protodefs[type]->socktype, 1)) debugx(1, DBG_ERR, "createlistener: failed to resolve %s", arg); for (res = hp->addrinfo; res; res = res->ai_next) { @@ -1918,7 +2003,7 @@ void createlistener(uint8_t type, char *arg) { if (!sp) debugx(1, DBG_ERR, "malloc failed"); *sp = s; - if (pthread_create(&th, NULL, protodefs[type]->listener, (void *)sp)) + if (pthread_create(&th, &pthread_attr, protodefs[type]->listener, (void *)sp)) debugerrnox(errno, DBG_ERR, "pthread_create failed"); pthread_detach(th); } @@ -2154,16 +2239,40 @@ struct list *createsubrealmservers(struct realm *realm, struct list *srvconfs) { debug(DBG_ERR, "malloc failed"); continue; } + debug(DBG_DBG, "%s: copying config %s", __func__, conf->name); *srvconf = *conf; + /* Shallow copy -- sharing all the pointers. addserver() + * will take care of servers (which btw has to be NUL) but + * the rest of them are shared with the config found in + * the srvconfs list. */ if (addserver(srvconf)) { srvconf->servers->dynamiclookuparg = stringcopy(realm->name, 0); srvconf->servers->dynstartup = 1; - if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) { + debug(DBG_DBG, "%s: new client writer for %s", + __func__, srvconf->servers->conf->name); +#if defined ENABLE_EXPERIMENTAL_DYNDISC + pthread_mutex_lock(&srvconf->servers->lock); +#endif + if (pthread_create(&clientth, &pthread_attr, clientwr, (void *)(srvconf->servers))) { +#if defined ENABLE_EXPERIMENTAL_DYNDISC + pthread_mutex_unlock(&srvconf->servers->lock); +#endif debugerrno(errno, DBG_ERR, "pthread_create failed"); freeserver(srvconf->servers, 1); srvconf->servers = NULL; +#if defined ENABLE_EXPERIMENTAL_DYNDISC + conf = srvconf; + continue; +#endif } else pthread_detach(clientth); + +#if defined ENABLE_EXPERIMENTAL_DYNDISC + /* If clientwr() could not find a NAPTR we have to + * wait for dynfailing=1 what is set in clientwr(). */ + pthread_mutex_lock(&srvconf->servers->lock); + pthread_mutex_unlock(&srvconf->servers->lock); +#endif } conf = srvconf; } @@ -2244,10 +2353,8 @@ int dynamicconfig(struct server *server) { close(fd[1]); pushgconffile(&cf, fdopen(fd[0], "r"), conf->dynamiclookupcommand); - ok = getgenericconfig(&cf, NULL, - "Server", CONF_CBK, confserver_cb, (void *)conf, - NULL - ); + ok = getgenericconfig(&cf, NULL, "Server", CONF_CBK, confserver_cb, + (void *) conf, NULL); freegconf(&cf); if (waitpid(pid, &status, 0) < 0) { @@ -2256,8 +2363,9 @@ int dynamicconfig(struct server *server) { } if (status) { - debug(DBG_INFO, "dynamicconfig: command exited with status %d", WEXITSTATUS(status)); - goto errexit; + debug(DBG_INFO, "dynamicconfig: command exited with status %d", + WEXITSTATUS(status)); + goto errexit; } if (ok) @@ -2365,7 +2473,9 @@ struct modattr *extractmodattr(char *nameval) { if (s[strlen(s) - 1] == '/') s[strlen(s) - 1] = '\0'; - t = strchr(s, '/'); + for (t = strchr(s, '/'); t; t = strchr(t+1, '/')) + if (t == s || t[-1] != '\\') + break; if (!t) return NULL; *t = '\0'; @@ -2407,10 +2517,12 @@ struct modattr *extractmodattr(char *nameval) { struct rewrite *getrewrite(char *alt1, char *alt2) { struct rewrite *r; - if ((r = hash_read(rewriteconfs, alt1, strlen(alt1)))) - return r; - if ((r = hash_read(rewriteconfs, alt2, strlen(alt2)))) - return r; + if (alt1) + if ((r = hash_read(rewriteconfs, alt1, strlen(alt1)))) + return r; + if (alt2) + if ((r = hash_read(rewriteconfs, alt2, strlen(alt2)))) + return r; return NULL; } @@ -2519,6 +2631,9 @@ int setttlattr(struct options *opts, char *defaultattr) { } void freeclsrvconf(struct clsrvconf *conf) { + assert(conf); + assert(conf->name); + debug(DBG_DBG, "%s: freeing %p (%s)", __func__, conf, conf->name); free(conf->name); if (conf->hostsrc) freegconfmstr(conf->hostsrc); @@ -2539,8 +2654,8 @@ void freeclsrvconf(struct clsrvconf *conf) { free(conf->rewriteusername); } free(conf->dynamiclookupcommand); - free(conf->rewritein); - free(conf->rewriteout); + conf->rewritein=NULL; + conf->rewriteout=NULL; if (conf->hostports) freehostports(conf->hostports); if (conf->lock) { @@ -2621,7 +2736,10 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) { !mergeconfstring(&dst->matchcertattr, &src->matchcertattr) || !mergeconfstring(&dst->confrewritein, &src->confrewritein) || !mergeconfstring(&dst->confrewriteout, &src->confrewriteout) || - !mergeconfstring(&dst->dynamiclookupcommand, &src->dynamiclookupcommand)) + !mergeconfstring(&dst->confrewriteusername, &src->confrewriteusername) || + !mergeconfstring(&dst->dynamiclookupcommand, &src->dynamiclookupcommand) || + !mergeconfstring(&dst->fticks_viscountry, &src->fticks_viscountry) || + !mergeconfstring(&dst->fticks_visinst, &src->fticks_visinst)) return 0; if (src->pdef) dst->pdef = src->pdef; @@ -2634,10 +2752,31 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) { return 1; } +/** Set *AF according to IPV4ONLY and IPV6ONLY: + - If both are set, the function fails. + - If exactly one is set, *AF is set accordingly. + - If none is set, *AF is not affected. + Return 0 on success and !0 on failure. + In the case of an error, *AF is not affected. */ +int config_hostaf(const char *desc, int ipv4only, int ipv6only, int *af) { + assert(af != NULL); + if (ipv4only && ipv6only) { + debug(DBG_ERR, "error in block %s, at most one of IPv4Only and " + "IPv6Only can be enabled", desc); + return -1; + } + if (ipv4only) + *af = AF_INET; + if (ipv6only) + *af = AF_INET6; + return 0; +} + int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) { struct clsrvconf *conf; char *conftype = NULL, *rewriteinalias = NULL; long int dupinterval = LONG_MIN, addttl = LONG_MIN; + uint8_t ipv4only = 0, ipv6only = 0; debug(DBG_DBG, "confclient_cb called for %s", block); @@ -2647,22 +2786,29 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char memset(conf, 0, sizeof(struct clsrvconf)); conf->certnamecheck = 1; - if (!getgenericconfig(cf, block, - "type", CONF_STR, &conftype, - "host", CONF_MSTR, &conf->hostsrc, - "secret", CONF_STR, &conf->secret, + if (!getgenericconfig( + cf, block, + "type", CONF_STR, &conftype, + "host", CONF_MSTR, &conf->hostsrc, + "IPv4Only", CONF_BLN, &ipv4only, + "IPv6Only", CONF_BLN, &ipv6only, + "secret", CONF_STR, &conf->secret, #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) - "tls", CONF_STR, &conf->tls, - "matchcertificateattribute", CONF_STR, &conf->matchcertattr, - "CertificateNameCheck", CONF_BLN, &conf->certnamecheck, + "tls", CONF_STR, &conf->tls, + "matchcertificateattribute", CONF_STR, &conf->matchcertattr, + "CertificateNameCheck", CONF_BLN, &conf->certnamecheck, #endif - "DuplicateInterval", CONF_LINT, &dupinterval, - "addTTL", CONF_LINT, &addttl, - "rewrite", CONF_STR, &rewriteinalias, - "rewriteIn", CONF_STR, &conf->confrewritein, - "rewriteOut", CONF_STR, &conf->confrewriteout, - "rewriteattribute", CONF_STR, &conf->confrewriteusername, - NULL + "DuplicateInterval", CONF_LINT, &dupinterval, + "addTTL", CONF_LINT, &addttl, + "rewrite", CONF_STR, &rewriteinalias, + "rewriteIn", CONF_STR, &conf->confrewritein, + "rewriteOut", CONF_STR, &conf->confrewriteout, + "rewriteattribute", CONF_STR, &conf->confrewriteusername, +#if defined(WANT_FTICKS) + "fticksVISCOUNTRY", CONF_STR, &conf->fticks_viscountry, + "fticksVISINST", CONF_STR, &conf->fticks_visinst, +#endif + NULL )) debugx(1, DBG_ERR, "configuration error"); @@ -2687,7 +2833,9 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) if (conf->type == RAD_TLS || conf->type == RAD_DTLS) { - conf->tlsconf = conf->tls ? tlsgettls(conf->tls, NULL) : tlsgettls("defaultclient", "default"); + conf->tlsconf = conf->tls + ? tlsgettls(conf->tls, NULL) + : tlsgettls("defaultClient", "default"); if (!conf->tlsconf) debugx(1, DBG_ERR, "error in block %s, no tls context defined", block); if (conf->matchcertattr && !addmatchcertattr(conf)) @@ -2695,6 +2843,12 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char } #endif + conf->hostaf = AF_UNSPEC; + if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf)) + debugx(1, DBG_ERR, "config error: ^"); + if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf)) + debugx(1, DBG_ERR, "error in block %s: ^", block); + if (dupinterval != LONG_MIN) { if (dupinterval < 0 || dupinterval > 255) debugx(1, DBG_ERR, "error in block %s, value of option DuplicateInterval is %d, must be 0-255", block, dupinterval); @@ -2712,7 +2866,9 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char conf->confrewritein = rewriteinalias; else free(rewriteinalias); - conf->rewritein = conf->confrewritein ? getrewrite(conf->confrewritein, NULL) : getrewrite("defaultclient", "default"); + conf->rewritein = conf->confrewritein + ? getrewrite(conf->confrewritein, NULL) + : getrewrite("defaultClient", "default"); if (conf->confrewriteout) conf->rewriteout = getrewrite(conf->confrewriteout, NULL); @@ -2723,8 +2879,8 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char } if (!addhostport(&conf->hostports, conf->hostsrc, conf->pdef->portdefault, 1) || - !resolvehostports(conf->hostports, conf->pdef->socktype)) - debugx(1, DBG_ERR, "resolve failed, exiting"); + !resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) + debugx(1, DBG_ERR, "%s: resolve failed, exiting", __func__); if (!conf->secret) { if (!conf->pdef->secretdefault) @@ -2747,7 +2903,9 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char int compileserverconfig(struct clsrvconf *conf, const char *block) { #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) if (conf->type == RAD_TLS || conf->type == RAD_DTLS) { - conf->tlsconf = conf->tls ? tlsgettls(conf->tls, NULL) : tlsgettls("defaultserver", "default"); + conf->tlsconf = conf->tls + ? tlsgettls(conf->tls, NULL) + : tlsgettls("defaultServer", "default"); if (!conf->tlsconf) { debug(DBG_ERR, "error in block %s, no tls context defined", block); return 0; @@ -2772,17 +2930,21 @@ int compileserverconfig(struct clsrvconf *conf, const char *block) { if (conf->retrycount == 255) conf->retrycount = conf->pdef->retrycountdefault; - conf->rewritein = conf->confrewritein ? getrewrite(conf->confrewritein, NULL) : getrewrite("defaultserver", "default"); + conf->rewritein = conf->confrewritein + ? getrewrite(conf->confrewritein, NULL) + : getrewrite("defaultServer", "default"); if (conf->confrewriteout) conf->rewriteout = getrewrite(conf->confrewriteout, NULL); if (!addhostport(&conf->hostports, conf->hostsrc, conf->portsrc, 0)) { - debug(DBG_ERR, "error in block %s, failed to parse %s", block, conf->hostsrc); + debug(DBG_ERR, "error in block %s, failed to parse %s", block, *conf->hostsrc); return 0; } - if (!conf->dynamiclookupcommand && !resolvehostports(conf->hostports, conf->pdef->socktype)) { - debug(DBG_ERR, "resolve failed, exiting"); + if (!conf->dynamiclookupcommand && + !resolvehostports(conf->hostports, conf->hostaf, + conf->pdef->socktype)) { + debug(DBG_ERR, "%s: resolve failed", __func__); return 0; } return 1; @@ -2792,6 +2954,7 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char struct clsrvconf *conf, *resconf; char *conftype = NULL, *rewriteinalias = NULL; long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN; + uint8_t ipv4only = 0, ipv6only = 0; debug(DBG_DBG, "confserver_cb called for %s", block); @@ -2812,6 +2975,8 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char if (!getgenericconfig(cf, block, "type", CONF_STR, &conftype, "host", CONF_MSTR, &conf->hostsrc, + "IPv4Only", CONF_BLN, &ipv4only, + "IPv6Only", CONF_BLN, &ipv6only, "port", CONF_STR, &conf->portsrc, "secret", CONF_STR, &conf->secret, #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) @@ -2859,6 +3024,12 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char free(conftype); conftype = NULL; + conf->hostaf = AF_UNSPEC; + if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf)) + debugx(1, DBG_ERR, "config error: ^"); + if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf)) + goto errexit; + conf->pdef = protodefs[conf->type]; if (!conf->confrewritein) @@ -2906,7 +3077,8 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char if (resconf || !conf->dynamiclookupcommand) { if (!compileserverconfig(conf, block)) - goto errexit; + return 0; /* Don't goto errexit and free resconf -- it's + * not ours to free. */ } if (!conf->secret) { @@ -2994,6 +3166,11 @@ void getmainconfig(const char *configfile) { struct gconffile *cfs; char **listenargs[RAD_PROTOCOUNT]; char *sourcearg[RAD_PROTOCOUNT]; +#if defined(WANT_FTICKS) + uint8_t *fticks_reporting_str = NULL; + uint8_t *fticks_mac_str = NULL; + uint8_t *fticks_key_str = NULL; +#endif int i; cfs = openconfigfile(configfile); @@ -3017,42 +3194,52 @@ void getmainconfig(const char *configfile) { if (!rewriteconfs) debugx(1, DBG_ERR, "malloc failed"); - if (!getgenericconfig(&cfs, NULL, + if (!getgenericconfig( + &cfs, NULL, #ifdef RADPROT_UDP - "ListenUDP", CONF_MSTR, &listenargs[RAD_UDP], - "SourceUDP", CONF_STR, &sourcearg[RAD_UDP], + "ListenUDP", CONF_MSTR, &listenargs[RAD_UDP], + "SourceUDP", CONF_STR, &sourcearg[RAD_UDP], #endif #ifdef RADPROT_TCP - "ListenTCP", CONF_MSTR, &listenargs[RAD_TCP], - "SourceTCP", CONF_STR, &sourcearg[RAD_TCP], + "ListenTCP", CONF_MSTR, &listenargs[RAD_TCP], + "SourceTCP", CONF_STR, &sourcearg[RAD_TCP], #endif #ifdef RADPROT_TLS - "ListenTLS", CONF_MSTR, &listenargs[RAD_TLS], - "SourceTLS", CONF_STR, &sourcearg[RAD_TLS], + "ListenTLS", CONF_MSTR, &listenargs[RAD_TLS], + "SourceTLS", CONF_STR, &sourcearg[RAD_TLS], #endif #ifdef RADPROT_DTLS - "ListenDTLS", CONF_MSTR, &listenargs[RAD_DTLS], - "SourceDTLS", CONF_STR, &sourcearg[RAD_DTLS], + "ListenDTLS", CONF_MSTR, &listenargs[RAD_DTLS], + "SourceDTLS", CONF_STR, &sourcearg[RAD_DTLS], #endif - "TTLAttribute", CONF_STR, &options.ttlattr, - "addTTL", CONF_LINT, &addttl, - "LogLevel", CONF_LINT, &loglevel, - "LogDestination", CONF_STR, &options.logdestination, - "LoopPrevention", CONF_BLN, &options.loopprevention, - "Client", CONF_CBK, confclient_cb, NULL, - "Server", CONF_CBK, confserver_cb, NULL, - "Realm", CONF_CBK, confrealm_cb, NULL, + "PidFile", CONF_STR, &options.pidfile, + "TTLAttribute", CONF_STR, &options.ttlattr, + "addTTL", CONF_LINT, &addttl, + "LogLevel", CONF_LINT, &loglevel, + "LogDestination", CONF_STR, &options.logdestination, + "LoopPrevention", CONF_BLN, &options.loopprevention, + "Client", CONF_CBK, confclient_cb, NULL, + "Server", CONF_CBK, confserver_cb, NULL, + "Realm", CONF_CBK, confrealm_cb, NULL, #if defined(RADPROT_TLS) || defined(RADPROT_DTLS) - "TLS", CONF_CBK, conftls_cb, NULL, + "TLS", CONF_CBK, conftls_cb, NULL, #endif - "Rewrite", CONF_CBK, confrewrite_cb, NULL, - NULL + "Rewrite", CONF_CBK, confrewrite_cb, NULL, +#if defined(WANT_FTICKS) + "FTicksReporting", CONF_STR, &fticks_reporting_str, + "FTicksMAC", CONF_STR, &fticks_mac_str, + "FTicksKey", CONF_STR, &fticks_key_str, + "FTicksSyslogFacility", CONF_STR, &options.ftickssyslogfacility, +#endif + "IPv4Only", CONF_BLN, &options.ipv4only, + "IPv6Only", CONF_BLN, &options.ipv6only, + NULL )) debugx(1, DBG_ERR, "configuration error"); if (loglevel != LONG_MIN) { - if (loglevel < 1 || loglevel > 4) - debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %d, must be 1, 2, 3 or 4", configfile, loglevel); + if (loglevel < 1 || loglevel > 5) + debugx(1, DBG_ERR, "error in %s, value of option LogLevel is %d, must be 1, 2, 3, 4 or 5", configfile, loglevel); options.loglevel = (uint8_t)loglevel; } if (addttl != LONG_MIN) { @@ -3063,6 +3250,11 @@ void getmainconfig(const char *configfile) { if (!setttlattr(&options, DEFAULT_TTL_ATTR)) debugx(1, DBG_ERR, "Failed to set TTLAttribute, exiting"); +#if defined(WANT_FTICKS) + fticks_configure(&options, &fticks_reporting_str, &fticks_mac_str, + &fticks_key_str); +#endif + for (i = 0; i < RAD_PROTOCOUNT; i++) if (listenargs[i] || sourcearg[i]) setprotoopts(i, listenargs[i], sourcearg[i]); @@ -3077,8 +3269,8 @@ void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *pretend, uint8 *configfile = optarg; break; case 'd': - if (strlen(optarg) != 1 || *optarg < '1' || *optarg > '4') - debugx(1, DBG_ERR, "Debug level must be 1, 2, 3 or 4, not %s", optarg); + if (strlen(optarg) != 1 || *optarg < '1' || *optarg > '5') + debugx(1, DBG_ERR, "Debug level must be 1, 2, 3, 4 or 5, not %s", optarg); *loglevel = *optarg - '0'; break; case 'f': @@ -3161,14 +3353,14 @@ void *sighandler(void *arg) { } int createpidfile(const char *pidfile) { - int r; + int r = 0; FILE *f = fopen(pidfile, "w"); if (f) r = fprintf(f, "%ld\n", (long) getpid()); return f && !fclose(f) && r >= 0; } -int main(int argc, char **argv) { +int radsecproxy_main(int argc, char **argv) { pthread_t sigth; sigset_t sigset; struct list_node *entry; @@ -3180,6 +3372,15 @@ int main(int argc, char **argv) { debug_init("radsecproxy"); debug_set_level(DEBUG_LEVEL); + if (pthread_attr_init(&pthread_attr)) + debugx(1, DBG_ERR, "pthread_attr_init failed"); + if (pthread_attr_setstacksize(&pthread_attr, PTHREAD_STACK_SIZE)) + debugx(1, DBG_ERR, "pthread_attr_setstacksize failed"); +#if defined(HAVE_MALLOPT) + if (mallopt(M_TRIM_THRESHOLD, 4 * 1024) != 1) + debugx(1, DBG_ERR, "mallopt failed"); +#endif + for (i = 0; i < RAD_PROTOCOUNT; i++) protodefs[i] = protoinits[i](i); @@ -3194,8 +3395,18 @@ int main(int argc, char **argv) { options.loglevel = loglevel; else if (options.loglevel) debug_set_level(options.loglevel); - if (!foreground) - debug_set_destination(options.logdestination ? options.logdestination : "x-syslog:///"); + if (!foreground) { + debug_set_destination(options.logdestination + ? options.logdestination + : "x-syslog:///", LOG_TYPE_DEBUG); +#if defined(WANT_FTICKS) + if (options.ftickssyslogfacility) { + debug_set_destination(options.ftickssyslogfacility, + LOG_TYPE_FTICKS); + free(options.ftickssyslogfacility); + } +#endif + } free(options.logdestination); if (!list_first(clconfs)) @@ -3211,6 +3422,8 @@ int main(int argc, char **argv) { debug_timestamp_on(); debug(DBG_INFO, "radsecproxy revision %s starting", PACKAGE_VERSION); + if (!pidfile) + pidfile = options.pidfile; if (pidfile && !createpidfile(pidfile)) debugx(1, DBG_ERR, "failed to create pidfile %s: %s", pidfile, strerror(errno)); @@ -3219,7 +3432,7 @@ int main(int argc, char **argv) { sigaddset(&sigset, SIGHUP); sigaddset(&sigset, SIGPIPE); pthread_sigmask(SIG_BLOCK, &sigset, NULL); - pthread_create(&sigth, NULL, sighandler, NULL); + pthread_create(&sigth, &pthread_attr, sighandler, NULL); for (entry = list_first(srvconfs); entry; entry = list_next(entry)) { srvconf = (struct clsrvconf *)entry->data; @@ -3227,7 +3440,7 @@ int main(int argc, char **argv) { continue; if (!addserver(srvconf)) debugx(1, DBG_ERR, "failed to add server"); - if (pthread_create(&srvconf->servers->clientth, NULL, clientwr, + if (pthread_create(&srvconf->servers->clientth, &pthread_attr, clientwr, (void *)(srvconf->servers))) debugx(1, DBG_ERR, "pthread_create failed"); }