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: 514e1194c6fa3d69f5715d0b6b8ca502392be767 $
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: 514e1194c6fa3d69f5715d0b6b8ca502392be767 $")
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, 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, 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
235int 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 */
245static 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,
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
361 comma = false;
362
363check_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
475setup_reply:
476 /*
477 * Setup the reply items.
478 */
479 lhs_rules.attr.list_def = request_attr_reply;
480
481 comma = false;
482
484
485 relative_map = NULL;
486
487reply_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
532next_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: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:329
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:427
size_t map_assignment_op_table_len
Definition map.c:345
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:230
#define tmpl_is_attr(vpt)
Definition tmpl.h:213
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:344
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition tmpl.h:812
@ 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
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: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
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