]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Allow coa_server in client stanzas to be a section as well as a pair
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 29 Dec 2014 17:41:59 +0000 (12:41 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 30 Dec 2014 21:26:32 +0000 (16:26 -0500)
When used as a section it defines a new home_server with fields inherited from the client.  This can be used to turn all clients into CoA home servers.

src/include/radiusd.h
src/include/realms.h
src/main/client.c
src/main/realms.c
src/modules/rlm_couchbase/mod.c
src/modules/rlm_ldap/clients.c

index f54af1e224102e964a5e16a589dcdc1fb2c5a548..6c212831e9b0bfa26b6fa81a60566b38cad0604f 100644 (file)
@@ -123,6 +123,7 @@ typedef struct radclient {
        char const              *coa_name;
        home_server_t           *coa_server;
        home_pool_t             *coa_pool;
+       bool                    defines_coa_server;     //!< Client also defines a home_server.
 #endif
 } RADCLIENT;
 
index 29566a719a997a90384bf04fc2a80fdc397eea0a..d8571155f7bce51f4eec5d74ab2e0780378fa16c 100644 (file)
@@ -189,8 +189,8 @@ int         realm_realm_add( REALM *r, CONF_SECTION *cs);
 void           home_server_update_request(home_server_t *home, REQUEST *request);
 home_server_t  *home_server_ldb(char const *realmname, home_pool_t *pool, REQUEST *request);
 home_server_t  *home_server_find(fr_ipaddr_t *ipaddr, uint16_t port, int proto);
-home_server_t  *home_server_afrom_cs(realm_config_t *rc, CONF_SECTION *cs);
-
+home_server_t  *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SECTION *cs);
+CONF_SECTION   *home_server_cs_afrom_client(CONF_SECTION *client);
 #ifdef WITH_COA
 home_server_t  *home_server_byname(char const *name, int type);
 #endif
index 335a1853f61f842cd1949f580d908e0c31266259..142fc5624a7eb93cd7d6f99b954d3b7e14cf2ae9 100644 (file)
@@ -217,6 +217,11 @@ bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
        fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
        DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
 
+       /*
+        *      If the client also defines a server, do that now.
+        */
+       if (client->defines_coa_server) if (!realm_home_server_add(client->coa_server)) return false;
+
        /*
         *      If "clients" is NULL, it means add to the global list,
         *      unless we're trying to add it to a virtual server...
@@ -506,10 +511,6 @@ static const CONF_PARSER client_config[] = {
        { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
 #endif
 
-#ifdef WITH_COA
-       { "coa_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, coa_name), NULL },
-#endif
-
        { NULL, -1, 0, NULL, NULL }
 };
 
@@ -768,9 +769,11 @@ error:
  * @param ctx to allocate new clients in.
  * @param cs to process as a client.
  * @param in_server Whether the client should belong to a specific virtual server.
+ * @param with_coa If true and coa_server or coa_pool aren't specified automatically
+ *     create a coa home_server section and add it to the client CONF_SECTION.
  * @return new RADCLIENT struct.
  */
-RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server)
+RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
 {
        RADCLIENT       *c;
        char const      *name2;
@@ -953,19 +956,54 @@ RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server)
        }
 
 #ifdef WITH_COA
