Keep track of a failing dynamic server and don't use it while failing.
[libradsec.git] / radsecproxy.c
index 303aba4..5248c41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no>
- * Copyright (C) 2010, 2011 NORDUnet A/S
+ * 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
@@ -64,6 +64,7 @@
 #include <libgen.h>
 #include <pthread.h>
 #include <errno.h>
+#include <assert.h>
 #include <openssl/ssl.h>
 #include <openssl/rand.h>
 #include <openssl/err.h>
@@ -1306,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)
@@ -1344,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);
@@ -1751,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));
@@ -1775,8 +1789,11 @@ 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;
        }
@@ -2173,10 +2190,17 @@ 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))) {
                    debugerrno(errno, DBG_ERR, "pthread_create failed");
                    freeserver(srvconf->servers, 1);
@@ -2544,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);
@@ -2646,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;
@@ -2690,6 +2720,7 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
            "rewriteattribute", CONF_STR, &conf->confrewriteusername,
 #if defined(WANT_FTICKS)
            "fticksVISCOUNTRY", CONF_STR, &conf->fticks_viscountry,
+           "fticksVISINST", CONF_STR, &conf->fticks_visinst,
 #endif
            NULL
            ))
@@ -2716,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))
@@ -2741,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);
 
@@ -2753,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)
@@ -2776,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;
@@ -2801,7 +2838,9 @@ 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);
 
@@ -2811,7 +2850,7 @@ int compileserverconfig(struct clsrvconf *conf, const char *block) {
     }
 
     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;
@@ -2935,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) {
@@ -3069,6 +3109,7 @@ void getmainconfig(const char *configfile) {
            "ListenDTLS", CONF_MSTR, &listenargs[RAD_DTLS],
            "SourceDTLS", CONF_STR, &sourcearg[RAD_DTLS],
 #endif
+            "PidFile", CONF_STR, &options.pidfile,
            "TTLAttribute", CONF_STR, &options.ttlattr,
            "addTTL", CONF_LINT, &addttl,
            "LogLevel", CONF_LINT, &loglevel,
@@ -3085,6 +3126,7 @@ void getmainconfig(const char *configfile) {
            "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
            ))
@@ -3239,8 +3281,18 @@ int radsecproxy_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))
@@ -3256,6 +3308,8 @@ int radsecproxy_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));