2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * @brief Manage clients allowed to communicate with the server.
22 * @copyright 2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23 * @copyright 2000,2006 The FreeRADIUS server project
24 * @copyright 2000 Alan DeKok <aland@ox.org>
25 * @copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/rad_assert.h>
37 #ifdef WITH_DYNAMIC_CLIENTS
43 struct radclient_list {
45 * FIXME: One set of trees for IPv4, and another for IPv6?
47 rbtree_t *trees[129]; /* for 0..128, inclusive. */
53 static rbtree_t *tree_num = NULL; /* client numbers 0..N */
54 static int tree_num_max = 0;
56 static RADCLIENT_LIST *root_clients = NULL;
58 #ifdef WITH_DYNAMIC_CLIENTS
59 static fr_fifo_t *deleted_clients = NULL;
63 * Callback for freeing a client.
65 void client_free(RADCLIENT *client)
69 #ifdef WITH_DYNAMIC_CLIENTS
70 if (client->dynamic == 2) {
73 if (!deleted_clients) {
74 deleted_clients = fr_fifo_create(NULL, 1024, (void (*)(void *))client_free);
75 if (!deleted_clients) return; /* MEMLEAK */
79 * Mark it as in the fifo, and remember when we
83 client->created = now = time(NULL); /* re-set it */
84 fr_fifo_push(deleted_clients, client);
87 * Peek at the head of the fifo. If it might
88 * still be in use, return. Otherwise, pop it
89 * from the queue and delete it.
91 client = fr_fifo_peek(deleted_clients);
92 rad_assert(client != NULL);
94 if ((client->created + 120) >= now) return;
96 client = fr_fifo_pop(deleted_clients);
97 rad_assert(client != NULL);
105 * Callback for comparing two clients.
107 static int client_ipaddr_cmp(void const *one, void const *two)
109 RADCLIENT const *a = one;
110 RADCLIENT const *b = two;
113 return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
117 rcode = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
118 if (rcode != 0) return rcode;
123 if ((a->proto == IPPROTO_IP) ||
124 (b->proto == IPPROTO_IP)) return 0;
126 return (a->proto - b->proto);
131 static int client_num_cmp(void const *one, void const *two)
133 RADCLIENT const *a = one;
134 RADCLIENT const *b = two;
136 return (a->number - b->number);
141 * Free a RADCLIENT list.
143 void client_list_free(RADCLIENT_LIST *clients)
147 if (!clients) clients = root_clients;
148 if (!clients) return; /* Clients may not have been initialised yet */
150 for (i = 0; i <= 128; i++) {
151 if (clients->trees[i]) rbtree_free(clients->trees[i]);
152 clients->trees[i] = NULL;
155 if (clients == root_clients) {
157 if (tree_num) rbtree_free(tree_num);
164 #ifdef WITH_DYNAMIC_CLIENTS
166 * FIXME: No fr_fifo_delete()
170 talloc_free(clients);
174 * Return a new, initialized, set of clients.
176 RADCLIENT_LIST *client_list_init(CONF_SECTION *cs)
178 RADCLIENT_LIST *clients = talloc_zero(cs, RADCLIENT_LIST);
180 if (!clients) return NULL;
182 clients->min_prefix = 128;
187 /** Add a client to a RADCLIENT_LIST
189 * @param clients list to add client to, may be NULL if global client list is being used.
190 * @param client to add.
191 * @return true on success, false on failure.
193 bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
196 char buffer[INET6_ADDRSTRLEN + 3];
198 if (!client) return false;
201 * Hack to fixup wildcard clients
203 * If the IP is all zeros, with a 32 or 128 bit netmask
204 * assume the user meant to configure 0.0.0.0/0 instead
205 * of 0.0.0.0/32 - which would require the src IP of
206 * the client to be all zeros.
208 if (fr_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
210 if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
214 if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
221 fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
222 DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
225 * If the client also defines a server, do that now.
227 if (client->defines_coa_server) if (!realm_home_server_add(client->coa_server)) return false;
230 * If "clients" is NULL, it means add to the global list,
231 * unless we're trying to add it to a virtual server...
234 if (client->server != NULL) {
238 cs = cf_section_sub_find_name2(main_config.config, "server", client->server);
240 ERROR("Failed to find virtual server %s", client->server);
245 * If this server has no "listen" section, add the clients
246 * to the global client list.
248 subcs = cf_section_sub_find(cs, "listen");
249 if (!subcs) goto global_clients;
252 * If the client list already exists, use that.
253 * Otherwise, create a new client list.
255 clients = cf_data_find(cs, "clients");
257 clients = client_list_init(cs);
259 ERROR("Out of memory");
263 if (cf_data_add(cs, "clients", clients, (void (*)(void *)) client_list_free) < 0) {
264 ERROR("Failed to associate clients with virtual server %s", client->server);
265 client_list_free(clients);
273 * Initialize the global list, if not done already.
276 root_clients = client_list_init(NULL);
277 if (!root_clients) return false;
279 clients = root_clients;
284 * Create a tree for it.
286 if (!clients->trees[client->ipaddr.prefix]) {
287 clients->trees[client->ipaddr.prefix] = rbtree_create(clients, client_ipaddr_cmp, NULL, 0);
288 if (!clients->trees[client->ipaddr.prefix]) {
293 #define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
296 * Cannot insert the same client twice.
298 old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client);
301 * If it's a complete duplicate, then free the new
302 * one, and return "OK".
304 if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) &&
305 (old->ipaddr.prefix == client->ipaddr.prefix) &&
306 namecmp(longname) && namecmp(secret) &&
307 namecmp(shortname) && namecmp(nas_type) &&
308 namecmp(login) && namecmp(password) && namecmp(server) &&
309 #ifdef WITH_DYNAMIC_CLIENTS
310 (old->lifetime == client->lifetime) &&
311 namecmp(client_server) &&
315 (old->coa_server == client->coa_server) &&
316 (old->coa_pool == client->coa_pool) &&
318 (old->message_authenticator == client->message_authenticator)) {
319 WARN("Ignoring duplicate client %s", client->longname);
324 ERROR("Failed to add duplicate client %s", client->shortname);
330 * Other error adding client: likely is fatal.
332 if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) {
338 tree_num = rbtree_create(clients, client_num_cmp, NULL, 0);
341 #ifdef WITH_DYNAMIC_CLIENTS
343 * More catching of clients added by rlm_sql.
345 * The sql modules sets the dynamic flag BEFORE calling
346 * us. The client_afrom_request() function sets it AFTER
349 if (client->dynamic && (client->lifetime == 0)) {
353 * If there IS an enclosing network,
354 * inherit the lifetime from it.
356 network = client_find(clients, &client->ipaddr, client->proto);
358 client->lifetime = network->lifetime;
363 client->number = tree_num_max;
365 if (tree_num) rbtree_insert(tree_num, client);
368 if (client->ipaddr.prefix < clients->min_prefix) {
369 clients->min_prefix = client->ipaddr.prefix;
372 (void) talloc_steal(clients, client); /* reparent it */
378 #ifdef WITH_DYNAMIC_CLIENTS
379 void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
383 if (!clients) clients = root_clients;
385 if (!client->dynamic) return;
387 rad_assert(client->ipaddr.prefix <= 128);
389 client->dynamic = 2; /* signal to client_free */
392 rbtree_deletebydata(tree_num, client);
394 rbtree_deletebydata(clients->trees[client->ipaddr.prefix], client);
400 * Find a client in the RADCLIENTS list by number.
401 * This is a support function for the statistics code.
403 RADCLIENT *client_findbynumber(RADCLIENT_LIST const *clients, int number)
405 if (!clients) clients = root_clients;
407 if (!clients) return NULL;
409 if (number >= tree_num_max) return NULL;
414 myclient.number = number;
416 return rbtree_finddata(tree_num, &myclient);
422 RADCLIENT *client_findbynumber(UNUSED const RADCLIENT_LIST *clients, UNUSED int number)
430 * Find a client in the RADCLIENTS list.
432 RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
434 int32_t i, max_prefix;
437 if (!clients) clients = root_clients;
439 if (!clients || !ipaddr) return NULL;
441 switch (ipaddr->af) {
454 for (i = max_prefix; i >= (int32_t) clients->min_prefix; i--) {
457 myclient.ipaddr = *ipaddr;
458 myclient.proto = proto;
459 fr_ipaddr_mask(&myclient.ipaddr, i);
461 if (!clients->trees[i]) continue;
463 data = rbtree_finddata(clients->trees[i], &myclient);
464 if (data) return data;
471 * Old wrapper for client_find
473 RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr)
475 return client_find(root_clients, ipaddr, IPPROTO_UDP);
478 static fr_ipaddr_t cl_ipaddr;
479 static uint32_t cl_netmask;
480 static char const *cl_srcipaddr = NULL;
482 static char const *hs_proto = NULL;
486 static CONF_PARSER limit_config[] = {
487 { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.max_connections), "16" },
489 { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.lifetime), "0" },
491 { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.idle_timeout), "30" },
493 { NULL, -1, 0, NULL, NULL } /* end the list */
497 static const CONF_PARSER client_config[] = {
498 { "ipaddr", FR_CONF_POINTER(PW_TYPE_COMBO_IP_PREFIX, &cl_ipaddr), NULL },
499 { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_PREFIX, &cl_ipaddr), NULL },
500 { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_PREFIX, &cl_ipaddr), NULL },
502 { "netmask", FR_CONF_POINTER(PW_TYPE_INTEGER, &cl_netmask), NULL },
504 { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
506 { "require_message_authenticator", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" },
508 { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
509 { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL },
511 { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
513 { "login", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, login), NULL },
514 { "password", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, password), NULL },
515 { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
516 { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, RADCLIENT, response_window), NULL },
519 { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
520 { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
523 #ifdef WITH_DYNAMIC_CLIENTS
524 { "dynamic_clients", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, client_server), NULL },
525 { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, lifetime), NULL },
526 { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
529 { NULL, -1, 0, NULL, NULL }
532 /** Create the linked list of clients from the new configuration type
536 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, bool tls_required)
538 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
541 bool global = false, in_server = false;
544 RADCLIENT_LIST *clients = NULL;
547 * Be forgiving. If there's already a clients, return
548 * it. Otherwise create a new one.
550 clients = cf_data_find(section, "clients");
551 if (clients) return clients;
553 clients = client_list_init(section);
554 if (!clients) return NULL;
556 if (cf_top_section(section) == section) global = true;
558 if (strcmp("server", cf_section_name1(section)) == 0) in_server = true;
560 for (cs = cf_subsection_find_next(section, NULL, "client");
562 cs = cf_subsection_find_next(section, cs, "client")) {
563 c = client_afrom_cs(cs, cs, in_server, false);
567 client_list_free(clients);
573 * TLS clients CANNOT use non-TLS listeners.
574 * non-TLS clients CANNOT use TLS listeners.
576 if (tls_required != c->tls_required) {
577 cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
583 * FIXME: Add the client as data via cf_data_add,
584 * for migration issues.
587 #ifdef WITH_DYNAMIC_CLIENTS
589 if (c->client_server) {
594 struct stat stat_buf;
598 * Find the directory where individual
599 * client definitions are stored.
601 cp = cf_pair_find(cs, "directory");
602 if (!cp) goto add_client;
604 value = cf_pair_value(cp);
606 cf_log_err_cs(cs, "The \"directory\" entry must not be empty");
610 DEBUG("including dynamic clients in %s", value);
612 dir = opendir(value);
614 cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
619 * Read the directory, ignoring "." files.
621 while ((dp = readdir(dir)) != NULL) {
625 if (dp->d_name[0] == '.') continue;
628 * Check for valid characters
630 for (p = dp->d_name; *p != '\0'; p++) {
631 if (isalpha((int)*p) ||
634 (*p == '.')) continue;
637 if (*p != '\0') continue;
639 snprintf(buf2, sizeof(buf2), "%s/%s", value, dp->d_name);
641 if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue;
643 dc = client_read(buf2, in_server, true);
645 cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2);
651 * Validate, and add to the list.
653 if (!client_add_dynamic(clients, c, dc)) {
657 } /* loop over the directory */
660 #endif /* HAVE_DIRENT_H */
663 #endif /* WITH_DYNAMIC_CLIENTS */
664 if (!client_add(clients, c)) {
665 cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs));
672 * Associate the clients structure with the section.
674 if (cf_data_add(section, "clients", clients, NULL) < 0) {
675 cf_log_err_cs(section, "Failed to associate clients with section %s", cf_section_name1(section));
676 client_list_free(clients);
681 * Replace the global list of clients with the new one.
682 * The old one is still referenced from the original
683 * configuration, and will be freed when that is freed.
685 if (global) root_clients = clients;
690 #ifdef WITH_DYNAMIC_CLIENTS
692 * We overload this structure a lot.
694 static const CONF_PARSER dynamic_config[] = {
695 { "FreeRADIUS-Client-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, ipaddr), NULL },
696 { "FreeRADIUS-Client-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, ipaddr), NULL },
697 { "FreeRADIUS-Client-IP-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV4_PREFIX, RADCLIENT, ipaddr), NULL },
698 { "FreeRADIUS-Client-IPv6-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV6_PREFIX, RADCLIENT, ipaddr), NULL },
699 { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
700 { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
702 { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL },
704 { "FreeRADIUS-Client-Secret", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
705 { "FreeRADIUS-Client-Shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
706 { "FreeRADIUS-Client-NAS-Type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
707 { "FreeRADIUS-Client-Virtual-Server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
709 { NULL, -1, 0, NULL, NULL }
712 /** Add a dynamic client
715 bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c)
720 * No virtual server defined. Inherit the parent's
723 if (master->server && !c->server) {
724 c->server = talloc_typed_strdup(c, master->server);
728 * If the client network isn't global (not tied to a
729 * virtual server), then ensure that this clients server
730 * is the same as the enclosing networks virtual server.
732 if (master->server && (strcmp(master->server, c->server) != 0)) {
733 ERROR("Cannot add client %s/%i: Virtual server %s is not the same as the virtual server for the network",
734 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->server);
739 if (!client_add(clients, c)) {
740 ERROR("Cannot add client %s/%i: Internal error",
741 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
747 * Initialize the remaining fields.
750 c->lifetime = master->lifetime;
751 c->created = time(NULL);
752 c->longname = talloc_typed_strdup(c, c->shortname);
754 INFO("Adding client %s/%i with shared secret \"%s\"",
755 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->secret);
764 /** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
766 * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
768 * @note Caller should free CONF_SECTION passed in as out, on error.
769 * Contents of that section will be in an undefined state.
771 * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
772 * (when this function is called recursively).
773 * Should be alloced with cf_section_alloc, or if there's a separate template section, the
774 * result of calling cf_section_dup on that section.
775 * @param[in] map section.
776 * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
777 * @param[in] data to pass to func, usually a result pointer.
778 * @return 0 on success else -1 on error.
780 int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
784 for (ci = cf_item_find_next(map, NULL);
786 ci = cf_item_find_next(map, ci)) {
793 * Recursively process map subsection
795 if (cf_item_is_section(ci)) {
796 CONF_SECTION *cs, *cc;
798 cs = cf_item_to_section(ci);
800 * Use pre-existing section or alloc a new one
802 cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
804 cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
805 cf_section_add(out, cc);
809 if (client_map_section(cc, cs, func, data) < 0) return -1;
813 cp = cf_item_to_pair(ci);
814 attr = cf_pair_attr(cp);
817 * The callback can return 0 (success) and not provide a value
818 * in which case we skip the mapping pair.
820 * Or return -1 in which case we error out.
822 if (func(&value, cp, data) < 0) {
823 cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
826 if (!value) continue;
829 * Replace an existing CONF_PAIR
831 old = cf_pair_find(out, attr);
833 cf_pair_replace(out, old, value);
839 * ...or add a new CONF_PAIR
841 cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
843 cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
848 cf_item_add(out, cf_pair_to_item(cp));
854 /** Allocate a new client from a config section
856 * @param ctx to allocate new clients in.
857 * @param cs to process as a client.
858 * @param in_server Whether the client should belong to a specific virtual server.
859 * @param with_coa If true and coa_server or coa_pool aren't specified automatically,
860 * create a coa home_server section and add it to the client CONF_SECTION.
861 * @return new RADCLIENT struct.
863 RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
868 name2 = cf_section_name2(cs);
870 cf_log_err_cs(cs, "Missing client name");
875 * The size is fine.. Let's create the buffer
877 c = talloc_zero(ctx, RADCLIENT);
880 memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
883 if (cf_section_parse(cs, c, client_config) < 0) {
884 cf_log_err_cs(cs, "Error parsing client section");
896 * Global clients can set servers to use, per-server clients cannot.
898 if (in_server && c->server) {
899 cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
904 * Allow the old method to specify "netmask". Just using "1.2.3.4" means it's a /32.
906 if (cl_netmask != 255) {
907 if ((cl_ipaddr.prefix != cl_netmask) &&
908 (((cl_ipaddr.af == AF_INET) && cl_ipaddr.prefix != 32) ||
909 ((cl_ipaddr.af == AF_INET6) && cl_ipaddr.prefix != 128))) {
910 cf_log_err_cs(cs, "Clients cannot use 'ipaddr/mask' and 'netmask' at the same time.");
914 cl_ipaddr.prefix = cl_netmask;
918 * Newer style client definitions with either ipaddr or ipaddr6
921 if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
925 * Sets ipv4/ipv6 address and prefix.
927 c->ipaddr = cl_ipaddr;
930 * Set the long name to be the result of a reverse lookup on the IP address.
932 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
933 c->longname = talloc_typed_strdup(c, buffer);
936 * Set the short name to the name2.
938 if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
940 * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
943 cf_log_err_cs(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
944 "directive found in client %s", name2);
948 c->proto = IPPROTO_UDP;
950 if (strcmp(hs_proto, "udp") == 0) {
954 } else if (strcmp(hs_proto, "tcp") == 0) {
956 c->proto = IPPROTO_TCP;
958 } else if (strcmp(hs_proto, "tls") == 0) {
960 c->proto = IPPROTO_TCP;
961 c->tls_required = true;
963 } else if (strcmp(hs_proto, "radsec") == 0) {
965 c->proto = IPPROTO_TCP;
966 c->tls_required = true;
968 } else if (strcmp(hs_proto, "*") == 0) {
970 c->proto = IPPROTO_IP; /* fake for dual */
973 cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
979 * If a src_ipaddr is specified, when we send the return packet
980 * we will use this address instead of the src from the
984 #ifdef WITH_UDPFROMTO
985 switch (c->ipaddr.af) {
987 if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
988 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
994 if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
995 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
1003 WARN("Server not built with udpfromto, ignoring client src_ipaddr");
1005 cl_srcipaddr = NULL;
1009 * A response_window of zero is OK, and means that it's
1010 * ignored by the rest of the server timers.
1012 if (timerisset(&c->response_window)) {
1013 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
1014 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
1015 FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
1018 #ifdef WITH_DYNAMIC_CLIENTS
1019 if (c->client_server) {
1020 c->secret = talloc_typed_strdup(c, "testing123");
1022 if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
1023 ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
1024 cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
1032 if (!c->secret || (c->secret[0] == '\0')) {
1034 char const *value = NULL;
1035 CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
1037 if (cp) value = cf_pair_value(cp);
1040 * Secrets aren't needed for DHCP.
1042 if (value && (strcmp(value, "yes") == 0)) return c;
1047 * If the client is TLS only, the secret can be
1048 * omitted. When omitted, it's hard-coded to
1049 * "radsec". See RFC 6614.
1051 if (c->tls_required) {
1052 c->secret = talloc_typed_strdup(cs, "radsec");
1057 cf_log_err_cs(cs, "secret must be at least 1 character long");
1067 * Point the client to the home server pool, OR to the
1068 * home server. This gets around the problem of figuring
1069 * out which port to use.
1071 cp = cf_pair_find(cs, "coa_server");
1073 c->coa_name = cf_pair_value(cp);
1074 c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
1076 c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
1078 if (!c->coa_pool && !c->coa_server) {
1079 cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
1083 * If we're implicitly adding a CoA home server for
1084 * every client, or there's a server subsection,
1085 * create a home server CONF_SECTION and then parse
1086 * it into a home_server_t.
1088 } else if (with_coa || cf_section_sub_find(cs, "coa_server")) {
1089 CONF_SECTION *server;
1090 home_server_t *home;
1092 if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix != 32)) ||
1093 ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix != 128))) {
1094 WARN("Subnets not supported for home servers. "
1095 "Not adding client %s as home_server", name2);
1099 server = home_server_cs_afrom_client(cs);
1100 if (!server) goto error;
1103 * Must be allocated in the context of the client,
1104 * as allocating using the context of the
1105 * realm_config_t without a mutex, by one of the
1106 * workers, would be bad.
1108 home = home_server_afrom_cs(NULL, NULL, server);
1110 talloc_free(server);
1114 rad_assert(home->type == HOME_TYPE_COA);
1116 c->coa_server = home;
1117 c->defines_coa_server = true;
1124 if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
1125 if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5))
1126 c->limit.idle_timeout = 5;
1127 if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5))
1128 c->limit.lifetime = 5;
1129 if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime))
1130 c->limit.idle_timeout = 0;
1137 /** Add a client from a result set (SQL)
1139 * @todo This function should die. SQL should use client_afrom_cs.
1141 * @param ctx Talloc context.
1142 * @param identifier Client IP Address / IPv4 subnet / IPv6 subnet / FQDN.
1143 * @param secret Client secret.
1144 * @param shortname Client friendly name.
1145 * @param type NAS-Type.
1146 * @param server Virtual-Server to associate clients with.
1147 * @param require_ma If true all packets from client must include a message-authenticator.
1148 * @return The new client, or NULL on error.
1150 RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char const *secret,
1151 char const *shortname, char const *type, char const *server, bool require_ma)
1156 rad_assert(identifier);
1159 c = talloc_zero(ctx, RADCLIENT);
1161 if (fr_pton(&c->ipaddr, identifier, -1, AF_UNSPEC, true) < 0) {
1162 ERROR("%s", fr_strerror());
1168 #ifdef WITH_DYNAMIC_CLIENTS
1171 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1172 c->longname = talloc_typed_strdup(c, buffer);
1175 * Other values (secret, shortname, nas_type, virtual_server)
1177 c->secret = talloc_typed_strdup(c, secret);
1178 if (shortname) c->shortname = talloc_typed_strdup(c, shortname);
1179 if (type) c->nas_type = talloc_typed_strdup(c, type);
1180 if (server) c->server = talloc_typed_strdup(c, server);
1181 c->message_authenticator = require_ma;
1186 /** Create a new client, consuming all attributes in the control list of the request
1188 * @param clients list to add new client to.
1189 * @param request Fake request.
1190 * @return a new client on success, else NULL on error.
1192 RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
1198 CONF_PAIR *cp = NULL;
1202 VALUE_PAIR *vp = NULL;
1204 if (!clients || !request) return NULL;
1206 snprintf(buffer, sizeof(buffer), "dynamic%i", cnt++);
1208 c = talloc_zero(clients, RADCLIENT);
1209 c->cs = cf_section_alloc(NULL, "client", buffer);
1210 talloc_steal(c, c->cs);
1211 c->ipaddr.af = AF_UNSPEC;
1212 c->src_ipaddr.af = AF_UNSPEC;
1214 fr_cursor_init(&cursor, &request->config);
1216 RDEBUG2("Converting control list to client fields");
1218 for (i = 0; dynamic_config[i].name != NULL; i++) {
1219 DICT_ATTR const *da;
1220 char *strvalue = NULL;
1222 da = dict_attrbyname(dynamic_config[i].name);
1224 RERROR("Cannot add client %s: attribute \"%s\" is not in the dictionary",
1225 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1226 dynamic_config[i].name);
1234 fr_cursor_first(&cursor);
1235 if (!fr_cursor_next_by_da(&cursor, da, TAG_ANY)) {
1237 * Not required. Skip it.
1239 if (!dynamic_config[i].dflt) continue;
1241 RERROR("Cannot add client %s: Required attribute \"%s\" is missing",
1242 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1243 dynamic_config[i].name);
1246 vp = fr_cursor_remove(&cursor);
1249 * Freed at the same time as the vp.
1251 strvalue = vp_aprints_value(vp, vp, '\'');
1253 switch (dynamic_config[i].type) {
1254 case PW_TYPE_IPV4_ADDR:
1255 if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
1256 c->ipaddr.af = AF_INET;
1257 c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1258 c->ipaddr.prefix = 32;
1259 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1260 } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
1261 #ifdef WITH_UDPFROMTO
1262 RDEBUG2("src_ipaddr = %s", strvalue);
1263 c->src_ipaddr.af = AF_INET;
1264 c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1265 c->src_ipaddr.prefix = 32;
1266 cp = cf_pair_alloc(c->cs, "src_ipaddr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1268 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
1274 case PW_TYPE_IPV6_ADDR:
1275 if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
1276 c->ipaddr.af = AF_INET6;
1277 c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1278 c->ipaddr.prefix = 128;
1279 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1280 } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
1281 #ifdef WITH_UDPFROMTO
1282 c->src_ipaddr.af = AF_INET6;
1283 c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1284 c->src_ipaddr.prefix = 128;
1285 cp = cf_pair_alloc(c->cs, "src_addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1287 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
1293 case PW_TYPE_IPV4_PREFIX:
1294 if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
1295 c->ipaddr.af = AF_INET;
1296 memcpy(&c->ipaddr.ipaddr.ip4addr, &vp->vp_ipv4prefix[2],
1297 sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
1298 fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
1299 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1304 case PW_TYPE_IPV6_PREFIX:
1305 if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
1306 c->ipaddr.af = AF_INET6;
1307 memcpy(&c->ipaddr.ipaddr.ip6addr, &vp->vp_ipv6prefix[2],
1308 sizeof(c->ipaddr.ipaddr.ip6addr));
1309 fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
1310 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1315 case PW_TYPE_STRING:
1317 CONF_PARSER const *parse;
1320 * Cache pointer to CONF_PAIR buffer in RADCLIENT struct
1322 p = (char **) ((char *) c + dynamic_config[i].offset);
1323 if (*p) TALLOC_FREE(*p);
1324 if (!vp->vp_strvalue[0]) break;
1327 * We could reuse the CONF_PAIR buff, this just keeps things
1328 * consistent between client_afrom_cs, and client_afrom_query.
1330 *p = talloc_strdup(c, strvalue);
1333 * This is fairly nasty... In order to figure out the CONF_PAIR
1334 * name associated with a field, find offsets that match between
1335 * the dynamic_config CONF_PARSER table, and the client_config
1336 * CONF_PARSER table.
1338 * This is so that things that expect to find CONF_PAIRs in the
1339 * client CONF_SECTION for fields like 'nas_type' can.
1341 for (parse = client_config; parse->name; parse++) {
1342 if (parse->offset == dynamic_config[i].offset) break;
1346 cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
1350 case PW_TYPE_BOOLEAN:
1352 CONF_PARSER const *parse;
1354 pi = (int *) ((bool *) ((char *) c + dynamic_config[i].offset));
1355 *pi = vp->vp_integer;
1358 * Same nastiness as above.
1360 for (parse = client_config; parse->name; parse++) {
1361 if (parse->offset == dynamic_config[i].offset) break;
1365 cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
1374 RERROR("Error creating equivalent conf pair for %s", vp->da->name);
1378 if (cf_pair_attr_type(cp) == T_SINGLE_QUOTED_STRING) {
1379 RDEBUG2("%s = '%s'", cf_pair_attr(cp), cf_pair_value(cp));
1381 RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
1383 cf_pair_add(c->cs, cp);
1388 fr_cursor_first(&cursor);
1389 vp = fr_cursor_remove(&cursor);
1394 value = vp_aprints_value(vp, vp, '\'');
1396 ERROR("Failed stringifying value of &control:%s", vp->da->name);
1400 if (vp->da->type == PW_TYPE_STRING) {
1401 RDEBUG2("%s = '%s'", vp->da->name, value);
1402 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
1403 T_BARE_WORD, T_SINGLE_QUOTED_STRING);
1405 RDEBUG2("%s = %s", vp->da->name, value);
1406 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
1407 T_BARE_WORD, T_BARE_WORD);
1409 cf_pair_add(c->cs, cp);
1412 } while ((vp = fr_cursor_remove(&cursor)));
1416 if (c->ipaddr.af == AF_UNSPEC) {
1417 RERROR("Cannot add client %s: No IP address was specified.",
1418 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1427 * Need to apply the same mask as we set for the client
1428 * else clients created with FreeRADIUS-Client-IPv6-Prefix
1429 * or FreeRADIUS-Client-IPv4-Prefix will fail this check.
1431 addr = request->packet->src_ipaddr;
1432 fr_ipaddr_mask(&addr, c->ipaddr.prefix);
1433 if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
1436 RERROR("Cannot add client %s: Not in specified subnet %s/%i",
1437 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
1438 ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)), c->ipaddr.prefix);
1443 if (!c->secret || !*c->secret) {
1444 RERROR("Cannot add client %s: No secret was specified",
1445 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1449 if (!client_add_dynamic(clients, request->client, c)) {
1453 if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
1454 RERROR("Cannot add client %s: Client IP and src address are different IP version",
1455 ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
1464 * Read a client definition from the given filename.
1466 RADCLIENT *client_read(char const *filename, int in_server, int flag)
1473 if (!filename) return NULL;
1475 cs = cf_section_alloc(NULL, "main", NULL);
1476 if (!cs) return NULL;
1478 if (cf_file_read(cs, filename) < 0) {
1483 cs = cf_section_sub_find(cs, "client");
1485 ERROR("No \"client\" section found in client file");
1489 c = client_afrom_cs(cs, cs, in_server, false);
1490 if (!c) return NULL;
1492 p = strrchr(filename, FR_DIR_SEP);
1499 if (!flag) return c;
1502 * Additional validations
1504 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1505 if (strcmp(p, buffer) != 0) {
1506 ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);