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.
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;
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
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...
{ "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 }
};
* @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;
}
#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
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)
{
/*
* @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 */
/*
*@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;