Better way of updating cf_data_add
[freeradius.git] / src / main / realms.c
index a49c18b..7abf7f0 100644 (file)
@@ -387,6 +387,10 @@ static CONF_PARSER home_server_config[] = {
 };
 
 
+static void null_free(UNUSED void *data)
+{
+}
+
 static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
 {
        const char *name2;
@@ -417,6 +421,24 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
        home->name = name2;
        home->cs = cs;
 
+        /*
+        *      For zombie period calculations.  We want to count
+        *      zombies from the time when the server starts, instead
+        *      of from 1970.
+        */
+       home->last_packet = time(NULL);
+
+       /*
+        *      Authentication servers have a default "no_response_fail = 0".
+        *      Accounting servers have a default "no_response_fail = 1".
+        *
+        *      This is because authentication packets are retried, so
+        *      they can fail over to another home server.  Accounting
+        *      packets are not retried, so they cannot fail over, and
+        *      instead should be rejected immediately.
+        */
+       home->no_response_fail = 2;
+
        memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
        memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
        if (cf_section_parse(cs, home, home_server_config) < 0) {
@@ -506,16 +528,18 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
 
        if (strcasecmp(hs_type, "auth") == 0) {
                home->type = HOME_TYPE_AUTH;
+               if (home->no_response_fail == 2) home->no_response_fail = 0;
                if (pool_type != home->type) {
                mismatch:
                        cf_log_err(cf_sectiontoitem(cs),
-                                  "Server pool cannot include home server %s of type \"%s\"",
+                                  "Home server %s of unexpected type \"%s\"",
                                   name2, hs_type);
                        goto error;
                }
 
        } else if (strcasecmp(hs_type, "acct") == 0) {
                home->type = HOME_TYPE_ACCT;
+               if (home->no_response_fail == 2) home->no_response_fail = 1;
                if (pool_type != home->type) goto mismatch;
 
        } else if (strcasecmp(hs_type, "auth+acct") == 0) {
@@ -726,6 +750,9 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
                home2->ping_user_password = NULL;
                home2->cs = cs;
 
+               if (home->no_response_fail == 2) home->no_response_fail = 0;
+               if (home2->no_response_fail == 2) home2->no_response_fail = 1;
+
                if (!rbtree_insert(home_servers_byname, home2)) {
                        cf_log_err(cf_sectiontoitem(cs),
                                   "Internal error %d adding home server %s.",
@@ -760,6 +787,11 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
 #endif
        }
 
+       /*
+        *      Mark it as already processed
+        */
+       cf_data_add(cs, "home_server", null_free, null_free);
+
        return 1;
 }
 
@@ -1556,15 +1588,22 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs)
 
 #ifdef HAVE_REGEX_H
        if (name2[0] == '~') {
+               int rcode;
                regex_t reg;
                
                /*
                 *      Include substring matches.
                 */
-               if (regcomp(&reg, name2 + 1,
-                           REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) {
+               rcode = regcomp(&reg, name2 + 1,
+                               REG_EXTENDED | REG_NOSUB | REG_ICASE);
+               if (rcode != 0) {
+                       char buffer[256];
+
+                       regerror(rcode, &reg, buffer, sizeof(buffer));
+
                        cf_log_err(cf_sectiontoitem(cs),
-                                  "Invalid regex in realm \"%s\"", name2);
+                                  "Invalid regex \"%s\": %s",
+                                  name2 + 1, buffer);
                        goto error;
                }
                regfree(&reg);
@@ -1800,6 +1839,22 @@ int realms_init(CONF_SECTION *config)
                        return 0;
                }
        }
+
+       /*
+        *      CoA home servers aren't tied to realms.
+        */
+       for (cs = cf_subsection_find_next(config, NULL, "home_server");
+            cs != NULL;
+            cs = cf_subsection_find_next(config, cs, "home_server")) {
+               /*
+                *      Server was already loaded.
+                */
+               if (cf_data_find(cs, "home_server")) continue;
+
+               if (!home_server_add(rc, cs, HOME_TYPE_COA)) {
+                       return 0;
+               }
+       }
 #endif
 
 
@@ -1959,7 +2014,7 @@ home_server *home_server_ldb(const char *realmname,
                break;
 
        case HOME_POOL_KEYED_BALANCE:
-               if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY)) != NULL) {
+               if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY, 0)) != NULL) {
                        hash = fr_hash(vp->vp_strvalue, vp->length);
                        start = hash % pool->num_home_servers;
                        break;
@@ -2131,11 +2186,6 @@ home_server *home_server_ldb(const char *realmname,
                         *      the 'hints' file.
                         */
                        request->proxy->vps =  paircopy(request->packet->vps);
-
-                       /*
-                        *      Set the source IP address for proxying.
-                        */
-                       request->proxy->src_ipaddr = found->src_ipaddr;
                }
 
                /*
@@ -2153,7 +2203,7 @@ home_server *home_server_ldb(const char *realmname,
                 */
                if (found->message_authenticator &&
                    (request->packet->code == PW_AUTHENTICATION_REQUEST) &&
-                   !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR)) {
+                   !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0)) {
                        radius_pairmake(request, &request->proxy->vps,
                                        "Message-Authenticator", "0x00",
                                        T_OP_SET);