The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
rlm_files.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: f8e96ec7f41a8c40c96119b5d61e6b1c9a7f186d $
19  * @file rlm_files.c
20  * @brief Process simple 'users' policy files.
21  *
22  * @copyright 2000,2006 The FreeRADIUS server project
23  * @copyright 2000 Jeff Carneal (jeff@apex.net)
24  */
25 RCSID("$Id: f8e96ec7f41a8c40c96119b5d61e6b1c9a7f186d $")
26 
27 #include <freeradius-devel/server/base.h>
28 #include <freeradius-devel/server/module_rlm.h>
29 #include <freeradius-devel/server/pairmove.h>
30 #include <freeradius-devel/server/users_file.h>
31 #include <freeradius-devel/util/htrie.h>
32 #include <freeradius-devel/unlang/call_env.h>
33 #include <freeradius-devel/unlang/function.h>
34 #include <freeradius-devel/unlang/transaction.h>
35 
36 #include <ctype.h>
37 #include <fcntl.h>
38 
39 typedef struct {
40  char const *filename;
41 } rlm_files_t;
42 
43 /** Structure produced by custom call_env parser
44  */
45 typedef struct {
46  tmpl_t *key_tmpl; //!< tmpl used to evaluate lookup key.
47  fr_htrie_t *htrie; //!< parsed files "user" data.
48  PAIR_LIST_LIST *def; //!< parsed files DEFAULT data.
50 
51 /** Call_env structure
52  */
53 typedef struct {
54  rlm_files_data_t *data; //!< Data from parsed call_env.
55  tmpl_t *match_attr; //!< Attribute to populate with matched key value.
56  char const *name; //!< Name of module instance - for debug output.
57  fr_value_box_list_t values; //!< Where the expanded tmpl value will be written.
59 
60 static fr_dict_t const *dict_freeradius;
61 
64  { .out = &dict_freeradius, .proto = "freeradius" },
65  { NULL }
66 };
67 
70 
73  { .out = &attr_fall_through, .name = "Fall-Through", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
74  { .out = &attr_next_shortest_prefix, .name = "Next-Shortest-Prefix", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
75 
76  { NULL }
77 };
78 
79 static const conf_parser_t module_config[] = {
82 };
83 
84 
85 static uint32_t pairlist_hash(void const *a)
86 {
87  return fr_value_box_hash(((PAIR_LIST_LIST const *)a)->box);
88 }
89 
90 static int8_t pairlist_cmp(void const *a, void const *b)
91 {
92  int ret;
93 
94  ret = fr_value_box_cmp(((PAIR_LIST_LIST const *)a)->box, ((PAIR_LIST_LIST const *)b)->box);
95  return CMP(ret, 0);
96 }
97 
98 static int pairlist_to_key(uint8_t **out, size_t *outlen, void const *a)
99 {
100  return fr_value_box_to_key(out, outlen, ((PAIR_LIST_LIST const *)a)->box);
101 }
102 
103 static int getrecv_filename(TALLOC_CTX *ctx, char const *filename, fr_htrie_t **ptree, PAIR_LIST_LIST **pdefault,
104  fr_type_t data_type, fr_dict_attr_t const *key_enum, fr_dict_t const *dict)
105 {
106  int rcode;
107  PAIR_LIST_LIST users;
108  PAIR_LIST_LIST search_list; // Temporary list header used for matching in htrie
109  PAIR_LIST *entry, *next;
110  PAIR_LIST_LIST *user_list, *default_list;
111  fr_htrie_t *tree;
112  fr_htrie_type_t htype;
113  fr_value_box_t *box;
114  map_t *reply_head;
115 
116  if (!filename) {
117  *ptree = NULL;
118  return 0;
119  }
120 
121  pairlist_list_init(&users);
122  rcode = pairlist_read(ctx, dict, filename, &users);
123  if (rcode < 0) {
124  return -1;
125  }
126 
127  htype = fr_htrie_hint(data_type);
128 
129  /*
130  * Walk through the 'users' file list
131  */
132  entry = NULL;
133  while ((entry = fr_dlist_next(&users.head, entry))) {
134  map_t *map = NULL;
135  map_t *prev, *next_map;
136  fr_dict_attr_t const *da;
137  map_t *sub_head, *set_head;
138 
139  reply_head = NULL;
140 
141  /*
142  * Do various sanity checks.
143  */
144  while ((map = map_list_next(&entry->check, map))) {
145  if (!tmpl_is_attr(map->lhs)) {
146  ERROR("%s[%d] Left side of check item %s is not an attribute",
147  entry->filename, entry->lineno, map->lhs->name);
148  return -1;
149  }
150 
151  /*
152  * Disallow regexes for now.
153  */
154  if ((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)) {
155  fr_assert(tmpl_is_regex(map->rhs));
156  }
157 
158  /*
159  * Move assignment operations to the reply list.
160  */
161  switch (map->op) {
162  case T_OP_EQ:
163  case T_OP_SET:
164  case T_OP_ADD_EQ:
165  prev = map_list_remove(&entry->check, map);
166  map_list_insert_after(&entry->reply, reply_head, map);
167  reply_head = map;
168  map = prev;
169  break;
170 
171  default:
172  break;
173  }
174  } /* end of loop over check items */
175 
176  /*
177  * Note that we also re-arrange any control items which are in the reply item list.
178  */
179  sub_head = set_head = NULL;
180 
181  /*
182  * Look for server configuration items
183  * in the reply list.
184  *
185  * It's a common enough mistake, that it's
186  * worth doing.
187  */
188  for (map = map_list_head(&entry->reply);
189  map != NULL;
190  map = next_map) {
191  next_map = map_list_next(&entry->reply, map);
192  if (!tmpl_is_attr(map->lhs)) {
193  ERROR("%s[%d] Left side of reply item %s is not an attribute",
194  entry->filename, entry->lineno, map->lhs->name);
195  return -1;
196  }
197  da = tmpl_attr_tail_da(map->lhs);
198 
199  if (fr_comparison_op[map->op] && (map->op != T_OP_LE) && (map->op != T_OP_GE)) {
200  ERROR("%s[%d] Invalid operator reply item %s %s ...",
201  entry->filename, entry->lineno, map->lhs->name, fr_tokens[map->op]);
202  return -1;
203  }
204 
205  /*
206  * Regex assignments aren't allowed.
207  *
208  * Execs are being deprecated.
209  */
210  if (tmpl_contains_regex(map->rhs) || tmpl_is_exec(map->rhs)) {
211  ERROR("%s[%d] Invalid right-hand side of assignment for attribute %s",
212  entry->filename, entry->lineno, da->name);
213  return -1;
214  }
215 
216  if (da == attr_next_shortest_prefix) {
217  if (htype != FR_HTRIE_TRIE) {
218  ERROR("%s[%d] Cannot use %s when key is not an IP / IP prefix",
219  entry->filename, entry->lineno, da->name);
220  return -1;
221  }
222 
223  if (!tmpl_is_data(map->rhs) || (tmpl_value_type(map->rhs) != FR_TYPE_BOOL)) {
224  ERROR("%s[%d] Value for %s must be static boolean",
225  entry->filename, entry->lineno, da->name);
226  return -1;
227  }
228 
229  entry->next_shortest_prefix = tmpl_value(map->rhs)->vb_bool;
230  (void) map_list_remove(&entry->reply, map);
231  continue;
232  }
233 
234  /*
235  * Check for Fall-Through in the reply list. If so, delete it and set the flag
236  * in the entry.
237  *
238  * Note that we don't free "map", as the map functions usually make the "next"
239  * map be talloc parented from the current one. So freeing this one will likely
240  * free all subsequent maps.
241  */
242  if (da == attr_fall_through) {
243  if (!tmpl_is_data(map->rhs) || (tmpl_value_type(map->rhs) != FR_TYPE_BOOL)) {
244  ERROR("%s[%d] Value for %s must be static boolean",
245  entry->filename, entry->lineno, da->name);
246  return -1;
247  }
248 
249  entry->fall_through = tmpl_value(map->rhs)->vb_bool;
250  (void) map_list_remove(&entry->reply, map);
251  continue;
252  }
253 
254  /*
255  * Removals are applied before anything else.
256  */
257  if (map->op == T_OP_SUB_EQ) {
258  if (sub_head == map) continue;
259 
260  (void) map_list_remove(&entry->reply, map);
261  map_list_insert_after(&entry->reply, sub_head, map);
262  sub_head = map;
263  continue;
264  }
265 
266  /*
267  * Over-rides are applied after deletions.
268  */
269  if (map->op == T_OP_SET) {
270  if (set_head == map) continue;
271 
272  if (!set_head) set_head = sub_head;
273 
274  (void) map_list_remove(&entry->reply, map);
275  map_list_insert_after(&entry->reply, set_head, map);
276  set_head = map;
277  continue;
278  }
279  }
280  }
281 
282  tree = fr_htrie_alloc(ctx, htype, pairlist_hash, pairlist_cmp, pairlist_to_key, NULL);
283  if (!tree) {
284  while ((entry = fr_dlist_pop_head(&users.head))) {
285  talloc_free(entry);
286  }
287  return -1;
288  }
289 
290  default_list = NULL;
291  MEM(box = fr_value_box_alloc(ctx, data_type, NULL));
292 
293  /*
294  * We've read the entries in linearly, but putting them
295  * into an indexed data structure would be much faster.
296  * Let's go fix that now.
297  */
298  for (entry = fr_dlist_head(&users.head); entry != NULL; entry = next) {
299  /*
300  * Remove this entry from the input list.
301  */
302  next = fr_dlist_next(&users.head, entry);
303  fr_dlist_remove(&users.head, entry);
304 
305  /*
306  * @todo - loop over entry->reply, calling
307  * unlang_fixup_update() or unlang_fixup_filter()
308  * to double-check the maps.
309  *
310  * Those functions do normalization and sanity
311  * checks which are needed if this module is
312  * going to call an unlang function to *apply*
313  * the maps.
314  */
315 
316  /*
317  * DEFAULT entries get their own list.
318  */
319  if (strcmp(entry->name, "DEFAULT") == 0) {
320  if (!default_list) {
321  default_list = talloc_zero(ctx, PAIR_LIST_LIST);
322  pairlist_list_init(default_list);
323  default_list->name = entry->name;
324 
325  /*
326  * Don't insert the DEFAULT list
327  * into the tree, instead make it
328  * it's own list.
329  */
330  *pdefault = default_list;
331  }
332 
333  /*
334  * Append the entry to the DEFAULT list
335  */
336  fr_dlist_insert_tail(&default_list->head, entry);
337  continue;
338  }
339 
340  /*
341  * Not DEFAULT, must be a normal user. First look
342  * for a matching list header already in the tree.
343  */
344  search_list.name = entry->name;
345  search_list.box = box;
346 
347  /*
348  * Has to be of the correct data type.
349  */
350  if (fr_value_box_from_str(box, box, data_type, key_enum,
351  entry->name, strlen(entry->name), NULL, false) < 0) {
352  ERROR("%s[%d] Failed parsing key %s - %s",
353  entry->filename, entry->lineno, entry->name, fr_strerror());
354  goto error;
355  }
356 
357  /*
358  * Find an exact match, especially for patricia tries.
359  */
360  user_list = fr_htrie_match(tree, &search_list);
361  if (!user_list) {
362  user_list = talloc_zero(ctx, PAIR_LIST_LIST);
363  pairlist_list_init(user_list);
364  user_list->name = entry->name;
365  user_list->box = fr_value_box_alloc(user_list, data_type, NULL);
366 
367  (void) fr_value_box_copy(user_list, user_list->box, box);
368 
369  /*
370  * Insert the new list header.
371  */
372  if (!fr_htrie_insert(tree, user_list)) {
373  ERROR("%s[%d] Failed inserting key %s - %s",
374  entry->filename, entry->lineno, entry->name, fr_strerror());
375  goto error;
376 
377  error:
379  talloc_free(tree);
380  return -1;
381  }
382  }
384 
385  /*
386  * Append the entry to the user list
387  */
388  fr_dlist_insert_tail(&user_list->head, entry);
389  }
390 
391  *ptree = tree;
392 
393  return 0;
394 }
395 
396 /** Lookup the expanded key value in files data.
397  *
398  */
399 static unlang_action_t CC_HINT(nonnull) mod_files_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
400 {
401  rlm_files_env_t *env = talloc_get_type_abort(uctx, rlm_files_env_t);
402  PAIR_LIST_LIST const *user_list;
403  PAIR_LIST const *user_pl, *default_pl;
404  bool found = false, trie = false;
405  PAIR_LIST_LIST my_list;
406  uint8_t key_buffer[16], *key;
407  size_t keylen = 0;
408  fr_edit_list_t *el, *child;
409  fr_htrie_t *tree = env->data->htrie;
410  PAIR_LIST_LIST *default_list = env->data->def;
411  fr_value_box_t *key_vb = fr_value_box_list_head(&env->values);
412 
413  if (!key_vb) {
414  RERROR("Missing key value");
416  }
417 
418  if (!tree && !default_list) RETURN_MODULE_NOOP;
419 
420  RDEBUG2("%s - Looking for key \"%pV\"", env->name, key_vb);
421 
422  el = unlang_interpret_edit_list(request);
423  MEM(child = fr_edit_list_alloc(request, 50, el));
424 
425  if (tree) {
426  my_list.name = NULL;
427  my_list.box = key_vb;
428  user_list = fr_htrie_find(tree, &my_list);
429 
430  trie = (tree->type == FR_HTRIE_TRIE);
431 
432  /*
433  * Convert the value-box to a key for use in a trie. The trie assumes that the key
434  * starts at the high bit of the data, and that isn't always the case. e.g. "bool" and
435  * "integer" may be in host byte order, in which case we have to convert them to network
436  * byte order.
437  */
438  if (user_list && trie) {
439  key = key_buffer;
440  keylen = sizeof(key_buffer) * 8;
441 
442  (void) fr_value_box_to_key(&key, &keylen, key_vb);
443 
444  RDEBUG3("Keylen %ld", keylen);
445  RHEXDUMP3(key, (keylen + 7) >> 3, "KEY ");
446  }
447 
448  user_pl = user_list ? fr_dlist_head(&user_list->head) : NULL;
449  } else {
450  user_pl = NULL;
451  user_list = NULL;
452  }
453 
454 redo:
455  default_pl = default_list ? fr_dlist_head(&default_list->head) : NULL;
456 
457  /*
458  * Find the entry for the user.
459  */
460  while (user_pl || default_pl) {
461  map_t *map = NULL;
462  PAIR_LIST const *pl;
463  bool match = true;
464 
465  /*
466  * Figure out which entry to match on.
467  */
468  if (!default_pl && user_pl) {
469  pl = user_pl;
470 
471  RDEBUG3("DEFAULT[] USER[%d]=%s", user_pl->lineno, user_pl->name);
472  user_pl = fr_dlist_next(&user_list->head, user_pl);
473 
474  } else if (!user_pl && default_pl) {
475  pl = default_pl;
476  RDEBUG3("DEFAULT[%d]= USER[]=", default_pl->lineno);
477  default_pl = fr_dlist_next(&default_list->head, default_pl);
478 
479  } else if (user_pl->order < default_pl->order) {
480  pl = user_pl;
481 
482  RDEBUG3("DEFAULT[%d]= USER[%d]=%s (choosing user)", default_pl->lineno, user_pl->lineno, user_pl->name);
483  user_pl = fr_dlist_next(&user_list->head, user_pl);
484 
485  } else {
486  pl = default_pl;
487  RDEBUG3("DEFAULT[%d]= USER[%d]=%s (choosing default)", default_pl->lineno, user_pl->lineno, user_pl->name);
488  default_pl = fr_dlist_next(&default_list->head, default_pl);
489  }
490 
491  /*
492  * Run the check items.
493  */
494  while ((map = map_list_next(&pl->check, map))) {
495  int rcode;
496 
497  RDEBUG3(" %s %s %s", map->lhs->name, fr_tokens[map->op], map->rhs ? map->rhs->name : "{ ... }");
498 
499  /*
500  * Control items get realized to VPs, and
501  * copied to a temporary list, which is
502  * then copied to control if the entire
503  * line matches.
504  */
505  switch (map->op) {
506  case T_OP_EQ:
507  case T_OP_SET:
508  case T_OP_ADD_EQ:
509  fr_assert(0);
510  goto fail;
511 
512  /*
513  * Evaluate the map, including regexes.
514  */
515  default:
516  rcode = radius_legacy_map_cmp(request, map);
517  if (rcode < 0) {
518  RPWARN("Failed parsing map for check item %s, skipping it", map->lhs->name);
519  fail:
520  fr_edit_list_abort(child);
522  }
523 
524  if (!rcode) {
525  RDEBUG3(" failed match");
526  match = false;
527  }
528  break;
529  }
530 
531  if (!match) break;
532  }
533 
534  if (!match) continue;
535 
536  RDEBUG2("%s - Found match \"%s\" on line %d of %s", env->name, pl->name, pl->lineno, pl->filename);
537  found = true;
538 
539  /*
540  * If match_attr is configured, populate the requested attribute with the
541  * key value from the matching line.
542  */
543  if (env->match_attr) {
544  tmpl_t match_rhs;
545  map_t match_map;
546 
547  match_map = (map_t) {
548  .lhs = env->match_attr,
549  .op = T_OP_SET,
550  .rhs = &match_rhs
551  };
552 
553  tmpl_init_shallow(&match_rhs, TMPL_TYPE_DATA, T_BARE_WORD, "", 0, NULL);
554  fr_value_box_bstrndup_shallow(&match_map.rhs->data.literal, NULL, pl->name,
555  talloc_array_length(pl->name) - 1, false);
556  if (map_to_request(request, &match_map, map_to_vp, NULL) < 0) {
557  RWARN("Failed populating %s with key value %s", env->match_attr->name, pl->name);
558  }
559  }
560 
561  if (map_list_num_elements(&pl->reply) > 0) {
562  RDEBUG2("%s - Preparing attribute updates:", env->name);
563  /* ctx may be reply */
564  RINDENT();
565  if (radius_legacy_map_list_apply(request, &pl->reply, child) < 0) {
566  RPWARN("Failed parsing reply item");
567  REXDENT();
568  goto fail;
569  }
570  REXDENT();
571  }
572 
573  if (pl->fall_through) continue;
574 
575  /*
576  * We're not doing patricia tries. Stop now.
577  */
578  if (!trie) break;
579 
580  /*
581  * We're doing patricia tries, but we've been
582  * told to not walk back up the trie, OR we're at the top of the tree. Stop.
583  */
584  if (!pl->next_shortest_prefix || (keylen == 0)) break;
585 
586  /*
587  * Walk back up the trie looking for shorter prefixes.
588  *
589  * Note that we've already found an entry, so we
590  * MUST start with that prefix, otherwise we
591  * would end up in an loop of finding the same
592  * prefix over and over.
593  */
594  if (keylen > user_list->box->vb_ip.prefix) keylen = user_list->box->vb_ip.prefix;
595 
596  do {
597  keylen--;
598  user_list = fr_trie_lookup_by_key(tree->store, key, keylen);
599  if (!user_list) {
600  user_pl = NULL;
601  continue;
602  }
603 
604  user_pl = fr_dlist_head(&user_list->head);
605  RDEBUG("%s - Found matching shorter subnet %s at key length %ld", env->name, user_pl->name, keylen);
606  goto redo;
607  } while (keylen > 0);
608  }
609 
610  /*
611  * See if we succeeded.
612  */
613  if (!found) {
614  fr_edit_list_abort(child);
615  RETURN_MODULE_NOOP; /* on to the next module */
616  }
617 
618  fr_edit_list_commit(child);
620 }
621 
622 /** Initiate a files data lookup
623  *
624  * The results of call_env parsing are a structure containing the
625  * tmpl_t representing the key and the parsed files data, meaning tmpl
626  * expansion does not happen by default.
627  * First we push the tmpl onto the stack for evaluation, then the lookup
628  * is done in mod_files_resume.
629  */
630 static unlang_action_t CC_HINT(nonnull) mod_files(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
631 {
632  rlm_files_env_t *env = talloc_get_type_abort(mctx->env_data, rlm_files_env_t);
633 
634  fr_value_box_list_init(&env->values);
635  env->name = mctx->mi->name;
636 
637  /*
638  * Set mod_files_resume as the repeat function
639  */
640  if (unlang_function_push(request, NULL, mod_files_resume, NULL, 0, UNLANG_SUB_FRAME, env) < 0) RETURN_MODULE_FAIL;
641 
642  /*
643  * Push evaluation of the key tmpl onto the stack
644  */
645  if (unlang_tmpl_push(env, &env->values, request, env->data->key_tmpl, NULL) < 0) RETURN_MODULE_FAIL;
647 }
648 
649 /** Custom call_env parser for loading files data
650  *
651  */
652 static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
653  call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
654 {
656  CONF_PAIR const *to_parse = cf_item_to_pair(ci);
657  rlm_files_data_t *files_data;
658  fr_type_t keytype;
659  fr_dict_attr_t const *key_enum = NULL;
660 
661  MEM(files_data = talloc_zero(ctx, rlm_files_data_t));
662 
663  if (tmpl_afrom_substr(ctx, &files_data->key_tmpl,
664  &FR_SBUFF_IN(cf_pair_value(to_parse), talloc_array_length(cf_pair_value(to_parse)) - 1),
666  t_rules) < 0) return -1;
667 
668  keytype = tmpl_expanded_type(files_data->key_tmpl);
669  if (fr_htrie_hint(keytype) == FR_HTRIE_INVALID) {
670  cf_log_err(ci, "Invalid data type '%s' for 'files' module", fr_type_to_str(keytype));
671  error:
672  talloc_free(files_data);
673  return -1;
674  }
675 
676  if (files_data->key_tmpl->type == TMPL_TYPE_ATTR) {
677  key_enum = tmpl_attr_tail_da(files_data->key_tmpl);
678  }
679 
680  if (getrecv_filename(files_data, inst->filename, &files_data->htrie, &files_data->def,
681  keytype, key_enum, t_rules->attr.dict_def) < 0) goto error;
682 
683  *(void **)out = files_data;
684  return 0;
685 }
686 
689  .env = (call_env_parser_t[]){
691  .pair.dflt = "%{%{Stripped-User-Name} || %{User-Name}}", .pair.dflt_quote = T_DOUBLE_QUOTED_STRING,
692  .pair.func = call_env_parse },
695  },
696 };
697 
698 /* globally exported name */
699 extern module_rlm_t rlm_files;
701  .common = {
702  .magic = MODULE_MAGIC_INIT,
703  .name = "files",
704  .inst_size = sizeof(rlm_files_t),
706  },
707  .method_group = {
708  .bindings = (module_method_binding_t[]){
709  { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_files, .method_env = &method_env },
711  }
712  }
713 };
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition: action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition: action.h:39
static fr_dict_t * dict
Definition: fuzzer.c:46
#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 UNUSED
Definition: build.h:313
#define CALL_ENV_TERMINATOR
Definition: call_env.h:231
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
Definition: call_env.h:235
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl must contain an attribute reference.
Definition: call_env.h:86
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition: call_env.h:85
module_instance_t const * mi
Module instance that the callenv is registered to.
Definition: call_env.h:224
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
Definition: call_env.h:384
Per method call config.
Definition: call_env.h:175
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:627
#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
@ CONF_FLAG_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
Definition: cf_parse.h:405
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:411
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
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_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1594
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition: cf_util.c:1638
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:289
#define CF_IDENT_ANY
Definition: cf_util.h:78
next
Definition: dcursor.h:178
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition: dict.h:267
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:280
Specifies an attribute which must be present for the module to function.
Definition: dict.h:266
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:279
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:63
static void * fr_dlist_pop_head(fr_dlist_head_t *list_head)
Remove the head item in a list.
Definition: dlist.h:672
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition: dlist.h:486
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition: dlist.h:638
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition: function.h:111
fr_htrie_t * fr_htrie_alloc(TALLOC_CTX *ctx, fr_htrie_type_t type, fr_hash_t hash_data, fr_cmp_t cmp_data, fr_trie_key_t get_key, fr_free_t free_data)
An abstraction over our internal hashes, rb trees, and prefix tries.
Definition: htrie.c:92
fr_htrie_type_t
Definition: htrie.h:49
@ FR_HTRIE_TRIE
Data is stored in a prefix trie.
Definition: htrie.h:53
@ FR_HTRIE_INVALID
Definition: htrie.h:50
static fr_htrie_type_t fr_htrie_hint(fr_type_t type)
Definition: htrie.h:149
static void * fr_htrie_match(fr_htrie_t *ht, void const *data)
Match data in a htrie.
Definition: htrie.h:96
static bool fr_htrie_insert(fr_htrie_t *ht, void const *data)
Insert data into a htrie.
Definition: htrie.h:112
void * store
What we're using to store node data.
Definition: htrie.h:82
fr_htrie_type_t type
type of the htrie
Definition: htrie.h:81
static void * fr_htrie_find(fr_htrie_t *ht, void const *data)
Find data in a htrie.
Definition: htrie.h:104
A hash/rb/prefix trie abstraction.
Definition: htrie.h:80
#define UNLANG_SUB_FRAME
Definition: interpret.h:36
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:443
#define RDEBUG3(fmt,...)
Definition: log.h:343
#define RWARN(fmt,...)
Definition: log.h:297
#define RERROR(fmt,...)
Definition: log.h:298
#define RPWARN(fmt,...)
Definition: log.h:301
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition: log.h:705
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:430
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
Definition: map.c:1487
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
Definition: map.c:1781
talloc_free(reap)
struct map_s map_t
Definition: map.h:33
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_VOID
User data.
Definition: merged_model.c:127
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
void * env_data
Per call environment data.
Definition: module_ctx.h:44
module_instance_t const * mi
Instance of the module being instantiated.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:39
int radius_legacy_map_cmp(request_t *request, map_t const *map)
Definition: pairmove.c:790
int radius_legacy_map_list_apply(request_t *request, map_list_t const *list, fr_edit_list_t *el)
Definition: pairmove.c:771
static const conf_parser_t config[]
Definition: base.c:183
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define RDEBUG(fmt,...)
Definition: radclient.h:53
#define RETURN_MODULE_NOOP
Definition: rcode.h:62
#define RETURN_MODULE_OK
Definition: rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition: rcode.h:40
fr_dict_attr_autoload_t rlm_files_dict_attr[]
Definition: rlm_files.c:72
static int pairlist_to_key(uint8_t **out, size_t *outlen, void const *a)
Definition: rlm_files.c:98
char const * filename
Definition: rlm_files.c:40
static unlang_action_t mod_files_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
Lookup the expanded key value in files data.
Definition: rlm_files.c:399
PAIR_LIST_LIST * def
parsed files DEFAULT data.
Definition: rlm_files.c:48
static int8_t pairlist_cmp(void const *a, void const *b)
Definition: rlm_files.c:90
static const call_env_method_t method_env
Definition: rlm_files.c:687
static fr_dict_attr_t const * attr_fall_through
Definition: rlm_files.c:68
static fr_dict_t const * dict_freeradius
Definition: rlm_files.c:60
fr_htrie_t * htrie
parsed files "user" data.
Definition: rlm_files.c:47
static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, call_env_ctx_t const *cec, UNUSED call_env_parser_t const *rule)
Custom call_env parser for loading files data.
Definition: rlm_files.c:652
static unlang_action_t mod_files(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Initiate a files data lookup.
Definition: rlm_files.c:630
tmpl_t * match_attr
Attribute to populate with matched key value.
Definition: rlm_files.c:55
static int getrecv_filename(TALLOC_CTX *ctx, char const *filename, fr_htrie_t **ptree, PAIR_LIST_LIST **pdefault, fr_type_t data_type, fr_dict_attr_t const *key_enum, fr_dict_t const *dict)
Definition: rlm_files.c:103
static uint32_t pairlist_hash(void const *a)
Definition: rlm_files.c:85
fr_dict_autoload_t rlm_files_dict[]
Definition: rlm_files.c:63
tmpl_t * key_tmpl
tmpl used to evaluate lookup key.
Definition: rlm_files.c:46
rlm_files_data_t * data
Data from parsed call_env.
Definition: rlm_files.c:54
static fr_dict_attr_t const * attr_next_shortest_prefix
Definition: rlm_files.c:69
char const * name
Name of module instance - for debug output.
Definition: rlm_files.c:56
fr_value_box_list_t values
Where the expanded tmpl value will be written.
Definition: rlm_files.c:57
static const conf_parser_t module_config[]
Definition: rlm_files.c:79
module_rlm_t rlm_files
Definition: rlm_files.c:700
Structure produced by custom call_env parser.
Definition: rlm_files.c:45
Call_env structure.
Definition: rlm_files.c:53
#define FR_SBUFF_IN(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition: section.h:40
char const * name
Instance name e.g. user_database.
Definition: module.h:335
void * data
Module's instance data.
Definition: module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition: module.h:151
Named methods exported by a module.
Definition: module.h:173
#define tmpl_value(_tmpl)
Definition: tmpl.h:948
#define tmpl_contains_regex(vpt)
Definition: tmpl.h:230
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition: tmpl.h:812
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define tmpl_is_exec(vpt)
Definition: tmpl.h:216
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition: tmpl.h:146
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
#define tmpl_is_data(vpt)
Definition: tmpl.h:211
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules))
Initialise a tmpl without copying the input name string.
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:950
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
#define tmpl_is_regex(vpt)
Definition: tmpl.h:218
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition: tmpl_eval.c:209
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
RETURN_MODULE_FAIL
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
eap_aka_sim_process_conf_t * inst
Value pair map.
Definition: map.h:77
fr_token_t op
The operator that controls insertion of the dst attribute.
Definition: map.h:82
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:78
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:79
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
#define talloc_get_type_abort_const
Definition: talloc.h:282
int unlang_tmpl_push(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *tmpl, unlang_tmpl_args_t *args)
Push a tmpl onto the stack for evaluation.
Definition: tmpl.c:259
char const * fr_tokens[T_TOKEN_LAST]
Definition: token.c:78
const bool fr_comparison_op[T_TOKEN_LAST]
Definition: token.c:198
@ T_OP_SUB_EQ
Definition: token.h:70
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
@ T_OP_SET
Definition: token.h:84
@ T_OP_ADD_EQ
Definition: token.h:69
@ T_OP_REG_EQ
Definition: token.h:102
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
@ T_OP_LE
Definition: token.h:100
@ T_OP_GE
Definition: token.h:98
@ T_OP_REG_NE
Definition: token.h:103
fr_edit_list_t * unlang_interpret_edit_list(request_t *request)
Definition: transaction.c:100
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
static fr_event_list_t * el
static int next_map(UNUSED request_t *request, UNUSED unlang_frame_state_edit_t *state, edit_map_t *current)
Definition: edit.c:940
int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list)
Definition: users_file.c:235
char const * name
Key for matching entry.
Definition: users_file.h:39
fr_dlist_head_t head
Head of the list of PAIR_LISTs.
Definition: users_file.h:51
char const * filename
Filename entry read from.
Definition: users_file.h:45
int lineno
Line number entry read from.
Definition: users_file.h:46
char const * name
name of the key used for matching entry.
Definition: users_file.h:52
bool fall_through
go to the next one
Definition: users_file.h:43
static void pairlist_list_init(PAIR_LIST_LIST *list)
Definition: users_file.h:59
int order
Sequence of entry in source file.
Definition: users_file.h:42
map_list_t check
List of maps for comparison / modifying control list.
Definition: users_file.h:40
fr_value_box_t * box
parsed version of "name".
Definition: users_file.h:53
bool next_shortest_prefix
for prefix tries
Definition: users_file.h:44
map_list_t reply
List of maps for modifying reply list.
Definition: users_file.h:41
void fr_edit_list_commit(fr_edit_list_t *el)
Commit an edit list.
Definition: edit.c:841
void fr_edit_list_abort(fr_edit_list_t *el)
Abort the entries in an edit list.
Definition: edit.c:194
fr_edit_list_t * fr_edit_list_alloc(TALLOC_CTX *ctx, int hint, fr_edit_list_t *parent)
Allocate an edit list.
Definition: edit.c:790
Track a series of edits.
Definition: edit.c:102
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition: value.c:5315
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition: value.c:6129
fr_sbuff_parse_rules_t const * value_parse_rules_quoted[T_TOKEN_LAST]
Parse rules for quoted strings.
Definition: value.c:606
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:676
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3740
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition: value.c:3681
int fr_value_box_to_key(uint8_t **out, size_t *outlen, fr_value_box_t const *value)
Get a key from a value box.
Definition: value.c:2084
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition: value.c:4232
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:621
static fr_slen_t data
Definition: value.h:1265
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:997