The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
users_file.c
Go to the documentation of this file.
1 /*
2  * files.c Read config files into memory.
3  *
4  * Version: $Id: 7fd39a9690d7289452a5de507e019f3cb7212ab7 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * @copyright 2000,2006 The FreeRADIUS server project
21  * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
22  * @copyright 2000 Alan DeKok (aland@freeradius.org)
23  */
24 
25 RCSID("$Id: 7fd39a9690d7289452a5de507e019f3cb7212ab7 $")
26 
27 #include <freeradius-devel/server/log.h>
28 #include <freeradius-devel/util/debug.h>
29 #include <freeradius-devel/server/users_file.h>
30 
31 #include <freeradius-devel/util/misc.h>
32 #include <freeradius-devel/util/pair_legacy.h>
33 #include <freeradius-devel/util/syserror.h>
34 
35 #include <sys/stat.h>
36 
37 #include <ctype.h>
38 #include <fcntl.h>
39 
40 static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list,
41  bool complain, int *order);
42 
43 static inline void line_error_marker(char const *src_file, int src_line,
44  char const *user_file, int user_line,
45  fr_sbuff_t *sbuff, char const *error)
46 {
47  char *end;
48  fr_sbuff_marker_t start;
49 
50  fr_sbuff_marker(&start, sbuff);
51  end = fr_sbuff_adv_to_chr(sbuff, SIZE_MAX, '\n');
52  if (!end) end = fr_sbuff_end(sbuff);
53  fr_sbuff_set(sbuff, &start);
54  fr_sbuff_marker_release(&start);
55 
56  fr_log_marker(LOG_DST, L_ERR, src_file, src_line,
57  fr_sbuff_start(sbuff), end - fr_sbuff_start(sbuff),
58  fr_sbuff_used(sbuff), error, "%s[%d]: ", user_file, user_line);
59 }
60 /** Print out a line oriented error marker at the current position of the sbuff
61  *
62  * @param[in] _sbuff to print error for.
63  * @param[in] _error message.
64  */
65 #define ERROR_MARKER(_sbuff, _error) line_error_marker(__FILE__, __LINE__, file, lineno, _sbuff, _error)
66 
67 static inline void line_error_marker_adj(char const *src_file, int src_line,
68  char const *user_file, int user_line,
69  fr_sbuff_t *sbuff, ssize_t marker_idx, char const *error)
70 {
71  char *end;
72  fr_sbuff_marker_t start;
73 
74  fr_sbuff_marker(&start, sbuff);
75  end = fr_sbuff_adv_to_chr(sbuff, SIZE_MAX, '\n');
76  if (!end) end = fr_sbuff_end(sbuff);
77  fr_sbuff_set(sbuff, &start);
78  fr_sbuff_marker_release(&start);
79 
80  fr_log_marker(LOG_DST, L_ERR, src_file, src_line,
81  fr_sbuff_current(sbuff), end - fr_sbuff_current(sbuff),
82  marker_idx, error, "%s[%d]: ", user_file, user_line);
83 }
84 /** Print out a line oriented error marker relative to the current position of the sbuff
85  *
86  * @param[in] _sbuff to print error for.
87  * @param[in] _idx Where the error occurred.
88  * @param[in] _error message.
89  */
90 #define ERROR_MARKER_ADJ(_sbuff, _idx, _error) line_error_marker_adj(__FILE__, __LINE__, file, lineno, _sbuff, _idx, _error)
91 
93  { L("!*"), T_OP_CMP_FALSE },
94  { L("!="), T_OP_NE },
95  { L("!~"), T_OP_REG_NE },
96  { L("+="), T_OP_ADD_EQ },
97  { L(":="), T_OP_SET },
98  { L("<"), T_OP_LT },
99  { L("<="), T_OP_LE },
100  { L("="), T_OP_EQ },
101  { L("=*"), T_OP_CMP_TRUE },
102  { L("=="), T_OP_CMP_EQ },
103  { L("=~"), T_OP_REG_EQ },
104  { L(">"), T_OP_GT },
105  { L(">="), T_OP_GE }
106 };
108 
110  L("\t"),
111  L("\n"),
112  L(" "),
113  L("#"),
114 );
115 
116 static fr_sbuff_parse_rules_t const rhs_term = {
117  .escapes = &(fr_sbuff_unescape_rules_t){
118  .chr = '\\',
119  /*
120  * Allow barewords to contain whitespace
121  * if they're escaped.
122  */
123  .subs = {
124  ['\t'] = '\t',
125  ['\n'] = '\n',
126  [' '] = ' '
127  },
128  .do_hex = true,
129  .do_oct = false
130  },
131  .terminals = &FR_SBUFF_TERMS(
132  L(""),
133  L("\t"),
134  L("\n"),
135  L("#"),
136  L(","),
137  )
138 };
139 
140 /*
141  * Caller saw a $INCLUDE at the start of a line.
142  */
143 static int users_include(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_sbuff_t *sbuff, PAIR_LIST_LIST *list,
144  char const *file, int lineno, int *order)
145 {
146  size_t len;
147  char *newfile, *p, c;
149 
150  fr_sbuff_advance(sbuff, 8);
151 
152  /*
153  * Skip spaces after the $INCLUDE.
154  */
155  if (fr_sbuff_adv_past_blank(sbuff, SIZE_MAX, NULL) == 0) {
156  ERROR_MARKER(sbuff, "Unexpected text after $INCLUDE");
157  return -1;
158  }
159 
160  /*
161  * Remember when the name started, and skip over the name
162  * until spaces, comments, or LF
163  */
164  fr_sbuff_marker(&name, sbuff);
165  len = fr_sbuff_adv_until(sbuff, SIZE_MAX, &name_terms, 0);
166  if (len == 0) {
167  ERROR_MARKER(sbuff, "No filename after $INCLUDE");
168  fr_sbuff_marker_release(&name);
169  return -1;
170  }
171 
172  /*
173  * If the input file is a relative path, try to copy the
174  * leading directory from it. If there's no leading
175  * directory, just use the $INCLUDE name as-is.
176  *
177  * If there is a leading directory in the input name,
178  * paste that as the directory to the $INCLUDE name.
179  *
180  * Otherwise the $INCLUDE name is an absolute path, use
181  * it as -is.
182  */
183  c = fr_sbuff_char(&name, '\0');
184  if (c != '/') {
185  p = strrchr(file, '/');
186 
187  if (!p) goto copy_name;
188 
189  newfile = talloc_asprintf(NULL, "%.*s/%.*s",
190  (int) (p - file), file,
191  (int) len, fr_sbuff_current(&name));
192  } else {
193  copy_name:
194  newfile = talloc_asprintf(NULL, "%.*s", (int) len, fr_sbuff_current(&name));
195  }
196  fr_sbuff_marker_release(&name);
197 
198  /*
199  * Skip spaces and comments after the name.
200  */
201  fr_sbuff_adv_past_blank(sbuff, SIZE_MAX, NULL);
202  if (fr_sbuff_next_if_char(sbuff, '#')) {
203  (void) fr_sbuff_adv_to_chr(sbuff, SIZE_MAX, '\n');
204  }
205 
206  /*
207  * There's no LF, but if we skip non-spaces and
208  * non-comments to find the LF, then there must be extra
209  * text after the filename. That's an error.
210  *
211  * Unless the line has EOF after the filename. in which
212  * case this error will get hit, too.
213  */
214  if (!fr_sbuff_is_char(sbuff, '\n') &&
215  (fr_sbuff_adv_to_chr(sbuff, SIZE_MAX, '\n') != NULL)) {
216  ERROR_MARKER(sbuff, "Unexpected text after filename");
217  talloc_free(newfile);
218  return -1;
219  }
220 
221  /*
222  * Read the $INCLUDEd file recursively.
223  */
224  if (pairlist_read_internal(ctx, dict, newfile, list, false, order) != 0) {
225  ERROR("%s[%d]: Could not read included file %s: %s",
226  file, lineno, newfile, fr_syserror(errno));
227  talloc_free(newfile);
228  return -1;
229  }
230  talloc_free(newfile);
231 
232  return 0;
233 }
234 
235 int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list)
236 {
237  int order = 0;
238 
239  return pairlist_read_internal(ctx, dict, file, list, true, &order);
240 }
241 
242 /*
243  * Read the users file. Return a PAIR_LIST.
244  */
245 static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, int *order)
246 {
247  char *q;
248  int lineno = 1;
249  map_t *new_map, *relative_map;
250  FILE *fp;
251  fr_sbuff_t sbuff;
253  tmpl_rules_t lhs_rules, rhs_rules;
254  char *filename = talloc_strdup(ctx, file);
255  char buffer[8192];
256 
257  DEBUG2("Reading file %s", file);
258 
259  /*
260  * Open the file. The error message should be a little
261  * more useful...
262  */
263  if ((fp = fopen(file, "r")) == NULL) {
264  if (complain) ERROR("Couldn't open %s for reading: %s", file, fr_syserror(errno));
265  return -1;
266  }
267 
268  fr_sbuff_init_file(&sbuff, &fctx, buffer, sizeof(buffer), fp, SIZE_MAX);
269 
270  lhs_rules = (tmpl_rules_t) {
271  .attr = {
272  .dict_def = dict,
273  .prefix = TMPL_ATTR_REF_PREFIX_AUTO,
274  .list_def = request_attr_request,
275  .list_presence = TMPL_ATTR_LIST_ALLOW,
276  }
277  };
278  rhs_rules = (tmpl_rules_t) {
279  .attr = {
280  .dict_def = dict,
281  .prefix = TMPL_ATTR_REF_PREFIX_YES,
282  .list_def = request_attr_request,
283  .list_presence = TMPL_ATTR_LIST_ALLOW,
284  }
285  };
286 
287  while (true) {
288  size_t len;
289  ssize_t slen;
290  bool comma;
291  bool leading_spaces;
292  PAIR_LIST *t;
293 
294  /*
295  * If the line is empty or has only comments,
296  * then we don't care about leading spaces.
297  */
298  leading_spaces = (fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL) > 0);
299  if (fr_sbuff_next_if_char(&sbuff, '#')) {
300  (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
301  }
302  if (fr_sbuff_next_if_char(&sbuff, '\n')) {
303  lineno++;
304  continue;
305  }
306 
307  /*
308  * We're trying to read a key value. It MUST have
309  * been at the start of the line. So whatever
310  * this is, it's wrong.
311  */
312  if (leading_spaces) {
313  ERROR_MARKER(&sbuff, "Entry does not begin with a key value");
314  fail:
315  fclose(fp);
316  return -1;
317  }
318 
319  /*
320  * $INCLUDE filename. This will do some sanity checks, and then add the new entries to
321  * the tail of the current list.
322  */
323  if (fr_sbuff_is_str(&sbuff, "$INCLUDE", 8)) {
324  if (users_include(ctx, dict, &sbuff, list, file, lineno, order) < 0) goto fail;
325 
326  if (fr_sbuff_next_if_char(&sbuff, '\n')) {
327  lineno++;
328  continue;
329  }
330 
331  /*
332  * The next character is not LF, but the
333  * function skipped to LF. So, by
334  * process of elimination, we must be at
335  * EOF.
336  */
337  break;
338  } /* else it wasn't $INCLUDE */
339 
340  /*
341  * We MUST be either at a valid entry, OR at EOF.
342  */
343  MEM(t = talloc_zero(ctx, PAIR_LIST));
344  map_list_init(&t->check);
345  map_list_init(&t->reply);
346  t->filename = filename;
347  t->lineno = lineno;
348  t->order = (*order)++;
349 
350  /*
351  * Copy the name from the entry.
352  */
353  len = fr_sbuff_out_abstrncpy_until(t, &q, &sbuff, SIZE_MAX, &name_terms, NULL);
354  if (len == 0) {
355  talloc_free(t);
356  break;
357  }
358  t->name = q;
359 
360  lhs_rules.attr.list_def = request_attr_control;
361  comma = false;
362 
363 check_item:
364  /*
365  * Skip spaces before the item, and allow the
366  * check list to end on comment or LF.
367  *
368  * Note that we _don't_ call map_afrom_substr() to
369  * skip spaces, as it will skip LF, too!
370  */
371  (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
372  if (fr_sbuff_is_char(&sbuff, '#')) goto check_item_comment;
373  if (fr_sbuff_is_char(&sbuff, '\n')) goto check_item_end;
374 
375  /*
376  * Try to parse the check item.
377  */
378  slen = map_afrom_substr(t, &new_map, NULL, &sbuff, check_cmp_op_table, check_cmp_op_table_len,
379  &lhs_rules, &rhs_rules, &rhs_term);
380  if (!new_map) {
381  ERROR_MARKER_ADJ(&sbuff, slen, fr_strerror());
382  fail_entry:
383  talloc_free(t);
384  goto fail;
385  }
386 
387  fr_assert(new_map->lhs != NULL);
388  fr_assert(new_map->rhs != NULL);
389 
390  /*
391  * The default rule says that the check
392  * items look at the control list, but
393  * protocol attributes should be compared in the request.
394  */
395  if (!tmpl_attr_tail_da(new_map->lhs)->flags.internal) {
397  }
398 
399  if (tmpl_contains_regex(new_map->rhs)) {
400  if (tmpl_is_regex_uncompiled(new_map->rhs) &&
401  (tmpl_regex_compile(new_map->rhs, false) < 0)) {
402  ERROR("%s[%d]: Failed compiling regular expression /%s/ - %s",
403  file, lineno, new_map->rhs->name, fr_strerror());
404  return -1;
405  }
406 
407  goto do_insert;
408  }
409 
410  do_insert:
411  fr_assert(!new_map->parent);
412  map_list_insert_tail(&t->check, new_map);
413 
414  /*
415  * There can be spaces before any comma.
416  */
417  (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
418 
419  /*
420  * Allow a comma after this item. But remember
421  * if we had a comma.
422  */
423  if (fr_sbuff_next_if_char(&sbuff, ',')) {
424  comma = true;
425  goto check_item;
426  }
427  comma = false;
428 
429  check_item_comment:
430  /*
431  * There wasn't a comma after the item, so the
432  * next thing MUST be a comment, LF, EOF.
433  *
434  * If there IS stuff before the LF, then it's
435  * unknown text.
436  */
437  if (fr_sbuff_next_if_char(&sbuff, '#')) {
438  (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
439  }
440  check_item_end:
441  if (fr_sbuff_next_if_char(&sbuff, '\n')) {
442  /*
443  * The check item list ended with a comma.
444  * That's bad.
445  */
446  if (comma) {
447  ERROR_MARKER(&sbuff, "Invalid comma ending the check item list");
448  goto fail_entry;
449  }
450 
451  lineno++;
452  goto setup_reply;
453  }
454 
455  /*
456  * We didn't see SPACE LF or SPACE COMMENT LF.
457  * There's something else going on.
458  */
459  if (fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n') != NULL) {
460  ERROR_MARKER(&sbuff, "Unexpected text after check item");
461  goto fail_entry;
462  }
463 
464  /*
465  * The next character is not LF, but we
466  * skipped to LF above. So, by process
467  * of elimination, we must be at EOF.
468  */
469  if (!fr_sbuff_is_char(&sbuff, '\n')) {
470  add_entry:
471  fr_dlist_insert_tail(&list->head, &t);
472  break;
473  }
474 
475 setup_reply:
476  /*
477  * Setup the reply items.
478  */
479  lhs_rules.attr.list_def = request_attr_reply;
480 
481  comma = false;
482 
483  rhs_rules.attr.list_def = request_attr_request;
484 
485  relative_map = NULL;
486 
487 reply_item:
488  /*
489  * Reply items start with spaces. If there's no
490  * spaces, then the current entry is done. Add
491  * it to the list, and go back to reading the
492  * user name or $INCLUDE.
493  */
494  if (fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL) == 0) {
495  if (comma) {
496  ERROR("%s[%d]: Unexpected trailing comma in previous line", file, lineno);
497  goto fail_entry;
498  }
499 
500  /*
501  * The line doesn't begin with spaces.
502  * The list of reply items MUST be
503  * finished. Go look for an entry name.
504  *
505  * Note that we don't allow comments in
506  * the middle of the reply item list. Oh
507  * well.
508  */
509  fr_dlist_insert_tail(&list->head, t);
510  continue;
511 
512  } else if (lineno == (t->lineno + 1)) {
513  fr_assert(comma == false);
514 
515  } else if (!comma) {
516  ERROR("%s[%d]: Missing comma in previous line", file, lineno);
517  goto fail_entry;
518  }
519 
520  /*
521  * SPACES COMMENT or SPACES LF means "end of
522  * reply item list"
523  */
524  if (fr_sbuff_is_char(&sbuff, '#')) {
525  (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
526  }
527  if (fr_sbuff_next_if_char(&sbuff, '\n')) {
528  lineno++;
529  goto add_entry;
530  }
531 
532 next_reply_item:
533  /*
534  * Unlike check items, we don't skip spaces or
535  * comments here. All of the code paths which
536  * lead to here have already checked for those
537  * cases.
538  */
539  slen = map_afrom_substr(t, &new_map, &relative_map, &sbuff, map_assignment_op_table, map_assignment_op_table_len,
540  &lhs_rules, &rhs_rules, &rhs_term);
541  if (!new_map) {
542  ERROR_MARKER_ADJ(&sbuff, slen, fr_strerror());
543  goto fail;
544  }
545 
546  fr_assert(new_map->lhs != NULL);
547 
548  if (!tmpl_is_attr(new_map->lhs)) {
549  ERROR("%s[%d]: Unknown attribute '%s'",
550  file, lineno, new_map->lhs->name);
551  goto fail_entry;
552  }
553 
554  /*
555  * We no longer really care what the RHS is, or what the list is on the LHS. The caller
556  * takes care of checking that for us.
557  */
558 
559  if (!new_map->parent) map_list_insert_tail(&t->reply, new_map);
560 
561  (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
562 
563  /*
564  * Commas separate entries on the same line. And
565  * we allow spaces after commas, too.
566  */
567  if (fr_sbuff_next_if_char(&sbuff, ',')) {
568  comma = true;
569  (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
570  } else {
571  comma = false;
572  }
573 
574  /*
575  * Comments or LF will end this particular line.
576  *
577  * Reading the next line will cause a complaint
578  * if this line ended with a comma.
579  */
580  if (fr_sbuff_next_if_char(&sbuff, '#')) {
581  (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
582  }
583 
584  if (fr_sbuff_next_if_char(&sbuff, '\n')) {
585  lineno++;
586  goto reply_item;
587  }
588 
589  /*
590  * Not comment or LF, the content MUST be another
591  * pair.
592  */
593  if (comma) goto next_reply_item;
594 
595  ERROR_MARKER(&sbuff, "Unexpected text after reply");
596  goto fail_entry;
597  }
598 
599  /*
600  * Else we were looking for an entry. We didn't get one
601  * because we were at EOF, so that's OK.
602  */
603 
604  fclose(fp);
605 
606  return 0;
607 }
static int const char char buffer[256]
Definition: acutest.h:574
int const char * file
Definition: acutest.h:702
static fr_dict_t * dict
Definition: fuzzer.c:46
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
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
#define LOG_DST
Definition: network.c:29
fr_table_num_sorted_t const map_assignment_op_table[]
Definition: map.c:330
ssize_t map_afrom_substr(TALLOC_CTX *ctx, map_t **out, map_t **parent_p, fr_sbuff_t *in, fr_table_num_sorted_t const *op_table, size_t op_table_len, tmpl_rules_t const *lhs_rules, tmpl_rules_t const *rhs_rules, fr_sbuff_parse_rules_t const *p_rules)
Parse sbuff into (which may contain refs) to map_t.
Definition: map.c:428
size_t map_assignment_op_table_len
Definition: map.c:346
talloc_free(reap)
void fr_log_marker(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *str, size_t str_len, ssize_t marker_idx, char const *marker, char const *line_prefix_fmt,...)
Print out an error marker.
Definition: log.c:750
@ L_ERR
Error message.
Definition: log.h:56
@ TMPL_ATTR_REF_PREFIX_AUTO
Attribute refs may have a '&' prefix.
Definition: merged_model.c:231
@ TMPL_ATTR_REF_PREFIX_YES
Attribute refs must have '&' prefix.
Definition: merged_model.c:229
long int ssize_t
Definition: merged_model.c:24
#define DEBUG2(fmt,...)
Definition: radclient.h:43
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
fr_dict_attr_t const * request_attr_control
Definition: request.c:43
fr_dict_attr_t const * request_attr_reply
Definition: request.c:42
static char const * name
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
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
Definition: sbuff.c:1811
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
Definition: sbuff.c:2047
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition: sbuff.h:167
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define fr_sbuff_end(_sbuff_or_marker)
#define fr_sbuff_adv_past_blank(_sbuff, _len, _tt)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_used(_sbuff_or_marker)
Set of terminal elements.
Definition: merged_model.c:161
File sbuff extension structure.
Definition: sbuff.h:125
Set of parsing rules for *unescape_until functions.
Definition: merged_model.c:163
void tmpl_attr_set_list(tmpl_t *vpt, fr_dict_attr_t const *list)
#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
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition: tmpl.h:344
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
Definition: tmpl.h:274
struct tmpl_rules_s tmpl_rules_t
Definition: tmpl.h:236
#define tmpl_is_regex_uncompiled(vpt)
Definition: tmpl.h:219
Optional arguments passed to vp_tmpl functions.
Definition: tmpl.h:341
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
Value pair map.
Definition: map.h:77
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
Definition: map.h:78
map_t * parent
Definition: map.h:88
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
Definition: map.h:79
fr_dict_attr_t const * list_def
Default list to use with unqualified attribute reference.
Definition: tmpl.h:307
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition: tmpl.h:285
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: syserror.c:243
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
@ T_OP_CMP_TRUE
Definition: token.h:104
@ T_OP_EQ
Definition: token.h:83
@ T_OP_SET
Definition: token.h:84
@ T_OP_NE
Definition: token.h:97
@ T_OP_ADD_EQ
Definition: token.h:69
@ T_OP_CMP_FALSE
Definition: token.h:105
@ T_OP_REG_EQ
Definition: token.h:102
@ T_OP_CMP_EQ
Definition: token.h:106
@ T_OP_LE
Definition: token.h:100
@ T_OP_GE
Definition: token.h:98
@ T_OP_GT
Definition: token.h:99
@ T_OP_LT
Definition: token.h:101
@ T_OP_REG_NE
Definition: token.h:103
static size_t check_cmp_op_table_len
Definition: users_file.c:107
#define ERROR_MARKER_ADJ(_sbuff, _idx, _error)
Print out a line oriented error marker relative to the current position of the sbuff.
Definition: users_file.c:90
static void line_error_marker_adj(char const *src_file, int src_line, char const *user_file, int user_line, fr_sbuff_t *sbuff, ssize_t marker_idx, char const *error)
Definition: users_file.c:67
#define ERROR_MARKER(_sbuff, _error)
Print out a line oriented error marker at the current position of the sbuff.
Definition: users_file.c:65
int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list)
Definition: users_file.c:235
static fr_table_num_sorted_t const check_cmp_op_table[]
Definition: users_file.c:92
static int users_include(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_sbuff_t *sbuff, PAIR_LIST_LIST *list, char const *file, int lineno, int *order)
Definition: users_file.c:143
static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, int *order)
Definition: users_file.c:245
static fr_sbuff_parse_rules_t const rhs_term
Definition: users_file.c:116
static const fr_sbuff_term_t name_terms
Definition: users_file.c:109
static void line_error_marker(char const *src_file, int src_line, char const *user_file, int user_line, fr_sbuff_t *sbuff, char const *error)
Definition: users_file.c:43
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
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
map_list_t reply
List of maps for modifying reply list.
Definition: users_file.h:41
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554