The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
pair_legacy.c
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /** AVP manipulation and search API
18  *
19  * @file src/lib/util/pair_legacy.c
20  *
21  * @copyright 2000,2006,2015 The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: d17a69e00c3278f3e469b6ef334bff05e4867c01 $")
25 
26 #include <freeradius-devel/util/dict.h>
27 #include <freeradius-devel/util/pair.h>
28 #include <freeradius-devel/util/pair_legacy.h>
29 #include <freeradius-devel/util/misc.h>
30 #include <freeradius-devel/util/proto.h>
31 #include <freeradius-devel/util/regex.h>
32 
33 #include <freeradius-devel/protocol/radius/rfc2865.h>
34 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
35 
38  L("\t"),
39  L("\n"),
40  L(" "),
41  L("!*"),
42  L("!="),
43  L("!~"),
44  L("&&"), /* Logical operator */
45  L(")"), /* Close condition/sub-condition */
46  L("+="),
47  L("-="),
48  L(":="),
49  L("<"),
50  L("<="),
51  L("=*"),
52  L("=="),
53  L("=~"),
54  L(">"),
55  L(">="),
56  L("||"), /* Logical operator */
57  );
58 
60  { L("+="), T_OP_ADD_EQ },
61  { L(":="), T_OP_EQ },
62  { L("="), T_OP_EQ },
63 };
65 
67  { L("!*"), T_OP_CMP_FALSE },
68  { L("!="), T_OP_NE },
69  { L("!~"), T_OP_REG_NE },
70  { L("+="), T_OP_ADD_EQ },
71  { L(":="), T_OP_SET },
72  { L("<"), T_OP_LT },
73  { L("<="), T_OP_LE },
74  { L("="), T_OP_EQ },
75  { L("=*"), T_OP_CMP_TRUE },
76  { L("=="), T_OP_CMP_EQ },
77  { L("=~"), T_OP_REG_EQ },
78  { L(">"), T_OP_GT },
79  { L(">="), T_OP_GE }
80 };
82 
83 /*
84  * Stop parsing bare words at whitespace, comma, or end of list.
85  *
86  * Note that we don't allow escaping of bare words here, as that screws up parsing of raw attributes with
87  * 0x... prefixes.
88  */
89 static fr_sbuff_parse_rules_t const bareword_unquoted = {
90  .terminals = &FR_SBUFF_TERMS(
91  L(""),
92  L("\t"),
93  L("\n"),
94  L("\r"),
95  L(" "),
96  L(","),
97  L("}")
98  )
99 };
100 
101 
103 {
104  char quote;
105  ssize_t slen;
106  fr_sbuff_parse_rules_t const *rules;
107 
108  if (fr_sbuff_next_if_char(in, '"')) {
110  quote = '"';
111 
112  } else if (fr_sbuff_next_if_char(in, '\'')) {
114  quote = '\'';
115 
116  /*
117  * We don't support backticks here.
118  */
119  } else if (fr_sbuff_is_char(in, '\'')) {
120  fr_strerror_const("Backticks are not supported here");
121  return 0;
122 
123  } else {
124  rules = &bareword_unquoted;
125  quote = '\0';
126  }
127 
128  slen = fr_value_box_from_substr(vp, &vp->data, vp->da->type, vp->da, in, rules, tainted);
129  if (slen < 0) return slen - (quote != 0);
130 
131  if (quote && !fr_sbuff_next_if_char(in, quote)) {
132  fr_strerror_const("Unterminated string");
133  return 0;
134  }
135 
136  return slen + ((quote != 0) << 1);
137 }
138 
139 /** Parse a #fr_pair_list_t from a substring
140  *
141  * @param[in] root where we start parsing from
142  * @param[in,out] relative where we left off, or where we should continue from
143  * @param[in] in input sbuff
144  * @return
145  * - <0 on error
146  * - 0 on no input
147  * - >0 on how many bytes of input we read
148  *
149  */
151  fr_sbuff_t *in)
152 {
153  int i, components;
154  bool raw, raw_octets;
155  bool was_relative = false;
156  bool append;
157  bool keep_going;
158  fr_token_t op;
159  fr_slen_t slen;
160  fr_pair_t *vp;
161  fr_dict_attr_t const *internal = NULL;
162  fr_sbuff_marker_t lhs_m, rhs_m;
163  fr_sbuff_t our_in = FR_SBUFF(in);
164 
165  if (!root->ctx || !root->da || !root->list) return 0;
166 
167  if (fr_dict_internal()) internal = fr_dict_root(fr_dict_internal());
168  if (internal == root->da) internal = NULL;
169 
170  if (fr_sbuff_remaining(&our_in) == 0) return 0;
171 
172 redo:
173  append = true;
174  raw = raw_octets = false;
175  relative->last_char = 0;
176 
177  fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
178 
179  /*
180  * Relative attributes start from the input list / parent.
181  *
182  * Absolute attributes start from the root list / parent.
183  *
184  * Once we decide where we are coming from, all subsequent operations are on the "relative"
185  * structure.
186  */
187  if (!fr_sbuff_next_if_char(&our_in, '.')) {
188  *relative = *root;
189 
190  append = !was_relative;
191  was_relative = false;
192 
193  /*
194  * Be nice to people who expect to see '&' everywhere.
195  */
196  (void) fr_sbuff_next_if_char(&our_in, '&');
197 
198  /*
199  * Raw attributes can only be at our root.
200  *
201  * "raw.foo" means that SOME component of the OID is raw. But the starting bits might be known.
202  */
203  if (fr_sbuff_is_str_literal(&our_in, "raw.")) {
204  raw = true;
205  fr_sbuff_advance(&our_in, 4);
206  }
207  } else if (!relative->ctx || !relative->da || !relative->list) {
208  fr_strerror_const("The '.Attribute' syntax can only be used if the previous attribute is structural, and the line ends with ','");
209  return -1;
210  } else {
211  was_relative = true;
212  }
213 
214  /*
215  * Set the LHS marker to be after any initial '.'
216  */
217  fr_sbuff_marker(&lhs_m, &our_in);
218 
219  /*
220  * Skip over the attribute name. We need to get the operator _before_ creating the VPs.
221  */
222  components = 0;
223  do {
224  if (fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, fr_dict_attr_allowed_chars, NULL) == 0) break;
225  components++;
226  } while (fr_sbuff_next_if_char(&our_in, '.'));
227 
228  /*
229  * Couldn't find anything.
230  */
231  if (!components) {
232  fr_strerror_const("Empty input");
233  return 0;
234  }
235 
236  fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
237 
238  /*
239  * Look for the operator.
240  */
241  if (relative->allow_compare) {
243  } else {
245  }
246  if (op == T_INVALID) {
247  fr_strerror_const("Expecting operator");
248  return fr_sbuff_error(&our_in);
249  }
250 
251  /*
252  * Skip past whitespace, and set a marker at the RHS. Then reset the input to the LHS attribute
253  * name, so that we can go back and parse / create the attributes.
254  */
255  fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
256 
257  fr_sbuff_marker(&rhs_m, &our_in);
258 
259  /*
260  * Peek ahead to see if the final element is defined to be structural, but the caller instead
261  * wants to parse it as raw octets.
262  */
263  if (raw) raw_octets = fr_sbuff_is_str_literal(&our_in, "0x");
264 
265  fr_sbuff_set(&our_in, &lhs_m);
266 
267  /*
268  * Parse each OID component, creating pairs along the way.
269  */
270  i = 1;
271  do {
273  fr_dict_attr_t const *da = NULL;
274  fr_dict_attr_t const *da_unknown = NULL;
275 
276  slen = fr_dict_oid_component(&err, &da, relative->da, &our_in, &bareword_terminals);
277  if (err == FR_DICT_ATTR_NOTFOUND) {
278  if (raw) {
279  if (fr_sbuff_is_digit(&our_in)) {
280  slen = fr_dict_unknown_afrom_oid_substr(NULL, &da_unknown, relative->da, &our_in);
281  if (slen < 0) return fr_sbuff_error(&our_in) + slen;
282 
283  fr_assert(da_unknown);
284 
285  /*
286  * Append from the root list, starting at the root depth.
287  */
288  vp = fr_pair_afrom_da_depth_nested(root->ctx, root->list, da_unknown,
289  root->da->depth);
290  fr_dict_unknown_free(&da_unknown);
291 
292  if (!vp) return fr_sbuff_error(&our_in);
293 
294  PAIR_VERIFY(vp);
295 
296  /*
297  * The above function MAY have jumped ahead a few levels. Ensure
298  * that the relative structure is set correctly for the parent,
299  * but only if the parent changed.
300  */
301  if (relative->da != vp->da->parent) {
302  fr_pair_t *parent_vp;
303 
304  parent_vp = fr_pair_parent(vp);
305  fr_assert(parent_vp);
306 
307  relative->ctx = parent_vp;
308  relative->da = parent_vp->da;
309  relative->list = &parent_vp->vp_group;
310  }
311 
312  /*
313  * Update the new relative information for the current VP, which
314  * may be structural, or a key field.
315  */
316  fr_assert(!fr_sbuff_is_char(&our_in, '.')); /* be sure the loop exits */
317  goto update_relative;
318  }
319 
320  goto notfound;
321  }
322 
323  if (internal) {
324  slen = fr_dict_oid_component(&err, &da, internal, &our_in, &bareword_terminals);
325  }
326  }
327 
328  if (err != FR_DICT_ATTR_OK) {
329  notfound:
330  fr_sbuff_marker(&rhs_m, &our_in);
331  fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, fr_dict_attr_allowed_chars, NULL);
332 
333  fr_strerror_printf("Unknown attribute \"%.*s\" for parent \"%s\"",
334  (int) fr_sbuff_diff(&our_in, &rhs_m), fr_sbuff_current(&rhs_m),
335  relative->da->name);
336  return fr_sbuff_error(&our_in);
337  }
338  fr_assert(da != NULL);
339 
340 #if 0
341  /*
342  * @todo - If we're at the root, then aliases can cause us to jump over intermediate
343  * attributes. In which case we have to create the intermediate attributes, too.
344  */
345  if (relative->da) {
346  if (relative->da->flags.is_root) {
347  fr_assert(da->depth == 1);
348  }
349  }
350 #endif
351 
352  /*
353  * Intermediate components are always found / created. The final component is
354  * always appended, no matter the operator.
355  */
356  if (i < components) {
357  if (append) {
358  vp = fr_pair_find_last_by_da(relative->list, NULL, da);
359  if (!vp) {
360  if (fr_pair_append_by_da(relative->ctx, &vp, relative->list, da) < 0) {
361  return fr_sbuff_error(&our_in);
362  }
363  }
364  } else {
365  vp = fr_pair_afrom_da(relative->ctx, da);
366  if (!vp) return fr_sbuff_error(&our_in);
367 
368  fr_pair_append(relative->list, vp);
369  }
370 
371  /*
372  * We had a raw type and we're passing
373  * raw octets to it. We don't care if
374  * its structural or anything else. Just
375  * create the raw attribute.
376  */
377  } else if (raw_octets) {
378  if (!da_unknown) da_unknown = fr_dict_unknown_attr_afrom_da(NULL, da);
379  if (!da_unknown) return fr_sbuff_error(&our_in);
380 
381  fr_assert(da_unknown->type == FR_TYPE_OCTETS);
382 
383  if (fr_pair_append_by_da(relative->ctx, &vp, relative->list, da_unknown) < 0) {
384  fr_dict_unknown_free(&da_unknown);
385  return fr_sbuff_error(&our_in);
386  }
387  fr_dict_unknown_free(&da_unknown);
388  fr_assert(vp->vp_type == FR_TYPE_OCTETS);
389 
390  /*
391  * Just create the leaf attribute.
392  */
393  } else if (da->parent->type == FR_TYPE_STRUCT) {
394  fr_pair_t *tail = fr_pair_list_tail(relative->list);
395 
396  /*
397  * If the structure member is _less_ than the last one, go create a new structure
398  * in the grandparent.
399  */
400  if (tail && (tail->da->attr >= da->attr) && !da->flags.array) {
401  fr_pair_t *parent_vp, *grand_vp;
402 
403  parent_vp = fr_pair_list_parent(relative->list);
404  if (!parent_vp) goto leaf;
405 
406  fr_assert(da->parent == parent_vp->da);
407 
408  grand_vp = fr_pair_parent(parent_vp);
409  if (!grand_vp) goto leaf;
410 
411  /*
412  * Create a new parent in the context of the grandparent.
413  */
414  if (fr_pair_append_by_da(grand_vp, &vp, &grand_vp->vp_group, parent_vp->da) < 0) {
415  return fr_sbuff_error(&our_in);
416  }
417 
418  relative->ctx = vp;
419  fr_assert(relative->da == vp->da);
420  relative->list = &vp->vp_group;
421  }
422 
423  goto leaf;
424  } else {
425  leaf:
426  if (fr_pair_append_by_da(relative->ctx, &vp, relative->list, da) < 0) {
427  return fr_sbuff_error(&our_in);
428  }
429  }
430 
431  fr_assert(vp != NULL);
432 
433  update_relative:
434  /*
435  * Reset the parsing to the new namespace if necessary.
436  */
437  switch (vp->vp_type) {
438  case FR_TYPE_TLV:
439  case FR_TYPE_STRUCT:
440  case FR_TYPE_VSA:
441  case FR_TYPE_VENDOR:
442  relative->ctx = vp;
443  relative->da = vp->da;
444  relative->list = &vp->vp_group;
445  break;
446 
447  /*
448  * Groups reset the namespace to the da referenced by the group.
449  *
450  * Internal groups get their namespace to the root namespace.
451  */
452  case FR_TYPE_GROUP:
453  relative->ctx = vp;
454  relative->da = fr_dict_attr_ref(vp->da);
455  if (relative->da == internal) {
456  relative->da = fr_dict_root(root->da->dict);
457  }
458  relative->list = &vp->vp_group;
459  break;
460 
461  default:
462  /*
463  * Key fields have children in their namespace, but the children go into the
464  * parents context and list.
465  */
467  fr_pair_t *parent_vp;
468 
469  parent_vp = fr_pair_parent(vp);
470  fr_assert(parent_vp);
471 
472  relative->ctx = parent_vp;
473  relative->da = vp->da;
474  relative->list = &parent_vp->vp_group;
475  }
476  break;
477  }
478 
479  i++;
480  } while (fr_sbuff_next_if_char(&our_in, '.'));
481 
482  if (relative->allow_compare) {
483  vp->op = op;
484  } else {
485  vp->op = T_OP_EQ;
486  }
487 
488  /*
489  * Reset the parser to the RHS so that we can parse the value.
490  */
491  fr_sbuff_set(&our_in, &rhs_m);
492 
493  /*
494  * The RHS is a list, go parse the nested attributes.
495  */
496  if (fr_sbuff_next_if_char(&our_in, '{')) {
497  fr_pair_parse_t child = (fr_pair_parse_t) {
498  .allow_compare = root->allow_compare,
499  };
500 
501  if (!fr_type_is_structural(vp->vp_type)) {
502  fr_strerror_const("Cannot assign list to leaf data type");
503  return fr_sbuff_error(&our_in);
504  }
505 
506  while (true) {
507  fr_sbuff_adv_past_whitespace(&our_in, SIZE_MAX, NULL);
508 
509  if (fr_sbuff_is_char(&our_in, '}')) {
510  break;
511  }
512 
513  slen = fr_pair_list_afrom_substr(relative, &child, &our_in);
514  if (!slen) break;
515 
516  if (slen < 0) return fr_sbuff_error(&our_in) + slen;
517  }
518 
519  if (!fr_sbuff_next_if_char(&our_in, '}')) {
520  fr_strerror_const("Failed to end list with '}'");
521  return fr_sbuff_error(&our_in);
522  }
523 
524  goto done;
525  }
526 
527  if (fr_type_is_structural(vp->vp_type)) {
528  fr_strerror_printf("Group list for %s MUST start with '{'", vp->da->name);
529  return fr_sbuff_error(&our_in);
530  }
531 
532  slen = fr_pair_value_from_substr(vp, &our_in, relative->tainted);
533  if (slen <= 0) return fr_sbuff_error(&our_in) + slen;
534 
535 done:
536  PAIR_VERIFY(vp);
537 
538  keep_going = false;
539  if (fr_sbuff_next_if_char(&our_in, ',')) {
540  keep_going = true;
541  relative->last_char = ',';
542  }
543 
544  if (relative->allow_crlf) {
545  size_t len;
546 
547  len = fr_sbuff_adv_past_allowed(&our_in, SIZE_MAX, sbuff_char_line_endings, NULL);
548  if (len) {
549  keep_going |= true;
550  if (!relative->last_char) relative->last_char = '\n';
551  }
552  }
553 
554  keep_going &= ((fr_sbuff_remaining(&our_in) > 0) || (fr_sbuff_extend(&our_in) > 0));
555 
556  if (keep_going) goto redo;
557 
558  FR_SBUFF_SET_RETURN(in, &our_in);
559 }
560 
561 /** Read valuepairs from the fp up to End-Of-File.
562  *
563  * @param[in] ctx for talloc
564  * @param[in] dict to resolve attributes in.
565  * @param[in,out] out where the parsed fr_pair_ts will be appended.
566  * @param[in] fp to read valuepairs from.
567  * @param[out] pfiledone true if file parsing complete;
568  * @return
569  * - 0 on success
570  * - -1 on error
571  */
572 int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
573 {
574  fr_pair_list_t tmp_list;
575  fr_pair_parse_t root, relative;
576  bool found = false;
577  char buf[8192];
578 
579  /*
580  * Read all of the attributes on the current line.
581  *
582  * If we get nothing but an EOL, it's likely OK.
583  */
584  fr_pair_list_init(&tmp_list);
585 
586  root = (fr_pair_parse_t) {
587  .ctx = ctx,
588  .da = fr_dict_root(dict),
589  .list = &tmp_list,
590  .allow_crlf = true,
591  .allow_compare = true,
592  };
593  relative = (fr_pair_parse_t) { };
594 
595  while (fgets(buf, sizeof(buf), fp) != NULL) {
596  /*
597  * If we get a '\n' by itself, we assume that's
598  * the end of that VP list.
599  */
600  if ((buf[0] == '\n') || (buf[0] == '\r')) {
601  if (found) {
602  *pfiledone = false;
603  break;
604  }
605  continue;
606  }
607 
608  /*
609  * Comments get ignored
610  */
611  if (buf[0] == '#') continue;
612 
613  /*
614  * Leave "relative" between calls, so that we can do:
615  *
616  * foo = {}
617  * .bar = baz
618  *
619  * and get
620  *
621  * foo = { bar = baz }
622  */
623  if (fr_pair_list_afrom_substr(&root, &relative, &FR_SBUFF_IN(buf, strlen(buf))) < 0) {
624  *pfiledone = false;
625  fr_pair_list_free(&tmp_list);
626  return -1;
627  }
628 
629  found = true;
630  }
631 
632  fr_pair_list_append(out, &tmp_list);
633 
634  *pfiledone = true;
635  return 0;
636 }
637 
638 
639 /** Move pairs from source list to destination list respecting operator
640  *
641  * @note This function does some additional magic that's probably not needed in most places. Consider using
642  * radius_legacy_map_cmp() and radius_legacy_map_apply() instead.
643  *
644  * @note fr_pair_list_free should be called on the head of the source list to free
645  * unmoved attributes (if they're no longer needed).
646  *
647  * @param[in,out] to destination list.
648  * @param[in,out] from source list.
649  * @param[in] op operator for list move.
650  */
652 {
653  fr_pair_t *vp, *next, *found;
654  fr_pair_list_t head_append, head_prepend;
655 
656  if (!to || fr_pair_list_empty(from)) return;
657 
658  /*
659  * We're editing the "to" list while we're adding new
660  * attributes to it. We don't want the new attributes to
661  * be edited, so we create an intermediate list to hold
662  * them during the editing process.
663  */
664  fr_pair_list_init(&head_append);
665 
666  /*
667  * Any attributes that are requested to be prepended
668  * are added to a temporary list here
669  */
670  fr_pair_list_init(&head_prepend);
671 
672  /*
673  * We're looping over the "from" list, moving some
674  * attributes out, but leaving others in place.
675  */
676  for (vp = fr_pair_list_head(from); vp != NULL; vp = next) {
677  PAIR_VERIFY(vp);
678  next = fr_pair_list_next(from, vp);
679 
680  /*
681  * We never move Fall-Through.
682  */
683  if (fr_dict_attr_is_top_level(vp->da) && (vp->da->attr == FR_FALL_THROUGH) &&
684  (fr_dict_by_da(vp->da) == fr_dict_internal())) {
685  continue;
686  }
687 
688  /*
689  * Unlike previous versions, we treat all other
690  * attributes as normal. i.e. there's no special
691  * treatment for passwords or Hint.
692  */
693 
694  switch (vp->op) {
695  /*
696  * Anything else are operators which
697  * shouldn't occur. We ignore them, and
698  * leave them in place.
699  */
700  default:
701  continue;
702 
703  /*
704  * Add it to the "to" list, but only if
705  * it doesn't already exist.
706  */
707  case T_OP_EQ:
708  found = fr_pair_find_by_da(to, NULL, vp->da);
709  if (!found) goto do_add;
710  continue;
711 
712  /*
713  * Add it to the "to" list, and delete any attribute
714  * of the same vendor/attr which already exists.
715  */
716  case T_OP_SET:
717  found = fr_pair_find_by_da(to, NULL, vp->da);
718  if (!found) goto do_add;
719 
720  /*
721  * Delete *all* matching attributes.
722  */
723  fr_pair_delete_by_da(to, found->da);
724  goto do_add;
725 
726  /*
727  * Move it from the old list and add it
728  * to the new list.
729  */
730  case T_OP_ADD_EQ:
731  do_add:
732  fr_pair_remove(from, vp);
733  fr_pair_append(&head_append, vp);
734  continue;
735 
736  case T_OP_PREPEND:
737  fr_pair_remove(from, vp);
738  fr_pair_prepend(&head_prepend, vp);
739  continue;
740  }
741  } /* loop over the "from" list. */
742 
743  /*
744  * If the op parameter was prepend, add the "new list
745  * attributes first as those whose individual operator
746  * is prepend should be prepended to the resulting list
747  */
748  if (op == T_OP_PREPEND) fr_pair_list_prepend(to, &head_append);
749 
750  /*
751  * If there are any items in the prepend list prepend
752  * it to the "to" list
753  */
754  fr_pair_list_prepend(to, &head_prepend);
755 
756  /*
757  * If the op parameter was not prepend, take the "new"
758  * list, and append it to the "to" list.
759  */
760  if (op != T_OP_PREPEND) fr_pair_list_append(to, &head_append);
761 
762  fr_pair_list_free(from);
763 }
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
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
fr_slen_t fr_dict_unknown_afrom_oid_substr(TALLOC_CTX *ctx, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in))
Create a fr_dict_attr_t from an ASCII attribute and value.
Definition: dict_unknown.c:403
static fr_slen_t err
Definition: dict.h:645
bool const fr_dict_attr_allowed_chars[UINT8_MAX+1]
Characters that are allowed in dictionary attribute names.
Definition: dict_util.c:45
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
fr_dict_attr_t * fr_dict_unknown_attr_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da))
Initialise an octets type attribute from a da.
Definition: dict_unknown.c:378
fr_dict_t const * fr_dict_by_da(fr_dict_attr_t const *da)
Attempt to locate the protocol dictionary containing an attribute.
Definition: dict_util.c:2203
fr_dict_t const * fr_dict_internal(void)
Definition: dict_util.c:4204
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
Definition: dict.h:578
fr_dict_attr_err_t
Errors returned by attribute lookup functions.
Definition: dict.h:272
@ FR_DICT_ATTR_OK
No error.
Definition: dict.h:273
@ FR_DICT_ATTR_NOTFOUND
Attribute couldn't be found.
Definition: dict.h:274
fr_slen_t fr_dict_oid_component(fr_dict_attr_err_t *err, fr_dict_attr_t const **out, fr_dict_attr_t const *parent, fr_sbuff_t *in, fr_sbuff_term_t const *tt))
Parse an OID component, resolving it to a defined attribute.
Definition: dict_util.c:1823
#define fr_dict_attr_is_key_field(_da)
Definition: dict.h:149
static fr_slen_t in
Definition: dict.h:645
static fr_dict_attr_t const * fr_dict_attr_ref(fr_dict_attr_t const *da)
Return the reference associated with a group type attribute.
Definition: dict_ext.h:164
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
Definition: merged_model.c:119
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
Definition: merged_model.c:122
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
long int ssize_t
Definition: merged_model.c:24
ssize_t fr_slen_t
Definition: merged_model.c:35
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition: pair.c:688
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
Definition: pair.c:1461
fr_pair_t * fr_pair_parent(fr_pair_t const *vp)
Return a pointer to the parent pair.
Definition: pair.c:937
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition: pair.c:278
fr_pair_t * fr_pair_find_last_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the last pair with a matching da.
Definition: pair.c:712
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition: pair.c:1340
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition: pair.c:1684
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
Definition: pair.c:1309
fr_pair_t * fr_pair_list_parent(fr_pair_list_t const *list)
Return a pointer to the parent pair which contains this list.
Definition: pair.c:951
fr_pair_t * fr_pair_afrom_da_depth_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da, int start)
Create a pair (and all intermediate parents), and append it to the list.
Definition: pair.c:403
static fr_sbuff_parse_rules_t const bareword_unquoted
Definition: pair_legacy.c:89
static fr_table_num_sorted_t const pair_assignment_op_table[]
Definition: pair_legacy.c:59
fr_slen_t fr_pair_list_afrom_substr(fr_pair_parse_t const *root, fr_pair_parse_t *relative, fr_sbuff_t *in)
Parse a fr_pair_list_t from a substring.
Definition: pair_legacy.c:150
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone)
Read valuepairs from the fp up to End-Of-File.
Definition: pair_legacy.c:572
void fr_pair_list_move_op(fr_pair_list_t *to, fr_pair_list_t *from, fr_token_t op)
Move pairs from source list to destination list respecting operator.
Definition: pair_legacy.c:651
static size_t pair_comparison_op_table_len
Definition: pair_legacy.c:81
static fr_table_num_sorted_t const pair_comparison_op_table[]
Definition: pair_legacy.c:66
static fr_sbuff_term_t const bareword_terminals
Definition: pair_legacy.c:36
static ssize_t fr_pair_value_from_substr(fr_pair_t *vp, fr_sbuff_t *in, bool tainted)
Definition: pair_legacy.c:102
static ssize_t pair_assignment_op_table_len
Definition: pair_legacy.c:64
struct fr_pair_parse_s fr_pair_parse_t
fr_pair_list_t * list
list where output is placed
Definition: pair_legacy.h:45
TALLOC_CTX * ctx
Definition: pair_legacy.h:43
bool allow_compare
allow comparison operators
Definition: pair_legacy.h:46
fr_dict_attr_t const * da
root da to start parsing from
Definition: pair_legacy.h:44
bool tainted
source is tainted
Definition: pair_legacy.h:48
bool allow_crlf
allow CRLF, and treat like comma
Definition: pair_legacy.h:47
char last_char
last character we read - ',', ' ', or 0 for EOF
Definition: pair_legacy.h:49
static bool done
Definition: radclient.c:80
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static UINT8_MAX+1], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
Definition: sbuff.c:1736
bool const sbuff_char_line_endings[UINT8_MAX+1]
Definition: sbuff.c:96
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_out_by_longest_prefix(_match_len, _out, _table, _sbuff, _def)
#define fr_sbuff_is_str_literal(_sbuff, _str)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_diff(_a, _b)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_TERMS(...)
Initialise a terminal structure with a list of sorted strings.
Definition: sbuff.h:167
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define fr_sbuff_is_digit(_sbuff_or_marker)
#define fr_sbuff_error(_sbuff_or_marker)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_remaining(_sbuff_or_marker)
Set of terminal elements.
Definition: merged_model.c:161
fr_assert(0)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:45
enum fr_token fr_token_t
@ T_INVALID
Definition: token.h:39
@ 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
@ T_OP_PREPEND
Definition: token.h:85
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
fr_pair_t * fr_pair_list_tail(fr_pair_list_t const *list)
Get the tail of a valuepair list.
Definition: pair_inline.c:56
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition: pair_inline.c:94
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition: pair_inline.c:70
#define PAIR_VERIFY(_x)
Definition: pair.h:190
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
void fr_pair_list_append(fr_pair_list_t *dst, fr_pair_list_t *src)
Appends a list of fr_pair_t from a temporary list to a destination list.
Definition: pair_inline.c:182
void fr_pair_list_prepend(fr_pair_list_t *dst, fr_pair_list_t *src)
Move a list of fr_pair_t from a temporary list to the head of a destination list.
Definition: pair_inline.c:195
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
#define fr_type_is_structural(_x)
Definition: types.h:371
ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *rules, bool tainted)
Convert string value to a fr_value_box_t type.
Definition: value.c:4751
fr_sbuff_parse_rules_t const value_parse_rules_single_quoted
Definition: value.c:553
FR_SBUFF_SET_RETURN(sbuff, &our_sbuff)
fr_sbuff_parse_rules_t const value_parse_rules_double_quoted
Definition: value.c:547
static size_t char ** out
Definition: value.h:984