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: a22000bc83fcdf197d33c276820a210f2574ea7e $
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: a22000bc83fcdf197d33c276820a210f2574ea7e $")
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  char const *name; //!< Name of module instance - for debug output
56  fr_value_box_list_t values; //!< Where the expanded tmpl value will be written.
58 
59 static fr_dict_t const *dict_freeradius;
60 
63  { .out = &dict_freeradius, .proto = "freeradius" },
64  { NULL }
65 };
66 
69 
72  { .out = &attr_fall_through, .name = "Fall-Through", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
73  { .out = &attr_next_shortest_prefix, .name = "Next-Shortest-Prefix", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
74 
75  { NULL }
76 };
77 
78 static const conf_parser_t module_config[] = {
81 };
82 
83 
84 static uint32_t pairlist_hash(void const *a)
85 {
86  return fr_value_box_hash(((PAIR_LIST_LIST const *)a)->box);
87 }
88 
89 static int8_t pairlist_cmp(void const *a, void const *b)
90 {
91  int ret;
92 
93  ret = fr_value_box_cmp(((PAIR_LIST_LIST const *)a)->box, ((PAIR_LIST_LIST const *)b)->box);
94  return CMP(ret, 0);
95 }
96 
97 static int pairlist_to_key(uint8_t **out, size_t *outlen, void const *a)
98 {
99  return fr_value_box_to_key(out, outlen, ((PAIR_LIST_LIST const *)a)->box);
100 }
101 
102 static int getrecv_filename(TALLOC_CTX *ctx, char const *filename, fr_htrie_t **ptree, PAIR_LIST_LIST **pdefault,
103  fr_type_t data_type, fr_dict_t const *dict)
104 {
105  int rcode;
106  PAIR_LIST_LIST users;
107  PAIR_LIST_LIST search_list; // Temporary list header used for matching in htrie
108  PAIR_LIST *entry, *next;
109  PAIR_LIST_LIST *user_list, *default_list;
110  fr_htrie_t *tree;
111  fr_htrie_type_t htype;
112  fr_value_box_t *box;
113  map_t *reply_head;
114 
115  if (!filename) {
116  *ptree = NULL;
117  return 0;
118  }
119 
120  pairlist_list_init(&users);
121  rcode = pairlist_read(ctx, dict, filename, &users);
122  if (rcode < 0) {
123  return -1;
124  }
125 
126  htype = fr_htrie_hint(data_type);
127 
128  /*
129  * Walk through the 'users' file list
130  */
131  entry = NULL;
132  while ((entry = fr_dlist_next(&users.head, entry))) {
133  map_t *map = NULL;
134  map_t *prev, *next_map;
135  fr_dict_attr_t const *da;
136  map_t *sub_head, *set_head;
137 
138  reply_head = NULL;
139 
140  /*
141  * Do various sanity checks.
142  */
143  while ((map = map_list_next(&entry->check, map))) {
144  if (!tmpl_is_attr(map->lhs)) {
145  ERROR("%s[%d] Left side of check item %s is not an attribute",
146  entry->filename, entry->lineno, map->lhs->name);
147  return -1;
148  }
149 
150  /*
151  * Disallow regexes for now.
152  */
153  if ((map->op == T_OP_REG_EQ) || (map->op == T_OP_REG_NE)) {
154  fr_assert(tmpl_is_regex(map->rhs));
155  }
156 
157  /*
158  * Move assignment operations to the reply list.
159  */
160  switch (map->op) {
161  case T_OP_EQ:
162  case T_OP_SET:
163  case T_OP_ADD_EQ:
164  prev = map_list_remove(&entry->check, map);
165  map_list_insert_after(&entry->reply, reply_head, map);
166  reply_head = map;
167  map = prev;
168  break;
169 
170  default:
171  break;
172  }
173  } /* end of loop over check items */
174 
175  /*
176  * Note that we also re-arrange any control items which are in the reply item list.
177  */
178  sub_head = set_head = NULL;
179 
180  /*
181  * Look for server configuration items
182  * in the reply list.
183  *
184  * It's a common enough mistake, that it's
185  * worth doing.
186  */
187  for (map = map_list_head(&entry->reply);
188  map != NULL;
189  map = next_map) {
190  next_map = map_list_next(&entry->reply, map);
191  if (!tmpl_is_attr(map->lhs)) {
192  ERROR("%s[%d] Left side of reply item %s is not an attribute",
193  entry->filename, entry->lineno, map->lhs->name);
194  return -1;
195  }
196  da = tmpl_attr_tail_da(map->lhs);
197 
198  if (fr_comparison_op[map->op] && (map->op != T_OP_LE) && (map->op != T_OP_GE)) {
199  ERROR("%s[%d] Invalid operator reply item %s %s ...",
200  entry->filename, entry->lineno, map->lhs->name, fr_tokens[map->op]);
201  return -1;
202  }
203 
204  /*
205  * Regex assignments aren't allowed.
206  *
207  * Execs are being deprecated.
208  */
209  if (tmpl_contains_regex(map->rhs) || tmpl_is_exec(map->rhs)) {
210  ERROR("%s[%d] Invalid right-hand side of assignment for attribute %s",
211  entry->filename, entry->lineno, da->name);
212  return -1;
213  }
214 
215  if (da == attr_next_shortest_prefix) {
216  if (htype != FR_HTRIE_TRIE) {
217  ERROR("%s[%d] Cannot use %s when key is not an IP / IP prefix",
218  entry->filename, entry->lineno, da->name);
219  return -1;
220  }
221 
222  if (!tmpl_is_data(map->rhs) || (tmpl_value_type(map->rhs) != FR_TYPE_BOOL)) {
223  ERROR("%s[%d] Value for %s must be static boolean",
224  entry->filename, entry->lineno, da->name);
225  return -1;
226  }
227 
228  entry->next_shortest_prefix = tmpl_value(map->rhs)->vb_bool;
229  (void) map_list_remove(&entry->reply, map);
230  continue;
231  }
232 
233  /*
234  * Check for Fall-Through in the reply list. If so, delete it and set the flag
235  * in the entry.
236  *
237  * Note that we don't free "map", as the map functions usually make the "next"
238  * map be talloc parented from the current one. So freeing this one will likely
239  * free all subsequent maps.
240  */
241  if (da == attr_fall_through) {
242  if (!tmpl_is_data(map->rhs) || (tmpl_value_type(map->rhs) != FR_TYPE_BOOL)) {
243  ERROR("%s[%d] Value for %s must be static boolean",
244  entry->filename, entry->lineno, da->name);
245  return -1;
246  }
247 
248  entry->fall_through = tmpl_value(map->rhs)->vb_bool;
249  (void) map_list_remove(&entry->reply, map);
250  continue;
251  }
252 
253  /*
254  * Removals are applied before anything else.
255  */
256  if (map->op == T_OP_SUB_EQ) {
257  if (sub_head == map) continue;
258 
259  (void) map_list_remove(&entry->reply, map);
260  map_list_insert_after(&entry->reply, sub_head, map);
261  sub_head = map;
262  continue;
263  }
264 
265  /*
266  * Over-rides are applied after deletions.
267  */
268  if (map->op == T_OP_SET) {
269  if (set_head == map) continue;
270 
271  if (!set_head) set_head = sub_head;
272 
273  (void) map_list_remove(&entry->reply, map);
274  map_list_insert_after(&entry->reply, set_head, map);
275  set_head = map;
276  continue;
277  }
278  }
279  }
280 
281  tree = fr_htrie_alloc(ctx, htype, pairlist_hash, pairlist_cmp, pairlist_to_key, NULL);
282  if (!tree) {
283  while ((entry = fr_dlist_pop_head(&users.head))) {
284  talloc_free(entry);
285  }
286  return -1;
287  }
288 
289  default_list = NULL;
290  box = fr_value_box_alloc(ctx, data_type, NULL);
291 
292  /*
293  * We've read the entries in linearly, but putting them
294  * into an indexed data structure would be much faster.
295  * Let's go fix that now.
296  */
297  for (entry = fr_dlist_head(&users.head); entry != NULL; entry = next) {
298  /*
299  * Remove this entry from the input list.
300  */
301  next = fr_dlist_next(&users.head, entry);
302  fr_dlist_remove(&users.head, entry);
303 
304  /*
305  * @todo - loop over entry->reply, calling
306  * unlang_fixup_update() or unlang_fixup_filter()
307  * to double-check the maps.
308  *
309  * Those functions do normalization and sanity
310  * checks which are needed if this module is
311  * going to call an unlang function to *apply*
312  * the maps.
313  */
314 
315  /*
316  * DEFAULT entries get their own list.
317  */
318  if (strcmp(entry->name, "DEFAULT") == 0) {
319  if (!default_list) {
320  default_list = talloc_zero(ctx, PAIR_LIST_LIST);
321  pairlist_list_init(default_list);
322  default_list->name = entry->name;
323 
324  /*
325  * Don't insert the DEFAULT list
326  * into the tree, instead make it
327  * it's own list.
328  */
329  *pdefault = default_list;
330  }
331 
332  /*
333  * Append the entry to the DEFAULT list
334  */
335  fr_dlist_insert_tail(&default_list->head, entry);
336  continue;
337  }
338 
339  /*
340  * Not DEFAULT, must be a normal user. First look
341  * for a matching list header already in the tree.
342  */
343  search_list.name = entry->name;
344  search_list.box = box;
345 
346  /*
347  * Has to be of the correct data type.
348  */
349  if (fr_value_box_from_str(box, box, data_type, NULL,
350  entry->name, strlen(entry->name), NULL, false) < 0) {
351  ERROR("%s[%d] Failed parsing key %s - %s",
352  entry->filename, entry->lineno, entry->name, fr_strerror());
353  goto error;
354  }
355 
356  /*
357  * Find an exact match, especially for patricia tries.
358  */
359  user_list = fr_htrie_match(tree, &search_list);
360  if (!user_list) {
361  user_list = talloc_zero(ctx, PAIR_LIST_LIST);
362  pairlist_list_init(user_list);
363  user_list->name = entry->name;
364  user_list->box = fr_value_box_alloc(user_list, data_type, NULL);
365 
366  (void) fr_value_box_copy(user_list, user_list->box, box);
367 
368  /*
369  * Insert the new list header.
370  */
371  if (!fr_htrie_insert(tree, user_list)) {
372  ERROR("%s[%d] Failed inserting key %s - %s",
373  entry->filename, entry->lineno, entry->name, fr_strerror());
374  goto error;
375 
376  error:
378  talloc_free(tree);
379  return -1;
380  }
381  }
383 
384  /*
385  * Append the entry to the user list
386  */
387  fr_dlist_insert_tail(&user_list->head, entry);
388  }
389 
390  *ptree = tree;
391 
392  return 0;
393 }
394 
395 /** Lookup the expanded key value in files data.
396  *
397  */
398 static unlang_action_t CC_HINT(nonnull) mod_files_resume(rlm_rcode_t *p_result, UNUSED int *priority, request_t *request, void *uctx)
399 {
400  rlm_files_env_t *env = talloc_get_type_abort(uctx, rlm_files_env_t);
401  PAIR_LIST_LIST const *user_list;
402  PAIR_LIST const *user_pl, *default_pl;
403  bool found = false, trie = false;
404  PAIR_LIST_LIST my_list;
405  uint8_t key_buffer[16], *key;
406  size_t keylen = 0;
407  fr_edit_list_t *el, *child;
408  fr_htrie_t *tree = env->data->htrie;
409  PAIR_LIST_LIST *default_list = env->data->def;
410  fr_value_box_t *key_vb = fr_value_box_list_head(&env->values);
411 
412  if (!key_vb) {
413  RERROR("Missing key value");
415  }
416 
417  if (!tree && !default_list) RETURN_MODULE_NOOP;
418 
419  RDEBUG2("%s - Looking for key \"%pV\"", env->name, key_vb);
420 
421  el = unlang_interpret_edit_list(request);
422  MEM(child = fr_edit_list_alloc(request, 50, el));
423 
424  if (tree) {
425  my_list.name = NULL;
426  my_list.box = key_vb;
427  user_list = fr_htrie_find(tree, &my_list);
428 
429  trie = (tree->type == FR_HTRIE_TRIE);
430 
431  /*
432  * Convert the value-box to a key for use in a trie. The trie assumes that the key
433  * starts at the high bit of the data, and that isn't always the case. e.g. "bool" and
434  * "integer" may be in host byte order, in which case we have to convert them to network
435  * byte order.
436  */
437  if (user_list && trie) {
438  key = key_buffer;
439  keylen = sizeof(key_buffer) * 8;
440 
441  (void) fr_value_box_to_key(&key, &keylen, key_vb);
442 
443  RDEBUG3("Keylen %ld", keylen);
444  RHEXDUMP3(key, (keylen + 7) >> 3, "KEY ");
445  }
446 
447  user_pl = user_list ? fr_dlist_head(&user_list->head) : NULL;
448  } else {
449  user_pl = NULL;
450  user_list = NULL;
451  }
452 
453 redo:
454  default_pl = default_list ? fr_dlist_head(&default_list->head) : NULL;
455 
456  /*
457  * Find the entry for the user.
458  */
459  while (user_pl || default_pl) {
460  map_t *map = NULL;
461  PAIR_LIST const *pl;
462  bool match = true;
463 
464  /*
465  * Figure out which entry to match on.
466  */
467  if (!default_pl && user_pl) {
468  pl = user_pl;
469 
470  RDEBUG3("DEFAULT[] USER[%d]=%s", user_pl->lineno, user_pl->name);
471  user_pl = fr_dlist_next(&user_list->head, user_pl);
472 
473  } else if (!user_pl && default_pl) {
474  pl = default_pl;
475  RDEBUG3("DEFAULT[%d]= USER[]=", default_pl->lineno);
476  default_pl = fr_dlist_next(&default_list->head, default_pl);
477 
478  } else if (user_pl->order < default_pl->order) {
479  pl = user_pl;
480 
481  RDEBUG3("DEFAULT[%d]= USER[%d]=%s (choosing user)", default_pl->lineno, user_pl->lineno, user_pl->name);
482  user_pl = fr_dlist_next(&user_list->head, user_pl);
483 
484  } else {
485  pl = default_pl;
486  RDEBUG3("DEFAULT[%d]= USER[%d]=%s (choosing default)", default_pl->lineno, user_pl->lineno, user_pl->name);
487  default_pl = fr_dlist_next(&default_list->head, default_pl);
488  }
489 
490  /*
491  * Run the check items.
492  */
493  while ((map = map_list_next(&pl->check, map))) {
494  int rcode;
495 
496  RDEBUG3(" %s %s %s", map->lhs->name, fr_tokens[map->op], map->rhs ? map->rhs->name : "{ ... }");
497 
498  /*
499  * Control items get realized to VPs, and
500  * copied to a temporary list, which is
501  * then copied to control if the entire
502  * line matches.
503  */
504  switch (map->op) {
505  case T_OP_EQ:
506  case T_OP_SET:
507  case T_OP_ADD_EQ:
508  fr_assert(0);
509  goto fail;
510 
511  /*
512  * Evaluate the map, including regexes.
513  */
514  default:
515  rcode = radius_legacy_map_cmp(request, map);
516  if (rcode < 0) {
517  RPWARN("Failed parsing map for check item %s, skipping it", map->lhs->name);
518  fail:
519  fr_edit_list_abort(child);
521  }
522 
523  if (!rcode) {
524  RDEBUG3(" failed match");
525  match = false;
526  }
527  break;
528  }
529 
530  if (!match) break;
531  }
532 
533  if (!match) continue;
534 
535  RDEBUG2("%s - Found match \"%s\" on line %d of %s", env->name, pl->name, pl->lineno, pl->filename);
536  found = true;
537 
538  if (map_list_num_elements(&pl->reply) > 0) {
539  RDEBUG2("%s - Preparing attribute updates:", env->name);
540  /* ctx may be reply */
541  RINDENT();
542  if (radius_legacy_map_list_apply(request, &pl->reply, child) < 0) {
543  RPWARN("Failed parsing reply item");
544  REXDENT();
545  goto fail;
546  }
547  REXDENT();
548  }
549 
550  if (pl->fall_through) continue;
551 
552  /*
553  * We're not doing patricia tries. Stop now.
554  */
555  if (!trie) break;
556 
557  /*
558  * We're doing patricia tries, but we've been
559  * told to not walk back up the trie, OR we're at the top of the tree. Stop.
560  */
561  if (!pl->next_shortest_prefix || (keylen == 0)) break;
562 
563  /*
564  * Walk back up the trie looking for shorter prefixes.
565  *
566  * Note that we've already found an entry, so we
567  * MUST start with that prefix, otherwise we
568  * would end up in an loop of finding the same
569  * prefix over and over.
570  */
571  if (keylen > user_list->box->vb_ip.prefix) keylen = user_list->box->vb_ip.prefix;
572 
573  do {
574  keylen--;
575  user_list = fr_trie_lookup_by_key(tree->store, key, keylen);
576  if (!user_list) {
577  user_pl = NULL;
578  continue;
579  }
580 
581  user_pl = fr_dlist_head(&user_list->head);
582  RDEBUG("%s - Found matching shorter subnet %s at key length %ld", env->name, user_pl->name, keylen);
583  goto redo;
584  } while (keylen > 0);
585  }
586 
587  /*
588  * See if we succeeded.
589  */
590  if (!found) {
591  fr_edit_list_abort(child);
592  RETURN_MODULE_NOOP; /* on to the next module */
593  }
594 
595  fr_edit_list_commit(child);
597 }
598 
599 /** Initiate a files data lookup
600  *
601  * The results of call_env parsing are a structure containing the
602  * tmpl_t representing the key and the parsed files data, meaning tmpl
603  * expansion does not happen by default.
604  * First we push the tmpl onto the stack for evaluation, then the lookup
605  * is done in mod_files_resume.
606  */
607 static unlang_action_t CC_HINT(nonnull) mod_files(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
608 {
609  rlm_files_env_t *env = talloc_get_type_abort(mctx->env_data, rlm_files_env_t);
610 
611  fr_value_box_list_init(&env->values);
612  env->name = mctx->inst->name;
613 
614  /*
615  * Set mod_files_resume as the repeat function
616  */
617  if (unlang_function_push(request, NULL, mod_files_resume, NULL, 0, UNLANG_SUB_FRAME, env) < 0) RETURN_MODULE_FAIL;
618 
619  /*
620  * Push evaluation of the key tmpl onto the stack
621  */
622  if (unlang_tmpl_push(env, &env->values, request, env->data->key_tmpl, NULL) < 0) RETURN_MODULE_FAIL;
624 }
625 
626 /** Custom call_env parser for loading files data
627  *
628  */
629 static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci,
630  UNUSED char const *section_name1, UNUSED char const *section_name2,
631  void const *data, UNUSED call_env_parser_t const *rule)
632 {
634  CONF_PAIR const *to_parse = cf_item_to_pair(ci);
635  rlm_files_data_t *files_data;
636  fr_type_t keytype;
637 
638  MEM(files_data = talloc_zero(ctx, rlm_files_data_t));
639 
640  if (tmpl_afrom_substr(ctx, &files_data->key_tmpl,
641  &FR_SBUFF_IN(cf_pair_value(to_parse), talloc_array_length(cf_pair_value(to_parse)) - 1),
642  cf_pair_value_quote(to_parse), NULL, t_rules) < 0) return -1;
643 
644  keytype = tmpl_expanded_type(files_data->key_tmpl);
645  if (fr_htrie_hint(keytype) == FR_HTRIE_INVALID) {
646  cf_log_err(ci, "Invalid data type '%s' for 'files' module", fr_type_to_str(keytype));
647  error:
648  talloc_free(files_data);
649  return -1;
650  }
651 
652  if (getrecv_filename(files_data, inst->filename, &files_data->htrie, &files_data->def,
653  keytype, t_rules->attr.dict_def) < 0) goto error;
654 
655  *(void **)out = files_data;
656  return 0;
657 }
658 
661  .env = (call_env_parser_t[]){
663  .pair.dflt = "%{%{Stripped-User-Name} || %{User-Name}}", .pair.dflt_quote = T_DOUBLE_QUOTED_STRING,
664  .pair.func = call_env_parse },
666  },
667 };
668 
669 /* globally exported name */
670 extern module_rlm_t rlm_files;
672  .common = {
673  .magic = MODULE_MAGIC_INIT,
674  .name = "files",
675  .inst_size = sizeof(rlm_files_t),
677  },
678  .method_names = (module_method_name_t[]){
679  { .name1 = CF_IDENT_ANY, .name2 = CF_IDENT_ANY, .method = mod_files,
680  .method_env = &method_env },
682  }
683 
684 };
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:444
#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:212
#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:216
@ CALL_ENV_FLAG_PARSE_ONLY
The result of parsing will not be evaluated at runtime.
Definition: call_env.h:83
#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:365
Per method call config.
Definition: call_env.h:171
#define CONF_PARSER_TERMINATOR
Definition: cf_parse.h:626
char const * name1
Name of the CONF_ITEM to parse.
Definition: cf_parse.h:564
#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:406
@ CONF_FLAG_FILE_INPUT
File matching value must exist, and must be readable.
Definition: cf_parse.h:412
Defines a CONF_PAIR to C data type mapping.
Definition: cf_parse.h:563
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:629
char const * cf_pair_value(CONF_PAIR const *pair)
Return the value of a CONF_PAIR.
Definition: cf_util.c:1511
fr_token_t cf_pair_value_quote(CONF_PAIR const *pair)
Return the value (rhs) quoting of a pair.
Definition: cf_util.c:1555
#define cf_log_err(_cf, _fmt,...)
Definition: cf_util.h:265
#define CF_IDENT_ANY
Definition: cf_util.h:78
#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:250
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
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
char const *_CONST name
Instance name.
Definition: dl_module.h:163
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition: dl_module.h:65
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 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
talloc_free(reap)
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
dl_module_inst_t const * inst
Dynamic loader API handle for the module.
Definition: module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
Specifies a module method identifier.
Definition: module_method.c:36
module_t common
Common fields presented by all modules.
Definition: module_rlm.h:37
int radius_legacy_map_cmp(request_t *request, map_t const *map)
Definition: pairmove.c:791
int radius_legacy_map_list_apply(request_t *request, map_list_t const *list, fr_edit_list_t *el)
Definition: pairmove.c:772
static const conf_parser_t config[]
Definition: base.c:188
#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:71
static int pairlist_to_key(uint8_t **out, size_t *outlen, void const *a)
Definition: rlm_files.c:97
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:398
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:89
static const call_env_method_t method_env
Definition: rlm_files.c:659
static fr_dict_attr_t const * attr_fall_through
Definition: rlm_files.c:67
static fr_dict_t const * dict_freeradius
Definition: rlm_files.c:59
fr_htrie_t * htrie
parsed files "user" data.
Definition: rlm_files.c:47
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:607
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_t const *dict)
Definition: rlm_files.c:102
static uint32_t pairlist_hash(void const *a)
Definition: rlm_files.c:84
fr_dict_autoload_t rlm_files_dict[]
Definition: rlm_files.c:62
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:68
char const * name
Name of module instance - for debug output.
Definition: rlm_files.c:55
static int call_env_parse(TALLOC_CTX *ctx, void *out, tmpl_rules_t const *t_rules, CONF_ITEM *ci, UNUSED char const *section_name1, UNUSED char const *section_name2, void const *data, UNUSED call_env_parser_t const *rule)
Custom call_env parser for loading files data.
Definition: rlm_files.c:629
fr_value_box_list_t values
Where the expanded tmpl value will be written.
Definition: rlm_files.c:56
static const conf_parser_t module_config[]
Definition: rlm_files.c:78
module_rlm_t rlm_files
Definition: rlm_files.c:671
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 MODULE_NAME_TERMINATOR
Definition: module.h:135
#define tmpl_value(_tmpl)
Definition: tmpl.h:932
#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:796
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define tmpl_is_exec(vpt)
Definition: tmpl.h:216
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
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:934
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:207
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:270
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_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:1264
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:911
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:5264
uint32_t fr_value_box_hash(fr_value_box_t const *vb)
Hash the contents of a value box.
Definition: value.c:6077
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:640
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:3689
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition: value.c:3630
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:2039
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static fr_slen_t data
Definition: value.h:1259
int nonnull(2, 5))
static size_t char ** out
Definition: value.h:984