The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
unit_test_module.c
Go to the documentation of this file.
1 /*
2  * This program 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
5  * (at 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  * $Id: d916d8f01a59fb74db713e691c62ab4a9c54e9ad $
18  *
19  * @file unit_test_module.c
20  * @brief Module test framework
21  *
22  * @copyright 2000-2018 The FreeRADIUS server project
23  * @copyright 2013 Alan DeKok (aland@freeradius.org)
24  * @copyright 2018 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
25  */
26 RCSID("$Id: d916d8f01a59fb74db713e691c62ab4a9c54e9ad $")
27 
28 #include <freeradius-devel/server/base.h>
29 #include <freeradius-devel/server/map_proc.h>
30 #include <freeradius-devel/server/module_rlm.h>
31 #include <freeradius-devel/util/debug.h>
32 #include <freeradius-devel/util/rand.h>
33 #include <freeradius-devel/util/value.h>
34 #include <freeradius-devel/util/strerror.h>
35 #include <freeradius-devel/util/sbuff.h>
36 #include <freeradius-devel/io/listen.h>
37 
38 #include <freeradius-devel/tls/base.h>
39 #include <freeradius-devel/tls/version.h>
40 
41 #include <freeradius-devel/unlang/base.h>
42 
43 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
44 #include <freeradius-devel/radius/radius.h>
45 
46 #ifdef HAVE_GETOPT_H
47 # include <getopt.h>
48 #endif
49 
50 #include <ctype.h>
51 
52 #define EXIT_WITH_FAILURE \
53 do { \
54  ret = EXIT_FAILURE; \
55  goto cleanup; \
56 } while (0)
57 
58 /*
59  * Global variables.
60  */
61 static bool filedone = false;
62 static int my_debug_lvl = 0;
63 
64 char const *radiusd_version = RADIUSD_VERSION_BUILD("unit_test_module");
65 
66 static fr_dict_t const *dict_freeradius;
67 static fr_dict_t const *dict_protocol;
68 
69 #define PROTOCOL_NAME unit_test_module_dict[1].proto
70 
73  { .out = &dict_freeradius, .proto = "freeradius" },
74  { .out = &dict_protocol, .proto = "radius" }, /* hacked in-place with '-p protocol' */
75  { NULL }
76 };
77 
79 static fr_dict_attr_t const *attr_net;
80 
83  { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_protocol },
84  { .out = &attr_net, .name = "Net", .type = FR_TYPE_TLV, .dict = &dict_freeradius },
85 
86  { NULL }
87 };
88 
89 /*
90  * Static functions.
91  */
92 static void usage(main_config_t const *config, int status);
93 
94 static fr_client_t *client_alloc(TALLOC_CTX *ctx, char const *ip, char const *name)
95 {
96  CONF_SECTION *cs;
97  fr_client_t *client;
98 
99  cs = cf_section_alloc(ctx, NULL, "client", name);
100  MEM(cf_pair_alloc(cs, "ipaddr", ip, T_OP_EQ, T_BARE_WORD, T_BARE_WORD));
101  MEM(cf_pair_alloc(cs, "secret", "supersecret", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
102  MEM(cf_pair_alloc(cs, "nas_type", "test", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
103  MEM(cf_pair_alloc(cs, "shortname", "test", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
107 
108  client = client_afrom_cs(ctx, cs, NULL, 0);
109  if (!client) {
110  PERROR("Failed creating test client");
111  fr_assert(0);
112  }
113  talloc_steal(client, cs);
114  fr_assert(client);
115 
116  return client;
117 }
118 
119 static void pair_mutable(fr_pair_t *vp)
120 {
121  if (fr_type_is_leaf(vp->vp_type)) {
122  vp->data.immutable = false;
123 
124  return;
125  }
126 
127  fr_pair_list_foreach(&vp->vp_group, child) {
128  pair_mutable(child);
129  }
130 }
131 
132 static request_t *request_from_internal(TALLOC_CTX *ctx)
133 {
134  request_t *request;
135 
136  /*
137  * Create and initialize the new request.
138  */
139  request = request_alloc_internal(ctx, NULL);
140  if (!request->packet) request->packet = fr_packet_alloc(request, false);
141  if (!request->reply) request->reply = fr_packet_alloc(request, false);
142 
143  request->packet->socket = (fr_socket_t){
144  .type = SOCK_DGRAM,
145  .inet = {
146  .src_ipaddr = {
147  .af = AF_INET,
148  .prefix = 32,
149  .addr = {
150  .v4 = {
151  .s_addr = htonl(INADDR_LOOPBACK)
152  }
153  }
154  },
155  .src_port = 18120,
156  .dst_ipaddr = {
157  .af = AF_INET,
158  .prefix = 32,
159  .addr = {
160  .v4 = {
161  .s_addr = htonl(INADDR_LOOPBACK)
162  }
163  }
164  },
165  .dst_port = 1812
166  }
167  };
168 
169  request->log.dst = talloc_zero(request, log_dst_t);
170  request->log.dst->func = vlog_request;
171  request->log.dst->uctx = &default_log;
172  request->log.dst->lvl = fr_debug_lvl;
173 
174  request->master_state = REQUEST_ACTIVE;
175  request->log.lvl = fr_debug_lvl;
176  request->async = talloc_zero(request, fr_async_t);
177 
178  if (fr_packet_pairs_from_packet(request->request_ctx, &request->request_pairs, request->packet) < 0) {
179  talloc_free(request);
180  fprintf(stderr, "Failed converting packet IPs to attributes");
181  return NULL;
182  }
183 
184  return request;
185 }
186 
187 static request_t *request_from_file(TALLOC_CTX *ctx, FILE *fp, fr_client_t *client, CONF_SECTION *server_cs)
188 {
189  fr_pair_t *vp;
190  request_t *request;
191  fr_dcursor_t cursor;
192 
193  static int number = 0;
194 
195  /*
196  * Create and initialize the new request.
197  */
198  request = request_local_alloc_external(ctx, NULL);
199 
200  /*
201  * FIXME - Should be less RADIUS centric, but everything
202  * else assumes RADIUS at the moment so we can fix this later.
203  */
204  request->dict = dict_protocol;
205  if (!request->dict) {
206  fr_strerror_printf_push("%s dictionary failed to load", PROTOCOL_NAME);
207  error:
208  talloc_free(request);
209  return NULL;
210  }
211 
212  request->packet = fr_packet_alloc(request, false);
213  if (!request->packet) {
214  fr_strerror_const("No memory");
215  goto error;
216  }
217  request->packet->timestamp = fr_time();
218 
219  request->reply = fr_packet_alloc(request, false);
220  if (!request->reply) {
221  fr_strerror_const("No memory");
222  goto error;
223  }
224 
225  request->client = client;
226  request->number = number++;
227  request->name = talloc_typed_asprintf(request, "%" PRIu64, request->number);
228  request->master_state = REQUEST_ACTIVE;
229 
230  /*
231  * Read packet from fp
232  */
233  if (fr_pair_list_afrom_file(request->request_ctx, dict_protocol, &request->request_pairs, fp, &filedone) < 0) {
234  goto error;
235  }
236 
237  /*
238  * Pretend that the attributes came in "over the wire".
239  *
240  * @todo - do this only for protocol attributes, and not internal ones?
241  */
242  fr_pair_list_tainted(&request->request_pairs);
243 
244  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_packet_type);
245  if (!vp) {
246  fr_strerror_printf("Input packet does not specify a Packet-Type");
247  goto error;
248  }
249  /*
250  * Set the defaults for IPs, etc.
251  */
252  request->packet->code = vp->vp_uint32;
253 
254  /*
255  * Now delete the packet-type to ensure
256  * the virtual attribute gets used in
257  * the tests.
258  */
259  fr_pair_delete_by_da(&request->request_pairs, attr_packet_type);
260 
261  request->packet->socket = (fr_socket_t){
262  .type = SOCK_DGRAM,
263  .inet = {
264  .src_ipaddr = {
265  .af = AF_INET,
266  .prefix = 32,
267  .addr = {
268  .v4 = {
269  .s_addr = htonl(INADDR_LOOPBACK)
270  }
271  }
272  },
273  .src_port = 18120,
274  .dst_ipaddr = {
275  .af = AF_INET,
276  .prefix = 32,
277  .addr = {
278  .v4 = {
279  .s_addr = htonl(INADDR_LOOPBACK)
280  }
281  }
282  },
283  .dst_port = 1812
284  }
285  };
286 
287  /*
288  * Fill in the packet header from attributes, and then
289  * re-realize the attributes.
290  */
291  vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_packet_type);
292  if (vp) request->packet->code = vp->vp_uint32;
293 
294  fr_packet_pairs_to_packet(request->packet, &request->request_pairs);
295 
296  /*
297  * The input might have updated only some of the Net.*
298  * attributes. So for consistency, we create all of them
299  * from the packet header.
300  */
301  if (fr_packet_pairs_from_packet(request->request_ctx, &request->request_pairs, request->packet) < 0) {
302  fr_strerror_const("Failed converting packet IPs to attributes");
303  goto error;
304  }
305 
306  /*
307  * For laziness in the tests, allow the Net.* to be mutable
308  */
309  for (vp = fr_pair_dcursor_by_ancestor_init(&cursor, &request->request_pairs, attr_net);
310  vp != NULL;
311  vp = fr_dcursor_next(&cursor)) {
312  pair_mutable(vp);
313  }
314 
315  if (fr_debug_lvl) {
316  for (vp = fr_pair_dcursor_init(&cursor, &request->request_pairs);
317  vp;
318  vp = fr_dcursor_next(&cursor)) {
319  /*
320  * Take this opportunity to verify all the fr_pair_ts are still valid.
321  */
322  if (!talloc_get_type(vp, fr_pair_t)) {
323  ERROR("Expected fr_pair_t pointer got \"%s\"", talloc_get_name(vp));
324 
326  fr_assert(0);
327  }
328 
329  fr_log(&default_log, L_DBG, __FILE__, __LINE__, "%pP", vp);
330  }
331  }
332 
333  /*
334  * Build the reply template from the request.
335  */
336  fr_socket_addr_swap(&request->reply->socket, &request->packet->socket);
337 
338  request->reply->id = request->packet->id;
339  request->reply->code = 0; /* UNKNOWN code */
340  memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector));
341  request->reply->data = NULL;
342  request->reply->data_len = 0;
343 
344  /*
345  * Debugging
346  */
347  request->log.dst = talloc_zero(request, log_dst_t);
348  request->log.dst->func = vlog_request;
349  request->log.dst->uctx = &default_log;
350  request->log.dst->lvl = fr_debug_lvl;
351 
352  request->master_state = REQUEST_ACTIVE;
353  request->log.lvl = fr_debug_lvl;
354  request->async = talloc_zero(request, fr_async_t);
355 
356 
357  /*
358  * New async listeners
359  */
360  request->async = talloc_zero(request, fr_async_t);
361  unlang_call_push(request, server_cs, UNLANG_TOP_FRAME);
362 
363  return request;
364 }
365 
366 
367 static void print_packet(FILE *fp, fr_packet_t *packet, fr_pair_list_t *list)
368 {
370  fr_log_t log;
371 
372  (void) fr_log_init_fp(&log, fp);
373 
375  if (dv) {
376  fr_log(&default_log, L_DBG, __FILE__, __LINE__, "Packet-Type = %s", dv->name);
377  } else {
378  fr_log(&default_log, L_DBG, __FILE__, __LINE__, "Packet-Type = %u", packet->code);
379  }
380 
381  fr_pair_list_log(&default_log, 2, list);
382 }
383 
384 /*
385  * A common function for reports of too much text when handling xlat
386  * and xlat_expr in do_xlats().
387  * The convolution deals with the edge case of the line being so long
388  * that it plus the surrounding text from the format could won't fit
389  * in the output sbuff, along with the fact that you don't print the
390  * %d or %.*s. OTOH it does include slen, but...
391  * * the format string is 41 characters minus 6 for %d and %.*s
392  * * given that slen reflects text read from line, once slen is
393  * large enough, we know line will fit
394  */
395 static inline CC_HINT(always_inline) void too_much_text(fr_sbuff_t *out, ssize_t slen, fr_sbuff_t *line)
396 {
397  char const *format = "ERROR offset %d 'Too much text' ::%.*s::";
398 
399  (void) fr_sbuff_in_sprintf(out, format, (int) slen,
400  fr_sbuff_remaining(out) - (strlen(format) - 5),
402 }
403 
404 /*
405  * Read a file composed of xlat's and expected results
406  */
407 static bool do_xlats(fr_event_list_t *el, request_t *request, char const *filename, FILE *fp)
408 {
409  int lineno = 0;
410  ssize_t len;
411  char line_buff[8192];
412  char output_buff[8192];
413  char unescaped[sizeof(output_buff)];
415  fr_sbuff_t out = FR_SBUFF_OUT(output_buff, sizeof(output_buff));
416 
417  static fr_sbuff_escape_rules_t unprintables = {
418  .name = "unprintables",
419  .chr = '\\',
420  .esc = {
423  },
424  .do_utf8 = true,
425  .do_oct = true
426  };
427 
428  while (fgets(line_buff, sizeof(line_buff), fp) != NULL) {
429  lineno++;
430 
431  line = FR_SBUFF_IN(line_buff, sizeof(line_buff));
432  fr_sbuff_set_to_start(&out);
433  if (!fr_sbuff_adv_to_chr(&line, SIZE_MAX, '\n')) {
434  if (!feof(fp)) {
435  fprintf(stderr, "%s[%d] Line too long\n", filename, lineno);
436  return false;
437  }
438  } else {
439  fr_sbuff_terminate(&line);
440  }
441  line.end = line.p;
442  fr_sbuff_set_to_start(&line);
443 
444  /*
445  * Ignore blank lines and comments
446  */
447  fr_sbuff_adv_past_whitespace(&line, SIZE_MAX, NULL);
448  if (*fr_sbuff_current(&line) < ' ') continue;
449  if (fr_sbuff_is_char(&line, '#')) continue;
450 
451  /*
452  * Look for "match", as it needs the output_buffer to be left alone.
453  */
454  if (fr_sbuff_adv_past_str_literal(&line, "match ") > 0) {
455  size_t output_len = strlen(output_buff);
456 
457  if (!fr_sbuff_is_str(&line, output_buff, output_len) || (output_len != fr_sbuff_remaining(&line))) {
458  fprintf(stderr, "Mismatch at %s[%u]\n\tgot : %s (%zu)\n\texpected : %s (%zu)\n",
459  filename, lineno, output_buff, output_len, fr_sbuff_current(&line), fr_sbuff_remaining(&line));
460  return false;
461  }
462  continue;
463  }
464 
465  /*
466  * The rest of the keywords create output.
467  */
468  output_buff[0] = '\0';
469  out = FR_SBUFF_OUT(output_buff, sizeof(output_buff));
470 
471  /*
472  * Look for "xlat"
473  */
474  if (fr_sbuff_adv_past_str_literal(&line, "xlat ") > 0) {
475  ssize_t slen;
476  TALLOC_CTX *xlat_ctx = talloc_init_const("xlat");
477  xlat_exp_head_t *head = NULL;
478  fr_sbuff_parse_rules_t p_rules = { .escapes = &fr_value_unescape_double };
479  tmpl_rules_t t_rules = (tmpl_rules_t) {
480  .attr = {
482  .list_def = request_attr_request,
483  .allow_unresolved = true,
484  },
485  .xlat = {
486  .runtime_el = el,
487  },
488  .at_runtime = true,
489  };
490 
491 
492  slen = xlat_tokenize(xlat_ctx, &head, &line, &p_rules, &t_rules, 0);
493  if (slen <= 0) {
494  talloc_free(xlat_ctx);
495  fr_sbuff_in_sprintf(&out, "ERROR offset %d '%s'", (int) -slen, fr_strerror());
496  continue;
497  }
498 
499  if (fr_sbuff_remaining(&line) > 0) {
500  talloc_free(xlat_ctx);
501  too_much_text(&out, slen, &line);
502  continue;
503  }
504 
505  len = xlat_eval_compiled(unescaped, sizeof(unescaped), request, head, NULL, NULL);
506  if (len < 0) {
507  char const *err = fr_strerror();
508  talloc_free(xlat_ctx);
509  (void) fr_sbuff_in_sprintf(&out, "ERROR expanding xlat: %s", *err ? err : "no error provided");
510  continue;
511  }
512 
513  /*
514  * Escape the output as if it were a double quoted string.
515  */
516  fr_sbuff_in_escape(&out, unescaped, len, &unprintables);
517 
518  TALLOC_FREE(xlat_ctx); /* also frees 'head' */
519  continue;
520  }
521 
522  /*
523  * Look for "xlat_expr"
524  */
525  if (fr_sbuff_adv_past_str_literal(&line, "xlat_expr ") > 0) {
526  ssize_t slen;
527  TALLOC_CTX *xlat_ctx = talloc_init_const("xlat");
528  xlat_exp_head_t *head = NULL;
529 
530  slen = xlat_tokenize_expression(xlat_ctx, &head,
531  &line,
532  NULL,
533  &(tmpl_rules_t) {
534  .attr = {
535  .dict_def = dict_protocol,
536  .list_def = request_attr_request,
537  .allow_unresolved = true,
538  },
539  .xlat = {
540  .runtime_el = el,
541  },
542  .at_runtime = true,
543  });
544  if (slen <= 0) {
545  talloc_free(xlat_ctx);
546  fr_sbuff_in_sprintf(&out, "ERROR offset %d '%s'", (int) -slen, fr_strerror());
547  continue;
548  }
549 
550  if (fr_sbuff_remaining(&line) > 0) {
551  talloc_free(xlat_ctx);
552  too_much_text(&out, slen, &line);
553  continue;
554  }
555 
556  if (xlat_resolve(head, NULL) < 0) {
557  talloc_free(xlat_ctx);
558  (void) fr_sbuff_in_sprintf(&out, "ERROR resolving xlat: %s", fr_strerror());
559  continue;
560  }
561 
562  len = xlat_eval_compiled(unescaped, sizeof(unescaped), request, head, NULL, NULL);
563  if (len < 0) {
564  char const *err = fr_strerror();
565  talloc_free(xlat_ctx);
566  (void) fr_sbuff_in_sprintf(&out, "ERROR expanding xlat: %s", *err ? err : "no error provided");
567  continue;
568  }
569 
570  /*
571  * Escape the output as if it were a double quoted string.
572  */
573  fr_sbuff_in_escape(&out, unescaped, len, &unprintables);
574 
575  TALLOC_FREE(xlat_ctx); /* also frees 'head' */
576  continue;
577  }
578 
579  fprintf(stderr, "Unknown keyword in %s[%d]\n", filename, lineno);
580  return false;
581  }
582 
583  return true;
584 }
585 
586 /*
587  * Verify the result of the map.
588  */
589 static int map_proc_verify(CONF_SECTION *cs, UNUSED void *mod_inst, UNUSED void *proc_inst,
590  tmpl_t const *src, UNUSED map_list_t const *maps)
591 {
592  if (!src) {
593  cf_log_err(cs, "Missing source");
594 
595  return -1;
596  }
597 
598  return 0;
599 }
600 
601 static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void *mod_inst, UNUSED void *proc_inst,
602  UNUSED request_t *request, UNUSED fr_value_box_list_t *src,
603  UNUSED map_list_t const *maps)
604 {
606 }
607 
608 static request_t *request_clone(request_t *old, int number, CONF_SECTION *server_cs)
609 {
610  request_t *request;
611 
612  request = request_alloc_internal(NULL, NULL);
613  if (!request) return NULL;
614 
615  if (!request->packet) request->packet = fr_packet_alloc(request, false);
616  if (!request->reply) request->reply = fr_packet_alloc(request, false);
617 
618  memcpy(request->packet, old->packet, sizeof(*request->packet));
619  (void) fr_pair_list_copy(request->request_ctx, &request->request_pairs, &old->request_pairs);
620  request->packet->timestamp = fr_time();
621  request->number = number;
622  request->name = talloc_typed_asprintf(request, "%" PRIu64, request->number);
623 
624  unlang_call_push(request, server_cs, UNLANG_TOP_FRAME);
625 
626  request->master_state = REQUEST_ACTIVE;
627  request->dict = old->dict;
628 
629  return request;
630 }
631 
632 static void cancel_request(UNUSED fr_event_list_t *el, UNUSED fr_time_t when, void *uctx)
633 {
634  request_t *request = talloc_get_type_abort(uctx, request_t);
635  unlang_interpret_signal(request, FR_SIGNAL_CANCEL);
636 }
637 
638 /**
639  *
640  * @hidecallgraph
641  */
642 int main(int argc, char *argv[])
643 {
644  int ret = EXIT_SUCCESS;
645  int c;
646  int count = 1;
647  const char *input_file = NULL;
648  const char *xlat_input_file = NULL;
649  const char *output_file = NULL;
650  const char *filter_file = NULL;
651  FILE *fp = NULL;
652  request_t *request = NULL;
653  fr_pair_t *vp;
654  fr_pair_list_t filter_vps;
655  bool xlat_only = false;
656  fr_event_list_t *el = NULL;
657  fr_event_timer_t const *cancel_timer = NULL;
658  fr_client_t *client = NULL;
659  fr_dict_t *dict = NULL;
660  fr_dict_t const *dict_check;
661  char const *receipt_file = NULL;
662 
663  TALLOC_CTX *autofree;
664  TALLOC_CTX *thread_ctx;
665 
666  char *p;
668 
669  CONF_SECTION *server_cs;
670 
671 #ifndef NDEBUG
672  size_t memory_used_before = 0;
673  size_t memory_used_after = 0;
674 #endif
675 
676 
677  fr_pair_list_init(&filter_vps);
678 
679  /*
680  * Must be called first, so the handler is called last
681  */
683 
685  thread_ctx = talloc_new(autofree);
686 
688  if (!config) {
689  fr_perror("unit_test_module");
690  fr_exit_now(EXIT_FAILURE);
691  }
692 
693  p = strrchr(argv[0], FR_DIR_SEP);
694  if (!p) {
695  main_config_name_set_default(config, argv[0], false);
696  } else {
697  main_config_name_set_default(config, p + 1, false);
698  }
699 
701 
702  /*
703  * If the server was built with debugging enabled always install
704  * the basic fatal signal handlers.
705  */
706 #ifndef NDEBUG
707  if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0]) < 0) {
708  fr_perror("%s", config->name);
709  fr_exit_now(EXIT_FAILURE);
710  }
711 #else
713 #endif
714 
715  fr_debug_lvl = 0;
716  fr_time_start();
717 
718  /*
719  * The tests should have only IPs, not host names.
720  */
722 
723  /*
724  * We always log to stdout.
725  */
727  default_log.fd = STDOUT_FILENO;
728  default_log.print_level = true;
729 
730  /* Process the options. */
731  while ((c = getopt(argc, argv, "c:d:D:f:hi:I:mMn:o:p:r:S:xXz")) != -1) {
732  switch (c) {
733  case 'c':
734  count = atoi(optarg);
735  break;
736 
737  case 'd':
739  break;
740 
741  case 'D':
743  break;
744 
745  case 'f':
746  filter_file = optarg;
747  break;
748 
749  case 'h':
750  usage(config, EXIT_SUCCESS);
751  break;
752 
753  case 'i':
754  input_file = optarg;
755  break;
756 
757  case 'I':
758  xlat_input_file = optarg;
759  xlat_only = true;
760  break;
761 
762  case 'M':
763  talloc_enable_leak_report();
764  break;
765 
766  case 'n':
767  config->name = optarg;
768  break;
769 
770  case 'o':
771  output_file = optarg;
772  break;
773 
774  case 'p':
775  PROTOCOL_NAME = optarg;
776  break;
777 
778  case 'r':
779  receipt_file = optarg;
780  break;
781 
782  case 'S': /* Migration support */
783  if (main_config_parse_option(optarg) < 0) {
784  fprintf(stderr, "%s: Unknown configuration option '%s'\n",
785  config->name, optarg);
786  fr_exit_now(EXIT_FAILURE);
787  }
788  break;
789 
790  case 'X':
791  fr_debug_lvl += 2;
792  default_log.print_level = true;
793  break;
794 
795  case 'x':
796  fr_debug_lvl++;
797  if (fr_debug_lvl > 2) default_log.print_level = true;
798  break;
799 
800  case 'z':
801  my_debug_lvl++;
802  break;
803 
804  default:
805  usage(config, EXIT_FAILURE);
806  break;
807  }
808  }
809 
810  if (receipt_file && (fr_unlink(receipt_file) < 0)) {
811  fr_perror("%s", config->name);
813  }
814 
815 #ifdef WITH_TLS
816  /*
817  * Mismatch between build time OpenSSL and linked SSL, better to die
818  * here than segfault later.
819  */
821 
822  /*
823  * Initialising OpenSSL once, here, is safer than having individual modules do it.
824  * Must be called before display_version to ensure relevant engines are loaded.
825  *
826  * fr_openssl_init() must be called before *ANY* OpenSSL functions are used, which is why
827  * it's called so early.
828  */
829  if (fr_openssl_init() < 0) EXIT_WITH_FAILURE;
830 #endif
831 
833 
834  /*
835  * Mismatch between the binary and the libraries it depends on
836  */
838  fr_perror("%s", config->name);
839  ret = EXIT_FAILURE;
840  goto cleanup;
841  }
842 
843  /*
844  * Initialize the DL infrastructure, which is used by the
845  * config file parser.
846  */
847  modules_init(config->lib_dir);
848 
849  if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
850  fr_perror("%s", config->name);
852  }
853 
855  fr_perror("%s", config->name);
857  }
858 
859 #ifdef WITH_TLS
860  if (fr_tls_dict_init() < 0) EXIT_WITH_FAILURE;
861 #endif
862 
863  /*
864  * Load the custom dictionary
865  */
866  if (fr_dict_read(dict, config->raddb_dir, FR_DICTIONARY_FILE) == -1) {
867  PERROR("Failed to initialize the dictionaries");
869  }
870 
872  fr_perror("%s", config->name);
874  }
876  fr_perror("%s", config->name);
878  }
879 
880  if (request_global_init() < 0) {
881  fr_perror("unit_test_module");
883  }
884 
885  if (map_proc_register(NULL, "test-fail", mod_map_proc, map_proc_verify, 0, 0) < 0) {
887  }
888 
889  /*
890  * Initialise the interpreter, registering operations.
891  * This initialises
892  */
893  if (unlang_global_init() < 0) {
894  fr_perror("%s", config->name);
896  }
897 
898  /*
899  * Ensure that we load the correct virtual server for the
900  * protocol, if necessary.
901  */
902  if (!getenv("PROTOCOL")) {
903  setenv("PROTOCOL", PROTOCOL_NAME, true);
904  }
905 
906  /*
907  * Setup the global structures for module lists
908  */
909  if (modules_rlm_init() < 0) {
910  fr_perror("%s", config->name);
912  }
913  if (virtual_servers_init() < 0) {
914  fr_perror("%s", config->name);
916  }
917 
918  if (main_config_init(config) < 0) {
920  }
921 
922  /*
923  * Create a dummy client on 127.0.0.1, if one doesn't already exist.
924  */
925  client = client_find(NULL, &(fr_ipaddr_t) { .af = AF_INET, .prefix = 32, .addr.v4.s_addr = htonl(INADDR_LOOPBACK) },
926  IPPROTO_IP);
927  if (!client) {
928  client = client_alloc(NULL, "127.0.0.1", "test");
929  client_add(NULL, client);
930  }
931 
932  if (server_init(config->root_cs) < 0) EXIT_WITH_FAILURE;
933 
934  server_cs = virtual_server_find("default");
935  if (!server_cs) {
936  ERROR("Cannot find virtual server 'default'");
938  }
939 
940  /*
941  * Do some sanity checking.
942  */
943  dict_check = virtual_server_dict_by_name("default");
944  if (!dict_check || (dict_check != dict_protocol)) {
945  ERROR("Virtual server namespace does not match requested namespace '%s'", PROTOCOL_NAME);
947  }
948 
949  /*
950  * Create a dummy event list
951  */
952  el = fr_event_list_alloc(NULL, NULL, NULL);
953  fr_assert(el != NULL);
954 
955  /*
956  * Simulate thread specific instantiation
957  */
960  if (xlat_thread_instantiate(thread_ctx, el) < 0) EXIT_WITH_FAILURE;
961  unlang_thread_instantiate(thread_ctx);
962 
963  /*
964  * Set the panic action (if required)
965  */
966  {
967  char const *panic_action = NULL;
968 
969  panic_action = getenv("PANIC_ACTION");
970  if (!panic_action) panic_action = config->panic_action;
971 
972  if (panic_action && (fr_fault_setup(autofree, panic_action, argv[0]) < 0)) {
973  fr_perror("%s", config->name);
975  }
976  }
977 
978  setlinebuf(stdout); /* unbuffered output */
979 
980 #ifndef NDEBUG
981  memory_used_before = talloc_total_size(autofree);
982 #endif
983 
984  if (!input_file && !xlat_only) input_file = "-";
985 
986  if (input_file) {
987  if (strcmp(input_file, "-") == 0) {
988  fp = stdin;
989  } else {
990  fp = fopen(input_file, "r");
991  if (!fp) {
992  fprintf(stderr, "Failed reading %s: %s\n",
993  input_file, fr_syserror(errno));
995  }
996  }
997 
998  /*
999  * Grab the VPs from stdin, or from the file.
1000  */
1001  request = request_from_file(autofree, fp, client, server_cs);
1002  if (!request) {
1003  fr_perror("Failed reading input from %s", input_file);
1005  }
1006  } else {
1007  request = request_from_internal(autofree);
1008  }
1009 
1010  /*
1011  * For simplicity, read xlat's.
1012  */
1013  if (xlat_only) {
1014  if (fp && (fp != stdin)) fclose(fp);
1015 
1016  fp = fopen(xlat_input_file, "r");
1017  if (!fp) {
1018  fprintf(stderr, "Failed reading %s: %s\n",
1019  xlat_input_file, fr_syserror(errno));
1021  }
1022 
1023  if (!do_xlats(el, request, xlat_input_file, fp)) ret = EXIT_FAILURE;
1024  if (input_file) fclose(fp);
1025  goto cleanup;
1026  }
1027 
1028  /*
1029  * No filter file, OR there's no more input, OR we're
1030  * reading from a file, and it's different from the
1031  * filter file.
1032  */
1033  if (!filter_file || filedone ||
1034  ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) {
1035  if (output_file) {
1036  if (fp && (fp != stdin)) fclose(fp);
1037  fp = NULL;
1038  }
1039  filedone = false;
1040  }
1041 
1042  /*
1043  * There is a filter file. If necessary, open it. If we
1044  * already are reading it via "input_file", then we don't
1045  * need to re-open it.
1046  */
1047  if (filter_file) {
1048  if (!fp) {
1049  fp = fopen(filter_file, "r");
1050  if (!fp) {
1051  fprintf(stderr, "Failed reading %s: %s\n", filter_file, fr_syserror(errno));
1053  }
1054  }
1055 
1056  if (fr_pair_list_afrom_file(request->request_ctx, dict_protocol, &filter_vps, fp, &filedone) < 0) {
1057  fr_perror("Failed reading attributes from %s", filter_file);
1059  }
1060 
1061  /*
1062  * Filter files can't be empty.
1063  */
1064  if (fr_pair_list_empty(&filter_vps)) {
1065  fr_perror("No attributes in filter file %s", filter_file);
1067  }
1068 
1069  /*
1070  * FIXME: loop over input packets.
1071  */
1072  fclose(fp);
1073  }
1074 
1075  if (count == 1) {
1076  fr_event_timer_in(request, el, &cancel_timer, config->max_request_time, cancel_request, request);
1077  unlang_interpret_synchronous(el, request);
1078 
1079  } else {
1080  int i;
1081  request_t *cached = request;
1082 
1083  for (i = 0; i < count; i++) {
1084 #ifndef NDEBUG
1085  size_t request_used_before, request_used_after;
1086 #endif
1087 
1088  request = request_clone(cached, i, server_cs);
1089 
1090 #ifndef NDEBUG
1091  request_used_before = talloc_total_size(autofree);
1092 
1093  /*
1094  * Artificially limit the number of instructions which are run.
1095  */
1096  if (config->ins_max) {
1097  if (config->ins_countup) {
1098  request->ins_max = i + 1;
1099  } else {
1100  request->ins_max = config->ins_max;
1101  }
1102 
1103  if (request->ins_max < 10) request->ins_max = 10;
1104 
1105  request->ins_count = 0;
1106  }
1107 #endif
1108 
1109  fr_event_timer_in(request, el, &cancel_timer, config->max_request_time, cancel_request, request);
1110  unlang_interpret_synchronous(el, request);
1111  talloc_free(request);
1112 
1113 #ifndef NDEBUG
1114  request_used_after = talloc_total_size(autofree);
1115  fr_assert(request_used_after == request_used_before);
1116 #endif
1117  }
1118 
1119  request = cached;
1120  }
1121 
1122  if (!output_file || (strcmp(output_file, "-") == 0)) {
1123  fp = stdout;
1124  } else {
1125  fp = fopen(output_file, "w");
1126  if (!fp) {
1127  fprintf(stderr, "Failed writing %s: %s\n", output_file, fr_syserror(errno));
1128  goto cleanup;
1129  }
1130  }
1131 
1132  print_packet(fp, request->reply, &request->reply_pairs);
1133 
1134  if (output_file) fclose(fp);
1135 
1136  /*
1137  * Update the list with the response type, so that it can
1138  * be matched in filters.
1139  *
1140  * Some state machines already include a response Packet-Type
1141  * so we need to try and update it, else we end up with two!
1142  */
1143  if (!fr_pair_list_empty(&filter_vps)) {
1144  fr_pair_t const *failed[2];
1145 
1147  vp->vp_uint32 = request->reply->code;
1148 
1149 
1150  if (!fr_pair_validate(failed, &filter_vps, &request->reply_pairs)) {
1151  fr_pair_validate_debug(failed);
1152  fr_perror("Output file %s does not match attributes in filter %s",
1153  output_file ? output_file : "-", filter_file);
1154  ret = EXIT_FAILURE;
1155  goto cleanup;
1156  }
1157  }
1158 
1159  INFO("Exiting normally");
1160 
1161 cleanup:
1162  talloc_free(request);
1163 
1164  /*
1165  * No leaks.
1166  */
1167 #ifndef NDEBUG
1168  memory_used_after = talloc_total_size(autofree);
1169  if (memory_used_after != memory_used_before) {
1170  printf("WARNING: May have leaked memory (%zd - %zd = %zd)\n",
1171  memory_used_after, memory_used_before, memory_used_after - memory_used_before);
1172  }
1173 #endif
1174 
1175  /*
1176  * Free thread data
1177  */
1178  talloc_free(thread_ctx);
1179 
1180  /*
1181  * Ensure all thread local memory is cleaned up
1182  * at the appropriate time. This emulates what's
1183  * done with worker/network threads in the
1184  * scheduler.
1185  */
1187 
1188  /*
1189  * Give processes a chance to exit
1190  */
1192 
1193  /*
1194  * Free the event list.
1195  */
1196  talloc_free(el);
1197 
1198  /*
1199  * Ensure all thread local memory is cleaned up
1200  * at the appropriate time. This emulates what's
1201  * done with worker/network threads in the
1202  * scheduler.
1203  */
1205 
1206  server_free();
1207 
1208  /*
1209  * Free any resources used by the unlang interpreter.
1210  */
1212 
1213  /*
1214  * Virtual servers need to be freed before modules
1215  * as state entries containing data with module-specific
1216  * destructors may exist.
1217  */
1219 
1220  /*
1221  * Free modules, this needs to be done explicitly
1222  * because some libraries used by modules use atexit
1223  * handlers registered after ours, and they may deinit
1224  * themselves before we free the modules and cause
1225  * crashes on exit.
1226  */
1227  modules_rlm_free();
1228 
1229  /*
1230  * And now nothing should be left anywhere except the
1231  * parsed configuration items.
1232  */
1234 
1235 #ifdef WITH_TLS
1236  fr_tls_dict_free();
1237 #endif
1238 
1239  /*
1240  * Free any autoload dictionaries
1241  */
1243 
1244  /*
1245  * Free our explicitly loaded internal dictionary
1246  */
1247  if (fr_dict_free(&dict, __FILE__) < 0) {
1248  fr_perror("unit_test_module - dict");
1249  ret = EXIT_FAILURE;
1250  }
1251 
1252  /*
1253  * Free any openssl resources and the TLS dictionary
1254  */
1255 #ifdef WITH_TLS
1256  fr_openssl_free();
1257 #endif
1258 
1259  if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
1260  fr_perror("unit_test_module");
1261  ret = EXIT_FAILURE;
1262  }
1263 
1264  if (talloc_free(autofree) < 0) {
1265  fr_perror("unit_test_module - autofree");
1266  ret = EXIT_FAILURE;
1267  }
1268 
1269  /*
1270  * Ensure our atexit handlers run before any other
1271  * atexit handlers registered by third party libraries.
1272  */
1274 
1275  return ret;
1276 }
1277 
1278 
1279 /*
1280  * Display the syntax for starting this program.
1281  */
1282 static NEVER_RETURNS void usage(main_config_t const *config, int status)
1283 {
1284  FILE *output = status ? stderr : stdout;
1285 
1286  fprintf(output, "Usage: %s [options]\n", config->name);
1287  fprintf(output, "Options:\n");
1288  fprintf(output, " -c <count> Run packets through the interpreter <count> times\n");
1289  fprintf(output, " -d <raddb_dir> Configuration files are in \"raddb_dir/*\".\n");
1290  fprintf(output, " -D <dict_dir> Dictionary files are in \"dict_dir/*\".\n");
1291  fprintf(output, " -f <file> Filter reply against attributes in 'file'.\n");
1292  fprintf(output, " -h Print this help message.\n");
1293  fprintf(output, " -i <file> File containing request attributes.\n");
1294  fprintf(output, " -m On SIGINT or SIGQUIT exit cleanly instead of immediately.\n");
1295  fprintf(output, " -n <name> Read raddb/name.conf instead of raddb/radiusd.conf.\n");
1296  fprintf(output, " -o <file> Output file for the reply.\n");
1297  fprintf(output, " -p <radius|...> Define which protocol namespace is used to read the file\n");
1298  fprintf(output, " Use radius, dhcpv4, or dhcpv6\n");
1299  fprintf(output, " -X Turn on full debugging.\n");
1300  fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
1301  fprintf(output, " -r <receipt_file> Create the <receipt_file> as a 'success' exit.\n");
1302 
1303  fr_exit_now(status);
1304 }
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
int const char int line
Definition: acutest.h:702
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition: atexit.c:160
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition: atexit.c:286
#define fr_atexit_thread_trigger_all(...)
Definition: atexit.h:233
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
#define UNUSED
Definition: build.h:313
unlang_action_t unlang_call_push(request_t *request, CONF_SECTION *server_cs, bool top_frame)
Push a call frame onto the stack.
Definition: call.c:147
A section grouping multiple CONF_PAIR.
Definition: cf_priv.h:89
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:1220
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition: cf_util.h:137
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static char panic_action[512]
The command to execute when panicking.
Definition: debug.c:96
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition: debug.c:1180
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition: debug.c:1120
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:1215
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition: debug.c:1196
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition: debug.h:232
void dependency_version_print(void)
Definition: dependency.c:369
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *internal_name, char const *dependent)
(Re-)Initialize the special internal dictionary
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
static fr_slen_t err
Definition: dict.h:645
fr_dict_enum_value_t * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict_util.c:2946
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition: dict_util.c:3581
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition: dict_util.c:3647
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename)
Read supplementary attribute definitions into an existing dictionary.
char const * name
Enum name.
Definition: dict.h:210
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir)
Initialise the global protocol hashes.
Definition: dict_util.c:3984
Specifies an attribute which must be present for the module to function.
Definition: dict.h:249
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Value of an enumerated attribute.
Definition: dict.h:209
#define fr_event_timer_in(...)
Definition: event.h:255
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
Definition: file.c:348
ssize_t fr_touch(int *fd_out, char const *filename, mode_t mode, bool mkdir, mode_t dir_mode)
Create an empty file.
Definition: file.c:304
bool fr_hostname_lookups
hostname -> IP lookups?
Definition: inet.c:52
bool fr_reverse_lookups
IP -> hostname lookups?
Definition: inet.c:51
IPv4/6 prefix.
Definition: merged_model.c:272
void unlang_interpret_signal(request_t *request, fr_signal_t action)
Send a signal (usually stop) to a request.
Definition: interpret.c:1184
#define UNLANG_TOP_FRAME
Definition: interpret.h:35
rlm_rcode_t unlang_interpret_synchronous(fr_event_list_t *el, request_t *request)
Execute an unlang section synchronously.
Minimal data structure to use the new code.
Definition: listen.h:58
void server_free(void)
Free src/lib/server/.
Definition: base.c:111
int server_init(CONF_SECTION *cs)
Initialize src/lib/server/.
Definition: base.c:41
Describes a host allowed to send packets to the server.
Definition: client.h:77
void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt, va_list ap, void *uctx)
Send a log message to its destination, possibly including fields from the request.
Definition: log.c:286
#define PERROR(_fmt,...)
Definition: log.h:228
Definition: log.h:70
void fr_packet_pairs_to_packet(fr_packet_t *packet, fr_pair_list_t const *list)
Convert pairs to information in a packet.
Definition: packet.c:136
int fr_packet_pairs_from_packet(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_packet_t const *packet)
Allocate a "Net." struct with src/dst host and port.
Definition: packet.c:86
void unlang_global_free(void)
Definition: base.c:134
int unlang_global_init(void)
Definition: base.c:74
fr_event_list_t * fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t status, void *status_uctx)
Initialise a new event list.
Definition: event.c:2892
talloc_free(reap)
unsigned int fr_event_list_reap_signal(fr_event_list_t *el, fr_time_delta_t timeout, int signal)
Send a signal to all the processes we have in our reap list, and reap them.
Definition: event.c:1997
Stores all information relating to an event list.
Definition: event.c:411
A timer event.
Definition: event.c:102
int fr_debug_lvl
Definition: log.c:42
fr_log_t default_log
Definition: log.c:290
int fr_log_init_fp(fr_log_t *log, FILE *fp)
Initialise a file logging destination to a FILE*.
Definition: log.c:1078
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition: log.c:599
@ L_DST_STDOUT
Log to stdout.
Definition: log.h:78
@ L_DBG
Only displayed when debugging is enabled.
Definition: log.h:59
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition: packet.c:38
int main_config_parse_option(char const *value)
Definition: main_config.c:1516
int main_config_free(main_config_t **config)
Definition: main_config.c:1429
void main_config_raddb_dir_set(main_config_t *config, char const *name)
Set the global radius config directory.
Definition: main_config.c:859
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
Definition: main_config.c:840
int main_config_init(main_config_t *config)
Definition: main_config.c:1033
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
Definition: main_config.c:1000
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
Definition: main_config.c:988
Main server configuration.
Definition: main_config.h:51
int map_proc_register(void *mod_inst, char const *name, map_proc_func_t evaluate, map_proc_instantiate_t instantiate, size_t inst_size, fr_value_box_safe_for_t literals_safe_for)
Register a map processor.
Definition: map_proc.c:111
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
long int ssize_t
Definition: merged_model.c:24
int modules_rlm_free(void)
Cleanup all global structures.
Definition: module_rlm.c:1138
int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Allocates thread-specific data for all registered backend modules.
Definition: module_rlm.c:939
int modules_rlm_init(void)
Initialise the module list structure.
Definition: module_rlm.c:1156
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
void fr_pair_list_tainted(fr_pair_list_t *list)
Mark up a list of VPs as tainted.
Definition: pair.c:3454
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
void fr_pair_validate_debug(fr_pair_t const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition: pair.c:2090
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition: pair.c:1684
bool fr_pair_validate(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check.
Definition: pair.c:2125
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
Read valuepairs from the fp up to End-Of-File.
Definition: pair_legacy.c:572
static const conf_parser_t config[]
Definition: base.c:188
static TALLOC_CTX * autofree
Definition: radclient-ng.c:104
#define INFO(fmt,...)
Definition: radict.c:54
static bool cleanup
Definition: radsniff.c:60
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
int request_global_init(void)
Definition: request.c:698
#define request_alloc_internal(_ctx, _args)
Allocate a new internal request.
Definition: request.h:304
#define request_local_alloc_external(_ctx, _args)
Allocate a new external request outside of the request pool.
Definition: request.h:315
@ REQUEST_ACTIVE
Definition: request.h:61
static char const * name
ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff.
Definition: sbuff.c:1579
char * fr_sbuff_adv_to_chr(fr_sbuff_t *sbuff, size_t len, char c)
Wind position to first instance of specified char.
Definition: sbuff.c:1915
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
Definition: sbuff.c:1554
#define fr_sbuff_adv_past_str_literal(_sbuff, _needle)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define fr_sbuff_remaining(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SBUFF_CHAR_UNPRINTABLES_LOW
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition: pair.h:129
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
struct tmpl_rules_s tmpl_rules_t
Definition: tmpl.h:236
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_client_t * client_find(fr_client_list_t const *clients, fr_ipaddr_t const *ipaddr, int proto)
Definition: client.c:375
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:697
bool client_add(fr_client_list_t *clients, fr_client_t *client)
Add a client to a fr_client_list_t.
Definition: client.c:184
void modules_init(char const *lib_dir)
Perform global initialisation for modules.
Definition: module.c:1163
return count
Definition: module.c:175
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition: state_test.c:8
Definition: log.h:96
fr_log_dst_t dst
Log destination.
Definition: log.h:97
int fd
File descriptor to write messages to.
Definition: log.h:112
bool print_level
sometimes we don't want log levels printed
Definition: log.h:106
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition: talloc.h:51
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
Definition: talloc.h:112
int fr_time_start(void)
Initialize the local time.
Definition: time.c:150
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
"server local" time.
Definition: time.h:69
int fr_openssl_version_consistent(void)
Definition: version.c:325
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
static fr_event_list_t * el
static request_t * request_from_file(TALLOC_CTX *ctx, FILE *fp, fr_client_t *client, CONF_SECTION *server_cs)
static bool filedone
int main(int argc, char *argv[])
static fr_dict_attr_t const * attr_packet_type
#define PROTOCOL_NAME
static request_t * request_clone(request_t *old, int number, CONF_SECTION *server_cs)
static fr_dict_t const * dict_freeradius
static int map_proc_verify(CONF_SECTION *cs, UNUSED void *mod_inst, UNUSED void *proc_inst, tmpl_t const *src, UNUSED map_list_t const *maps)
static fr_dict_attr_t const * attr_net
static void pair_mutable(fr_pair_t *vp)
static request_t * request_from_internal(TALLOC_CTX *ctx)
static void usage(main_config_t const *config, int status)
static fr_dict_t const * dict_protocol
fr_dict_attr_autoload_t unit_test_module_dict_attr[]
char const * radiusd_version
static int my_debug_lvl
static void cancel_request(UNUSED fr_event_list_t *el, UNUSED fr_time_t when, void *uctx)
static unlang_action_t mod_map_proc(rlm_rcode_t *p_result, UNUSED void *mod_inst, UNUSED void *proc_inst, UNUSED request_t *request, UNUSED fr_value_box_list_t *src, UNUSED map_list_t const *maps)
static fr_client_t * client_alloc(TALLOC_CTX *ctx, char const *ip, char const *name)
#define EXIT_WITH_FAILURE
static void too_much_text(fr_sbuff_t *out, ssize_t slen, fr_sbuff_t *line)
static void print_packet(FILE *fp, fr_packet_t *packet, fr_pair_list_t *list)
fr_dict_autoload_t unit_test_module_dict[]
static bool do_xlats(fr_event_list_t *el, request_t *request, char const *filename, FILE *fp)
int unlang_thread_instantiate(TALLOC_CTX *ctx)
Create thread-specific data structures for unlang.
Definition: compile.c:4965
ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition: xlat_eval.c:1462
static fr_slen_t head
Definition: xlat.h:408
int xlat_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Create thread specific instance tree and create thread instances.
Definition: xlat_inst.c:439
fr_slen_t xlat_tokenize(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules, fr_value_box_safe_for_t literals_safe_for)
Tokenize an xlat expansion.
int xlat_resolve(xlat_exp_head_t *head, xlat_res_rules_t const *xr_rules)
Walk over an xlat tree recursively, resolving any unresolved functions or references.
fr_slen_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules)
Definition: xlat_expr.c:3017
#define FR_DICTIONARY_FILE
Definition: conf.h:7
#define FR_DICTIONARY_INTERNAL_DIR
Definition: conf.h:8
unsigned int code
Packet code (type).
Definition: packet.h:61
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:260
#define fr_pair_list_log(_log, _lvl, _list)
Definition: pair.h:850
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:590
#define fr_pair_dcursor_by_ancestor_init(_cursor, _list, _da)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
Definition: pair.h:645
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
Definition: socket.h:121
Holds information necessary for binding or connecting to a socket.
Definition: socket.h:63
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition: strerror.c:733
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition: strerror.h:84
#define fr_strerror_const(_msg)
Definition: strerror.h:223
#define fr_type_is_leaf(_x)
Definition: types.h:372
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition: version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition: version.h:81
fr_sbuff_unescape_rules_t fr_value_unescape_double
Definition: value.c:266
#define fr_box_uint32(_val)
Definition: value.h:305
int format(printf, 5, 0))
static size_t char ** out
Definition: value.h:984
CONF_SECTION * virtual_server_find(char const *name)
Return virtual server matching the specified name.
int virtual_servers_init(void)
Performs global initialisation for the virtual server code.
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
int virtual_servers_free(void)
int virtual_servers_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Perform thread instantiation for all process modules and listeners.