The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
users_file.c
Go to the documentation of this file.
1/*
2 * files.c Read config files into memory.
3 *
4 * Version: $Id: ad055a4fe0af6611e7700d7ec273d5845bed178a $
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
25RCSID("$Id: ad055a4fe0af6611e7700d7ec273d5845bed178a $")
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
40static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list,
41 bool complain, bool v3_compat, int *order);
42
43static 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;
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
67static 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;
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
116static 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 */
143static 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, bool v3_compat, 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, v3_compat, 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
235int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool v3_compat)
236{
237 int order = 0;
238
239 return pairlist_read_internal(ctx, dict, file, list, true, v3_compat, &order);
240}
241
242/*
243 * Read the users file. Return a PAIR_LIST.
244 */
245static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, bool v3_compat, 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 .list_def = request_attr_request,
274 .list_presence = TMPL_ATTR_LIST_ALLOW,
275 },
276 .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
277
278 };
279 rhs_rules = (tmpl_rules_t) {
280 .attr = {
281 .dict_def = dict,
282 .list_def = request_attr_request,
283 .list_presence = TMPL_ATTR_LIST_ALLOW,
284 .bare_word_enum = v3_compat,
285 },
286 .literals_safe_for = FR_VALUE_BOX_SAFE_FOR_ANY,
287 };
288
289 while (true) {
290 size_t len;
291 ssize_t slen;
292 bool comma;
293 bool leading_spaces;
294 PAIR_LIST *t;
295
296 /*
297 * If the line is empty or has only comments,
298 * then we don't care about leading spaces.
299 */
300 leading_spaces = (fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL) > 0);
301 if (fr_sbuff_next_if_char(&sbuff, '#')) {
302 (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
303 }
304 if (fr_sbuff_next_if_char(&sbuff, '\n')) {
305 lineno++;
306 continue;
307 }
308
309 /*
310 * We're trying to read a key value. It MUST have
311 * been at the start of the line. So whatever
312 * this is, it's wrong.
313 */
314 if (leading_spaces) {
315 ERROR_MARKER(&sbuff, "Entry does not begin with a key value");
316 fail:
317 fclose(fp);
318 return -1;
319 }
320
321 /*
322 * $INCLUDE filename. This will do some sanity checks, and then add the new entries to
323 * the tail of the current list.
324 */
325 if (fr_sbuff_is_str(&sbuff, "$INCLUDE", 8)) {
326 if (users_include(ctx, dict, &sbuff, list, file, lineno, v3_compat, order) < 0) goto fail;
327
328 if (fr_sbuff_next_if_char(&sbuff, '\n')) {
329 lineno++;
330 continue;
331 }
332
333 /*
334 * The next character is not LF, but the
335 * function skipped to LF. So, by
336 * process of elimination, we must be at
337 * EOF.
338 */
339 break;
340 } /* else it wasn't $INCLUDE */
341
342 /*
343 * We MUST be either at a valid entry, OR at EOF.
344 */
345 MEM(t = talloc_zero(ctx, PAIR_LIST));
346 map_list_init(&t->check);
347 map_list_init(&t->reply);
348 t->filename = filename;
349 t->lineno = lineno;
350 t->order = (*order)++;
351
352 /*
353 * Copy the name from the entry.
354 */
355 len = fr_sbuff_out_abstrncpy_until(t, &q, &sbuff, SIZE_MAX, &name_terms, NULL);
356 if (len == 0) {
357 talloc_free(t);
358 break;
359 }
360 t->name = q;
361
363 comma = false;
364
365check_item:
366 /*
367 * Skip spaces before the item, and allow the
368 * check list to end on comment or LF.
369 *
370 * Note that we _don't_ call map_afrom_substr() to
371 * skip spaces, as it will skip LF, too!
372 */
373 (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
374 if (fr_sbuff_is_char(&sbuff, '#')) goto check_item_comment;
375 if (fr_sbuff_is_char(&sbuff, '\n')) goto check_item_end;
376
377 /*
378 * Try to parse the check item.
379 */
380 slen = map_afrom_substr(t, &new_map, NULL, &sbuff, check_cmp_op_table, check_cmp_op_table_len,
381 &lhs_rules, &rhs_rules, &rhs_term);
382 if (!new_map) {
383 ERROR_MARKER_ADJ(&sbuff, slen, fr_strerror());
384 fail_entry:
385 talloc_free(t);
386 goto fail;
387 }
388
389 fr_assert(new_map->lhs != NULL);
390 fr_assert(new_map->rhs != NULL);
391
392 /*
393 * The default rule says that the check
394 * items look at the control list, but
395 * protocol attributes should be compared in the request.
396 */
397 if (!tmpl_attr_tail_da(new_map->lhs)->flags.internal) {
399 }
400
401 if (tmpl_contains_regex(new_map->rhs)) {
402 if (tmpl_is_regex_uncompiled(new_map->rhs) &&
403 (tmpl_regex_compile(new_map->rhs, false) < 0)) {
404 ERROR("%s[%d]: Failed compiling regular expression /%s/ - %s",
405 file, lineno, new_map->rhs->name, fr_strerror());
406 return -1;
407 }
408
409 goto do_insert;
410 }
411
412 do_insert:
413 fr_assert(!new_map->parent);
414 map_list_insert_tail(&t->check, new_map);
415
416 /*
417 * There can be spaces before any comma.
418 */
419 (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
420
421 /*
422 * Allow a comma after this item. But remember
423 * if we had a comma.
424 */
425 if (fr_sbuff_next_if_char(&sbuff, ',')) {
426 comma = true;
427 goto check_item;
428 }
429 comma = false;
430
431 check_item_comment:
432 /*
433 * There wasn't a comma after the item, so the
434 * next thing MUST be a comment, LF, EOF.
435 *
436 * If there IS stuff before the LF, then it's
437 * unknown text.
438 */
439 if (fr_sbuff_next_if_char(&sbuff, '#')) {
440 (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
441 }
442 check_item_end:
443 if (fr_sbuff_next_if_char(&sbuff, '\n')) {
444 /*
445 * The check item list ended with a comma.
446 * That's bad.
447 */
448 if (comma) {
449 ERROR_MARKER(&sbuff, "Invalid comma ending the check item list");
450 goto fail_entry;
451 }
452
453 lineno++;
454 goto setup_reply;
455 }
456
457 /*
458 * We didn't see SPACE LF or SPACE COMMENT LF.
459 * There's something else going on.
460 */
461 if (fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n') != NULL) {
462 ERROR_MARKER(&sbuff, "Unexpected text after check item");
463 goto fail_entry;
464 }
465
466 /*
467 * The next character is not LF, but we
468 * skipped to LF above. So, by process
469 * of elimination, we must be at EOF.
470 */
471 if (!fr_sbuff_is_char(&sbuff, '\n')) {
472 add_entry:
473 fr_dlist_insert_tail(&list->head, t);
474 break;
475 }
476
477setup_reply:
478 /*
479 * Setup the reply items.
480 */
481 lhs_rules.attr.list_def = request_attr_reply;
482
483 comma = false;
484
486
487 relative_map = NULL;
488
489reply_item:
490 /*
491 * Reply items start with spaces. If there's no
492 * spaces, then the current entry is done. Add
493 * it to the list, and go back to reading the
494 * user name or $INCLUDE.
495 */
496 if (fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL) == 0) {
497 if (comma) {
498 ERROR("%s[%d]: Unexpected trailing comma in previous line", file, lineno);
499 goto fail_entry;
500 }
501
502 /*
503 * The line doesn't begin with spaces.
504 * The list of reply items MUST be
505 * finished. Go look for an entry name.
506 *
507 * Note that we don't allow comments in
508 * the middle of the reply item list. Oh
509 * well.
510 */
511 fr_dlist_insert_tail(&list->head, t);
512 continue;
513
514 } else if (lineno == (t->lineno + 1)) {
515 fr_assert(comma == false);
516
517 } else if (!comma) {
518 ERROR("%s[%d]: Missing comma in previous line", file, lineno);
519 goto fail_entry;
520 }
521
522 /*
523 * SPACES COMMENT or SPACES LF means "end of
524 * reply item list"
525 */
526 if (fr_sbuff_is_char(&sbuff, '#')) {
527 (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
528 }
529 if (fr_sbuff_next_if_char(&sbuff, '\n')) {
530 lineno++;
531 goto add_entry;
532 }
533
534next_reply_item:
535 /*
536 * Unlike check items, we don't skip spaces or
537 * comments here. All of the code paths which
538 * lead to here have already checked for those
539 * cases.
540 */
541 slen = map_afrom_substr(t, &new_map, &relative_map, &sbuff, map_assignment_op_table, map_assignment_op_table_len,
542 &lhs_rules, &rhs_rules, &rhs_term);
543 if (!new_map) {
544 ERROR_MARKER_ADJ(&sbuff, slen, fr_strerror());
545 goto fail;
546 }
547
548 fr_assert(new_map->lhs != NULL);
549
550 if (!tmpl_is_attr(new_map->lhs)) {
551 ERROR("%s[%d]: Unknown attribute '%s'",
552 file, lineno, new_map->lhs->name);
553 goto fail_entry;
554 }
555
556 /*
557 * We no longer really care what the RHS is, or what the list is on the LHS. The caller
558 * takes care of checking that for us.
559 */
560
561 if (!new_map->parent) map_list_insert_tail(&t->reply, new_map);
562
563 (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
564
565 /*
566 * Commas separate entries on the same line. And
567 * we allow spaces after commas, too.
568 */
569 if (fr_sbuff_next_if_char(&sbuff, ',')) {
570 comma = true;
571 (void) fr_sbuff_adv_past_blank(&sbuff, SIZE_MAX, NULL);
572 } else {
573 comma = false;
574 }
575
576 /*
577 * Comments or LF will end this particular line.
578 *
579 * Reading the next line will cause a complaint
580 * if this line ended with a comma.
581 */
582 if (fr_sbuff_next_if_char(&sbuff, '#')) {
583 (void) fr_sbuff_adv_to_chr(&sbuff, SIZE_MAX, '\n');
584 }
585
586 if (fr_sbuff_next_if_char(&sbuff, '\n')) {
587 lineno++;
588 goto reply_item;
589 }
590
591 /*
592 * Not comment or LF, the content MUST be another
593 * pair.
594 */
595 if (comma) goto next_reply_item;
596
597 ERROR_MARKER(&sbuff, "Unexpected text after reply");
598 goto fail_entry;
599 }
600
601 /*
602 * Else we were looking for an entry. We didn't get one
603 * because we were at EOF, so that's OK.
604 */
605
606 fclose(fp);
607
608 return 0;
609}
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
#define RCSID(id)
Definition build.h:485
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define MEM(x)
Definition debug.h:36
#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:367
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:465
size_t map_assignment_op_table_len
Definition map.c:383
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:734
@ L_ERR
Error message.
Definition log.h:56
long int ssize_t
#define fr_assert(_expr)
Definition rad_assert.h:38
#define DEBUG2(fmt,...)
Definition radclient.h:43
fr_dict_attr_t const * request_attr_request
Definition request.c:45
fr_dict_attr_t const * request_attr_control
Definition request.c:47
fr_dict_attr_t const * request_attr_reply
Definition request.c:46
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:1956
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:1852
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:2088
#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:192
#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.
File sbuff extension structure.
Definition sbuff.h:150
Set of parsing rules for *unescape_until functions.
void tmpl_attr_set_list(tmpl_t *vpt, fr_dict_attr_t const *list)
#define tmpl_contains_regex(vpt)
Definition tmpl.h:231
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:340
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:806
@ TMPL_ATTR_LIST_ALLOW
Attribute refs are allowed to have a list.
Definition tmpl.h:267
struct tmpl_rules_s tmpl_rules_t
Definition tmpl.h:238
#define tmpl_is_regex_uncompiled(vpt)
Definition tmpl.h:219
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:337
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:300
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:278
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:49
@ 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
static int pairlist_read_internal(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool complain, bool v3_compat, int *order)
Definition users_file.c:245
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, bool v3_compat, int *order)
Definition users_file.c:143
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
int pairlist_read(TALLOC_CTX *ctx, fr_dict_t const *dict, char const *file, PAIR_LIST_LIST *list, bool v3_compat)
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
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
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:166