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