X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=radsecproxy.c;h=b7b206349b7e8d8053178d1c34ccb7c7cdedfe8c;hb=refs%2Fheads%2Fmaint-1.6;hp=d8500c16461bdf3fbcb6a9646c7c8a6f34d009ca;hpb=8b7224cfaf6961c48c018e6cfc500d577c8caaac;p=libradsec.git diff --git a/radsecproxy.c b/radsecproxy.c index d8500c1..b7b2063 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -52,6 +52,9 @@ #include #include #include +#if defined(HAVE_MALLOPT) +#include +#endif #ifdef SYS_SOLARIS9 #include #endif @@ -327,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); @@ -768,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; } @@ -1274,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; @@ -1292,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; @@ -1377,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; @@ -1440,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; } @@ -1463,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; @@ -1489,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; } @@ -1758,22 +1796,27 @@ void *clientwr(void *arg) { conf = server->conf; -#define ZZZ 60 +#define ZZZ 900 if (server->dynamiclookuparg && !dynamicconfig(server)) { dynconffail = 1; server->dynstartup = 0; server->dynfailing = 1; - debug(DBG_WARN, "%s: dynamicconfig(%s) failed, sleeping %ds", - __func__, server->conf->name, ZZZ); +#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 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->pdef->socktype)) { + if (!resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) { debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ); sleep(ZZZ); goto errexit; @@ -1798,7 +1841,10 @@ void *clientwr(void *arg) { 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; } @@ -1907,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); @@ -1926,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) { @@ -1954,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); } @@ -2201,12 +2250,29 @@ struct list *createsubrealmservers(struct realm *realm, struct list *srvconfs) { srvconf->servers->dynstartup = 1; debug(DBG_DBG, "%s: new client writer for %s", __func__, srvconf->servers->conf->name); - if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) { +#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; } @@ -2407,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'; @@ -2586,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) { @@ -2684,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); @@ -2701,6 +2790,8 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char 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, @@ -2752,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); @@ -2782,7 +2879,7 @@ 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)) + !resolvehostports(conf->hostports, conf->hostaf, conf->pdef->socktype)) debugx(1, DBG_ERR, "%s: resolve failed, exiting", __func__); if (!conf->secret) { @@ -2844,7 +2941,9 @@ int compileserverconfig(struct clsrvconf *conf, const char *block) { return 0; } - if (!conf->dynamiclookupcommand && !resolvehostports(conf->hostports, conf->pdef->socktype)) { + if (!conf->dynamiclookupcommand && + !resolvehostports(conf->hostports, conf->hostaf, + conf->pdef->socktype)) { debug(DBG_ERR, "%s: resolve failed", __func__); return 0; } @@ -2855,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); @@ -2875,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) @@ -2922,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) @@ -3123,6 +3231,8 @@ void getmainconfig(const char *configfile) { "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"); @@ -3262,6 +3372,15 @@ int radsecproxy_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); @@ -3313,7 +3432,7 @@ int radsecproxy_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; @@ -3321,7 +3440,7 @@ int radsecproxy_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"); }