"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/main/client.c" (10 Jun 2021, 41237 Bytes) of package /linux/misc/freeradius-server-3.0.23.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "client.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.22_vs_3.0.23.

    1 /*
    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.
    6  *
    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.
   11  *
   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
   15  */
   16 
   17 /**
   18  * $Id: d717e38bfb35293471a2c97ea526b4cda4532e0b $
   19  * @file main/client.c
   20  * @brief Manage clients allowed to communicate with the server.
   21  *
   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>
   26  */
   27 RCSID("$Id: d717e38bfb35293471a2c97ea526b4cda4532e0b $")
   28 
   29 #include <freeradius-devel/radiusd.h>
   30 #include <freeradius-devel/rad_assert.h>
   31 
   32 #include <sys/stat.h>
   33 
   34 #include <ctype.h>
   35 #include <fcntl.h>
   36 
   37 #ifdef WITH_DYNAMIC_CLIENTS
   38 #ifdef HAVE_DIRENT_H
   39 #include <dirent.h>
   40 #endif
   41 #endif
   42 
   43 struct radclient_list {
   44     char const  *name;  /* name of this list */
   45     char const  *server; /* virtual server associated with this client list */
   46 
   47     /*
   48      *  FIXME: One set of trees for IPv4, and another for IPv6?
   49      */
   50     rbtree_t    *trees[129]; /* for 0..128, inclusive. */
   51     uint32_t        min_prefix;
   52 
   53     bool        parsed;
   54 };
   55 
   56 
   57 #ifdef WITH_STATS
   58 static rbtree_t     *tree_num = NULL;     /* client numbers 0..N */
   59 static int      tree_num_max = 0;
   60 #endif
   61 static RADCLIENT_LIST   *root_clients = NULL;
   62 
   63 /*
   64  *  Callback for freeing a client.
   65  */
   66 void client_free(RADCLIENT *client)
   67 {
   68     if (!client) return;
   69 
   70     talloc_free(client);
   71 }
   72 
   73 /*
   74  *  Callback for comparing two clients.
   75  */
   76 static int client_ipaddr_cmp(void const *one, void const *two)
   77 {
   78     RADCLIENT const *a = one;
   79     RADCLIENT const *b = two;
   80 #ifndef WITH_TCP
   81 
   82     return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
   83 #else
   84     int rcode;
   85 
   86     rcode = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
   87     if (rcode != 0) return rcode;
   88 
   89     /*
   90      *  Wildcard match
   91      */
   92     if ((a->proto == IPPROTO_IP) ||
   93         (b->proto == IPPROTO_IP)) return 0;
   94 
   95     return (a->proto - b->proto);
   96 #endif
   97 }
   98 
   99 #ifdef WITH_STATS
  100 static int client_num_cmp(void const *one, void const *two)
  101 {
  102     RADCLIENT const *a = one;
  103     RADCLIENT const *b = two;
  104 
  105     return (a->number - b->number);
  106 }
  107 #endif
  108 
  109 /*
  110  *  Free a RADCLIENT list.
  111  */
  112 void client_list_free(RADCLIENT_LIST *clients)
  113 {
  114     int i;
  115 
  116     if (!clients) clients = root_clients;
  117     if (!clients) return;   /* Clients may not have been initialised yet */
  118 
  119     for (i = 0; i <= 128; i++) {
  120         if (clients->trees[i]) rbtree_free(clients->trees[i]);
  121         clients->trees[i] = NULL;
  122     }
  123 
  124     if (clients == root_clients) {
  125 #ifdef WITH_STATS
  126         if (tree_num) rbtree_free(tree_num);
  127         tree_num = NULL;
  128         tree_num_max = 0;
  129 #endif
  130         root_clients = NULL;
  131     }
  132 
  133 #ifdef WITH_DYNAMIC_CLIENTS
  134     /*
  135      *  FIXME: No fr_fifo_delete()
  136      */
  137 #endif
  138 
  139     talloc_free(clients);
  140 }
  141 
  142 /*
  143  *  Return a new, initialized, set of clients.
  144  */
  145 RADCLIENT_LIST *client_list_init(CONF_SECTION *cs)
  146 {
  147     RADCLIENT_LIST *clients = talloc_zero(cs, RADCLIENT_LIST);
  148 
  149     if (!clients) return NULL;
  150 
  151     clients->min_prefix = 128;
  152 
  153     /*
  154      *  Associate the "clients" list with the virtual server.
  155      */
  156     if (cs && (cf_data_add(cs, "clients", clients, NULL) < 0)) {
  157         ERROR("Failed to associate client list with section %s\n", cf_section_name1(cs));
  158         client_list_free(clients);
  159         return false;
  160     }
  161 
  162     return clients;
  163 }
  164 
  165 /** Add a client to a RADCLIENT_LIST
  166  *
  167  * @param clients list to add client to, may be NULL if global client list is being used.
  168  * @param client to add.
  169  * @return true on success, false on failure.
  170  */
  171 bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
  172 {
  173     RADCLIENT *old;
  174     char buffer[INET6_ADDRSTRLEN + 3];
  175 
  176     if (!client) return false;
  177 
  178     /*
  179      *  Initialize the global list, if not done already.
  180      */
  181     if (!root_clients) {
  182         root_clients = client_list_init(NULL);
  183         if (!root_clients) {
  184             ERROR("Cannot add client - failed creating client list");
  185             return false;
  186         }
  187     }
  188 
  189     /*
  190      *  Hack to fixup wildcard clients
  191      *
  192      *  If the IP is all zeros, with a 32 or 128 bit netmask
  193      *  assume the user meant to configure 0.0.0.0/0 instead
  194      *  of 0.0.0.0/32 - which would require the src IP of
  195      *  the client to be all zeros.
  196      */
  197     if (fr_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
  198     case AF_INET:
  199         if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
  200         break;
  201 
  202     case AF_INET6:
  203         if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
  204         break;
  205 
  206     default:
  207         rad_assert(0);
  208     }
  209 
  210     fr_ntop(buffer, sizeof(buffer), &client->ipaddr);
  211     DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
  212 
  213     /*
  214      *  If the client also defines a server, do that now.
  215      */
  216     if (client->defines_coa_server) if (!realm_home_server_add(client->coa_server)) return false;
  217 
  218     /*
  219      *  If there's no client list, BUT there's a virtual
  220      *  server, try to add the client to the appropriate
  221      *  "clients" section for that virtual server.
  222      */
  223     if (!clients && client->server) {
  224         CONF_SECTION *cs;
  225         CONF_SECTION *subcs;
  226         CONF_PAIR *cp;
  227         char const *section_name;
  228 
  229         cs = cf_section_sub_find_name2(main_config.config, "server", client->server);
  230         if (!cs) {
  231             ERROR("Cannot add client - virtual server %s does not exist", client->server);
  232             return false;
  233         }
  234 
  235         /*
  236          *  If this server has no "listen" section, add the clients
  237          *  to the global client list.
  238          */
  239         subcs = cf_section_sub_find(cs, "listen");
  240         if (!subcs) {
  241             DEBUG("No 'listen' section in virtual server %s.  Adding client to global client list",
  242                   client->server);
  243             goto check_list;
  244         }
  245 
  246         cp = cf_pair_find(subcs, "clients");
  247         if (!cp) {
  248             DEBUG("No 'clients' configuration item in first listener of virtual server %s.  Adding client to global client list",
  249                   client->server);
  250             goto check_list;
  251         }
  252 
  253         /*
  254          *  Duplicate the lookup logic in common_socket_parse()
  255          *
  256          *  Explicit list given: use it.
  257          */
  258         section_name = cf_pair_value(cp);
  259         if (!section_name) goto check_list;
  260 
  261         subcs = cf_section_sub_find_name2(main_config.config, "clients", section_name);
  262         if (!subcs) {
  263             subcs = cf_section_find(section_name);
  264         }
  265         if (!subcs) {
  266             cf_log_err_cs(cs,
  267                    "Failed to find clients %s {...}",
  268                    section_name);
  269             return false;
  270         }
  271 
  272         DEBUG("Adding client to client list %s", section_name);
  273 
  274         /*
  275          *  If the client list already exists, use that.
  276          *  Otherwise, create a new client list.
  277          *
  278          *  @todo - add the client to _all_ listeners?
  279          */
  280         clients = cf_data_find(subcs, "clients");
  281         if (clients) goto check_list;
  282 
  283         clients = client_list_init(subcs);
  284         if (!clients) {
  285             ERROR("Cannot add client - failed creating client list %s for server %s", section_name,
  286                   client->server);
  287             return false;
  288         }
  289     }
  290 
  291 check_list:
  292     if (!clients) clients = root_clients;
  293     client->list = clients;
  294 
  295     /*
  296      *  Create a tree for it.
  297      */
  298     if (!clients->trees[client->ipaddr.prefix]) {
  299         clients->trees[client->ipaddr.prefix] = rbtree_create(clients, client_ipaddr_cmp, NULL, 0);
  300         if (!clients->trees[client->ipaddr.prefix]) {
  301             return false;
  302         }
  303     }
  304 
  305 #define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
  306 
  307     /*
  308      *  Cannot insert the same client twice.
  309      */
  310     old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client);
  311     if (old) {
  312         /*
  313          *  If it's a complete duplicate, then free the new
  314          *  one, and return "OK".
  315          */
  316         if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) &&
  317             (old->ipaddr.prefix == client->ipaddr.prefix) &&
  318             namecmp(longname) && namecmp(secret) &&
  319             namecmp(shortname) && namecmp(nas_type) &&
  320             namecmp(login) && namecmp(password) && namecmp(server) &&
  321 #ifdef WITH_DYNAMIC_CLIENTS
  322             (old->lifetime == client->lifetime) &&
  323             namecmp(client_server) &&
  324 #endif
  325 #ifdef WITH_COA
  326             namecmp(coa_name) &&
  327             (old->coa_server == client->coa_server) &&
  328             (old->coa_pool == client->coa_pool) &&
  329 #endif
  330             (old->message_authenticator == client->message_authenticator)) {
  331             WARN("Ignoring duplicate client %s", client->longname);
  332             client_free(client);
  333             return true;
  334         }
  335 
  336         ERROR("Failed to add duplicate client %s", client->shortname);
  337         return false;
  338     }
  339 #undef namecmp
  340 
  341     /*
  342      *  Other error adding client: likely is fatal.
  343      */
  344     if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) {
  345         return false;
  346     }
  347 
  348 #ifdef WITH_STATS
  349     if (!tree_num) {
  350         tree_num = rbtree_create(clients, client_num_cmp, NULL, 0);
  351     }
  352 
  353 #ifdef WITH_DYNAMIC_CLIENTS
  354     /*
  355      *  More catching of clients added by rlm_sql.
  356      *
  357      *  The sql modules sets the dynamic flag BEFORE calling
  358      *  us.  The client_afrom_request() function sets it AFTER
  359      *  calling us.
  360      */
  361     if (client->dynamic && (client->lifetime == 0)) {
  362         RADCLIENT *network;
  363 
  364         /*
  365          *  If there IS an enclosing network,
  366          *  inherit the lifetime from it.
  367          */
  368         network = client_find(clients, &client->ipaddr, client->proto);
  369         if (network) {
  370             client->lifetime = network->lifetime;
  371         }
  372     }
  373 #endif
  374 
  375     client->number = tree_num_max;
  376     tree_num_max++;
  377     if (tree_num) rbtree_insert(tree_num, client);
  378 #endif
  379 
  380     if (client->ipaddr.prefix < clients->min_prefix) {
  381         clients->min_prefix = client->ipaddr.prefix;
  382     }
  383 
  384     (void) talloc_steal(clients, client); /* reparent it */
  385 
  386     return true;
  387 }
  388 
  389 
  390 #ifdef WITH_DYNAMIC_CLIENTS
  391 void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
  392 {
  393     if (!client) return;
  394 
  395     if (!clients) clients = root_clients;
  396 
  397     if (!client->dynamic) return;
  398 
  399     rad_assert(client->ipaddr.prefix <= 128);
  400 
  401 #ifdef WITH_STATS
  402     rbtree_deletebydata(tree_num, client);
  403 #endif
  404     rbtree_deletebydata(clients->trees[client->ipaddr.prefix], client);
  405 }
  406 #endif
  407 
  408 #ifdef WITH_STATS
  409 /*
  410  *  Find a client in the RADCLIENTS list by number.
  411  *  This is a support function for the statistics code.
  412  */
  413 RADCLIENT *client_findbynumber(RADCLIENT_LIST const *clients, int number)
  414 {
  415     if (!clients) clients = root_clients;
  416 
  417     if (!clients) return NULL;
  418 
  419     if (number >= tree_num_max) return NULL;
  420 
  421     if (tree_num) {
  422         RADCLIENT myclient;
  423 
  424         myclient.number = number;
  425 
  426         return rbtree_finddata(tree_num, &myclient);
  427     }
  428 
  429     return NULL;
  430 }
  431 #else
  432 RADCLIENT *client_findbynumber(UNUSED const RADCLIENT_LIST *clients, UNUSED int number)
  433 {
  434     return NULL;
  435 }
  436 #endif
  437 
  438 
  439 /*
  440  *  Find a client in the RADCLIENTS list.
  441  */
  442 RADCLIENT *client_find(RADCLIENT_LIST const *clients, fr_ipaddr_t const *ipaddr, int proto)
  443 {
  444   int32_t i, max_prefix;
  445     RADCLIENT myclient;
  446 
  447     if (!clients) clients = root_clients;
  448 
  449     if (!clients || !ipaddr) return NULL;
  450 
  451     switch (ipaddr->af) {
  452     case AF_INET:
  453         max_prefix = 32;
  454         break;
  455 
  456     case AF_INET6:
  457         max_prefix = 128;
  458         break;
  459 
  460     default :
  461         return NULL;
  462     }
  463 
  464     for (i = max_prefix; i >= (int32_t) clients->min_prefix; i--) {
  465         void *data;
  466 
  467         myclient.ipaddr = *ipaddr;
  468         myclient.proto = proto;
  469         fr_ipaddr_mask(&myclient.ipaddr, i);
  470 
  471         if (!clients->trees[i]) continue;
  472 
  473         data = rbtree_finddata(clients->trees[i], &myclient);
  474         if (data) return data;
  475     }
  476 
  477     return NULL;
  478 }
  479 
  480 /*
  481  *  Old wrapper for client_find
  482  */
  483 RADCLIENT *client_find_old(fr_ipaddr_t const *ipaddr)
  484 {
  485     return client_find(root_clients, ipaddr, IPPROTO_UDP);
  486 }
  487 
  488 static fr_ipaddr_t cl_ipaddr;
  489 static uint32_t cl_netmask;
  490 static char const *cl_srcipaddr = NULL;
  491 static char const *hs_proto = NULL;
  492 
  493 #ifdef WITH_TCP
  494 static CONF_PARSER limit_config[] = {
  495     { "max_connections", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.max_connections),   "16" },
  496 
  497     { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.lifetime),   "0" },
  498 
  499     { "idle_timeout", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, limit.idle_timeout), "30" },
  500 
  501     CONF_PARSER_TERMINATOR
  502 };
  503 #endif
  504 
  505 static const CONF_PARSER client_config[] = {
  506     { "ipaddr", FR_CONF_POINTER(PW_TYPE_COMBO_IP_PREFIX, &cl_ipaddr), NULL },
  507     { "ipv4addr", FR_CONF_POINTER(PW_TYPE_IPV4_PREFIX, &cl_ipaddr), NULL },
  508     { "ipv6addr", FR_CONF_POINTER(PW_TYPE_IPV6_PREFIX, &cl_ipaddr), NULL },
  509 
  510     { "netmask", FR_CONF_POINTER(PW_TYPE_INTEGER, &cl_netmask), NULL },
  511 
  512     { "src_ipaddr", FR_CONF_POINTER(PW_TYPE_STRING, &cl_srcipaddr), NULL },
  513 
  514     { "require_message_authenticator",  FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), "no" },
  515 
  516     { "secret", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_SECRET, RADCLIENT, secret), NULL },
  517     { "shortname", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), NULL },
  518 
  519     { "nas_type", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
  520 
  521     { "login", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, login), NULL },
  522     { "password", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, password), NULL },
  523     { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
  524     { "response_window", FR_CONF_OFFSET(PW_TYPE_TIMEVAL, RADCLIENT, response_window), NULL },
  525 
  526 #ifdef WITH_TCP
  527     { "proto", FR_CONF_POINTER(PW_TYPE_STRING, &hs_proto), NULL },
  528     { "limit", FR_CONF_POINTER(PW_TYPE_SUBSECTION, NULL), (void const *) limit_config },
  529 #endif
  530 
  531 #ifdef WITH_DYNAMIC_CLIENTS
  532     { "dynamic_clients", FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, client_server), NULL },
  533     { "lifetime", FR_CONF_OFFSET(PW_TYPE_INTEGER, RADCLIENT, lifetime), NULL },
  534     { "rate_limit", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, rate_limit), NULL },
  535 #endif
  536 
  537     CONF_PARSER_TERMINATOR
  538 };
  539 
  540 /** Create the linked list of clients from the new configuration type
  541  *
  542  */
  543 #ifdef WITH_TLS
  544 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, bool tls_required)
  545 #else
  546 RADCLIENT_LIST *client_list_parse_section(CONF_SECTION *section, UNUSED bool tls_required)
  547 #endif
  548 {
  549     bool        global = false, in_server = false;
  550     CONF_SECTION    *cs;
  551     RADCLIENT   *c = NULL;
  552     RADCLIENT_LIST  *clients = NULL;
  553 
  554     /*
  555      *  Be forgiving.  If there's already a clients, return
  556      *  it.  Otherwise create a new one.
  557      */
  558     clients = cf_data_find(section, "clients");
  559     if (clients) {
  560         /*
  561          *  Modules are initialized before the listeners.
  562          *  Which means that we MIGHT have read clients
  563          *  from SQL before parsing this "clients"
  564          *  section.  So there may already be a clients
  565          *  list.
  566          *
  567          *  But the list isn't _our_ list that we parsed,
  568          *  so we still need to parse the clients here.
  569          */
  570         if (clients->parsed) return clients;        
  571     } else {
  572         clients = client_list_init(section);
  573         if (!clients) return NULL;
  574     }
  575 
  576     if (cf_top_section(section) == section) {
  577         global = true;
  578         clients->name = "global";
  579         clients->server = NULL;
  580     }
  581 
  582     if (strcmp("server", cf_section_name1(section)) == 0) {
  583         clients->name = NULL;
  584         clients->server = cf_section_name2(section);
  585         in_server = true;
  586     }
  587 
  588     for (cs = cf_subsection_find_next(section, NULL, "client");
  589          cs;
  590          cs = cf_subsection_find_next(section, cs, "client")) {
  591         c = client_afrom_cs(cs, cs, in_server, false);
  592         if (!c) {
  593         error:
  594             client_free(c);
  595             client_list_free(clients);
  596             return NULL;
  597         }
  598 
  599 #ifdef WITH_TLS
  600         /*
  601          *  TLS clients CANNOT use non-TLS listeners.
  602          *  non-TLS clients CANNOT use TLS listeners.
  603          */
  604         if (tls_required != c->tls_required) {
  605             cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener");
  606             goto error;
  607         }
  608 #endif
  609 
  610         /*
  611          *  FIXME: Add the client as data via cf_data_add,
  612          *  for migration issues.
  613          */
  614 
  615 #ifdef WITH_DYNAMIC_CLIENTS
  616 #ifdef HAVE_DIRENT_H
  617         if (c->client_server) {
  618             char const  *value;
  619             CONF_PAIR   *cp;
  620             DIR     *dir;
  621             struct dirent   *dp;
  622             struct stat stat_buf;
  623             char        buf2[2048];
  624 
  625             /*
  626              *  Find the directory where individual
  627              *  client definitions are stored.
  628              */
  629             cp = cf_pair_find(cs, "directory");
  630             if (!cp) goto add_client;
  631 
  632             value = cf_pair_value(cp);
  633             if (!value) {
  634                 cf_log_err_cs(cs, "The \"directory\" entry must not be empty");
  635                 goto error;
  636             }
  637 
  638             DEBUG("including dynamic clients in %s", value);
  639 
  640             dir = opendir(value);
  641             if (!dir) {
  642                 cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno));
  643                 goto error;
  644             }
  645 
  646             /*
  647              *  Read the directory, ignoring "." files.
  648              */
  649             while ((dp = readdir(dir)) != NULL) {
  650                 char const *p;
  651                 RADCLIENT *dc;
  652 
  653                 if (dp->d_name[0] == '.') continue;
  654 
  655                 /*
  656                  *  Check for valid characters
  657                  */
  658                 for (p = dp->d_name; *p != '\0'; p++) {
  659                     if (isalpha((int)*p) ||
  660                         isdigit((int)*p) ||
  661                         (*p == ':') ||
  662                         (*p == '.')) continue;
  663                     break;
  664                 }
  665                 if (*p != '\0') continue;
  666 
  667                 snprintf(buf2, sizeof(buf2), "%s/%s", value, dp->d_name);
  668 
  669                 if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue;
  670 
  671                 dc = client_read(buf2, in_server, true);
  672                 if (!dc) {
  673                     cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2);
  674                     closedir(dir);
  675                     goto error;
  676                 }
  677 
  678                 /*
  679                  *  Validate, and add to the list.
  680                  */
  681                 if (!client_add_dynamic(clients, c, dc)) {
  682                     closedir(dir);
  683                     goto error;
  684                 }
  685             } /* loop over the directory */
  686             closedir(dir);
  687         }
  688 #endif /* HAVE_DIRENT_H */
  689 
  690     add_client:
  691 #endif /* WITH_DYNAMIC_CLIENTS */
  692         if (!client_add(clients, c)) {
  693             cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs));
  694             goto error;
  695         }
  696 
  697     }
  698 
  699     /*
  700      *  Replace the global list of clients with the new one.
  701      *  The old one is still referenced from the original
  702      *  configuration, and will be freed when that is freed.
  703      */
  704     if (global) root_clients = clients;
  705 
  706     clients->parsed = true;
  707     return clients;
  708 }
  709 
  710 #ifdef WITH_DYNAMIC_CLIENTS
  711 /*
  712  *  We overload this structure a lot.
  713  */
  714 static const CONF_PARSER dynamic_config[] = {
  715     { "FreeRADIUS-Client-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, ipaddr), NULL },
  716     { "FreeRADIUS-Client-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, ipaddr), NULL },
  717     { "FreeRADIUS-Client-IP-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV4_PREFIX, RADCLIENT, ipaddr), NULL },
  718     { "FreeRADIUS-Client-IPv6-Prefix", FR_CONF_OFFSET(PW_TYPE_IPV6_PREFIX, RADCLIENT, ipaddr), NULL },
  719     { "FreeRADIUS-Client-Src-IP-Address", FR_CONF_OFFSET(PW_TYPE_IPV4_ADDR, RADCLIENT, src_ipaddr), NULL },
  720     { "FreeRADIUS-Client-Src-IPv6-Address", FR_CONF_OFFSET(PW_TYPE_IPV6_ADDR, RADCLIENT, src_ipaddr), NULL },
  721 
  722     { "FreeRADIUS-Client-Require-MA", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, RADCLIENT, message_authenticator), NULL },
  723 
  724     { "FreeRADIUS-Client-Secret",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, secret), "" },
  725     { "FreeRADIUS-Client-Shortname",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, shortname), "" },
  726     { "FreeRADIUS-Client-NAS-Type",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, nas_type), NULL },
  727     { "FreeRADIUS-Client-Virtual-Server",  FR_CONF_OFFSET(PW_TYPE_STRING, RADCLIENT, server), NULL },
  728 
  729     CONF_PARSER_TERMINATOR
  730 };
  731 
  732 /** Add a dynamic client
  733  *
  734  */
  735 bool client_add_dynamic(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c)
  736 {
  737     char buffer[128];
  738 
  739     /*
  740      *  No virtual server defined.  Inherit the parent's
  741      *  definition.
  742      */
  743     if (master->server && !c->server) {
  744         c->server = talloc_typed_strdup(c, master->server);
  745     }
  746 
  747     /*
  748      *  If the client network isn't global (not tied to a
  749      *  virtual server), then ensure that this clients server
  750      *  is the same as the enclosing networks virtual server.
  751      */
  752     if (master->server && (strcmp(master->server, c->server) != 0)) {
  753         ERROR("Cannot add client %s/%i: Virtual server %s is not the same as the virtual server for the network",
  754               ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->server);
  755 
  756         goto error;
  757     }
  758 
  759     if (!client_add(clients, c)) {
  760         ERROR("Cannot add client %s/%i: Internal error",
  761               ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
  762 
  763         goto error;
  764     }
  765 
  766     /*
  767      *  Initialize the remaining fields.
  768      */
  769     c->dynamic = true;
  770     c->lifetime = master->lifetime;
  771     c->created = time(NULL);
  772     c->longname = talloc_typed_strdup(c, c->shortname);
  773 
  774     if (rad_debug_lvl <= 2) {
  775         INFO("Adding client %s/%i",
  776              ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix);
  777     } else {
  778         INFO("Adding client %s/%i with shared secret \"%s\"",
  779              ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)), c->ipaddr.prefix, c->secret);
  780     }
  781     return true;
  782 
  783 error:
  784     client_free(c);
  785     return false;
  786 }
  787 
  788 /** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
  789  *
  790  * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
  791  *
  792  * @note Caller should free CONF_SECTION passed in as out, on error.
  793  *   Contents of that section will be in an undefined state.
  794  *
  795  * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
  796  *  (when this function is called recursively).
  797  *  Should be alloced with cf_section_alloc, or if there's a separate template section, the
  798  *  result of calling cf_section_dup on that section.
  799  * @param[in] map section.
  800  * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
  801  * @param[in] data to pass to func, usually a result pointer.
  802  * @return 0 on success else -1 on error.
  803  */
  804 int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
  805 {
  806     CONF_ITEM const *ci;
  807 
  808     for (ci = cf_item_find_next(map, NULL);
  809          ci != NULL;
  810          ci = cf_item_find_next(map, ci)) {
  811             CONF_PAIR const *cp;
  812             CONF_PAIR *old;
  813             char *value;
  814         char const *attr;
  815 
  816         /*
  817          *  Recursively process map subsection
  818          */
  819         if (cf_item_is_section(ci)) {
  820             CONF_SECTION *cs, *cc;
  821 
  822             cs = cf_item_to_section(ci);
  823             /*
  824              *  Use pre-existing section or alloc a new one
  825              */
  826             cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs));
  827             if (!cc) {
  828                 cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs));
  829                 cf_section_add(out, cc);
  830                 if (!cc) return -1;
  831             }
  832 
  833             if (client_map_section(cc, cs, func, data) < 0) return -1;
  834             continue;
  835         }
  836 
  837         cp = cf_item_to_pair(ci);
  838         attr = cf_pair_attr(cp);
  839 
  840         /*
  841          *  The callback can return 0 (success) and not provide a value
  842          *  in which case we skip the mapping pair.
  843          *
  844          *  Or return -1 in which case we error out.
  845          */
  846         if (func(&value, cp, data) < 0) {
  847             cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
  848             return -1;
  849         }
  850         if (!value) continue;
  851 
  852         /*
  853          *  Replace an existing CONF_PAIR
  854          */
  855         old = cf_pair_find(out, attr);
  856         if (old) {
  857             cf_pair_replace(out, old, value);
  858             talloc_free(value);
  859             continue;
  860         }
  861 
  862         /*
  863          *  ...or add a new CONF_PAIR
  864          */
  865         cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
  866         if (!cp) {
  867             cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
  868             talloc_free(value);
  869             return -1;
  870         }
  871         talloc_free(value);
  872         cf_item_add(out, cf_pair_to_item(cp));
  873     }
  874 
  875     return 0;
  876 }
  877 
  878 /** Allocate a new client from a config section
  879  *
  880  * @param ctx to allocate new clients in.
  881  * @param cs to process as a client.
  882  * @param in_server Whether the client should belong to a specific virtual server.
  883  * @param with_coa If true and coa_server or coa_pool aren't specified automatically,
  884  *  create a coa home_server section and add it to the client CONF_SECTION.
  885  * @return new RADCLIENT struct.
  886  */
  887 RADCLIENT *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
  888 {
  889     RADCLIENT   *c;
  890     char const  *name2;
  891 
  892     name2 = cf_section_name2(cs);
  893     if (!name2) {
  894         cf_log_err_cs(cs, "Missing client name");
  895         return NULL;
  896     }
  897 
  898     /*
  899      *  The size is fine.. Let's create the buffer
  900      */
  901     c = talloc_zero(ctx, RADCLIENT);
  902     c->cs = cs;
  903 
  904     memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
  905     cl_netmask = 255;
  906 
  907     if (cf_section_parse(cs, c, client_config) < 0) {
  908         cf_log_err_cs(cs, "Error parsing client section");
  909     error:
  910         client_free(c);
  911 #ifdef WITH_TCP
  912         hs_proto = NULL;
  913         cl_srcipaddr = NULL;
  914 #endif
  915 
  916         return NULL;
  917     }
  918 
  919     /*
  920      *  Global clients can set servers to use, per-server clients cannot.
  921      */
  922     if (in_server && c->server) {
  923         cf_log_err_cs(cs, "Clients inside of an server section cannot point to a server");
  924         goto error;
  925     }
  926 
  927     /*
  928      *  Allow the old method to specify "netmask".  Just using "1.2.3.4" means it's a /32.
  929      */
  930     if (cl_netmask != 255) {
  931         if ((cl_ipaddr.prefix != cl_netmask) &&
  932             (((cl_ipaddr.af == AF_INET) && cl_ipaddr.prefix != 32) ||
  933              ((cl_ipaddr.af == AF_INET6) && cl_ipaddr.prefix != 128))) {
  934             cf_log_err_cs(cs, "Clients cannot use 'ipaddr/mask' and 'netmask' at the same time.");
  935             goto error;
  936         }
  937 
  938         cl_ipaddr.prefix = cl_netmask;
  939     }
  940 
  941     /*
  942      *  Newer style client definitions with either ipaddr or ipaddr6
  943      *  config items.
  944      */
  945     if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
  946         char buffer[128];
  947 
  948         /*
  949          *  Sets ipv4/ipv6 address and prefix.
  950          */
  951         c->ipaddr = cl_ipaddr;
  952 
  953         /*
  954          *  Set the long name to be the result of a reverse lookup on the IP address.
  955          */
  956         ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
  957         c->longname = talloc_typed_strdup(c, buffer);
  958 
  959         /*
  960          *  Set the short name to the name2.
  961          */
  962         if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
  963     /*
  964      *  No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
  965      */
  966     } else {
  967         WARN("No 'ipaddr' or 'ipv4addr' or 'ipv6addr' field found in client %s. "
  968              "Please fix your configuration", name2);
  969         WARN("Support for old-style clients will be removed in a future release");
  970 
  971 #ifdef WITH_TCP
  972         if (cf_pair_find(cs, "proto") != NULL) {
  973             cf_log_err_cs(cs, "Cannot use 'proto' inside of old-style client definition");
  974             goto error;
  975         }
  976 #endif
  977         if (fr_pton(&c->ipaddr, name2, -1, AF_UNSPEC, true) < 0) {
  978             cf_log_err_cs(cs, "Failed parsing client name \"%s\" as ip address or hostname: %s", name2,
  979                       fr_strerror());
  980             goto error;
  981         }
  982 
  983         c->longname = talloc_typed_strdup(c, name2);
  984         if (!c->shortname) c->shortname = talloc_typed_strdup(c, c->longname);
  985     }
  986 
  987     c->proto = IPPROTO_UDP;
  988     if (hs_proto) {
  989         if (strcmp(hs_proto, "udp") == 0) {
  990             hs_proto = NULL;
  991 
  992 #ifdef WITH_TCP
  993         } else if (strcmp(hs_proto, "tcp") == 0) {
  994             hs_proto = NULL;
  995             c->proto = IPPROTO_TCP;
  996 #  ifdef WITH_TLS
  997         } else if (strcmp(hs_proto, "tls") == 0) {
  998             hs_proto = NULL;
  999             c->proto = IPPROTO_TCP;
 1000             c->tls_required = true;
 1001 
 1002         } else if (strcmp(hs_proto, "radsec") == 0) {
 1003             hs_proto = NULL;
 1004             c->proto = IPPROTO_TCP;
 1005             c->tls_required = true;
 1006 #  endif
 1007         } else if (strcmp(hs_proto, "*") == 0) {
 1008             hs_proto = NULL;
 1009             c->proto = IPPROTO_IP; /* fake for dual */
 1010 #endif
 1011         } else {
 1012             cf_log_err_cs(cs, "Unknown proto \"%s\".", hs_proto);
 1013             goto error;
 1014         }
 1015     }
 1016 
 1017     /*
 1018      *  If a src_ipaddr is specified, when we send the return packet
 1019      *  we will use this address instead of the src from the
 1020      *  request.
 1021      */
 1022     if (cl_srcipaddr) {
 1023 #ifdef WITH_UDPFROMTO
 1024         switch (c->ipaddr.af) {
 1025         case AF_INET:
 1026             if (fr_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
 1027                 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
 1028                 goto error;
 1029             }
 1030             break;
 1031 
 1032         case AF_INET6:
 1033             if (fr_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false) < 0) {
 1034                 cf_log_err_cs(cs, "Failed parsing src_ipaddr: %s", fr_strerror());
 1035                 goto error;
 1036             }
 1037             break;
 1038         default:
 1039             rad_assert(0);
 1040         }
 1041 #else
 1042         WARN("Server not built with udpfromto, ignoring client src_ipaddr");
 1043 #endif
 1044         cl_srcipaddr = NULL;
 1045     }
 1046 
 1047     /*
 1048      *  A response_window of zero is OK, and means that it's
 1049      *  ignored by the rest of the server timers.
 1050      */
 1051     if (timerisset(&c->response_window)) {
 1052         FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, >=, 0, 1000);
 1053         FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, 60, 0);
 1054         FR_TIMEVAL_BOUND_CHECK("response_window", &c->response_window, <=, main_config.max_request_time, 0);
 1055     }
 1056 
 1057 #ifdef WITH_DYNAMIC_CLIENTS
 1058     if (c->client_server) {
 1059         c->secret = talloc_typed_strdup(c, "testing123");
 1060 
 1061         if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix == 32)) ||
 1062             ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix == 128))) {
 1063             cf_log_err_cs(cs, "Dynamic clients MUST be a network, not a single IP address");
 1064             goto error;
 1065         }
 1066 
 1067         return c;
 1068     }
 1069 #endif
 1070 
 1071     if (!c->secret || (c->secret[0] == '\0')) {
 1072 #ifdef WITH_DHCP
 1073         char const *value = NULL;
 1074         CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
 1075 
 1076         if (cp) value = cf_pair_value(cp);
 1077 
 1078         /*
 1079          *  Secrets aren't needed for DHCP.
 1080          */
 1081         if (value && (strcmp(value, "yes") == 0)) return c;
 1082 #endif
 1083 
 1084 #ifdef WITH_TLS
 1085         /*
 1086          *  If the client is TLS only, the secret can be
 1087          *  omitted.  When omitted, it's hard-coded to
 1088          *  "radsec".  See RFC 6614.
 1089          */
 1090         if (c->tls_required) {
 1091             c->secret = talloc_typed_strdup(cs, "radsec");
 1092         } else
 1093 #endif
 1094 
 1095         {
 1096             cf_log_err_cs(cs, "secret must be at least 1 character long");
 1097             goto error;
 1098         }
 1099     }
 1100 
 1101 #ifdef WITH_COA
 1102     {
 1103         CONF_PAIR *cp;
 1104 
 1105         /*
 1106          *  Point the client to the home server pool, OR to the
 1107          *  home server.  This gets around the problem of figuring
 1108          *  out which port to use.
 1109          */
 1110         cp = cf_pair_find(cs, "coa_server");
 1111         if (cp) {
 1112             c->coa_name = cf_pair_value(cp);
 1113             c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
 1114             if (!c->coa_pool) {
 1115                 c->coa_server = home_server_byname(c->coa_name, HOME_TYPE_COA);
 1116             }
 1117             if (!c->coa_pool && !c->coa_server) {
 1118                 cf_log_err_cs(cs, "No such home_server or home_server_pool \"%s\"", c->coa_name);
 1119                 goto error;
 1120             }
 1121         /*
 1122          *  If we're implicitly adding a CoA home server for
 1123          *  every client, or there's a server subsection,
 1124          *  create a home server CONF_SECTION and then parse
 1125          *  it into a home_server_t.
 1126          */
 1127         } else if (with_coa || cf_section_sub_find(cs, "coa_server")) {
 1128             CONF_SECTION *server;
 1129             home_server_t *home;
 1130 
 1131             if (((c->ipaddr.af == AF_INET) && (c->ipaddr.prefix != 32)) ||
 1132                 ((c->ipaddr.af == AF_INET6) && (c->ipaddr.prefix != 128))) {
 1133                 WARN("Subnets not supported for home servers.  "
 1134                      "Not adding client %s as home_server", name2);
 1135                 goto done_coa;
 1136             }
 1137 
 1138             server = home_server_cs_afrom_client(cs);
 1139             if (!server) goto error;
 1140 
 1141             /*
 1142              *  Must be allocated in the context of the client,
 1143              *  as allocating using the context of the
 1144              *  realm_config_t without a mutex, by one of the
 1145              *  workers, would be bad.
 1146              */
 1147             home = home_server_afrom_cs(NULL, NULL, server);
 1148             if (!home) {
 1149                 talloc_free(server);
 1150                 goto error;
 1151             }
 1152 
 1153             rad_assert(home->type == HOME_TYPE_COA);
 1154 
 1155             c->coa_server = home;
 1156             c->defines_coa_server = true;
 1157         }
 1158     }
 1159 done_coa:
 1160 #endif
 1161 
 1162 #ifdef WITH_TCP
 1163     if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
 1164         if ((c->limit.idle_timeout > 0) && (c->limit.idle_timeout < 5))
 1165             c->limit.idle_timeout = 5;
 1166         if ((c->limit.lifetime > 0) && (c->limit.lifetime < 5))
 1167             c->limit.lifetime = 5;
 1168         if ((c->limit.lifetime > 0) && (c->limit.idle_timeout > c->limit.lifetime))
 1169             c->limit.idle_timeout = 0;
 1170     }
 1171 #endif
 1172 
 1173     return c;
 1174 }
 1175 
 1176 /** Add a client from a result set (SQL)
 1177  *
 1178  * @todo This function should die. SQL should use client_afrom_cs.
 1179  *
 1180  * @param ctx Talloc context.
 1181  * @param identifier Client IP Address / IPv4 subnet / IPv6 subnet / FQDN.
 1182  * @param secret Client secret.
 1183  * @param shortname Client friendly name.
 1184  * @param type NAS-Type.
 1185  * @param server Virtual-Server to associate clients with.
 1186  * @param require_ma If true all packets from client must include a message-authenticator.
 1187  * @return The new client, or NULL on error.
 1188  */
 1189 RADCLIENT *client_afrom_query(TALLOC_CTX *ctx, char const *identifier, char const *secret,
 1190                   char const *shortname, char const *type, char const *server, bool require_ma)
 1191 {
 1192     RADCLIENT *c;
 1193     char buffer[128];
 1194 
 1195     c = talloc_zero(ctx, RADCLIENT);
 1196 
 1197     if (fr_pton(&c->ipaddr, identifier, -1, AF_UNSPEC, true) < 0) {
 1198         ERROR("%s", fr_strerror());
 1199         talloc_free(c);
 1200 
 1201         return NULL;
 1202     }
 1203 
 1204 #ifdef WITH_DYNAMIC_CLIENTS
 1205     c->dynamic = true;
 1206 #endif
 1207     ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
 1208     c->longname = talloc_typed_strdup(c, buffer);
 1209 
 1210     /*
 1211      *  Other values (secret, shortname, nas_type, virtual_server)
 1212      */
 1213     c->secret = talloc_typed_strdup(c, secret);
 1214     if (shortname) c->shortname = talloc_typed_strdup(c, shortname);
 1215     if (type) c->nas_type = talloc_typed_strdup(c, type);
 1216     if (server) c->server = talloc_typed_strdup(c, server);
 1217     c->message_authenticator = require_ma;
 1218 
 1219     return c;
 1220 }
 1221 
 1222 /** Create a new client, consuming all attributes in the control list of the request
 1223  *
 1224  * @param clients list to add new client to.
 1225  * @param request Fake request.
 1226  * @return a new client on success, else NULL on error.
 1227  */
 1228 RADCLIENT *client_afrom_request(RADCLIENT_LIST *clients, REQUEST *request)
 1229 {
 1230     static int  cnt;
 1231     int     i, *pi;
 1232     char        **p;
 1233     RADCLIENT   *c;
 1234     CONF_PAIR   *cp = NULL;
 1235     char        buffer[128];
 1236 
 1237     vp_cursor_t cursor;
 1238     VALUE_PAIR  *vp = NULL;
 1239 
 1240     if (!clients || !request) return NULL;
 1241 
 1242     /*
 1243      *  Hack for the "dynamic_clients" module.
 1244      */
 1245     if (request->client->dynamic) {
 1246         c = request->client;
 1247         goto validate;
 1248     }
 1249 
 1250     snprintf(buffer, sizeof(buffer), "dynamic%i", cnt++);
 1251 
 1252     c = talloc_zero(clients, RADCLIENT);
 1253     c->cs = cf_section_alloc(NULL, "client", buffer);
 1254     talloc_steal(c, c->cs);
 1255     c->ipaddr.af = AF_UNSPEC;
 1256     c->src_ipaddr.af = AF_UNSPEC;
 1257 
 1258     fr_cursor_init(&cursor, &request->config);
 1259 
 1260     RDEBUG2("Converting control list to client fields");
 1261     RINDENT();
 1262     for (i = 0; dynamic_config[i].name != NULL; i++) {
 1263         DICT_ATTR const *da;
 1264         char *strvalue = NULL;
 1265 
 1266         da = dict_attrbyname(dynamic_config[i].name);
 1267         if (!da) {
 1268             RERROR("Cannot add client %s: attribute \"%s\" is not in the dictionary",
 1269                    ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
 1270                    dynamic_config[i].name);
 1271         error:
 1272             REXDENT();
 1273             talloc_free(vp);
 1274             client_free(c);
 1275             return NULL;
 1276         }
 1277 
 1278         fr_cursor_first(&cursor);
 1279         if (!fr_cursor_next_by_da(&cursor, da, TAG_ANY)) {
 1280             /*
 1281              *  Not required.  Skip it.
 1282              */
 1283             if (!dynamic_config[i].dflt) continue;
 1284 
 1285             RERROR("Cannot add client %s: Required attribute \"%s\" is missing",
 1286                    ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
 1287                    dynamic_config[i].name);
 1288             goto error;
 1289         }
 1290         vp = fr_cursor_remove(&cursor);
 1291 
 1292         /*
 1293          *  Freed at the same time as the vp.
 1294          */
 1295         strvalue = vp_aprints_value(vp, vp, '\'');
 1296 
 1297         switch (dynamic_config[i].type) {
 1298         case PW_TYPE_IPV4_ADDR:
 1299             if (da->attr == PW_FREERADIUS_CLIENT_IP_ADDRESS) {
 1300                 c->ipaddr.af = AF_INET;
 1301                 c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
 1302                 c->ipaddr.prefix = 32;
 1303                 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1304             } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) {
 1305 #ifdef WITH_UDPFROMTO
 1306                 RDEBUG2("src_ipaddr = %s", strvalue);
 1307                 c->src_ipaddr.af = AF_INET;
 1308                 c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
 1309                 c->src_ipaddr.prefix = 32;
 1310                 cp = cf_pair_alloc(c->cs, "src_ipaddr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1311 #else
 1312                 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address");
 1313 #endif
 1314             }
 1315 
 1316             break;
 1317 
 1318         case PW_TYPE_IPV6_ADDR:
 1319             if (da->attr == PW_FREERADIUS_CLIENT_IPV6_ADDRESS) {
 1320                 c->ipaddr.af = AF_INET6;
 1321                 c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
 1322                 c->ipaddr.prefix = 128;
 1323                 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1324             } else if (da->attr == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) {
 1325 #ifdef WITH_UDPFROMTO
 1326                 c->src_ipaddr.af = AF_INET6;
 1327                 c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
 1328                 c->src_ipaddr.prefix = 128;
 1329                 cp = cf_pair_alloc(c->cs, "src_addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1330 #else
 1331                 RWARN("Server not built with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address");
 1332 #endif
 1333             }
 1334 
 1335             break;
 1336 
 1337         case PW_TYPE_IPV4_PREFIX:
 1338             if (da->attr == PW_FREERADIUS_CLIENT_IP_PREFIX) {
 1339                 c->ipaddr.af = AF_INET;
 1340                 memcpy(&c->ipaddr.ipaddr.ip4addr, &vp->vp_ipv4prefix[2],
 1341                        sizeof(c->ipaddr.ipaddr.ip4addr.s_addr));
 1342                 fr_ipaddr_mask(&c->ipaddr, (vp->vp_ipv4prefix[1] & 0x3f));
 1343                 cp = cf_pair_alloc(c->cs, "ipv4addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1344             }
 1345 
 1346             break;
 1347 
 1348         case PW_TYPE_IPV6_PREFIX:
 1349             if (da->attr == PW_FREERADIUS_CLIENT_IPV6_PREFIX) {
 1350                 c->ipaddr.af = AF_INET6;
 1351                 memcpy(&c->ipaddr.ipaddr.ip6addr, &vp->vp_ipv6prefix[2],
 1352                        sizeof(c->ipaddr.ipaddr.ip6addr));
 1353                 fr_ipaddr_mask(&c->ipaddr, vp->vp_ipv6prefix[1]);
 1354                 cp = cf_pair_alloc(c->cs, "ipv6addr", strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1355             }
 1356 
 1357             break;
 1358 
 1359         case PW_TYPE_STRING:
 1360         {
 1361             CONF_PARSER const *parse;
 1362 
 1363             /*
 1364              *  Cache pointer to CONF_PAIR buffer in RADCLIENT struct
 1365              */
 1366             p = (char **) ((char *) c + dynamic_config[i].offset);
 1367             if (*p) TALLOC_FREE(*p);
 1368             if (!vp->vp_strvalue[0]) break;
 1369 
 1370             /*
 1371              *  We could reuse the CONF_PAIR buff, this just keeps things
 1372              *  consistent between client_afrom_cs, and client_afrom_query.
 1373              */
 1374             *p = talloc_strdup(c, vp->vp_strvalue);
 1375 
 1376             /*
 1377              *  This is fairly nasty... In order to figure out the CONF_PAIR
 1378              *  name associated with a field, find offsets that match between
 1379              *  the dynamic_config CONF_PARSER table, and the client_config
 1380              *  CONF_PARSER table.
 1381              *
 1382              *  This is so that things that expect to find CONF_PAIRs in the
 1383              *  client CONF_SECTION for fields like 'nas_type' can.
 1384              */
 1385             for (parse = client_config; parse->name; parse++) {
 1386                 if (parse->offset == dynamic_config[i].offset) break;
 1387             }
 1388 
 1389             if (!parse) break;
 1390 
 1391             cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING);
 1392         }
 1393             break;
 1394 
 1395         case PW_TYPE_BOOLEAN:
 1396         {
 1397             CONF_PARSER const *parse;
 1398 
 1399             pi = (int *) ((bool *) ((char *) c + dynamic_config[i].offset));
 1400             *pi = vp->vp_integer;
 1401 
 1402             /*
 1403              *  Same nastiness as above.
 1404              */
 1405             for (parse = client_config; parse->name; parse++) {
 1406                 if (parse->offset == dynamic_config[i].offset) break;
 1407             }
 1408             if (!parse) break;
 1409 
 1410             cp = cf_pair_alloc(c->cs, parse->name, strvalue, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
 1411         }
 1412             break;
 1413 
 1414         default:
 1415             goto error;
 1416         }
 1417 
 1418         if (!cp) {
 1419             RERROR("Error creating equivalent conf pair for %s", vp->da->name);
 1420             goto error;
 1421         }
 1422 
 1423         if (cf_pair_attr_type(cp) == T_SINGLE_QUOTED_STRING) {
 1424             RDEBUG2("%s = '%s'", cf_pair_attr(cp), cf_pair_value(cp));
 1425         } else {
 1426             RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
 1427         }
 1428         cf_pair_add(c->cs, cp);
 1429 
 1430         talloc_free(vp);
 1431     }
 1432 
 1433     fr_cursor_first(&cursor);
 1434     vp = fr_cursor_remove(&cursor);
 1435     if (vp) {
 1436         do {
 1437             char *value;
 1438 
 1439             value = vp_aprints_value(vp, vp, '\'');
 1440             if (!value) {
 1441                 ERROR("Failed stringifying value of &control:%s", vp->da->name);
 1442                 goto error;
 1443             }
 1444 
 1445             if (vp->da->type == PW_TYPE_STRING) {
 1446                 RDEBUG2("%s = '%s'", vp->da->name, value);
 1447                 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
 1448                            T_BARE_WORD, T_SINGLE_QUOTED_STRING);
 1449             } else {
 1450                 RDEBUG2("%s = %s", vp->da->name, value);
 1451                 cp = cf_pair_alloc(c->cs, vp->da->name, value, T_OP_SET,
 1452                            T_BARE_WORD, T_BARE_WORD);
 1453             }
 1454             cf_pair_add(c->cs, cp);
 1455 
 1456             talloc_free(vp);
 1457         } while ((vp = fr_cursor_remove(&cursor)));
 1458     }
 1459     REXDENT();
 1460 
 1461 validate:
 1462     if (c->ipaddr.af == AF_UNSPEC) {
 1463         RERROR("Cannot add client %s: No IP address was specified.",
 1464                ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
 1465 
 1466         goto error;
 1467     }
 1468 
 1469     {
 1470         fr_ipaddr_t addr;
 1471 
 1472         /*
 1473          *  Need to apply the same mask as we set for the client
 1474          *  else clients created with FreeRADIUS-Client-IPv6-Prefix
 1475          *  or FreeRADIUS-Client-IPv4-Prefix will fail this check.
 1476          */
 1477         addr = request->packet->src_ipaddr;
 1478         fr_ipaddr_mask(&addr, c->ipaddr.prefix);
 1479         if (fr_ipaddr_cmp(&addr, &c->ipaddr) != 0) {
 1480             char buf2[128];
 1481 
 1482             RERROR("Cannot add client %s: Not in specified subnet %s/%i",
 1483                    ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)),
 1484                    ip_ntoh(&c->ipaddr, buf2, sizeof(buf2)), c->ipaddr.prefix);
 1485             goto error;
 1486         }
 1487     }
 1488 
 1489     if (!c->secret || !*c->secret) {
 1490         RERROR("Cannot add client %s: No secret was specified",
 1491                ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
 1492         goto error;
 1493     }
 1494 
 1495     if (!client_add_dynamic(clients, request->client, c)) {
 1496         return NULL;
 1497     }
 1498 
 1499     if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) {
 1500         RERROR("Cannot add client %s: Client IP and src address are different IP version",
 1501                ip_ntoh(&request->packet->src_ipaddr, buffer, sizeof(buffer)));
 1502 
 1503         goto error;
 1504     }
 1505 
 1506     return c;
 1507 }
 1508 
 1509 /*
 1510  *  Read a client definition from the given filename.
 1511  */
 1512 RADCLIENT *client_read(char const *filename, int in_server, int flag)
 1513 {
 1514     char const *p;
 1515     RADCLIENT *c;
 1516     CONF_SECTION *cs;
 1517     char buffer[256];
 1518 
 1519     if (!filename) return NULL;
 1520 
 1521     cs = cf_section_alloc(NULL, "main", NULL);
 1522     if (!cs) return NULL;
 1523 
 1524     if (cf_file_read(cs, filename) < 0) {
 1525         talloc_free(cs);
 1526         return NULL;
 1527     }
 1528 
 1529     cs = cf_section_sub_find(cs, "client");
 1530     if (!cs) {
 1531         ERROR("No \"client\" section found in client file");
 1532         return NULL;
 1533     }
 1534 
 1535     c = client_afrom_cs(cs, cs, in_server, false);
 1536     if (!c) return NULL;
 1537 
 1538     p = strrchr(filename, FR_DIR_SEP);
 1539     if (p) {
 1540         p++;
 1541     } else {
 1542         p = filename;
 1543     }
 1544 
 1545     if (!flag) return c;
 1546 
 1547     /*
 1548      *  Additional validations
 1549      */
 1550     ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
 1551     if (strcmp(p, buffer) != 0) {
 1552         ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);
 1553         client_free(c);
 1554         return NULL;
 1555     }
 1556 
 1557     return c;
 1558 }
 1559 #endif
 1560