X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=radsecproxy.c;h=5248c417bc68ca691ea9edc2d0ed7e695b79a3a1;hb=39e90a8cfdfe5bc95d2d01aa680e328c3476ff33;hp=c058ac745e8ed9252f342f1f07d52a2a875f67d6;hpb=bd55e739319266857e433d9715d4e5c370fcb562;p=libradsec.git diff --git a/radsecproxy.c b/radsecproxy.c index c058ac7..5248c41 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 @@ -62,12 +63,13 @@ #include #include #include +#include +#include #include #include #include #include #include "debug.h" -#include "list.h" #include "hash.h" #include "util.h" #include "hostport.h" @@ -76,6 +78,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; @@ -370,24 +375,24 @@ int addserver(struct clsrvconf *conf) { goto errexit; } if (pthread_mutex_init(conf->servers->requests[i].lock, NULL)) { - debug(DBG_ERR, "mutex init failed"); + debugerrno(errno, DBG_ERR, "mutex init failed"); free(conf->servers->requests[i].lock); conf->servers->requests[i].lock = NULL; goto errexit; } } if (pthread_mutex_init(&conf->servers->lock, NULL)) { - debug(DBG_ERR, "mutex init failed"); + debugerrno(errno, DBG_ERR, "mutex init failed"); goto errexit; } conf->servers->newrq = 0; if (pthread_mutex_init(&conf->servers->newrq_mutex, NULL)) { - debug(DBG_ERR, "mutex init failed"); + debugerrno(errno, DBG_ERR, "mutex init failed"); pthread_mutex_destroy(&conf->servers->lock); goto errexit; } if (pthread_cond_init(&conf->servers->newrq_cond, NULL)) { - debug(DBG_ERR, "mutex init failed"); + debugerrno(errno, DBG_ERR, "mutex init failed"); pthread_mutex_destroy(&conf->servers->newrq_mutex); pthread_mutex_destroy(&conf->servers->lock); goto errexit; @@ -559,43 +564,7 @@ void sendreply(struct request *rq) { pthread_mutex_unlock(&to->replyq->mutex); } -int pwdencrypt(uint8_t *in, uint8_t len, char *shared, uint8_t sharedlen, uint8_t *auth) { - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static unsigned char first = 1; - static EVP_MD_CTX mdctx; - unsigned char hash[EVP_MAX_MD_SIZE], *input; - unsigned int md_len; - uint8_t i, offset = 0, out[128]; - - pthread_mutex_lock(&lock); - if (first) { - EVP_MD_CTX_init(&mdctx); - first = 0; - } - - input = auth; - for (;;) { - if (!EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) || - !EVP_DigestUpdate(&mdctx, (uint8_t *)shared, sharedlen) || - !EVP_DigestUpdate(&mdctx, input, 16) || - !EVP_DigestFinal_ex(&mdctx, hash, &md_len) || - md_len != 16) { - pthread_mutex_unlock(&lock); - return 0; - } - for (i = 0; i < 16; i++) - out[offset + i] = hash[i] ^ in[offset + i]; - input = out + offset - 16; - offset += 16; - if (offset == len) - break; - } - memcpy(in, out, len); - pthread_mutex_unlock(&lock); - return 1; -} - -int pwddecrypt(uint8_t *in, uint8_t len, char *shared, uint8_t sharedlen, uint8_t *auth) { +int pwdcrypt(char encrypt_flag, uint8_t *in, uint8_t len, char *shared, uint8_t sharedlen, uint8_t *auth) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static unsigned char first = 1; static EVP_MD_CTX mdctx; @@ -621,7 +590,10 @@ int pwddecrypt(uint8_t *in, uint8_t len, char *shared, uint8_t sharedlen, uint8_ } for (i = 0; i < 16; i++) out[offset + i] = hash[i] ^ in[offset + i]; - input = in + offset; + if (encrypt_flag) + input = out + offset; + else + input = in + offset; offset += 16; if (offset == len) break; @@ -883,14 +855,14 @@ int pwdrecrypt(uint8_t *pwd, uint8_t len, char *oldsecret, char *newsecret, uint return 0; } - if (!pwddecrypt(pwd, len, oldsecret, strlen(oldsecret), oldauth)) { + if (!pwdcrypt(0, pwd, len, oldsecret, strlen(oldsecret), oldauth)) { debug(DBG_WARN, "pwdrecrypt: cannot decrypt password"); return 0; } #ifdef DEBUG printfchars(NULL, "pwdrecrypt: password", "%02x ", pwd, len); #endif - if (!pwdencrypt(pwd, len, newsecret, strlen(newsecret), newauth)) { + if (!pwdcrypt(1, pwd, len, newsecret, strlen(newsecret), newauth)) { debug(DBG_WARN, "pwdrecrypt: cannot encrypt password"); return 0; } @@ -1092,15 +1064,19 @@ int dorewritemod(struct radmsg *msg, struct list *modattrs) { } int dorewrite(struct radmsg *msg, struct rewrite *rewrite) { - if (!rewrite) - return 1; - if (rewrite->removeattrs || rewrite->removevendorattrs) - dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs); - if (rewrite->addattrs && !dorewriteadd(msg, rewrite->addattrs)) - return 0; - if (rewrite->modattrs && !dorewritemod(msg, rewrite->modattrs)) - return 0; - return 1; + int rv = 1; /* Success. */ + + if (rewrite) { + if (rewrite->removeattrs || rewrite->removevendorattrs) + dorewriterm(msg, rewrite->removeattrs, rewrite->removevendorattrs); + if (rewrite->modattrs) + if (!dorewritemod(msg, rewrite->modattrs)) + rv = 0; + if (rewrite->addattrs) + if (!dorewriteadd(msg, rewrite->addattrs)) + rv = 0; + } + return rv; } int rewriteusername(struct request *rq, struct tlv *attr) { @@ -1116,23 +1092,48 @@ int rewriteusername(struct request *rq, struct tlv *attr) { return 1; } -int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) { - struct tlv *vattr; +/** Create vendor specific tlv with ATTR. ATTR is consumed (freed) if + * all is well with the new tlv, i.e. if the function returns + * !NULL. */ +static struct tlv * +makevendortlv(uint32_t vendor, struct tlv *attr) +{ + struct tlv *newtlv = NULL; uint8_t l, *v; + if (!attr) + return NULL; l = attr->l + 6; v = malloc(l); if (v) { - vendor = htonl(vendor); + vendor = htonl(vendor & 0x00ffffff); /* MSB=0 according to RFC 2865. */ memcpy(v, &vendor, 4); tlv2buf(v + 4, attr); - v[5] += 2; - vattr = maketlv(RAD_Attr_Vendor_Specific, l, v); - if (vattr && radmsg_add(msg, vattr)) - return 1; + v[5] += 2; /* Vendor length increased for type and length fields. */ + newtlv = maketlv(RAD_Attr_Vendor_Specific, l, v); + if (newtlv == NULL) + free(v); + else + freetlv(attr); + } + return newtlv; +} + +/** Ad vendor attribute with VENDOR + ATTR and push it on MSG. ATTR + * is consumed. */ +int addvendorattr(struct radmsg *msg, uint32_t vendor, struct tlv *attr) { + struct tlv *vattr; + + vattr = makevendortlv(vendor, attr); + if (!vattr) { + freetlv(attr); + return 0; + } + if (!radmsg_add(msg, vattr)) { freetlv(vattr); + return 0; } - return 0; + return 1; } void addttlattr(struct radmsg *msg, uint32_t *attrtype, uint8_t addttl) { @@ -1148,10 +1149,8 @@ void addttlattr(struct radmsg *msg, uint32_t *attrtype, uint8_t addttl) { freetlv(attr); } else { attr = maketlv(attrtype[1], 4, ttl); - if (attr) { + if (attr) addvendorattr(msg, attrtype[0], attr); - freetlv(attr); - } } } @@ -1308,6 +1307,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) @@ -1346,11 +1347,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); @@ -1639,26 +1644,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); @@ -1737,18 +1758,25 @@ void *clientwr(void *arg) { conf = server->conf; +#define ZZZ 60 + if (server->dynamiclookuparg && !dynamicconfig(server)) { dynconffail = 1; server->dynstartup = 0; - sleep(900); + server->dynfailing = 1; + debug(DBG_WARN, "%s: dynamicconfig(%s) failed, sleeping %ds", + __func__, server->conf->name, ZZZ); + sleep(ZZZ); goto errexit; } + /* 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)) { - debug(DBG_WARN, "clientwr: resolve failed"); - server->dynstartup = 0; - sleep(900); - goto errexit; + debug(DBG_WARN, "%s: resolve failed, sleeping %ds", __func__, ZZZ); + sleep(ZZZ); + goto errexit; } memset(&timeout, 0, sizeof(struct timespec)); @@ -1761,14 +1789,17 @@ 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)) { - debug(DBG_ERR, "clientwr: pthread_create failed"); + debugerrno(errno, DBG_ERR, "clientwr: pthread_create failed"); goto errexit; } } else @@ -1901,7 +1932,7 @@ void createlistener(uint8_t type, char *arg) { for (res = hp->addrinfo; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { - debug(DBG_WARN, "createlistener: socket failed"); + debugerrno(errno, DBG_WARN, "createlistener: socket failed"); continue; } setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); @@ -1913,7 +1944,7 @@ void createlistener(uint8_t type, char *arg) { setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); #endif if (bind(s, res->ai_addr, res->ai_addrlen)) { - debug(DBG_WARN, "createlistener: bind failed"); + debugerrno(errno, DBG_WARN, "createlistener: bind failed"); close(s); s = -1; continue; @@ -1924,7 +1955,7 @@ void createlistener(uint8_t type, char *arg) { debugx(1, DBG_ERR, "malloc failed"); *sp = s; if (pthread_create(&th, NULL, protodefs[type]->listener, (void *)sp)) - debugx(1, DBG_ERR, "pthread_create failed"); + debugerrnox(errno, DBG_ERR, "pthread_create failed"); pthread_detach(th); } if (!sp) @@ -2073,7 +2104,7 @@ struct realm *addrealm(struct list *realmlist, char *value, char **servers, char memset(realm, 0, sizeof(struct realm)); if (pthread_mutex_init(&realm->mutex, NULL)) { - debug(DBG_ERR, "mutex init failed"); + debugerrno(errno, DBG_ERR, "mutex init failed"); free(realm); realm = NULL; goto exit; @@ -2159,12 +2190,19 @@ 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; + debug(DBG_DBG, "%s: new client writer for %s", + __func__, srvconf->servers->conf->name); if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) { - debug(DBG_ERR, "pthread_create failed"); + debugerrno(errno, DBG_ERR, "pthread_create failed"); freeserver(srvconf->servers, 1); srvconf->servers = NULL; } else @@ -2226,12 +2264,12 @@ int dynamicconfig(struct server *server) { debug(DBG_DBG, "dynamicconfig: need dynamic server config for %s", server->dynamiclookuparg); if (pipe(fd) > 0) { - debug(DBG_ERR, "dynamicconfig: pipe error"); + debugerrno(errno, DBG_ERR, "dynamicconfig: pipe error"); goto errexit; } pid = fork(); if (pid < 0) { - debug(DBG_ERR, "dynamicconfig: fork error"); + debugerrno(errno, DBG_ERR, "dynamicconfig: fork error"); close(fd[0]); close(fd[1]); goto errexit; @@ -2249,20 +2287,24 @@ 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) { - debug(DBG_ERR, "dynamicconfig: wait error"); + debugerrno(errno, DBG_ERR, "dynamicconfig: wait error"); goto errexit; } if (status) { - debug(DBG_INFO, "dynamicconfig: command exited with status %d", WEXITSTATUS(status)); - goto errexit; + if (WEXITSTATUS(status) == 10) { + debug(DBG_INFO, "dynamicconfig: command signals empty config"); + } + else { + debug(DBG_INFO, "dynamicconfig: command exited with status %d", + WEXITSTATUS(status)); + goto errexit; + } } if (ok) @@ -2281,13 +2323,18 @@ uint8_t attrname2val(char *attrname) { return val > 0 && val < 256 ? val : 0; } +/* ATTRNAME is on the form vendor[:type]. + If only vendor is found, TYPE is set to 256 and 1 is returned. + If type is >= 256, 1 is returned. + Otherwise, 0 is returned. +*/ /* should accept both names and numeric values, only numeric right now */ int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) { char *s; *vendor = atoi(attrname); s = strchr(attrname, ':'); - if (!s) { + if (!s) { /* Only vendor was found. */ *type = 256; return 1; } @@ -2295,22 +2342,42 @@ int vattrname2val(char *attrname, uint32_t *vendor, uint32_t *type) { return *type < 256; } -/* should accept both names and numeric values, only numeric right now */ -struct tlv *extractattr(char *nameval) { +/** Extract attributes from string NAMEVAL, create a struct tlv and + * return the tlv. If VENDOR_FLAG, NAMEVAL is on the form + * "::" and otherwise it's ":". Return + * NULL if fields are missing or if conversion fails. + * + * FIXME: Should accept both names and numeric values, only numeric + * right now */ +struct tlv *extractattr(char *nameval, char vendor_flag) { int len, name = 0; - char *s; + int vendor = 0; /* Vendor 0 is reserved, see RFC 1700. */ + char *s, *s2; struct tlv *a; s = strchr(nameval, ':'); - name = atoi(nameval); - if (!s || name < 1 || name > 255) + if (!s) return NULL; + name = atoi(nameval); + + if (vendor_flag) { + s2 = strchr(s + 1, ':'); + if (!s2) + return NULL; + vendor = name; + name = atoi(s + 1); + s = s2; + } len = strlen(s + 1); if (len > 253) return NULL; + + if (name < 1 || name > 255) + return NULL; a = malloc(sizeof(struct tlv)); if (!a) return NULL; + a->v = (uint8_t *)stringcopy(s + 1, 0); if (!a->v) { free(a); @@ -2318,6 +2385,10 @@ struct tlv *extractattr(char *nameval) { } a->t = name; a->l = len; + + if (vendor_flag) + a = makevendortlv(vendor, a); + return a; } @@ -2383,14 +2454,17 @@ 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; } -void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, char **modattrs) { +void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, char **addvattrs, char **modattrs) +{ struct rewrite *rewrite = NULL; int i, n; uint8_t *rma = NULL; @@ -2407,7 +2481,7 @@ void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, c for (i = 0; i < n; i++) if (!(rma[i] = attrname2val(rmattrs[i]))) - debugx(1, DBG_ERR, "addrewrite: invalid attribute %s", rmattrs[i]); + debugx(1, DBG_ERR, "addrewrite: removing invalid attribute %s", rmattrs[i]); freegconfmstr(rmattrs); rma[i] = 0; } @@ -2420,7 +2494,7 @@ void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, c for (p = rmva, i = 0; i < n; i++, p += 2) if (!vattrname2val(rmvattrs[i], p, p + 1)) - debugx(1, DBG_ERR, "addrewrite: invalid vendor attribute %s", rmvattrs[i]); + debugx(1, DBG_ERR, "addrewrite: removing invalid vendor attribute %s", rmvattrs[i]); freegconfmstr(rmvattrs); *p = 0; } @@ -2430,15 +2504,30 @@ void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, c if (!adda) debugx(1, DBG_ERR, "malloc failed"); for (i = 0; addattrs[i]; i++) { - a = extractattr(addattrs[i]); + a = extractattr(addattrs[i], 0); if (!a) - debugx(1, DBG_ERR, "addrewrite: invalid attribute %s", addattrs[i]); + debugx(1, DBG_ERR, "addrewrite: adding invalid attribute %s", addattrs[i]); if (!list_push(adda, a)) debugx(1, DBG_ERR, "malloc failed"); } freegconfmstr(addattrs); } + if (addvattrs) { + if (!adda) + adda = list_create(); + if (!adda) + debugx(1, DBG_ERR, "malloc failed"); + for (i = 0; addvattrs[i]; i++) { + a = extractattr(addvattrs[i], 1); + if (!a) + debugx(1, DBG_ERR, "addrewrite: adding invalid vendor attribute %s", addvattrs[i]); + if (!list_push(adda, a)) + debugx(1, DBG_ERR, "malloc failed"); + } + freegconfmstr(addvattrs); + } + if (modattrs) { moda = list_create(); if (!moda) @@ -2446,7 +2535,7 @@ void addrewrite(char *value, char **rmattrs, char **rmvattrs, char **addattrs, c for (i = 0; modattrs[i]; i++) { m = extractmodattr(modattrs[i]); if (!m) - debugx(1, DBG_ERR, "addrewrite: invalid attribute %s", modattrs[i]); + debugx(1, DBG_ERR, "addrewrite: modifying invalid attribute %s", modattrs[i]); if (!list_push(moda, m)) debugx(1, DBG_ERR, "malloc failed"); } @@ -2479,6 +2568,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); @@ -2581,7 +2673,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; @@ -2607,22 +2702,27 @@ 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, + "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"); @@ -2647,7 +2747,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)) @@ -2672,7 +2774,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); @@ -2684,7 +2788,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)) - debugx(1, DBG_ERR, "resolve failed, exiting"); + debugx(1, DBG_ERR, "%s: resolve failed, exiting", __func__); if (!conf->secret) { if (!conf->pdef->secretdefault) @@ -2707,7 +2811,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; @@ -2732,17 +2838,19 @@ 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"); + debug(DBG_ERR, "%s: resolve failed", __func__); return 0; } return 1; @@ -2866,7 +2974,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) { @@ -2917,7 +3026,9 @@ int confrealm_cb(struct gconffile **cf, void *arg, char *block, char *opt, char } int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) { - char **rmattrs = NULL, **rmvattrs = NULL, **addattrs = NULL, **modattrs = NULL; + char **rmattrs = NULL, **rmvattrs = NULL; + char **addattrs = NULL, **addvattrs = NULL; + char **modattrs = NULL; debug(DBG_DBG, "confrewrite_cb called for %s", block); @@ -2925,11 +3036,12 @@ int confrewrite_cb(struct gconffile **cf, void *arg, char *block, char *opt, cha "removeAttribute", CONF_MSTR, &rmattrs, "removeVendorAttribute", CONF_MSTR, &rmvattrs, "addAttribute", CONF_MSTR, &addattrs, + "addVendorAttribute", CONF_MSTR, &addvattrs, "modifyAttribute", CONF_MSTR, &modattrs, NULL )) debugx(1, DBG_ERR, "configuration error"); - addrewrite(val, rmattrs, rmvattrs, addattrs, modattrs); + addrewrite(val, rmattrs, rmvattrs, addattrs, addvattrs, modattrs); return 1; } @@ -2951,6 +3063,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); @@ -2974,42 +3091,50 @@ 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 + 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) { @@ -3020,6 +3145,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]); @@ -3034,8 +3164,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': @@ -3048,7 +3178,7 @@ void getargs(int argc, char **argv, uint8_t *foreground, uint8_t *pretend, uint8 *pretend = 1; break; case 'v': - debug(DBG_ERR, "radsecproxy revision $Rev$"); + debug(DBG_ERR, "radsecproxy revision %s", PACKAGE_VERSION); debug(DBG_ERR, "This binary was built with support for the following transports:"); #ifdef RADPROT_UDP debug(DBG_ERR, " UDP"); @@ -3118,14 +3248,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, "%d\n", getpid()); + 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; @@ -3151,8 +3281,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)) @@ -3167,7 +3307,9 @@ int main(int argc, char **argv) { debugx(1, DBG_ERR, "daemon() failed: %s", strerror(errno)); debug_timestamp_on(); - debug(DBG_INFO, "radsecproxy revision $Rev$ starting"); + 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));