-       /*
-        *      Point the client to the home server pool, OR to the
-        *      home server.  This gets around the problem of figuring
-        *      out which port to use.
-        */
-       if (c->coa_name) {
-               c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
-               if (!c->coa_pool) {
-                       c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
-               }
-               if (!c->coa_pool && !c->coa_server) {
-                       cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
-                       goto error;
+       {
+               CONF_PAIR *cp;
+
+               /*
+                *      Point the client to the home server pool, OR to the
+                *      home server.  This gets around the problem of figuring
+                *      out which port to use.
+                */
+               cp = cf_pair_find(cs, "coa_server");
+               if (cp) {
+                       c->coa_name = cf_pair_value(cp);
+                       c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
+                       if (!c->coa_pool) {
+                               c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
+                       }
+                       if (!c->coa_pool && !c->coa_server) {
+                               cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
+                               goto error;
+                       }
+               /*
+                *      If we're implicitly adding a CoA home server for
+                *      every client, or there's a server subsection,
+                *      create a home server CONF_SECTION and then parse
+                *      it into a home_server_t.
+                */
+               } else if (with_coa || cf_section_sub_find(cs, "coa_server")) {
+                       CONF_SECTION *server;
+                       home_server_t *home;
+
+                       server = home_server_cs_afrom_client(cs);
+                       if (!server) goto error;
+
+                       /*
+                        *      Must be allocated in the context of the client,
+                        *      as allocating using the context of the
+                        *      realm_config_t without a mutex, by one of the
+                        *      workers, would be bad.
+                        */
+                       home = home_server_afrom_cs(c, NULL, server);
+                       if (!home) {
+                               talloc_free(server);
+                               goto error;
+                       }
+
+                       rad_assert(home->type == HOME_TYPE_COA);
+
+                       c->coa_server = home;
+                       c->defines_coa_server = true;
                }
        }
 #endif
index 9aa0fdfedc6aa80312b6b0a237a8a49ef5c01875..d43b0aae174e78dc0bd428c01715980b0d9fd734 100644 (file)
@@ -835,6 +835,77 @@ home_server_t *home_server_afrom_cs(TALLOC_CTX *ctx, realm_config_t *rc, CONF_SE
        return home;
 }
 
+/** Fixup a client configuration section to specify a home server
+ *
+ * This is used to create the equivalent CoA home server entry for a client,
+ * so that the server can originate CoA messages.
+ *
+ * The server section automatically inherits the following fields from the client:
+ *  - ipaddr/ipv4addr/ipv6addr
+ *  - secret
+ *  - src_ipaddr
+ *
+ * @note new CONF_SECTION will be allocated in the context of the client, but the client
+ *     CONF_SECTION will not be modified.
+ *
+ * @param client CONF_SECTION to inherit values from.
+ * @return a new server CONF_SCTION, or a pointer to the existing CONF_SECTION in the client.
+ */
+CONF_SECTION *home_server_cs_afrom_client(CONF_SECTION *client)
+{
+       CONF_SECTION *server, *cs;
+       CONF_PAIR *cp;
+
+       /*
+        *      Alloc a plain home server for both cases
+        *
+        *      There's no way these can be referenced by a pool,
+        *      and they may conflict with home servers in proxy.conf
+        *      so it's easier to not set a name.
+        */
+
+       /*
+        *
+        *      Duplicate the server section, so we don't mangle
+        *      the client CONF_SECTION we were passed.
+        */
+       cs = cf_section_sub_find(client, "coa_server");
+       if (cs) {
+               server = cf_section_dup(client, cs, "home_server", NULL);
+       } else {
+               server = cf_section_alloc(client, "home_server", NULL);
+       }
+
+       if (!cs || (!cf_pair_find(cs, "ipaddr") && !cf_pair_find(cs, "ipv4addr") && !cf_pair_find(cs, "ipv6addr"))) {
+               cp = cf_pair_find(client, "ipaddr");
+               if (!cp) cp = cf_pair_find(client, "ipv4addr");
+               if (!cp) cp = cf_pair_find(client, "ipv6addr");
+
+               cf_pair_add(server, cf_pair_dup(server, cp));
+       }
+
+       if (!cs || !cf_pair_find(cs, "secret")) {
+               cp = cf_pair_find(client, "secret");
+               if (cp) cf_pair_add(server, cp);
+       }
+
+       if (!cs || !cf_pair_find(cs, "src_ipaddr")) {
+               cp = cf_pair_find(client, "src_ipaddr");
+               if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
+       }
+
+       if (!cs || !(cp = cf_pair_find(cs, "type"))) {
+               cp = cf_pair_alloc(server, "type", "coa", T_OP_EQ, T_SINGLE_QUOTED_STRING);
+               if (cp) cf_pair_add(server, cf_pair_dup(server, cp));
+       } else if (strcmp(cf_pair_value(cp), "coa") != 0) {
+               talloc_free(server);
+               cf_log_err_cs(server, "server.type must be \"coa\"");
+               return NULL;
+       }
+
+       return server;
+}
+
 static home_pool_t *server_pool_alloc(char const *name, home_pool_type_t type,
                                      home_type_t server_type, int num_home_servers)
 {
index ef6a5e4b3049fd403a227a9cce9ae654a8ed6d8e..7e2a3e4ec00debf2d1100209d47d5aabd9f8f93f 100644 (file)
@@ -746,7 +746,7 @@ int mod_load_client_documents(rlm_couchbase_t *inst, CONF_SECTION *cs)
                /*
                 * @todo These should be parented from something.
                 */
-               c = client_afrom_cs(NULL, client, false);
+               c = client_afrom_cs(NULL, client, false, false);
                if (!c) {
                        ERROR("rlm_couchbase: failed to allocate client");
                        /* free config setion */
index 776a1a046c442889b915193e3dbce80e2a39d4d2..df69120d2a4b0e0acb1307235b9d6ba28781ba52 100644 (file)
@@ -254,7 +254,7 @@ int rlm_ldap_client_load(ldap_instance_t const *inst, CONF_SECTION *cs)
                /*
                 *@todo these should be parented from something
                 */
-               c = client_afrom_cs(NULL, cc, false);
+               c = client_afrom_cs(NULL, cc, false, false);
                if (!c) {
                        talloc_free(cc);
                        ret = -1;