The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
client.c
Go to the documentation of this file.
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: 95a5c55d3a3cc97ce2ec2a34f66600e3550fb718 $
19  * @file src/lib/server/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@freeradius.org)
25  * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
26  */
27 RCSID("$Id: 95a5c55d3a3cc97ce2ec2a34f66600e3550fb718 $")
28 
29 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
30 #include <freeradius-devel/server/cf_file.h>
31 #include <freeradius-devel/server/cf_parse.h>
32 #include <freeradius-devel/server/client.h>
33 #include <freeradius-devel/server/main_config.h>
34 #include <freeradius-devel/server/module.h>
35 #include <freeradius-devel/server/virtual_servers.h>
36 #include <freeradius-devel/unlang/call.h>
37 
38 #include <freeradius-devel/util/debug.h>
39 #include <freeradius-devel/util/base16.h>
40 #include <freeradius-devel/util/misc.h>
41 #include <freeradius-devel/util/sbuff.h>
42 #include <freeradius-devel/util/value.h>
43 #include <freeradius-devel/util/trie.h>
44 #include <freeradius-devel/util/token.h>
45 
46 #include <ctype.h>
47 #include <fcntl.h>
48 #include <sys/stat.h>
49 
50 //#define WITH_TRIE (1)
51 
52 /** Group of clients
53  *
54  */
56  char const *name; //!< Name of the client list.
57 #ifdef WITH_TRIE
58  fr_trie_t *v4_udp;
59  fr_trie_t *v6_udp;
60  fr_trie_t *v4_tcp;
61  fr_trie_t *v6_tcp;
62 #else
64 #endif
65 };
66 
67 static fr_client_list_t *root_clients = NULL; //!< Global client list.
68 
69 #ifndef WITH_TRIE
70 static int8_t client_cmp(void const *one, void const *two)
71 {
72  int ret;
73  fr_client_t const *a = one;
74  fr_client_t const *b = two;
75 
76  ret = fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
77  if (ret != 0) return ret;
78 
79  /*
80  * 0 is "wildcard", or "both" protocols
81  */
82  if ((a->proto == IPPROTO_IP) || (b->proto == IPPROTO_IP)) return 0;
83 
84  return CMP(a->proto, b->proto);
85 }
86 
87 #endif
88 
89 void client_list_free(void)
90 {
91  TALLOC_FREE(root_clients);
92 }
93 
94 /** Free a client
95  *
96  * It's up to the caller to ensure that it's deleted from any fr_client_list_t.
97  */
98 void client_free(fr_client_t *client)
99 {
100  if (!client) return;
101 
102  talloc_free(client);
103 }
104 
105 /** Return a new client list
106  *
107  * @note The container won't contain any clients.
108  *
109  * @return
110  * - New client list on success.
111  * - NULL on error (OOM).
112  */
114 {
115  fr_client_list_t *clients = talloc_zero(cs, fr_client_list_t);
116 
117  if (!clients) return NULL;
118 
119  clients->name = talloc_strdup(clients, cs ? cf_section_name1(cs) : "root");
120 
121 #ifdef WITH_TRIE
122  clients->v4_udp = fr_trie_alloc(clients, NULL, NULL);
123  if (!clients->v4_udp) {
124  talloc_free(clients);
125  return NULL;
126  }
127 
128  clients->v6_udp = fr_trie_alloc(clients, NULL, NULL);
129  if (!clients->v6_udp) {
130  talloc_free(clients);
131  return NULL;
132  }
133 
134  clients->v4_tcp = fr_trie_alloc(clients, NULL, NULL);
135  if (!clients->v4_tcp) {
136  talloc_free(clients);
137  return NULL;
138  }
139 
140  clients->v6_tcp = fr_trie_alloc(clients, NULL, NULL);
141  if (!clients->v6_tcp) {
142  talloc_free(clients);
143  return NULL;
144  }
145 #endif /* WITH_TRIE */
146 
147  return clients;
148 }
149 
150 #ifdef WITH_TRIE
151 /*
152  * @todo - either support client definitions where "proto = *",
153  * or update this code to allow for that. i.e. we create yet
154  * another set of v4/v6 tries, for "proto = *" clients. And then
155  * do lookups there, too. Or, just unify the udp/tcp tries, and
156  * instead do post-processing? Though those two clients can have
157  * different secrets... and the trie code doesn't allow 2
158  * fr_trie_user_t nodes in a row. So we would have to instead
159  * handle that ourselves, with a wrapper around the fr_client_t
160  * structure that does udp/tcp/wildcard demultiplexing
161  */
162 static fr_trie_t *clients_trie(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr,
163  int proto)
164 {
165  if (ipaddr->af == AF_INET) {
166  if (proto == IPPROTO_TCP) return clients->v4_tcp;
167 
168  return clients->v4_udp;
169  }
170 
171  fr_assert(ipaddr->af == AF_INET6);
172 
173  if (proto == IPPROTO_TCP) return clients->v6_tcp;
174 
175  return clients->v6_udp;
176 }
177 #endif /* WITH_TRIE */
178 
179 /** Add a client to a fr_client_list_t
180  *
181  * @param clients list to add client to, may be NULL if global client list is being used.
182  * @param client to add.
183  * @return
184  * - true on success.
185  * - false on failure.
186  */
187 bool client_add(fr_client_list_t *clients, fr_client_t *client)
188 {
189 #ifdef WITH_TRIE
190  fr_trie_t *trie;
191 #else
192 #endif
193  fr_client_t *old;
195 
196  if (!client) return false;
197 
198  /*
199  * Hack to fixup wildcard clients
200  *
201  * If the IP is all zeros, with a 32 or 128 bit netmask
202  * assume the user meant to configure 0.0.0.0/0 instead
203  * of 0.0.0.0/32 - which would require the src IP of
204  * the client to be all zeros.
205  */
206  if (fr_ipaddr_is_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) {
207  case AF_INET:
208  if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0;
209  break;
210 
211  case AF_INET6:
212  if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0;
213  break;
214 
215  default:
216  fr_assert(0);
217  }
218 
219  fr_inet_ntop_prefix(buffer, sizeof(buffer), &client->ipaddr);
220  DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix);
221 
222  /*
223  * If "clients" is NULL, it means add to the global list,
224  * unless we're trying to add it to a virtual server...
225  */
226  if (!clients) {
227  if (client->server != NULL) {
228  CONF_SECTION *cs;
229  CONF_SECTION *subcs;
230 
231  if (!client->cs) {
232  ERROR("Failed to find configuration section in client. Ignoring 'virtual_server' directive");
233  return false;
234  }
235 
236  cs = cf_section_find(cf_root(client->cs), "server", client->server);
237  if (!cs) {
238  ERROR("Failed to find virtual server %s", client->server);
239  return false;
240  }
241 
242  /*
243  * If this server has no "listen" section, add the clients
244  * to the global client list.
245  */
246  subcs = cf_section_find(cs, "listen", NULL);
247  if (!subcs) goto global_clients;
248 
249  /*
250  * If the client list already exists, use that.
251  * Otherwise, create a new client list.
252  */
253  clients = cf_data_value(cf_data_find(cs, fr_client_list_t, NULL));
254  if (!clients) {
255  MEM(clients = client_list_init(cs));
256  if (!cf_data_add(cs, clients, NULL, true)) {
257  ERROR("Failed to associate clients with virtual server %s", client->server);
258  talloc_free(clients);
259  return false;
260  }
261  }
262 
263  } else {
264  global_clients:
265  /*
266  * Initialize the global list, if not done already.
267  */
268  if (!root_clients) {
270  if (!root_clients) return false;
271  }
272  clients = root_clients;
273  }
274  }
275 
276 #define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0)))
277 
278 #ifdef WITH_TRIE
279  trie = clients_trie(clients, &client->ipaddr, client->proto);
280 
281  /*
282  * Cannot insert the same client twice.
283  */
284  old = fr_trie_match_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix);
285 
286 #else /* WITH_TRIE */
287 
288  if (!clients->tree[client->ipaddr.prefix]) {
289  clients->tree[client->ipaddr.prefix] = fr_rb_inline_talloc_alloc(clients, fr_client_t, node, client_cmp,
290  NULL);
291  if (!clients->tree[client->ipaddr.prefix]) {
292  return false;
293  }
294  }
295 
296  old = fr_rb_find(clients->tree[client->ipaddr.prefix], client);
297 #endif
298  if (old) {
299  /*
300  * If it's a complete duplicate, then free the new
301  * one, and return "OK".
302  */
303  if (namecmp(longname) && namecmp(secret) &&
304  namecmp(shortname) && namecmp(nas_type) &&
305  namecmp(server) &&
307  WARN("Ignoring duplicate client %s", client->longname);
308  client_free(client);
309  return true;
310  }
311 
312  ERROR("Failed to add duplicate client %s", client->shortname);
313  client_free(client);
314  return false;
315  }
316 #undef namecmp
317 
318 #ifdef WITH_TRIE
319  /*
320  * Other error adding client: likely is fatal.
321  */
322  if (fr_trie_insert_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix, client) < 0) {
323  client_free(client);
324  return false;
325  }
326 #else
327  if (!fr_rb_insert(clients->tree[client->ipaddr.prefix], client)) {
328  client_free(client);
329  return false;
330  }
331 #endif
332 
333  /*
334  * @todo - do we want to do this for dynamic clients?
335  */
336  (void) talloc_steal(clients, client); /* reparent it */
337 
338  return true;
339 }
340 
341 
343 {
344 #ifdef WITH_TRIE
345  fr_trie_t *trie;
346 #endif
347 
348  if (!client) return;
349 
350  if (!clients) clients = root_clients;
351 
352  fr_assert(client->ipaddr.prefix <= 128);
353 
354 #ifdef WITH_TRIE
355  trie = clients_trie(clients, &client->ipaddr, client->proto);
356 
357  /*
358  * Don't free the client. The caller is responsible for that.
359  */
360  (void) fr_trie_remove_by_key(trie, &client->ipaddr.addr, client->ipaddr.prefix);
361 #else
362 
363  if (!clients->tree[client->ipaddr.prefix]) return;
364 
365  (void) fr_rb_delete(clients->tree[client->ipaddr.prefix], client);
366 #endif
367 }
368 
370 {
371  return NULL;
372 }
373 
374 
375 /*
376  * Find a client in the fr_client_tS list.
377  */
378 fr_client_t *client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
379 {
380 #ifdef WITH_TRIE
381  fr_trie_t *trie;
382 #else
383  int i, max;
384  fr_client_t my_client, *client;
385 #endif
386 
387  if (!clients) clients = root_clients;
388 
389  if (!clients || !ipaddr) return NULL;
390 
391 #ifdef WITH_TRIE
392  trie = clients_trie(clients, ipaddr, proto);
393 
394  return fr_trie_lookup_by_key(trie, &ipaddr->addr, ipaddr->prefix);
395 #else
396 
397  if (proto == AF_INET) {
398  max = 32;
399  } else {
400  max = 128;
401  }
402 
403  if (max > ipaddr->prefix) max = ipaddr->prefix;
404 
405  my_client.proto = proto;
406  for (i = max; i >= 0; i--) {
407  if (!clients->tree[i]) continue;
408 
409  my_client.ipaddr = *ipaddr;
410  fr_ipaddr_mask(&my_client.ipaddr, i);
411  client = fr_rb_find(clients->tree[i], &my_client);
412  if (client) {
413  return client;
414  }
415  }
416 
417  return NULL;
418 #endif
419 }
420 
422 static char const *cl_srcipaddr = NULL;
423 static char const *hs_proto = NULL;
424 
426  { FR_CONF_OFFSET("max_connections", fr_client_t, limit.max_connections), .dflt = "16" },
427 
428  { FR_CONF_OFFSET("lifetime", fr_client_t, limit.lifetime), .dflt = "0" },
429 
430  { FR_CONF_OFFSET("idle_timeout", fr_client_t, limit.idle_timeout), .dflt = "30s" },
432 };
433 
434 static const conf_parser_t client_config[] = {
436  { FR_CONF_POINTER("ipv4addr", FR_TYPE_IPV4_PREFIX, 0, &cl_ipaddr) },
437  { FR_CONF_POINTER("ipv6addr", FR_TYPE_IPV6_PREFIX, 0, &cl_ipaddr) },
438 
439  { FR_CONF_POINTER("src_ipaddr", FR_TYPE_STRING, 0, &cl_srcipaddr) },
440 
442  { FR_CONF_OFFSET("shortname", fr_client_t, shortname) },
443 
444  { FR_CONF_OFFSET("nas_type", fr_client_t, nas_type) },
445 
446  { FR_CONF_OFFSET("track_connections", fr_client_t, use_connected) },
447 
448  { FR_CONF_OFFSET_IS_SET("require_message_authenticator", FR_TYPE_UINT32, 0, fr_client_t, require_message_authenticator),
449  .func = cf_table_parse_int,
451  .dflt = "no" },
452 
453  { FR_CONF_OFFSET_IS_SET("limit_proxy_state", FR_TYPE_UINT32, 0, fr_client_t, limit_proxy_state),
454  .func = cf_table_parse_int,
456  .dflt = "auto" },
457 
458  { FR_CONF_OFFSET("dedup_authenticator", fr_client_t, dedup_authenticator) },
459 
460  { FR_CONF_OFFSET("response_window", fr_client_t, response_window) },
461 
462  { FR_CONF_POINTER("proto", FR_TYPE_STRING, 0, &hs_proto) },
463  { FR_CONF_POINTER("limit", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) limit_config },
464 
466 };
467 
468 /** Create a list of clients from a client section
469  *
470  * Iterates over all client definitions in the specified section, adding them to a client list.
471  */
472 #ifdef WITH_TLS
473 #define TLS_UNUSED
474 #else
475 #define TLS_UNUSED UNUSED
476 #endif
477 
479 {
480  bool global = false;
481  CONF_SECTION *cs = NULL;
482  fr_client_t *c = NULL;
483  fr_client_list_t *clients = NULL;
484  CONF_SECTION *server_cs = NULL;
485 
486  /*
487  * Be forgiving. If there's already a clients, return
488  * it. Otherwise create a new one.
489  */
490  clients = cf_data_value(cf_data_find(section, fr_client_list_t, NULL));
491  if (clients) return clients;
492 
493  /*
494  * Parent the client list from the section.
495  */
496  clients = client_list_init(section);
497  if (!clients) return NULL;
498 
499  /*
500  * If the section is hung off the config root, this is
501  * the global client list, else it's virtual server
502  * specific client list.
503  */
504  if (cf_root(section) == section) global = true;
505 
506  if (strcmp("server", cf_section_name1(section)) == 0) server_cs = section;
507 
508  /*
509  * Iterate over all the clients in the section, adding
510  * them to the client list.
511  */
512  while ((cs = cf_section_find_next(section, cs, "client", CF_IDENT_ANY))) {
513  /*
514  * Check this before parsing the client.
515  */
516  if (proto) {
517  CONF_PAIR *cp;
518  int client_proto = IPPROTO_UDP;
519 
520  cp = cf_pair_find(cs, "proto");
521  if (cp) {
522  char const *value = cf_pair_value(cp);
523 
524  if (!value) {
525  cf_log_err(cs, "'proto' field must have a value");
526  talloc_free(clients);
527  return NULL;
528  }
529 
530  if (strcmp(value, "udp") == 0) {
531  /* do nothing */
532 
533  } else if (strcmp(value, "tcp") == 0) {
534  client_proto = IPPROTO_TCP;
535 #ifdef WITH_TLS
536  } else if (strcmp(value, "tls") == 0) {
537  client_proto = IPPROTO_TCP;
538 #endif
539  } else if (strcmp(value, "*") == 0) {
540  client_proto = IPPROTO_IP; /* fake for dual */
541  } else {
542  cf_log_err(cs, "Unknown proto \"%s\".", value);
543  talloc_free(clients);
544  return NULL;
545  }
546  }
547 
548  /*
549  * We don't have "proto = *", so the
550  * protocol MUST match what the caller
551  * asked for. Otherwise, we ignore the
552  * client.
553  */
554  if ((client_proto != IPPROTO_IP) && (proto != client_proto)) continue;
555  }
556 
557 
558  c = client_afrom_cs(cs, cs, server_cs, 0);
559  if (!c) {
560  error:
561  client_free(c);
562  talloc_free(clients);
563  return NULL;
564  }
565 
566  /*
567  * TCP sockets are always connected.
568  */
569  c->use_connected |= (c->proto == IPPROTO_TCP);
570 
571 #ifdef WITH_TLS
572  /*
573  * TLS clients CANNOT use non-TLS listeners.
574  * non-TLS clients CANNOT use TLS listeners.
575  */
576  if (tls_required != c->tls_required) {
577  cf_log_err(cs, "Client does not have the same TLS configuration as the listener");
578  goto error;
579  }
580 #endif
581 
582  if (!client_add(clients, c)) {
583  cf_log_err(cs, "Failed to add client %s", cf_section_name2(cs));
584  goto error;
585  }
586 
587  }
588 
589  /*
590  * Associate the clients structure with the section.
591  */
592  if (!cf_data_add(section, clients, NULL, false)) {
593  cf_log_err(section, "Failed to associate clients with section %s", cf_section_name1(section));
594  talloc_free(clients);
595  return NULL;
596  }
597 
598  /*
599  * Replace the global list of clients with the new one.
600  * The old one is still referenced from the original
601  * configuration, and will be freed when that is freed.
602  */
603  if (global) root_clients = clients;
604 
605  return clients;
606 }
607 
608 /** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes
609  *
610  * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
611  *
612  * @note Caller should free CONF_SECTION passed in as out, on error.
613  * Contents of that section will be in an undefined state.
614  *
615  * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section
616  * (when this function is called recursively).
617  * Should be alloced with cf_section_alloc, or if there's a separate template section, the
618  * result of calling cf_section_dup on that section.
619  * @param[in] map section.
620  * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value.
621  * @param[in] data to pass to func, usually a result pointer.
622  * @return
623  * - 0 on success.
624  * - -1 on failure.
625  */
627 {
628  CONF_ITEM const *ci;
629 
630  for (ci = cf_item_next(map, NULL);
631  ci != NULL;
632  ci = cf_item_next(map, ci)) {
633  CONF_PAIR const *cp;
634  CONF_PAIR *old;
635  char *value;
636  char const *attr;
637 
638  /*
639  * Recursively process map subsection
640  */
641  if (cf_item_is_section(ci)) {
642  CONF_SECTION *cs, *cc;
643 
644  cs = cf_item_to_section(ci);
645  /*
646  * Use pre-existing section or alloc a new one
647  */
649  if (!cc) {
651  if (!cc) return -1;
652  }
653 
654  if (client_map_section(cc, cs, func, data) < 0) return -1;
655  continue;
656  }
657 
658  cp = cf_item_to_pair(ci);
659  attr = cf_pair_attr(cp);
660 
661  /*
662  * The callback can return 0 (success) and not provide a value
663  * in which case we skip the mapping pair.
664  *
665  * Or return -1 in which case we error out.
666  */
667  if (func(&value, cp, data) < 0) {
668  cf_log_err(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp));
669  return -1;
670  }
671  if (!value) continue;
672 
673  /*
674  * Replace an existing CONF_PAIR
675  */
676  old = cf_pair_find(out, attr);
677  if (old) {
678  cf_pair_replace(out, old, value);
680  continue;
681  }
682 
683  /*
684  * ...or add a new CONF_PAIR
685  */
687  if (!cp) {
688  cf_log_err(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value);
690  return -1;
691  }
694  }
695 
696  return 0;
697 }
698 
699 /** Allocate a new client from a config section
700  *
701  * @param ctx to allocate new clients in.
702  * @param cs to process as a client.
703  * @param server_cs The virtual server that this client belongs to.
704  * @param extra 0 allocate sizeof(fr_client_t) bytes
705  * >sizeof(client_t) number of bytes to allocate
706  * @return new fr_client_t struct.
707  */
708 fr_client_t *client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
709 {
710  fr_client_t *c;
711  char const *name2;
712  CONF_PAIR *cp;
713 
714  name2 = cf_section_name2(cs);
715  if (!name2) {
716  cf_log_err(cs, "Missing client name");
717  return NULL;
718  }
719 
720  /*
721  * The size is fine.. Let's create the buffer
722  */
723  if (!extra) {
724  c = talloc_zero(ctx, fr_client_t);
725  if (!c) return NULL;
726  } else {
727  fr_assert(extra > sizeof(fr_client_t));
728 
729  c = (fr_client_t *) talloc_zero_array(ctx, uint8_t, extra);
730  if (!c) return NULL;
731 
732  talloc_set_name_const(c, "fr_client_t");
733  }
734 
735  c->cs = cs;
736 
737  memset(&cl_ipaddr, 0, sizeof(cl_ipaddr));
738  if (cf_section_rules_push(cs, client_config) < 0) return NULL;
739 
740  if (cf_section_parse(c, c, cs) < 0) {
741  cf_log_err(cs, "Error parsing client section");
742  error:
743  client_free(c);
744  hs_proto = NULL;
745  cl_srcipaddr = NULL;
746  return NULL;
747  }
748 
749  /*
750  * Allow for binary secrets.
751  */
752  cp = cf_pair_find(cs, "secret");
753  if (cp && (cf_pair_operator(cp) == T_BARE_WORD)) {
754  char const *value;
755 
756  value = cf_pair_value(cp);
757  if ((value[0] == '0') && (value[1] == 'x')) {
758  size_t bin_len, hex_len, converted;
759  uint8_t *bin;
760 
761  /*
762  * '0x...' plus trailing NUL.
763  */
764  hex_len = talloc_array_length(value) - 3;
765  bin_len = (hex_len / 2) + 1;
766  MEM(bin = talloc_array(c, uint8_t, bin_len));
767  converted = fr_base16_decode(NULL,
768  &FR_DBUFF_TMP(bin, bin_len),
769  &FR_SBUFF_IN(value + 2, hex_len), false);
770  if (converted < (bin_len - 1)) {
771  cf_log_err(cs, "Invalid hex string in shared secret");
772  goto error;
773  }
774 
776  c->secret = (char const *) bin;
777  }
778  }
779 
780  /*
781  * Find the virtual server for this client.
782  */
783  if (c->server) {
784  virtual_server_t const *vs;;
785  if (server_cs) {
786  cf_log_err(cs, "Clients inside of a 'server' section cannot point to a server");
787  goto error;
788  }
789 
790  vs = virtual_server_find(c->server);
791  if (!vs) goto error;
792 
793  c->server_cs = virtual_server_cs(vs);
794  if (!c->server_cs) {
795  cf_log_err(cs, "Failed to find virtual server %s", c->server);
796  goto error;
797  }
798 
799  } else if (server_cs) {
800  c->server = cf_section_name2(server_cs);
801  c->server_cs = server_cs;
802 
803  } /* else don't set c->server or c->server_cs, we will use listener->server */
804 
805  /*
806  * Newer style client definitions with either ipaddr or ipaddr6
807  * config items.
808  */
809  if (cf_pair_find(cs, "ipaddr") || cf_pair_find(cs, "ipv4addr") || cf_pair_find(cs, "ipv6addr")) {
810  char buffer[128];
811 
812  /*
813  * Sets ipv4/ipv6 address and prefix.
814  */
815  c->ipaddr = cl_ipaddr;
816 
817  /*
818  * Set the long name to be the result of a reverse lookup on the IP address.
819  */
820  fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer));
822 
823  /*
824  * Set the short name to the name2.
825  */
826  if (!c->shortname) c->shortname = talloc_typed_strdup(c, name2);
827  /*
828  * No "ipaddr" or "ipv6addr", use old-style "client <ipaddr> {" syntax.
829  */
830  } else {
831  cf_log_err(cs, "No 'ipaddr' or 'ipv4addr' or 'ipv6addr' configuration "
832  "directive found in client %s", name2);
833  goto error;
834  }
835 
836  c->proto = IPPROTO_UDP;
837  if (hs_proto) {
838  if (strcmp(hs_proto, "udp") == 0) {
839  hs_proto = NULL;
840 
841  } else if (strcmp(hs_proto, "tcp") == 0) {
842  hs_proto = NULL;
843  c->proto = IPPROTO_TCP;
844 #ifdef WITH_TLS
845  } else if (strcmp(hs_proto, "tls") == 0) {
846  hs_proto = NULL;
847  c->proto = IPPROTO_TCP;
848  c->tls_required = true;
849 
850 #endif
851  } else if (strcmp(hs_proto, "*") == 0) {
852  hs_proto = NULL;
853  c->proto = IPPROTO_IP; /* fake for dual */
854  } else {
855  cf_log_err(cs, "Unknown proto \"%s\".", hs_proto);
856  goto error;
857  }
858  }
859 
860  /*
861  * If a src_ipaddr is specified, when we send the return packet
862  * we will use this address instead of the src from the
863  * request.
864  */
865  if (cl_srcipaddr) {
866  switch (c->ipaddr.af) {
867  case AF_INET:
868  if (fr_inet_pton4(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
869  cf_log_perr(cs, "Failed parsing src_ipaddr");
870  goto error;
871  }
872  break;
873 
874  case AF_INET6:
875  if (fr_inet_pton6(&c->src_ipaddr, cl_srcipaddr, -1, true, false, true) < 0) {
876  cf_log_perr(cs, "Failed parsing src_ipaddr");
877  goto error;
878  }
879  break;
880  default:
881  cf_log_err(cs, "ipaddr was not defined");
882  goto error;
883  }
884  cl_srcipaddr = NULL;
885  } else {
886  c->src_ipaddr.af = c->ipaddr.af; /* leave the rest as IFADDR_ANY */
887  }
888 
889  /*
890  * A response_window of zero is OK, and means that it's
891  * ignored by the rest of the server timers.
892  */
894  FR_TIME_DELTA_BOUND_CHECK("response_window", c->response_window, >=, fr_time_delta_from_usec(1000));
895  FR_TIME_DELTA_BOUND_CHECK("response_window", c->response_window, <=, fr_time_delta_from_sec(60));
897  }
898 
899 #ifdef WITH_TLS
900  /*
901  * If the client is TLS only, the secret can be
902  * omitted. When omitted, it's hard-coded to
903  * "radsec". See RFC 6614.
904  */
905  if (c->tls_required) {
906  c->secret = talloc_typed_strdup(cs, "radsec");
907  }
908 #endif
909 
910  if ((c->proto == IPPROTO_TCP) || (c->proto == IPPROTO_IP)) {
917  }
918 
919  return c;
920 }
921 
922 /** Create a new client, consuming all attributes in the control list of the request
923  *
924  * @param ctx the talloc context
925  * @param request containing the client attributes.
926  * @return
927  * - New client on success.
928  * - NULL on error.
929  */
930 fr_client_t *client_afrom_request(TALLOC_CTX *ctx, request_t *request)
931 {
932  static int cnt;
933  CONF_SECTION *cs;
934  fr_client_t *c;
935  fr_sbuff_t *tmp;
936 
937  if (!request) return NULL;
938 
939  FR_SBUFF_TALLOC_THREAD_LOCAL(&tmp, 128, SIZE_MAX);
940 
941  if (unlikely(fr_sbuff_in_sprintf(tmp, "dynamic_%i_", cnt++) <= 0)) {
942  name_error:
943  RERROR("Failed to generate dynamic client name");
944  return NULL;
945  }
946  if (unlikely(fr_value_box_print(tmp, fr_box_ipaddr(request->packet->socket.inet.src_ipaddr), NULL) <= 0)) goto name_error;
947  fr_sbuff_set_to_start(tmp);
948 
949  cs = cf_section_alloc(ctx, NULL, "client", fr_sbuff_current(tmp));
950 
951  RDEBUG2("Converting &control.FreeRADIUS-Client-* to client {...} section");
952  RINDENT();
953 
954  fr_pair_list_foreach(&request->control_pairs, vp) {
955  CONF_PAIR *cp = NULL;
956  char const *value;
957  char const *attr;
958  fr_token_t v_token = T_BARE_WORD;
959 
960  if (!fr_dict_attr_is_top_level(vp->da)) continue;
961 
962  switch (vp->da->attr) {
963  case FR_FREERADIUS_CLIENT_IP_ADDRESS:
964  attr = "ipv4addr";
965  vb_to_str:
966  fr_sbuff_set_to_start(tmp);
968  RERROR("Failed to convert %pP to string", vp);
969  error:
970  talloc_free(cs);
971  return NULL;
972  }
973  value = fr_sbuff_start(tmp);
974  break;
975 
976  case FR_FREERADIUS_CLIENT_IP_PREFIX:
977  attr = "ipv4addr";
978  goto vb_to_str;
979 
980  case FR_FREERADIUS_CLIENT_IPV6_ADDRESS:
981  attr = "ipv6addr";
982  goto vb_to_str;
983 
984  case FR_FREERADIUS_CLIENT_IPV6_PREFIX:
985  attr = "ipv6addr";
986  goto vb_to_str;
987 
988  case FR_FREERADIUS_CLIENT_SECRET:
989  attr = "secret";
990  value = vp->vp_strvalue;
991  break;
992 
993  case FR_FREERADIUS_CLIENT_NAS_TYPE:
994  attr = "nas_type";
995  value = vp->vp_strvalue;
996  break;
997 
998  case FR_FREERADIUS_CLIENT_SHORTNAME:
999  attr = "shortname";
1000  value = vp->vp_strvalue;
1001  break;
1002 
1003  case FR_FREERADIUS_CLIENT_SRC_IP_ADDRESS:
1004  attr = "src_ipaddr";
1005  goto vb_to_str;
1006 
1007  case FR_FREERADIUS_CLIENT_REQUIRE_MA:
1008  attr = "require_message_authenticator";
1009  goto vb_to_str;
1010 
1011  case FR_FREERADIUS_CLIENT_LIMIT_PROXY_STATE:
1012  attr = "limit_proxy_state";
1013  goto vb_to_str;
1014 
1015  case FR_FREERADIUS_CLIENT_TRACK_CONNECTIONS:
1016  attr = "track_connections";
1017  goto vb_to_str;
1018 
1019  default:
1020  attr = vp->da->name;
1021  fr_sbuff_set_to_start(tmp);
1023  value = fr_sbuff_start(tmp);
1024  v_token = T_SINGLE_QUOTED_STRING;
1025  break;
1026  }
1027 
1028  cp = cf_pair_alloc(cs, attr, value, T_OP_SET, T_BARE_WORD, v_token);
1029  if (!cp) {
1030  RERROR("Error creating equivalent conf pair for %s", vp->da->name);
1031  goto error;
1032  }
1033 
1034  RDEBUG2("%s = %s", cf_pair_attr(cp), cf_pair_value(cp));
1035  }
1036 
1037  REXDENT();
1038 
1039  /*
1040  * @todo - allow for setting a DIFFERENT virtual server,
1041  * src IP, protocol, etc. This should all be in TLVs..
1042  */
1043  c = client_afrom_cs(cs, cs, unlang_call_current(request), 0);
1044  if (!c) goto error;
1045 
1046  return c;
1047 }
1048 
1049 /** Read a single client from a file
1050  *
1051  * This function supports asynchronous runtime loading of clients.
1052  *
1053  * @param[in] filename To read clients from.
1054  * @param[in] server_cs of virtual server clients should be added to.
1055  * @param[in] check_dns Check reverse lookup of IP address matches filename.
1056  * @return
1057  * - The new client on success.
1058  * - NULL on failure.
1059  */
1060 fr_client_t *client_read(char const *filename, CONF_SECTION *server_cs, bool check_dns)
1061 {
1062  char const *p;
1063  fr_client_t *c;
1064  CONF_SECTION *cs;
1065  char buffer[256];
1066 
1067  if (!filename) return NULL;
1068 
1069  cs = cf_section_alloc(NULL, NULL, "main", NULL);
1070  if (!cs) return NULL;
1071 
1072  if ((cf_file_read(cs, filename) < 0) || (cf_section_pass2(cs) < 0)) {
1073  talloc_free(cs);
1074  return NULL;
1075  }
1076 
1077  cs = cf_section_find(cs, "client", CF_IDENT_ANY);
1078  if (!cs) {
1079  ERROR("No \"client\" section found in client file");
1080  return NULL;
1081  }
1082 
1083  c = client_afrom_cs(cs, cs, server_cs, 0);
1084  if (!c) return NULL;
1085  talloc_steal(cs, c);
1086 
1087  p = strrchr(filename, FR_DIR_SEP);
1088  if (p) {
1089  p++;
1090  } else {
1091  p = filename;
1092  }
1093 
1094  if (!check_dns) return c;
1095 
1096  /*
1097  * Additional validations
1098  */
1099  fr_inet_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1100  if (strcmp(p, buffer) != 0) {
1101  ERROR("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);
1102  client_free(c);
1103  return NULL;
1104  }
1105 
1106  return c;
1107 }
1108 
1109 /** Search up a list of requests trying to locate one which has a client
1110  *
1111  */
1113 {
1114  fr_client_t *client;
1115  request_t *parent = request;
1116 
1117  do {
1118  client = parent->client;
1119  } while (!client && (parent = parent->parent));
1120 
1121  return client;
1122 }
static int const char char buffer[256]
Definition: acutest.h:574
#define fr_base16_decode(_err, _out, _in, _no_trailing)
Definition: base16.h:95
#define RCSID(id)
Definition: build.h:481
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
CONF_SECTION * unlang_call_current(request_t *request)
Return the last virtual server that was called.
Definition: call.c:225
int cf_file_read(CONF_SECTION *cs, char const *filename)
Definition: cf_file.c:3415
int cf_section_pass2(CONF_SECTION *cs)
Definition: cf_file.c:755
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition: cf_parse.c:985
int cf_table_parse_int(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule)
Generic function for parsing conf pair values as int.
Definition: cf_parse.c:1474
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:268
#define cf_section_rules_push(_cs, _rule)
Definition: cf_parse.h:659
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
Definition: cf_parse.h:310
#define FR_CONF_OFFSET_IS_SET(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct,...
Definition: cf_parse.h:282
#define FR_CONF_OFFSET_FLAGS(_name, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition: cf_parse.h:256
#define FR_TIME_DELTA_BOUND_CHECK(_name, _var, _op, _bound)
Definition: cf_parse.h:498
@ CONF_FLAG_SECRET
Only print value if debug level >= 3.
Definition: cf_parse.h:409
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Definition: cf_parse.h:399
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:564
Common header for all CONF_* types.
Definition: cf_priv.h:49
Configuration AVP similar to a fr_pair_t.
Definition: cf_priv.h:70
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:101
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: cf_util.c:664
char const * cf_pair_attr(CONF_PAIR const *pair)
Return the attr of a CONF_PAIR.
Definition: cf_util.c:1578
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition: cf_util.c:1028
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
Definition: cf_util.c:1439
char const * cf_section_name2(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1185
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
void * cf_data_value(CONF_DATA const *cd)
Return the user assigned value of CONF_DATA.
Definition: cf_util.c:1763
fr_token_t cf_pair_operator(CONF_PAIR const *pair)
Return the operator of a pair.
Definition: cf_util.c:1608
CONF_ITEM * cf_pair_to_item(CONF_PAIR const *cp)
Cast a CONF_PAIR to a CONF_ITEM.
Definition: cf_util.c:722
CONF_SECTION * cf_item_to_section(CONF_ITEM const *ci)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: cf_util.c:684
CONF_SECTION * cf_section_find_next(CONF_SECTION const *cs, CONF_SECTION const *prev, char const *name1, char const *name2)
Return the next matching section.
Definition: cf_util.c:1049
bool cf_item_is_section(CONF_ITEM const *ci)
Determine if CONF_ITEM is a CONF_SECTION.
Definition: cf_util.c:618
char const * cf_section_name1(CONF_SECTION const *cs)
Return the second identifier of a CONF_SECTION.
Definition: cf_util.c:1171
int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, char const *value)
Replace pair in a given section with a new pair, of the given value.
Definition: cf_util.c:1350
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition: cf_util.c:1279
#define cf_item_add(_parent, _child)
Definition: cf_util.h:83
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define cf_data_add(_cf, _data, _name, _free)
Definition: cf_util.h:255
#define cf_data_find(_cf, _type, _name)
Definition: cf_util.h:244
#define cf_root(_cf)
Definition: cf_util.h:98
#define cf_log_perr(_cf, _fmt,...)
Definition: cf_util.h:296
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:140
#define cf_item_next(_ci, _curr)
Definition: cf_util.h:92
#define CF_IDENT_ANY
Definition: cf_util.h:78
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
Definition: dbuff.h:514
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
Definition: dict.h:754
Test enumeration values.
Definition: dict_test.h:92
int fr_inet_pton6(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask)
Parse an IPv6 address or IPv6 prefix in presentation format (and others)
Definition: inet.c:629
char * fr_inet_ntop_prefix(char out[static FR_IPADDR_PREFIX_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print a fr_ipaddr_t as a CIDR style network prefix.
Definition: inet.c:1073
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition: inet.c:355
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition: inet.c:62
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition: inet.c:1346
void fr_ipaddr_mask(fr_ipaddr_t *addr, uint8_t prefix)
Zeroes out the host portion of an fr_ipaddr_t.
Definition: inet.c:217
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:69
int af
Address family.
Definition: inet.h:64
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
Definition: inet.h:93
union fr_ipaddr_t::@130 addr
IPv4/6 prefix.
Definition: merged_model.c:272
fr_time_delta_t response_window
How long the client has to respond.
Definition: client.h:141
char const * server
Name of the virtual server client is associated with.
Definition: client.h:129
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition: client.h:83
fr_radius_require_ma_t require_message_authenticator
Require RADIUS message authenticator for incoming packets.
Definition: client.h:94
char const * secret
Secret PSK.
Definition: client.h:90
fr_ipaddr_t src_ipaddr
IPv4/IPv6 address to send responses from (family must match ipaddr).
Definition: client.h:84
int(* client_value_cb_t)(char **out, CONF_PAIR const *cp, void *data)
Callback for retrieving values when building client sections.
Definition: client.h:68
int proto
Protocol number.
Definition: client.h:143
CONF_SECTION * cs
CONF_SECTION that was parsed to generate the client.
Definition: client.h:134
char const * longname
Client identifier.
Definition: client.h:87
fr_socket_limit_t limit
Connections per client (TCP clients only).
Definition: client.h:144
char const * shortname
Client nickname.
Definition: client.h:88
bool use_connected
do we use connected sockets for this client
Definition: client.h:120
CONF_SECTION * server_cs
Virtual server that the client is associated with.
Definition: client.h:130
Describes a host allowed to send packets to the server.
Definition: client.h:80
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define DEBUG3(_fmt,...)
Definition: log.h:266
#define RERROR(fmt,...)
Definition: log.h:298
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
talloc_free(reap)
main_config_t const * main_config
Main server configuration.
Definition: main_config.c:69
fr_time_delta_t max_request_time
How long a request can be processed for before timing out.
Definition: main_config.h:61
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
Definition: merged_model.c:92
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
int fr_inet_pton4(fr_ipaddr_t *out, char const *value, ssize_t inlen, bool resolve, bool fallback, bool mask_bits)
Definition: merged_model.c:275
unsigned char uint8_t
Definition: merged_model.c:30
size_t fr_radius_limit_proxy_state_table_len
Definition: base.c:99
size_t fr_radius_require_ma_table_len
Definition: base.c:90
fr_table_num_sorted_t const fr_radius_limit_proxy_state_table[]
Definition: base.c:92
fr_table_num_sorted_t const fr_radius_require_ma_table[]
Definition: base.c:83
static char * secret
Definition: radclient-ng.c:69
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define WARN(fmt,...)
Definition: radclient.h:47
static char const * proto(int id, int porttype)
Definition: radwho.c:85
#define fr_rb_inline_talloc_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black that verifies elements are of a specific talloc type.
Definition: rb.h:246
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
The main red black tree structure.
Definition: rb.h:73
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1573
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_time_delta_t idle_timeout
Definition: socket.h:38
fr_time_delta_t lifetime
Definition: socket.h:37
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition: client.c:378
#define namecmp(a)
static int8_t client_cmp(void const *one, void const *two)
Definition: client.c:70
char const * name
Name of the client list.
Definition: client.c:56
fr_client_list_t * client_list_init(CONF_SECTION *cs)
Return a new client list.
Definition: client.c:113
fr_rb_tree_t * tree[129]
Definition: client.c:63
int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
Create a client CONF_SECTION using a mapping section to map values from a result set to client attrib...
Definition: client.c:626
fr_client_list_t * client_list_parse_section(CONF_SECTION *section, int proto, TLS_UNUSED bool tls_required)
Definition: client.c:478
void client_free(fr_client_t *client)
Free a client.
Definition: client.c:98
fr_client_t * client_read(char const *filename, CONF_SECTION *server_cs, bool check_dns)
Read a single client from a file.
Definition: client.c:1060
static fr_ipaddr_t cl_ipaddr
Definition: client.c:421
#define TLS_UNUSED
Create a list of clients from a client section.
Definition: client.c:475
fr_client_t * client_from_request(request_t *request)
Search up a list of requests trying to locate one which has a client.
Definition: client.c:1112
static conf_parser_t limit_config[]
Definition: client.c:425
static char const * cl_srcipaddr
Definition: client.c:422
static const conf_parser_t client_config[]
Definition: client.c:434
static fr_client_list_t * root_clients
Global client list.
Definition: client.c:67
void client_list_free(void)
Definition: client.c:89
fr_client_t * client_findbynumber(UNUSED const fr_client_list_t *clients, UNUSED int number)
Definition: client.c:369
fr_client_t * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
Allocate a new client from a config section.
Definition: client.c:708
void client_delete(fr_client_list_t *clients, fr_client_t *client)
Definition: client.c:342
bool client_add(fr_client_list_t *clients, fr_client_t *client)
Add a client to a fr_client_list_t.
Definition: client.c:187
fr_client_t * client_afrom_request(TALLOC_CTX *ctx, request_t *request)
Create a new client, consuming all attributes in the control list of the request.
Definition: client.c:930
static char const * hs_proto
Definition: client.c:423
Group of clients.
Definition: client.c:55
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition: talloc.c:445
static int talloc_const_free(void const *ptr)
Free const'd memory.
Definition: talloc.h:224
#define fr_time_delta_lt(_a, _b)
Definition: time.h:285
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:590
#define fr_time_delta_wrap(_time)
Definition: time.h:152
#define fr_time_delta_ispos(_a)
Definition: time.h:290
static fr_time_delta_t fr_time_delta_from_usec(int64_t usec)
Definition: time.h:568
enum fr_token fr_token_t
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_SET
Definition: token.h:84
fr_trie_t * fr_trie_alloc(TALLOC_CTX *ctx, fr_trie_key_t get_key, fr_free_t free_data)
Allocate a trie.
Definition: trie.c:741
void * fr_trie_remove_by_key(fr_trie_t *ft, void const *key, size_t keylen)
Remove a key and return the associated user ctx.
Definition: trie.c:2154
void * fr_trie_match_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Match a key and length in a trie and return user ctx, if any.
Definition: trie.c:1286
int fr_trie_insert_by_key(fr_trie_t *ft, void const *key, size_t keylen, void const *data)
Insert a key and user ctx into a trie.
Definition: trie.c:1875
void * fr_trie_lookup_by_key(fr_trie_t const *ft, void const *key, size_t keylen)
Lookup a key in a trie and return user ctx, if any.
Definition: trie.c:1262
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:261
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition: pair_print.c:40
static fr_slen_t parent
Definition: pair.h:851
fr_sbuff_escape_rules_t fr_value_escape_single
Definition: value.c:388
ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules)
Print one boxed value to a string.
Definition: value.c:5352
#define fr_box_ipaddr(_val)
Definition: value.h:294
static fr_slen_t data
Definition: value.h:1265
static size_t char ** out
Definition: value.h:997
CONF_SECTION * virtual_server_cs(virtual_server_t const *vs)
Return the configuration section for a virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.