The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
pair.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.c
20  *
21  * @copyright 2021 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
22  * @copyright 2000,2006,2015,2020 The FreeRADIUS server project
23  */
24 RCSID("$Id: e11aab4236b63a2c9784cbd31eca037cde3b2715 $")
25 
26 #define _PAIR_PRIVATE 1
27 #define _PAIR_INLINE 1
28 
29 #include <freeradius-devel/util/debug.h>
30 #include <freeradius-devel/util/misc.h>
31 #include <freeradius-devel/util/pair.h>
32 #include <freeradius-devel/util/pair_legacy.h>
33 #include <freeradius-devel/util/proto.h>
34 #include <freeradius-devel/util/regex.h>
35 
36 FR_TLIST_FUNCS(fr_pair_order_list, fr_pair_t, order_entry)
37 
38 #include <freeradius-devel/util/pair_inline.c>
39 
40 /** Initialise a pair list header
41  *
42  * @param[in,out] list to initialise
43  *
44  * @hidecallergraph
45  */
47 {
48  /*
49  * Initialises the order list. This
50  * maintains the overall order of attributes
51  * in the list and allows us to iterate over
52  * all of them.
53  */
54  fr_pair_order_list_talloc_init(&list->order);
55 
56 #ifdef WITH_VERIFY_PTR
57  list->verified = true;
58 #endif
59  list->is_child = false;
60 }
61 
62 /** Free a fr_pair_t
63  *
64  * @note Do not call directly, use talloc_free instead.
65  *
66  * @param vp to free.
67  * @return 0
68  */
70 {
71 #ifdef TALLOC_DEBUG
72  talloc_report_depth_cb(NULL, 0, -1, fr_talloc_verify_cb, NULL);
73 #endif
74 
75 #if 0
76  /*
77  * We would like to enforce that a VP must be removed from a list before it's freed. However, we
78  * free pair_lists via talloc_free(). And the talloc code just frees things in (essentially) a
79  * random order. So this guarantee can't be enforced.
80  */
81  fr_assert(fr_pair_order_list_parent(vp) == NULL);
82 #endif
83 
84  /*
85  * Pairs with children have the children
86  * freed explicitly.
87  */
88  if (likely(vp->da != NULL)) switch (vp->vp_type) {
89  case FR_TYPE_STRUCTURAL:
90  fr_pair_list_free(&vp->vp_group);
91  break;
92 
93  case FR_TYPE_STRING:
94  case FR_TYPE_OCTETS:
95  if (vp->data.secret) memset_explicit(vp->vp_ptr, 0, vp->vp_length);
96  break;
97 
98  default:
99  if (vp->data.secret) memset_explicit(&vp->data, 0, sizeof(vp->data));
100  break;
101  }
102 
103 #ifndef NDEBUG
104  memset(vp, 0, sizeof(*vp));
105 #endif
106 
107  return 0;
108 }
109 
110 /** Allocate a new pair list on the heap
111  *
112  * @param[in] ctx to allocate the pair list in.
113  * @return
114  * - A new #fr_pair_list_t.
115  * - NULL if an error occurred.
116  */
118 {
119  fr_pair_list_t *pl;
120 
121  pl = talloc(ctx, fr_pair_list_t);
122  if (unlikely(!pl)) return NULL;
123 
124  fr_pair_list_init(pl);
125 
126  return pl;
127 }
128 
129 /** Initialise fields in an fr_pair_t without assigning a da
130  *
131  * @note Internal use by the allocation functions only.
132  */
133 static inline CC_HINT(always_inline) void pair_init_null(fr_pair_t *vp)
134 {
135  fr_pair_order_list_entry_init(vp);
136 
137  /*
138  * Legacy cruft
139  */
140  vp->op = T_OP_EQ;
141 }
142 
143 /** Initialise fields in an fr_pair_t without assigning a da
144  *
145  * Used only for temporary value-pairs which are not placed in any list.
146  */
148 {
149  memset(vp, 0, sizeof(*vp));
150 
152 }
153 
154 /** Dynamically allocate a new attribute with no #fr_dict_attr_t assigned
155  *
156  * This is not the function you're looking for (unless you're binding
157  * unknown attributes to pairs, and need to pre-allocate the memory).
158  * You probably want #fr_pair_afrom_da instead.
159  *
160  * @note You must assign a #fr_dict_attr_t before freeing this #fr_pair_t.
161  *
162  * @param[in] ctx to allocate the pair list in.
163  * @return
164  * - A new #fr_pair_t.
165  * - NULL if an error occurred.
166  */
167 fr_pair_t *fr_pair_alloc_null(TALLOC_CTX *ctx)
168 {
169  fr_pair_t *vp;
170 
171  vp = talloc_zero(ctx, fr_pair_t);
172  if (!vp) {
173  fr_strerror_printf("Out of memory");
174  return NULL;
175  }
176  talloc_set_destructor(vp, _fr_pair_free);
177 
179 
180  return vp;
181 }
182 
183 /** Continue initialising an fr_pair_t assigning a da
184  *
185  * @note Internal use by the pair allocation functions only.
186  */
187 static inline CC_HINT(always_inline) void pair_init_from_da(fr_pair_t *vp, fr_dict_attr_t const *da)
188 {
189  /*
190  * Use the 'da' to initialize more fields.
191  */
192  vp->da = da;
193 
194  if (likely(fr_type_is_leaf(da->type))) {
195  fr_value_box_init(&vp->data, da->type, da, false);
196  } else {
197 #ifndef NDEBUG
198  /*
199  * Make it very obvious if we failed
200  * to initialise something.
201  * Given the definition of fr_value_box_t, this entails
202  * writing const-qualified fields. The compiler allows it,
203  * but Coverity points it out as a defect, so it is annotated.
204  */
205  /* coverity[store_writes_const_field] */
206  memset(&vp->data, 0xff, sizeof(vp->data));
207 #endif
208 
209  /*
210  * Hack around const issues...
211  * Here again, the orkaround suffices for the compiler but
212  * not for Coverity, so again we annotate.
213  */
214  /* coverity[store_writes_const_field] */
215  memcpy(UNCONST(fr_type_t *, &vp->vp_type), &da->type, sizeof(vp->vp_type));
216  fr_pair_list_init(&vp->vp_group);
217  vp->vp_group.is_child = true;
218  fr_pair_order_list_talloc_init_children(vp, &vp->vp_group.order);
219  }
220 }
221 
222 /** A special allocation function which disables child autofree
223  *
224  * This is intended to allocate root attributes for requests.
225  * These roots are special in that they do not necessarily own
226  * the child attributes and _MUST NOT_ free them when they
227  * themselves are freed. The children are allocated in special
228  * ctxs which may be moved between session state entries and
229  * requests, or may belong to a parent request.
230  *
231  * @param[in] ctx to allocate the pair root in.
232  * @param[in] da The root attribute.
233  * @return
234  * - A new root pair on success.
235  * - NULL on failure.
236  * @hidecallergraph
237  */
238 fr_pair_t *fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
239 {
240  fr_pair_t *vp;
241 
242 #ifndef NDEBUG
243  if (da->type != FR_TYPE_GROUP) {
244  fr_strerror_const("Root must be a group type");
245  return NULL;
246  }
247 #endif
248 
249  vp = talloc_zero(ctx, fr_pair_t);
250  if (unlikely(!vp)) {
251  fr_strerror_const("Out of memory");
252  return NULL;
253  }
254 
255  if (unlikely(da->flags.is_unknown)) {
256  fr_strerror_const("Root attribute cannot be unknown");
257  return NULL;
258  }
259 
260  pair_init_from_da(vp, da);
261 
262  return vp;
263 }
264 
265 /** Dynamically allocate a new attribute and assign a #fr_dict_attr_t
266  *
267  * @note Will duplicate any unknown attributes passed as the da.
268  *
269  * @param[in] ctx for allocated memory, usually a pointer to a #fr_packet_t
270  * @param[in] da Specifies the dictionary attribute to build the #fr_pair_t from.
271  * If unknown, will be duplicated, with the memory being bound to
272  * the pair.
273  * @return
274  * - A new #fr_pair_t.
275  * - NULL if an error occurred.
276  * @hidecallergraph
277  */
278 fr_pair_t *fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
279 {
280  fr_pair_t *vp;
281 
282  vp = fr_pair_alloc_null(ctx);
283  if (!vp) {
284  fr_strerror_printf("Out of memory");
285  return NULL;
286  }
287 
288  /*
289  * If we get passed an unknown da, we need to ensure that
290  * it's parented by "vp".
291  */
292  if (da->flags.is_unknown) {
293  fr_dict_attr_t const *unknown;
294 
295  unknown = fr_dict_unknown_copy(vp, da);
296  da = unknown;
297  }
298 
299  pair_init_from_da(vp, da);
300 
301  return vp;
302 }
303 
304 /** Re-initialise an attribute with a different da
305  *
306  * If the new da has a different type to the old da, we'll attempt to cast
307  * the current value in place.
308  */
310 {
311  fr_dict_attr_t const *to_free;
312 
313  /*
314  * vp may be created from fr_pair_alloc_null(), in which case it has no da.
315  */
316  if (vp->da && !vp->da->flags.is_raw) {
317  if (vp->da == da) return 0;
318 
319  if (!fr_type_is_leaf(vp->vp_type)) return -1;
320 
321  if ((da->type != vp->vp_type) && (fr_value_box_cast_in_place(vp, &vp->data, da->type, da) < 0)) return -1;
322  } else {
323  fr_assert(fr_type_is_leaf(vp->vp_type) || (fr_pair_list_num_elements(&vp->vp_group) == 0));
324 
325  fr_value_box_init(&vp->data, da->type, da, false);
326  }
327 
328  to_free = vp->da;
329  vp->da = da;
330 
331  /*
332  * Only frees unknown fr_dict_attr_t's
333  */
334  fr_dict_unknown_free(&to_free);
335 
336  /*
337  * Ensure we update the attribute index in the parent.
338  */
339  if (list) {
340  fr_pair_remove(list, vp);
341 
342  fr_pair_append(list, vp);
343  }
344 
345  return 0;
346 }
347 
348 /** Create a new valuepair
349  *
350  * If attr and vendor match a dictionary entry then a VP with that #fr_dict_attr_t
351  * will be returned.
352  *
353  * If attr or vendor are unknown will call dict_attruknown to create a dynamic
354  * #fr_dict_attr_t of #FR_TYPE_OCTETS.
355  *
356  * Which type of #fr_dict_attr_t the #fr_pair_t was created with can be determined by
357  * checking @verbatim vp->da->flags.is_unknown @endverbatim.
358  *
359  * @param[in] ctx for allocated memory, usually a pointer to a #fr_packet_t.
360  * @param[in] parent of the attribute being allocated (usually a dictionary or vendor).
361  * @param[in] attr number.
362  * @return
363  * - A new #fr_pair_t.
364  * - NULL on error.
365  */
366 fr_pair_t *fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
367 {
368  fr_dict_attr_t const *da;
369  fr_pair_t *vp;
370 
371  vp = fr_pair_alloc_null(ctx);
372  if (unlikely(!vp)) return NULL;
373 
374  da = fr_dict_attr_child_by_num(parent, attr);
375  if (!da) {
376  fr_dict_attr_t *unknown;
377 
378  unknown = fr_dict_unknown_attr_afrom_num(vp, parent, attr);
379  if (!unknown) {
380  talloc_free(vp);
381  return NULL;
382  }
383  da = unknown;
384  }
385 
386  pair_init_from_da(vp, da);
387 
388  return vp;
389 }
390 
391 /** Create a pair (and all intermediate parents), and append it to the list
392  *
393  * Unlike fr_pair_afrom_da_nested(), this function starts off at an intermediate ctx and list.
394  *
395  * @param[in] ctx for allocated memory, usually a pointer to a #fr_packet_t.
396  * @param[out] list where the created pair is supposed to go.
397  * @param[in] da the da for the pair to create
398  * @param[in] start the starting depth. If start != 0, we must have ctx==vp at that depth, and list==&vp->vp_group
399  * @return
400  * - A new #fr_pair_t.
401  * - NULL on error.
402  */
403 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)
404 {
405  fr_pair_t *vp;
406  unsigned int i;
407  TALLOC_CTX *cur_ctx;
408  fr_dict_attr_t const *find; /* DA currently being looked for */
409  fr_pair_list_t *cur_list; /* Current list being searched */
410  fr_da_stack_t da_stack;
411 
412  fr_proto_da_stack_build(&da_stack, da);
413  cur_list = list;
414  cur_ctx = ctx;
415 
416  for (i = start; i <= da->depth; i++) {
417  find = da_stack.da[i];
418 
419  /*
420  * If we're asked to create a key field, then do it.
421  *
422  * Otherwise if we're creating a child struct (which is magically parented by the key
423  * field), then don't bother creating the key field. It will be automatically filled in
424  * by the encoder.
425  */
426  if ((find != da) && fr_dict_attr_is_key_field(find)) {
427  continue;
428  }
429 
430  vp = fr_pair_find_by_da(cur_list, NULL, find);
431  if (!vp || (vp->da == da)) {
432  if (fr_pair_append_by_da(cur_ctx, &vp, cur_list, find) < 0) return NULL;
433  }
434 
435  if (find == da) return vp;
436 
438 
439  cur_ctx = vp;
440  cur_list = &vp->vp_group;
441  }
442 
443  fr_assert(0);
444 
445  return NULL;
446 }
447 
448 /** Create a pair (and all intermediate parents), and append it to the list
449  *
450  * If the relevant leaf pair already exists, then a new one is created.
451  *
452  * This function is similar to fr_pair_update_by_da_parent(), except that function requires
453  * a parent pair, and this one takes a separate talloc ctx and pair list.
454  *
455  * @param[in] ctx for allocated memory, usually a pointer to a #fr_packet_t.
456  * @param[out] list where the created pair is supposed to go.
457  * @param[in] da the da for the pair to create
458  * @return
459  * - A new #fr_pair_t.
460  * - NULL on error.
461  */
463 {
464  if (da->depth <= 1) {
465  fr_pair_t *vp;
466 
467  if (fr_pair_append_by_da(ctx, &vp, list, da) < 0) return NULL;
468  return vp;
469  }
470 
471  return fr_pair_afrom_da_depth_nested(ctx, list, da, 0);
472 }
473 
474 /** Copy a single valuepair
475  *
476  * Allocate a new valuepair and copy the da from the old vp.
477  *
478  * @param[in] ctx for talloc
479  * @param[in] vp to copy.
480  * @return
481  * - A copy of the input VP.
482  * - NULL on error.
483  */
484 fr_pair_t *fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
485 {
486  fr_pair_t *n;
487 
488  PAIR_VERIFY(vp);
489 
490  n = fr_pair_afrom_da(ctx, vp->da);
491  if (!n) return NULL;
492 
493  n->op = vp->op;
494 
495  /*
496  * Groups are special.
497  */
498  if (fr_type_is_structural(n->vp_type)) {
499  if (fr_pair_list_copy(n, &n->vp_group, &vp->vp_group) < 0) {
500  talloc_free(n);
501  return NULL;
502  }
503 
504  } else {
505  fr_value_box_copy(n, &n->data, &vp->data);
506  }
507 
508  return n;
509 }
510 
511 /** Steal one VP
512  *
513  * @param[in] ctx to move fr_pair_t into
514  * @param[in] vp fr_pair_t to move into the new context.
515  */
516 int fr_pair_steal(TALLOC_CTX *ctx, fr_pair_t *vp)
517 {
518  fr_pair_t *nvp;
519 
520  nvp = talloc_steal(ctx, vp);
521  if (unlikely(!nvp)) {
522  fr_strerror_printf("Failed moving pair %pV to new ctx", vp);
523  return -1;
524  }
525 
526  return 0;
527 }
528 
529 #define IN_A_LIST_MSG "Pair %pV is already in a list, and cannot be moved"
530 #define NOT_IN_THIS_LIST_MSG "Pair %pV is not in the given list"
531 
532 /** Change a vp's talloc ctx and insert it into a new list
533  *
534  * @param[in] list_ctx to move vp into.
535  * @param[out] list to add vp to.
536  * @param[in] vp to move.
537  * @return
538  * - 0 on success.
539  * - -1 on failure (already in list).
540  */
541 int fr_pair_steal_append(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
542 {
543  if (fr_pair_order_list_in_a_list(vp)) {
545  return -1;
546  }
547 
548  if (unlikely(fr_pair_steal(list_ctx, vp) < 0)) return -1;
549 
550  if (unlikely(fr_pair_append(list, vp) < 0)) return -1;
551 
552  return 0;
553 }
554 
555 /** Change a vp's talloc ctx and insert it into a new list
556  *
557  * @param[in] list_ctx to move vp into.
558  * @param[out] list to add vp to.
559  * @param[in] vp to move.
560  * @return
561  * - 0 on success.
562  * - -1 on failure (already in list).
563  */
564 int fr_pair_steal_prepend(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
565 {
566  if (fr_pair_order_list_in_a_list(vp)) {
568  return -1;
569  }
570 
571  if (unlikely(fr_pair_steal(list_ctx, vp) < 0)) return -1;
572 
573  if (unlikely(fr_pair_prepend(list, vp) < 0)) return -1;
574 
575  return 0;
576 }
577 
578 /** Mark malformed attribute as raw
579  *
580  * @param[in] vp to mark as raw.
581  * @param[in] data to parse.
582  * @param[in] data_len of data to parse.
583  *
584  * @return
585  * - 0 on success
586  * - -1 on failure.
587  */
588 int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
589 {
590  fr_dict_attr_t *unknown;
591 
592  PAIR_VERIFY(vp);
593 
594  if (!fr_cond_assert(vp->da->flags.is_unknown == false)) return -1;
595 
596  if (!fr_cond_assert(vp->da->parent != NULL)) return -1;
597 
598  unknown = fr_dict_unknown_afrom_da(vp, vp->da);
599  if (!unknown) return -1;
600 
601  vp->da = unknown;
602  fr_assert(vp->da->type == FR_TYPE_OCTETS);
603 
604  fr_value_box_init(&vp->data, FR_TYPE_OCTETS, NULL, true);
605 
606  fr_pair_value_memdup(vp, data, data_len, true);
607 
608  return 0;
609 }
610 
611 /** Iterate over pairs with a specified da
612  *
613  * @param[in] list to iterate over.
614  * @param[in] current The fr_pair_t cursor->current. Will be advanced and checked to
615  * see if it matches the specified fr_dict_attr_t.
616  * @param[in] uctx The fr_dict_attr_t to search for.
617  * @return
618  * - Next matching fr_pair_t.
619  * - NULL if not more matching fr_pair_ts could be found.
620  */
621 static void *fr_pair_iter_next_by_da(fr_dlist_head_t *list, void *current, void *uctx)
622 {
623  fr_pair_t *c = current;
624  fr_dict_attr_t *da = uctx;
625 
626  while ((c = fr_dlist_next(list, c))) {
627  PAIR_VERIFY(c);
628  if (c->da == da) break;
629  }
630 
631  return c;
632 }
633 
634 /** Iterate over pairs which are decedents of the specified da
635  *
636  * @param[in] list to iterate over.
637  * @param[in] current The fr_pair_t cursor->current. Will be advanced and checked to
638  * see if it matches the specified fr_dict_attr_t.
639  * @param[in] uctx The fr_dict_attr_t to search for.
640  * @return
641  * - Next matching fr_pair_t.
642  * - NULL if not more matching fr_pair_ts could be found.
643  */
644 static void *fr_pair_iter_next_by_ancestor(fr_dlist_head_t *list, void *current, void *uctx)
645 {
646  fr_pair_t *c = current;
647  fr_dict_attr_t *da = uctx;
648 
649  while ((c = fr_dlist_next(list, c))) {
650  PAIR_VERIFY(c);
651  if (fr_dict_attr_common_parent(da, c->da, true)) break;
652  }
653 
654  return c;
655 }
656 
657 /** Return the number of instances of a given da in the specified list
658  *
659  * @param[in] list to search in.
660  * @param[in] da to look for in the list.
661  * @return
662  * - 0 if no instances exist.
663  * - >0 the number of instance of a given attribute.
664  */
665 unsigned int fr_pair_count_by_da(fr_pair_list_t const *list, fr_dict_attr_t const *da)
666 {
667  fr_pair_t *vp = NULL;
668  unsigned int count = 0;
669 
670  if (fr_pair_list_empty(list)) return 0;
671 
672  while ((vp = fr_pair_list_next(list, vp))) if (da == vp->da) count++;
673 
674  return count;
675 }
676 
677 /** Find the first pair with a matching da
678  *
679  * @param[in] list to search in.
680  * @param[in] prev the previous attribute in the list.
681  * @param[in] da the next da to find.
682  * @return
683  * - first matching fr_pair_t.
684  * - NULL if no fr_pair_ts match.
685  *
686  * @hidecallergraph
687  */
689 {
690  fr_pair_t *vp = UNCONST(fr_pair_t *, prev);
691 
692  if (fr_pair_list_empty(list)) return NULL;
693 
694  PAIR_LIST_VERIFY(list);
695 
696  while ((vp = fr_pair_list_next(list, vp))) if (da == vp->da) return vp;
697 
698  return NULL;
699 }
700 
701 /** Find the last pair with a matching da
702  *
703  * @param[in] list to search in.
704  * @param[in] prev the previous attribute in the list.
705  * @param[in] da the previous da to find.
706  * @return
707  * - first matching fr_pair_t.
708  * - NULL if no fr_pair_ts match.
709  *
710  * @hidecallergraph
711  */
713 {
714  fr_pair_t *vp = UNCONST(fr_pair_t *, prev);
715 
716  if (fr_pair_list_empty(list)) return NULL;
717 
718  PAIR_LIST_VERIFY(list);
719 
720  while ((vp = fr_pair_list_prev(list, vp))) if (da == vp->da) return vp;
721 
722  return NULL;
723 }
724 
725 /** Find a pair with a matching da at a given index
726  *
727  * @param[in] list to search in.
728  * @param[in] da to look for in the list.
729  * @param[in] idx Instance of the attribute to return.
730  * @return
731  * - first matching fr_pair_t.
732  * - NULL if no fr_pair_ts match.
733  *
734  * @hidecallergraph
735  */
736 fr_pair_t *fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
737 {
738  fr_pair_t *vp = NULL;
739 
740  if (fr_pair_list_empty(list)) return NULL;
741 
742  PAIR_LIST_VERIFY(list);
743 
744  while ((vp = fr_pair_list_next(list, vp))) {
745  if (da != vp->da) continue;
746 
747  if (idx == 0) return vp;
748 
749  idx--;
750  }
751  return NULL;
752 }
753 
754 /** Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree
755  *
756  * The list should be the one containing the top level attributes.
757  *
758  * @param[in] list to search in.
759  * @param[in] prev pair to start searching from.
760  * @param[in] da the next da to find.
761  * @return
762  * - first matching fr_pair_t.
763  * - NULL if no fr_pair_ts match.
764  */
766 {
767  fr_pair_t *vp;
768  fr_dict_attr_t const **find; /* DA currently being looked for */
769  fr_pair_list_t const *cur_list; /* Current list being searched */
770  fr_da_stack_t da_stack;
771 
772  if (fr_pair_list_empty(list)) return NULL;
773 
774  /*
775  * In the common case, we're looking for attributes in
776  * the root (at level 1), so we just skip to a special
777  * function for that
778  */
779  if (da->depth <= 1) return fr_pair_find_by_da(list, prev, da);
780 
781  fr_proto_da_stack_build(&da_stack, da);
782 
783  /*
784  * Find the relevant starting point for `prev`
785  */
786  if (prev) {
787  cur_list = fr_pair_parent_list(prev);
788  find = &da_stack.da[prev->da->depth - 1];
789  vp = UNCONST(fr_pair_t *, prev);
790  } else {
791  cur_list = list;
792  find = &da_stack.da[0];
793  vp = NULL;
794  }
795 
796  /*
797  * Loop over the list at each level until we find a matching da.
798  */
799  while (true) {
800  fr_pair_t *next;
801 
802  fr_assert((*find)->depth <= da->depth);
803 
804  /*
805  * Find a vp which matches a given da. If found,
806  * recurse into the child list to find the child
807  * attribute.
808  *
809  */
810  next = fr_pair_find_by_da(cur_list, vp, *find);
811  if (next) {
812  /*
813  * We've found a match for the requested
814  * da - return it.
815  */
816  if ((*find) == da) return next;
817 
818  /*
819  * Prepare to search the next level.
820  */
821  cur_list = &next->vp_group;
822  find++;
823  vp = NULL;
824  continue;
825  }
826 
827  /*
828  * We hit the end of the top-level list. Therefore we found nothing.
829  */
830  if (cur_list == list) break;
831 
832  /*
833  * We hit the end of *A* list. Go to the parent
834  * VP, and then find its list.
835  *
836  * We still then have to go to the next attribute
837  * in the parent list, as we've checked all of the
838  * children of this VP.
839  */
840  find--;
841  vp = fr_pair_list_parent(cur_list);
842  cur_list = fr_pair_parent_list(vp);
843  }
844 
845  /*
846  * Compatiblitity with flat atttrbutes
847  */
848  if (fr_pair_parent_list(prev) != list) prev = NULL;
849  return fr_pair_find_by_da(list, prev, da);
850 }
851 
852 /** Find the pair with the matching child attribute
853  *
854  * @param[in] list in which to search.
855  * @param[in] prev attribute to start search from.
856  * @param[in] parent attribute in which to lookup child.
857  * @param[in] attr id of child.
858  * @return
859  * - first matching value pair.
860  * - NULL if no pair found.
861  */
863  fr_dict_attr_t const *parent, unsigned int attr)
864 {
865  fr_dict_attr_t const *da;
866 
867  /* List head may be NULL if it contains no VPs */
868  if (fr_pair_list_empty(list)) return NULL;
869 
870  PAIR_LIST_VERIFY(list);
871 
872  da = fr_dict_attr_child_by_num(parent, attr);
873  if (!da) return NULL;
874 
875  return fr_pair_find_by_da(list, prev, da);
876 }
877 
878 /** Find the pair with the matching child attribute at a given index
879  *
880  * @param[in] list in which to search.
881  * @param[in] parent attribute in which to lookup child.
882  * @param[in] attr id of child.
883  * @param[in] idx Instance of the attribute to return.
884  * @return
885  * - first matching value pair.
886  * - NULL if no pair found.
887  */
889  fr_dict_attr_t const *parent, unsigned int attr, unsigned int idx)
890 {
891  fr_dict_attr_t const *da;
892 
893  /* List head may be NULL if it contains no VPs */
894  if (fr_pair_list_empty(list)) return NULL;
895 
896  PAIR_LIST_VERIFY(list);
897 
898  da = fr_dict_attr_child_by_num(parent, attr);
899  if (!da) return NULL;
900 
901  return fr_pair_find_by_da_idx(list, da, idx);
902 }
903 
904 /** Get the child list of a group
905  *
906  * @param[in] vp which MUST be of a type
907  * that can contain children.
908  * @return
909  * - NULL on error
910  * - pointer to head of the child list.
911  */
913 {
914  if (!fr_type_is_structural(vp->vp_type)) return NULL;
915 
916  return &vp->vp_group;
917 }
918 
919 /** Return a pointer to the parent pair list
920  *
921  */
923 {
924  FR_TLIST_HEAD(fr_pair_order_list) *parent;
925 
926  if (!vp) return NULL;
927 
928  parent = fr_pair_order_list_parent(vp);
929  if (!parent) return NULL;
930 
931  return (fr_pair_list_t *) (UNCONST(uint8_t *, parent) - offsetof(fr_pair_list_t, order));
932 }
933 
934 /** Return a pointer to the parent pair.
935  *
936  */
938 {
940 
941  if (!list) return NULL;
942 
943  if (!list->is_child) return NULL;
944 
945  return (fr_pair_t *) (UNCONST(uint8_t *, list) - offsetof(fr_pair_t, vp_group));
946 }
947 
948 /** Return a pointer to the parent pair which contains this list.
949  *
950  */
952 {
953  if (!list) return NULL;
954 
955  if (!list->is_child) return NULL;
956 
957  return (fr_pair_t *) (UNCONST(uint8_t *, list) - offsetof(fr_pair_t, vp_group));
958 }
959 
960 /** Keep attr tree and sublists synced on cursor insert
961  *
962  * @param[in] list Underlying order list from the fr_pair_list_t.
963  * @param[in] to_insert fr_pair_t being inserted.
964  * @param[in] uctx fr_pair_list_t containing the order list.
965  * @return
966  * - 0 on success.
967  */
968 static int _pair_list_dcursor_insert(fr_dlist_head_t *list, void *to_insert, UNUSED void *uctx)
969 {
970  fr_pair_t *vp = to_insert;
971  fr_tlist_head_t *tlist;
972 
973  tlist = fr_tlist_head_from_dlist(list);
974 
975  /*
976  * Mark the pair as inserted into the list.
977  */
978  fr_pair_order_list_set_head(tlist, vp);
979 
980  PAIR_VERIFY(vp);
981 
982  return 0;
983 }
984 
985 /** Keep attr tree and sublists synced on cursor removal
986  *
987  * @param[in] list Underlying order list from the fr_pair_list_t.
988  * @param[in] to_remove fr_pair_t being removed.
989  * @param[in] uctx fr_pair_list_t containing the order list.
990  * @return
991  * - 0 on success.
992  */
993 static int _pair_list_dcursor_remove(NDEBUG_UNUSED fr_dlist_head_t *list, void *to_remove, UNUSED void *uctx)
994 {
995  fr_pair_t *vp = to_remove;
997 
998 #ifndef NDEBUG
999  fr_tlist_head_t *tlist;
1000 
1001  tlist = fr_tlist_head_from_dlist(list);
1002 
1003  while (parent && (tlist != vp->order_entry.entry.list_head)) {
1004  tlist = &parent->order.head;
1006  }
1007 
1008  fr_assert(vp->order_entry.entry.list_head == tlist);
1010 #endif
1011 
1012  /*
1013  * Mark the pair as removed from the list.
1014  */
1015  fr_pair_order_list_set_head(NULL, vp);
1016 
1017  PAIR_VERIFY(vp);
1018 
1019  if (&parent->order.head.dlist_head == list) return 0;
1020 
1022  return 1;
1023 }
1024 
1025 /** Iterates over the leaves of a list
1026  *
1027  * @param[in] list to iterate over.
1028  * @param[in] vp the current CVP
1029  * @return
1030  * - NULL when done
1031  * - vp - a leaf pair
1032  */
1034 {
1035  fr_pair_t *next, *parent;
1036  fr_pair_list_t *parent_list;
1037 
1038  /*
1039  * Start: return the head of the top-level list.
1040  */
1041  if (!vp) {
1042  vp = fr_pair_list_head(list);
1043  if (!vp) goto next_parent_sibling;
1044 
1045  next_sibling:
1046  if (fr_type_is_leaf(vp->vp_type)) return vp;
1047 
1048  vp = fr_pair_list_iter_leaf(&vp->vp_group, NULL);
1049  if (vp) return vp;
1050 
1051  /*
1052  * vp is NULL, so we've processed all of its children.
1053  */
1054  }
1055 
1056  /*
1057  * Go to the next sibling in the parent list of vp.
1058  */
1059 next_parent_sibling:
1060  parent_list = fr_pair_parent_list(vp);
1061  if (!parent_list) return NULL;
1062 
1063  next = fr_pair_list_next(parent_list, vp);
1064  if (!next) {
1065  /*
1066  * We're done the top-level list.
1067  */
1068  if (parent_list == list) return NULL;
1069 
1071  fr_assert(&parent->vp_group == parent_list);
1072  vp = parent;
1073  goto next_parent_sibling;
1074  }
1075 
1076  /*
1077  * We do have a "next" attribute. Go check if we can return it.
1078  */
1079  vp = next;
1080  goto next_sibling;
1081 }
1082 
1083 /** Initialises a special dcursor with callbacks that will maintain the attr sublists correctly
1084  *
1085  * Filters can be applied later with fr_dcursor_filter_set.
1086  *
1087  * @note This is the only way to use a dcursor in non-const mode with fr_pair_list_t.
1088  *
1089  * @param[out] cursor to initialise.
1090  * @param[in] list to iterate over.
1091  * @param[in] iter Iterator to use when filtering pairs.
1092  * @param[in] uctx To pass to iterator.
1093  * @param[in] is_const whether the fr_pair_list_t is const.
1094  * @return
1095  * - NULL if src does not point to any items.
1096  * - The first pair in the list.
1097  */
1099  fr_dcursor_iter_t iter, void const *uctx,
1100  bool is_const)
1101 {
1102  return _fr_dcursor_init(cursor, fr_pair_order_list_dlist_head(&list->order),
1103  iter, NULL, uctx,
1105 }
1106 
1107 /** Initialises a special dcursor with callbacks that will maintain the attr sublists correctly
1108  *
1109  * Filters can be applied later with fr_dcursor_filter_set.
1110  *
1111  * @note This is the only way to use a dcursor in non-const mode with fr_pair_list_t.
1112  *
1113  * @param[out] cursor to initialise.
1114  * @param[in] list to iterate over.
1115  * @param[in] is_const whether the fr_pair_list_t is const.
1116  * @return
1117  * - NULL if src does not point to any items.
1118  * - The first pair in the list.
1119  */
1121  bool is_const)
1122 {
1123  return _fr_dcursor_init(cursor, fr_pair_order_list_dlist_head(&list->order),
1124  NULL, NULL, NULL,
1126 }
1127 
1128 /** Initialise a cursor that will return only attributes matching the specified #fr_dict_attr_t
1129  *
1130  * @param[in] cursor to initialise.
1131  * @param[in] list to iterate over.
1132  * @param[in] da to search for.
1133  * @param[in] is_const whether the fr_pair_list_t is const.
1134  * @return
1135  * - The first matching pair.
1136  * - NULL if no pairs match.
1137  */
1139  fr_pair_list_t const *list, fr_dict_attr_t const *da,
1140  bool is_const)
1141 {
1142  return _fr_dcursor_init(cursor, fr_pair_order_list_dlist_head(&list->order),
1143  fr_pair_iter_next_by_da, NULL, da,
1145 }
1146 
1147 /** Initialise a cursor that will return only attributes descended from the specified #fr_dict_attr_t
1148  *
1149  * @param[in] cursor to initialise.
1150  * @param[in] list to iterate over.
1151  * @param[in] da who's decentness to search for.
1152  * @param[in] is_const whether the fr_pair_list_t is const.
1153  * @return
1154  * - The first matching pair.
1155  * - NULL if no pairs match.
1156  */
1158  fr_pair_list_t const *list, fr_dict_attr_t const *da,
1159  bool is_const)
1160 {
1161  fr_pair_t *vp;
1162 
1163  fr_assert(fr_type_is_structural(da->type));
1164 
1165  /*
1166  * This function is only used by snmp.c and password.c. Once we've fully moved to
1167  * nested attributes, it should be removed.
1168  */
1169  fr_assert(da->parent->flags.is_root);
1170 
1171  vp = fr_pair_find_by_da(list, NULL, da);
1172  if (vp) {
1173  list = &vp->vp_group;
1174 
1175  return _fr_dcursor_init(cursor, fr_pair_order_list_dlist_head(&list->order),
1176  NULL, NULL, NULL,
1178  }
1179 
1180  return _fr_dcursor_init(cursor, fr_pair_order_list_dlist_head(&list->order),
1183 }
1184 
1185 /** Iterate over pairs
1186  *
1187  * @param[in] list to iterate over.
1188  * @param[in] current The fr_value_box_t cursor->current. Will be advanced and checked to
1189  * see if it matches the specified fr_dict_attr_t.
1190  * @param[in] uctx unused
1191  * @return
1192  * - Next matching fr_pair_t.
1193  * - NULL if not more matching fr_pair_ts could be found.
1194  */
1195 static void *_fr_pair_iter_next_value(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
1196 {
1197  fr_pair_t *vp;
1198 
1199  if (!current) {
1200  vp = NULL;
1201  } else {
1202  vp = (fr_pair_t *) ((uint8_t *) current - offsetof(fr_pair_t, data));
1203  PAIR_VERIFY(vp);
1204  }
1205 
1206  while ((vp = fr_dlist_next(list, vp))) {
1207  PAIR_VERIFY(vp);
1208  if (fr_type_is_leaf(vp->vp_type)) return &vp->data;
1209  }
1210 
1211  return NULL;
1212 }
1213 
1214 /*
1215  * The value dcursor just runs the iterator, and never uses the dlist. Inserts and deletes are forbidden.
1216  *
1217  * However, the underlying dcursor code needs a dlist, so we create a fake one to pass it. In debug
1218  * builds, the dcursor code will do things like try to check talloc types. So we need to pass it an
1219  * empty dlist with no talloc types.
1220  */
1222  .offset = offsetof(fr_dlist_head_t, entry),
1223  .type = NULL,
1224  .num_elements = 0,
1225  .entry = {
1226  .prev = &value_dlist.entry,
1227  .next = &value_dlist.entry,
1228  },
1229 };
1230 
1231 /** Initialises a special dcursor over a #fr_pair_list_t, but which returns #fr_value_box_t
1232  *
1233  * Filters can be applied later with fr_dcursor_filter_set.
1234  *
1235  * @note This is the only way to use a dcursor in non-const mode with fr_pair_list_t.
1236  * @note - the list cannot be modified, and structural attributes are not returned.
1237  *
1238  * @param[out] cursor to initialise.
1239  * @return
1240  * - NULL if src does not point to any items.
1241  * - The first pair in the list.
1242  */
1244 {
1245  return _fr_dcursor_init(cursor, &value_dlist,
1246  _fr_pair_iter_next_value, NULL, NULL, NULL, NULL, NULL, true);
1247 }
1248 
1249 /** Iterate over pairs
1250  *
1251  * @param[in] list to iterate over.
1252  * @param[in] current The fr_value_box_t cursor->current. Will be advanced and checked to
1253  * see if it matches the specified fr_dict_attr_t.
1254  * @param[in] uctx The parent dcursor
1255  * @return
1256  * - Next matching fr_pair_t.
1257  * - NULL if not more matching fr_pair_ts could be found.
1258  */
1259 static void *_fr_pair_iter_next_dcursor_value(UNUSED fr_dlist_head_t *list, void *current, void *uctx)
1260 {
1261  fr_pair_t *vp;
1262  fr_dcursor_t *parent = uctx;
1263 
1264  if (!current) {
1266  if (!vp) return NULL;
1267 
1268  PAIR_VERIFY(vp);
1269  return &vp->data;
1270  }
1271 
1272  while ((vp = fr_dcursor_next(parent))) {
1273  PAIR_VERIFY(vp);
1274 
1275  if (fr_type_is_leaf(vp->vp_type)) return &vp->data;
1276  }
1277 
1278  return NULL;
1279 }
1280 
1281 /** Initialises a special dcursor over another cursor which returns #fr_pair_t, but we return #fr_value_box_t
1282  *
1283  * Filters can be applied later with fr_dcursor_filter_set.
1284  *
1285  * @note - the list cannot be modified, and structural attributes are not returned.
1286  *
1287  * @param[out] cursor to initialise.
1288  * @param[in] parent to iterate over
1289  * @return
1290  * - NULL if src does not point to any items.
1291  * - The first pair in the list.
1292  */
1294 {
1295  return _fr_dcursor_init(cursor, &value_dlist,
1296  _fr_pair_iter_next_dcursor_value, NULL, parent, NULL, NULL, NULL, true);
1297 }
1298 
1299 /** Add a VP to the start of the list.
1300  *
1301  * Links an additional VP 'add' at the beginning a list.
1302  *
1303  * @param[in] list VP in linked list. Will add new VP to this list.
1304  * @param[in] to_add VP to add to list.
1305  * @return
1306  * - 0 on success.
1307  * - -1 on failure (pair already in list).
1308  */
1310 {
1311  PAIR_VERIFY(to_add);
1312 
1313 #ifdef WITH_VERIFY_PTR
1314  fr_assert(!fr_pair_order_list_in_a_list(to_add));
1315  list->verified = false;
1316 #endif
1317 
1318  if (fr_pair_order_list_in_a_list(to_add)) {
1320  return -1;
1321  }
1322 
1323  fr_pair_order_list_insert_head(&list->order, to_add);
1324 
1325  return 0;
1326 }
1327 
1328 /** Add a VP to the end of the list.
1329  *
1330  * Links an additional VP 'to_add' at the end of a list.
1331  *
1332  * @param[in] list VP in linked list. Will add new VP to this list.
1333  * @param[in] to_add VP to add to list.
1334  * @return
1335  * - 0 on success.
1336  * - -1 on failure (pair already in list).
1337  *
1338  * @hidecallergraph
1339  */
1341 {
1342  PAIR_VERIFY(to_add);
1343 
1344 #ifdef WITH_VERIFY_PTR
1345  fr_assert(!fr_pair_order_list_in_a_list(to_add));
1346  list->verified = false;
1347 #endif
1348 
1349  if (fr_pair_order_list_in_a_list(to_add)) {
1351  return -1;
1352  }
1353 
1354  fr_pair_order_list_insert_tail(&list->order, to_add);
1355 
1356  return 0;
1357 }
1358 
1359 /** Add a VP after another VP.
1360  *
1361  * @param[in] list VP in linked list. Will add new VP to this list.
1362  * @param[in] pos to insert pair after.
1363  * @param[in] to_add VP to add to list.
1364  * @return
1365  * - 0 on success.
1366  * - -1 on failure (pair already in list).
1367  */
1369 {
1370  PAIR_VERIFY(to_add);
1371 
1372 #ifdef WITH_VERIFY_PTR
1373  fr_assert(!fr_pair_order_list_in_a_list(to_add));
1374  list->verified = false;
1375 #endif
1376 
1377  if (fr_pair_order_list_in_a_list(to_add)) {
1379  return -1;
1380  }
1381 
1382  if (pos && !fr_pair_order_list_in_list(&list->order, pos)) {
1384  return -1;
1385  }
1386 
1387  fr_pair_order_list_insert_after(&list->order, pos, to_add);
1388 
1389  return 0;
1390 }
1391 
1392 /** Add a VP before another VP.
1393  *
1394  * @param[in] list VP in linked list. Will add new VP to this list.
1395  * @param[in] pos to insert pair after.
1396  * @param[in] to_add VP to add to list.
1397  * @return
1398  * - 0 on success.
1399  * - -1 on failure (pair already in list).
1400  */
1402 {
1403  PAIR_VERIFY(to_add);
1404 
1405 #ifdef WITH_VERIFY_PTR
1406  fr_assert(!fr_pair_order_list_in_a_list(to_add));
1407  fr_assert(!pos || fr_pair_order_list_in_a_list(pos));
1408  list->verified = false;
1409 #endif
1410 
1411  if (fr_pair_order_list_in_a_list(to_add)) {
1413  return -1;
1414  }
1415 
1416  if (pos && !fr_pair_order_list_in_list(&list->order, pos)) {
1418  return -1;
1419  }
1420 
1421  fr_pair_order_list_insert_before(&list->order, pos, to_add);
1422 
1423  return 0;
1424 }
1425 
1426 /** Replace a given VP
1427  *
1428  * @note Memory used by the VP being replaced will be freed.
1429  *
1430  * @param[in,out] list pair list
1431  * @param[in] to_replace pair to replace and free, on list
1432  * @param[in] vp New pair to insert.
1433  */
1435 {
1436  PAIR_VERIFY_WITH_LIST(list, to_replace);
1437  PAIR_VERIFY(vp);
1438 
1439 #ifdef WITH_VERIFY_PTR
1440  fr_assert(!fr_pair_order_list_in_a_list(vp));
1441  fr_assert(fr_pair_order_list_in_a_list(to_replace));
1442  list->verified = false;
1443 #endif
1444 
1445  fr_pair_insert_after(list, to_replace, vp);
1446  fr_pair_remove(list, to_replace);
1447  talloc_free(to_replace);
1448 }
1449 
1450 /** Alloc a new fr_pair_t (and append)
1451  *
1452  * @param[in] ctx to allocate new #fr_pair_t in.
1453  * @param[out] out Pair we allocated. May be NULL if the caller doesn't
1454  * care about manipulating the fr_pair_t.
1455  * @param[in,out] list in search and insert into.
1456  * @param[in] da of attribute to update.
1457  * @return
1458  * - 0 on success.
1459  * - -1 on failure.
1460  */
1461 int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
1462 {
1463  fr_pair_t *vp;
1464 
1465  vp = fr_pair_afrom_da(ctx, da);
1466  if (unlikely(!vp)) {
1467  if (out) *out = NULL;
1468  return -1;
1469  }
1470 
1471  fr_pair_append(list, vp);
1472  if (out) *out = vp;
1473 
1474  return 0;
1475 }
1476 
1477 /** Alloc a new fr_pair_t (and prepend)
1478  *
1479  * @param[in] ctx to allocate new #fr_pair_t in.
1480  * @param[out] out Pair we allocated. May be NULL if the caller doesn't
1481  * care about manipulating the fr_pair_t.
1482  * @param[in,out] list in search and insert into.
1483  * @param[in] da of attribute to update.
1484  * @return
1485  * - 0 on success.
1486  * - -1 on failure.
1487  */
1488 int fr_pair_prepend_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
1489 {
1490  fr_pair_t *vp;
1491 
1492  vp = fr_pair_afrom_da(ctx, da);
1493  if (unlikely(!vp)) {
1494  if (out) *out = NULL;
1495  return -1;
1496  }
1497 
1498  fr_pair_prepend(list, vp);
1499  if (out) *out = vp;
1500 
1501  return 0;
1502 }
1503 
1504 /** Alloc a new fr_pair_t, adding the parent attributes if required
1505  *
1506  * A child pair will be added to the first available matching parent
1507  * found.
1508  *
1509  * @param[in] ctx to allocate new #fr_pair_t in
1510  * @param[out] out Pair we allocated. May be NULL if the caller doesn't
1511  * care about manipulating the fr_pair_t.
1512  * @param[in] list in which to insert the pair.
1513  * @param[in] da of the attribute to create.
1514  * @return
1515  * - 0 on success.
1516  * - -1 on failure.
1517  */
1518 int fr_pair_append_by_da_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
1519 {
1520  fr_pair_t *vp = NULL;
1521  fr_da_stack_t da_stack;
1522  fr_dict_attr_t const **find;
1523  TALLOC_CTX *pair_ctx = ctx;
1524 
1525  /*
1526  * Fast path for non-nested attributes
1527  */
1528  if (da->depth <= 1) return fr_pair_append_by_da(ctx, out, list, da);
1529 
1530  fr_proto_da_stack_build(&da_stack, da);
1531  find = &da_stack.da[0];
1532 
1533  /*
1534  * Walk down the da stack looking for candidate parent
1535  * attributes and then allocating the leaf.
1536  */
1537  while (true) {
1538  fr_assert((*find)->depth <= da->depth);
1539 
1540  /*
1541  * We're not at the leaf, look for a potential parent
1542  */
1543  if ((*find) != da) vp = fr_pair_find_by_da(list, NULL, *find);
1544 
1545  /*
1546  * Nothing found, create the pair
1547  */
1548  if (!vp) {
1549  if (fr_pair_append_by_da(pair_ctx, &vp, list, *find) < 0) {
1550  if (out) *out = NULL;
1551  return -1;
1552  }
1553  }
1554 
1555  /*
1556  * We're at the leaf, return
1557  */
1558  if ((*find) == da) {
1559  if(out) *out = vp;
1560  return 0;
1561  }
1562 
1563  /*
1564  * Prepare for next level
1565  */
1566  list = &vp->vp_group;
1567  pair_ctx = vp;
1568  vp = NULL;
1569  find++;
1570  }
1571 }
1572 
1573 /** Return the first fr_pair_t matching the #fr_dict_attr_t or alloc a new fr_pair_t and its subtree (and append)
1574  *
1575  * @param[in] parent If parent->da is an ancestor of the specified
1576  * da, we continue building out the nested structure
1577  * from the parent.
1578  * If parent is NOT an ancestor, then it must be a group
1579  * attribute, and we will append the shallowest member
1580  * of the struct or TLV as a child, and build out everything
1581  * to the specified da.
1582  * @param[out] out Pair we allocated or found. May be NULL if the caller doesn't
1583  * care about manipulating the fr_pair_t.
1584  * @param[in] da of attribute to locate or alloc.
1585  * @return
1586  * - 1 if attribute already existed.
1587  * - 0 if we allocated a new attribute.
1588  * - -1 on memory allocation failure.
1589  * - -2 if the parent is not a group attribute.
1590  */
1592  fr_dict_attr_t const *da)
1593 {
1594  fr_pair_t *vp = NULL;
1595  fr_da_stack_t da_stack;
1596  fr_dict_attr_t const **find; /* ** to allow us to iterate */
1597  TALLOC_CTX *pair_ctx = parent;
1598  fr_pair_list_t *list = &parent->vp_group;
1599 
1600  /*
1601  * Fast path for non-nested attributes
1602  */
1603  if (da->depth <= 1) {
1604  vp = fr_pair_find_by_da(list, NULL, da);
1605  if (vp) {
1606  if (out) *out = vp;
1607  return 1;
1608  }
1609 
1610  return fr_pair_append_by_da(parent, out, list, da);
1611  }
1612 
1613  fr_proto_da_stack_build(&da_stack, da);
1614  /*
1615  * Is parent an ancestor of the attribute we're trying
1616  * to build? If so, we resume from the deepest pairs
1617  * already created.
1618  *
1619  * da stack excludes the root.
1620  */
1621  if ((parent->da->depth < da->depth) && (da_stack.da[parent->da->depth - 1] == parent->da)) {
1622  /*
1623  * Start our search from the parent's children
1624  */
1625  list = &parent->vp_group;
1626  find = &da_stack.da[parent->da->depth]; /* Next deepest attr than parent */
1627  /*
1628  * Disallow building one TLV tree into another
1629  */
1630  } else if (!fr_type_is_group(parent->da->type)) {
1631  fr_strerror_printf("Expected parent \"%s\" to be an ancestor of \"%s\" or a group. "
1632  "But it is not an acestor and is of type %s", parent->da->name, da->name,
1633  fr_type_to_str(parent->da->type));
1634  return -2;
1635  } else {
1636  find = &da_stack.da[0];
1637  }
1638 
1639  /*
1640  * Walk down the da stack looking for candidate parent
1641  * attributes and then allocating the leaf, and any
1642  * attributes between the leaf and parent.
1643  */
1644  while (true) {
1645  fr_assert((*find)->depth <= da->depth);
1646 
1647  vp = fr_pair_find_by_da(list, NULL, *find);
1648  /*
1649  * Nothing found at this level, create the pair
1650  */
1651  if (!vp) {
1652  if (fr_pair_append_by_da(pair_ctx, &vp, list, *find) < 0) {
1653  if (out) *out = NULL;
1654  return -1;
1655  }
1656  }
1657 
1658  /*
1659  * We're at the leaf, return
1660  */
1661  if ((*find) == da) {
1662  if (out) *out = vp;
1663  return 0;
1664  }
1665 
1666  /*
1667  * Prepare for next level
1668  */
1669  list = &vp->vp_group;
1670  pair_ctx = vp;
1671  vp = NULL;
1672  find++;
1673  }
1674 }
1675 
1676 /** Delete matching pairs from the specified list
1677  *
1678  * @param[in,out] list to search for attributes in or delete attributes from.
1679  * @param[in] da to match.
1680  * @return
1681  * - >0 the number of pairs deleted.
1682  * - 0 if no pairs were deleted.
1683  */
1685 {
1686  int cnt = 0;
1687 
1688  fr_pair_list_foreach(list, vp) {
1689  if (da == vp->da) {
1690  if (fr_pair_immutable(vp)) continue;
1691 
1692  cnt++;
1693  fr_pair_delete(list, vp);
1694  }
1695  }
1696 
1697  return cnt;
1698 }
1699 
1700 /** Delete matching pairs from the specified list, and prune any empty branches
1701  *
1702  * @param[in,out] list to search for attributes in or delete attributes from.
1703  * @param[in] da to match.
1704  * @return
1705  * - >0 the number of pairs deleted.
1706  * - 0 if no pairs were deleted.
1707  */
1709 {
1710  int cnt = 0;
1711  fr_pair_t *vp;
1712  fr_dict_attr_t const **find; /* DA currently being looked for */
1713  fr_pair_list_t *cur_list; /* Current list being searched */
1714  fr_da_stack_t da_stack;
1715 
1716  /*
1717  * Fast path for non-nested attributes
1718  */
1719  if (da->depth <= 1) return fr_pair_delete_by_da(list, da);
1720 
1721  /*
1722  * No pairs, fast path!
1723  */
1724  if (fr_pair_list_empty(list)) return 0;
1725 
1726  /*
1727  * Similar to fr_pair_find_by_da_nested()
1728  */
1729  fr_proto_da_stack_build(&da_stack, da);
1730  cur_list = list;
1731  find = &da_stack.da[0];
1732  vp = NULL;
1733 
1734  /*
1735  * Loop over the list at each level until we find a matching da.
1736  */
1737  while (true) {
1738  fr_pair_t *next;
1739 
1740  fr_assert((*find)->depth <= da->depth);
1741 
1742  /*
1743  * Find a vp which matches a given da. If found,
1744  * recurse into the child list to find the child
1745  * attribute.
1746  *
1747  */
1748  next = fr_pair_find_by_da(cur_list, vp, *find);
1749  if (next) {
1750  /*
1751  * We've found a match for the requested
1752  * da - delete it
1753  */
1754  if ((*find) == da) {
1755  do {
1756  fr_pair_delete(cur_list, next);
1757  cnt++;
1758  } while ((next = fr_pair_find_by_da(cur_list, vp, *find)) != NULL);
1759 
1760  return cnt;
1761  }
1762 
1763  /*
1764  * Prepare to search the next level.
1765  */
1766  cur_list = &next->vp_group;
1767  find++;
1768  vp = NULL;
1769  continue;
1770  }
1771 
1772  /*
1773  * We hit the end of the top-level list. Therefore we found nothing.
1774  */
1775  if (cur_list == list) break;
1776 
1777  /*
1778  * We hit the end of *A* list. Go to the parent
1779  * VP, and then find its list.
1780  *
1781  * We still then have to go to the next attribute
1782  * in the parent list, as we've checked all of the
1783  * children of this VP.
1784  */
1785  find--;
1786  vp = fr_pair_list_parent(cur_list);
1787  cur_list = fr_pair_parent_list(vp);
1788  }
1789 
1790  return fr_pair_delete_by_da(list, da);
1791 }
1792 
1793 /** Delete matching pairs from the specified list
1794  *
1795  * @param[in] list to delete attributes from.
1796  * @param[in] parent to match.
1797  * @param[in] attr to match.
1798  * @return
1799  * - >0 the number of pairs deleted.
1800  * - 0 if no pairs were delete.
1801  * - -1 if we couldn't resolve the attribute number.
1802  */
1804 {
1805  fr_dict_attr_t const *da;
1806 
1807  da = fr_dict_attr_child_by_num(parent, attr);
1808  if (!da) return -1;
1809 
1810  return fr_pair_delete_by_da(list, da);
1811 }
1812 
1813 /** Remove fr_pair_t from a list and free
1814  *
1815  * @param[in] list of value pairs to remove VP from.
1816  * @param[in] vp to remove
1817  * @return previous item in the list to the one being removed.
1818  */
1820 {
1821  fr_pair_t *prev;
1822 
1823  prev = fr_pair_remove(list, vp);
1824  talloc_free(vp);
1825 
1826  return prev;
1827 }
1828 
1829 /** Order attributes by their da, and tag
1830  *
1831  * Useful where attributes need to be aggregated, but not necessarily
1832  * ordered by attribute number.
1833  *
1834  * @param[in] a first dict_attr_t.
1835  * @param[in] b second dict_attr_t.
1836  * @return
1837  * - +1 if a > b
1838  * - 0 if a == b
1839  * - -1 if a < b
1840  */
1841 int8_t fr_pair_cmp_by_da(void const *a, void const *b)
1842 {
1843  fr_pair_t const *my_a = a;
1844  fr_pair_t const *my_b = b;
1845 
1846  PAIR_VERIFY(my_a);
1847  PAIR_VERIFY(my_b);
1848 
1849  return CMP(my_a->da, my_b->da);
1850 }
1851 
1852 /** Order attributes by their attribute number, and tag
1853  *
1854  * @param[in] a first dict_attr_t.
1855  * @param[in] b second dict_attr_t.
1856  * @return
1857  * - +1 if a > b
1858  * - 0 if a == b
1859  * - -1 if a < b
1860  */
1861 static inline int8_t pair_cmp_by_num(void const *a, void const *b)
1862 {
1863  int8_t rcode;
1864  unsigned int i, min;
1865  fr_pair_t const *my_a = a;
1866  fr_pair_t const *my_b = b;
1867  fr_da_stack_t da_stack_a, da_stack_b;
1868 
1869  PAIR_VERIFY(my_a);
1870  PAIR_VERIFY(my_b);
1871 
1872  fr_proto_da_stack_build(&da_stack_a, my_a->da);
1873  fr_proto_da_stack_build(&da_stack_b, my_b->da);
1874 
1875  if (da_stack_a.depth <= da_stack_b.depth) {
1876  min = da_stack_a.depth;
1877  } else {
1878  min = da_stack_b.depth;
1879  }
1880 
1881  for (i = 0; i < min; i++) {
1882  rcode = CMP(da_stack_a.da[i]->attr, da_stack_b.da[i]->attr);
1883  if (rcode != 0) return rcode;
1884  }
1885 
1886  /*
1887  * Sort attributes of similar depth together.
1888  *
1889  * What we really want to do is to sort by entire parent da_stack.
1890  */
1891  rcode = CMP(my_a->da->depth, my_b->da->depth);
1892  if (rcode != 0) return rcode;
1893 
1894  /*
1895  * Attributes of the same depth get sorted by their parents.
1896  */
1897  rcode = CMP(my_a->da->parent->attr, my_b->da->parent->attr);
1898  if (rcode != 0) return rcode;
1899 
1900  /*
1901  * If the attributes have the same parent, they get sorted by number.
1902  */
1903  return CMP(my_a->da->attr, my_b->da->attr);
1904 }
1905 
1906 /** Order attributes by their parent(s), attribute number, and tag
1907  *
1908  * Useful for some protocols where attributes of the same number should by aggregated
1909  * within a packet or container TLV.
1910  *
1911  * @param[in] a first dict_attr_t.
1912  * @param[in] b second dict_attr_t.
1913  * @return
1914  * - +1 if a > b
1915  * - 0 if a == b
1916  * - -1 if a < b
1917  */
1918 int8_t fr_pair_cmp_by_parent_num(void const *a, void const *b)
1919 {
1920  fr_pair_t const *vp_a = a;
1921  fr_pair_t const *vp_b = b;
1922  fr_dict_attr_t const *da_a = vp_a->da;
1923  fr_dict_attr_t const *da_b = vp_b->da;
1924  fr_da_stack_t da_stack_a;
1925  fr_da_stack_t da_stack_b;
1926  int8_t cmp;
1927  int i;
1928 
1929  /*
1930  * Fast path (assuming attributes
1931  * are in the same dictionary).
1932  */
1933  if ((da_a->parent->flags.is_root) && (da_b->parent->flags.is_root)) return pair_cmp_by_num(vp_a, vp_b);
1934 
1935  fr_proto_da_stack_build(&da_stack_a, da_a);
1936  fr_proto_da_stack_build(&da_stack_b, da_b);
1937 
1938  for (i = 0; (da_a = da_stack_a.da[i]) && (da_b = da_stack_b.da[i]); i++) {
1939  cmp = CMP(da_a->attr, da_b->attr);
1940  if (cmp != 0) return cmp;
1941  }
1942 
1943  /*
1944  * If a has a shallower attribute
1945  * hierarchy than b, it should come
1946  * before b.
1947  */
1948  return (da_a && !da_b) - (!da_a && da_b);
1949 }
1950 
1951 /** Compare two pairs, using the operator from "a"
1952  *
1953  * i.e. given two attributes, it does:
1954  *
1955  * (b->data) (a->operator) (a->data)
1956  *
1957  * e.g. "foo" != "bar"
1958  *
1959  * @param[in] a the head attribute
1960  * @param[in] b the second attribute
1961  * @return
1962  * - 1 if true.
1963  * - 0 if false.
1964  * - -1 on failure.
1965  */
1966 int fr_pair_cmp(fr_pair_t const *a, fr_pair_t const *b)
1967 {
1968  if (!a) return -1;
1969 
1970  PAIR_VERIFY(a);
1971  if (b) PAIR_VERIFY(b);
1972 
1973  switch (a->op) {
1974  case T_OP_CMP_TRUE:
1975  return (b != NULL);
1976 
1977  case T_OP_CMP_FALSE:
1978  return (b == NULL);
1979 
1980  /*
1981  * a is a regex, compile it, print b to a string,
1982  * and then do string comparisons.
1983  */
1984  case T_OP_REG_EQ:
1985  case T_OP_REG_NE:
1986 #ifndef HAVE_REGEX
1987  return -1;
1988 #else
1989  if (!b) return false;
1990 
1991  {
1992  ssize_t slen;
1993  regex_t *preg;
1994  char *value;
1995 
1996  if (!fr_cond_assert(a->vp_type == FR_TYPE_STRING)) return -1;
1997 
1998  slen = regex_compile(NULL, &preg, a->vp_strvalue, talloc_array_length(a->vp_strvalue) - 1,
1999  NULL, false, true);
2000  if (slen <= 0) {
2001  fr_strerror_printf_push("Error at offset %zu compiling regex for %s", -slen,
2002  a->da->name);
2003  return -1;
2004  }
2005  fr_pair_aprint(NULL, &value, NULL, b);
2006  if (!value) {
2007  talloc_free(preg);
2008  return -1;
2009  }
2010 
2011  /*
2012  * Don't care about substring matches, oh well...
2013  */
2014  slen = regex_exec(preg, value, talloc_array_length(value) - 1, NULL);
2015  talloc_free(preg);
2016  talloc_free(value);
2017 
2018  if (slen < 0) return -1;
2019  if (a->op == T_OP_REG_EQ) return (int)slen;
2020  return !slen;
2021  }
2022 #endif
2023 
2024  default: /* we're OK */
2025  if (!b) return false;
2026  break;
2027  }
2028 
2029  return fr_pair_cmp_op(a->op, b, a);
2030 }
2031 
2032 /** Determine equality of two lists
2033  *
2034  * This is useful for comparing lists of attributes inserted into a binary tree.
2035  *
2036  * @param a head list of #fr_pair_t.
2037  * @param b second list of #fr_pair_t.
2038  * @return
2039  * - -1 if a < b.
2040  * - 0 if the two lists are equal.
2041  * - 1 if a > b.
2042  * - -2 on error.
2043  */
2045 {
2046  fr_pair_t *a_p, *b_p;
2047 
2048  for (a_p = fr_pair_list_head(a), b_p = fr_pair_list_head(b);
2049  a_p && b_p;
2050  a_p = fr_pair_list_next(a, a_p), b_p = fr_pair_list_next(b, b_p)) {
2051  int ret;
2052 
2053  /* Same VP, no point doing expensive checks */
2054  if (a_p == b_p) continue;
2055 
2056  ret = (a_p->da < b_p->da) - (a_p->da > b_p->da);
2057  if (ret != 0) return ret;
2058 
2059  switch (a_p->vp_type) {
2060  case FR_TYPE_STRUCTURAL:
2061  ret = fr_pair_list_cmp(&a_p->vp_group, &b_p->vp_group);
2062  if (ret != 0) return ret;
2063  break;
2064 
2065  default:
2066  ret = fr_value_box_cmp(&a_p->data, &b_p->data);
2067  if (ret != 0) {
2068  (void)fr_cond_assert(ret >= -1); /* Comparison error */
2069  return ret;
2070  }
2071  }
2072 
2073  }
2074 
2075  if (!a_p && !b_p) return 0;
2076  if (!a_p) return -1;
2077 
2078  /* if(!b_p) */
2079  return 1;
2080 }
2081 
2082 /** Write an error to the library errorbuff detailing the mismatch
2083  *
2084  * Retrieve output with fr_strerror();
2085  *
2086  * @todo add thread specific talloc contexts.
2087  *
2088  * @param failed pair of attributes which didn't match.
2089  */
2090 void fr_pair_validate_debug(fr_pair_t const *failed[2])
2091 {
2092  fr_pair_t const *filter = failed[0];
2093  fr_pair_t const *list = failed[1];
2094 
2095  fr_strerror_clear(); /* Clear any existing messages */
2096 
2097  if (!list) {
2098  if (!filter) {
2099  (void) fr_cond_assert(filter != NULL);
2100  return;
2101  }
2102  fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
2103  return;
2104  }
2105 
2106  if (!filter || (filter->da != list->da)) {
2107  fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
2108  return;
2109  }
2110 
2111  fr_strerror_printf("Attribute value: %pP didn't match filter: %pP", list, filter);
2112 
2113  return;
2114 }
2115 
2116 /** Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check
2117  *
2118  * @note will sort both filter and list in place.
2119  *
2120  * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
2121  * May be NULL.
2122  * @param filter attributes to check list against.
2123  * @param list attributes, probably a request or reply
2124  */
2125 bool fr_pair_validate(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
2126 {
2127  fr_pair_t *check, *match;
2128 
2129  if (fr_pair_list_empty(filter) && fr_pair_list_empty(list)) return true;
2130 
2131  /*
2132  * This allows us to verify the sets of validate and reply are equal
2133  * i.e. we have a validate rule which matches every reply attribute.
2134  *
2135  * @todo this should be removed one we have sets and lists
2136  */
2139 
2140  check = fr_pair_list_head(filter);
2141  match = fr_pair_list_head(list);
2142  while (match || check) {
2143  /*
2144  * Lists are of different lengths
2145  */
2146  if (!match || !check) goto mismatch;
2147 
2148  /*
2149  * The lists are sorted, so if the head
2150  * attributes aren't of the same type, then we're
2151  * done.
2152  */
2153  if (!ATTRIBUTE_EQ(check, match)) goto mismatch;
2154 
2155  /*
2156  * They're of the same type, but don't have the
2157  * same values. This is a problem.
2158  *
2159  * Note that the RFCs say that for attributes of
2160  * the same type, order is important.
2161  */
2162  switch (check->vp_type) {
2163  case FR_TYPE_STRUCTURAL:
2164  /*
2165  * Return from here on failure, so that the nested mismatch
2166  * information is preserved.
2167  */
2168  if (!fr_pair_validate(failed, &check->vp_group, &match->vp_group)) return false;
2169  break;
2170 
2171  default:
2172  /*
2173  * This attribute passed the filter
2174  */
2175  if (!fr_pair_cmp(check, match)) goto mismatch;
2176  break;
2177  }
2178 
2179  check = fr_pair_list_next(filter, check);
2180  match = fr_pair_list_next(list, match);
2181  }
2182 
2183  return true;
2184 
2185 mismatch:
2186  if (failed) {
2187  failed[0] = check;
2188  failed[1] = match;
2189  }
2190  return false;
2191 }
2192 
2193 /** Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check
2194  *
2195  * @note will sort both filter and list in place.
2196  *
2197  * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
2198  * May be NULL.
2199  * @param filter attributes to check list against.
2200  * @param list attributes, probably a request or reply
2201  */
2202 bool fr_pair_validate_relaxed(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
2203 {
2204  fr_pair_t *last_check = NULL, *match = NULL;
2205 
2206  if (fr_pair_list_empty(filter) && fr_pair_list_empty(list)) return true;
2207 
2208  /*
2209  * This allows us to verify the sets of validate and reply are equal
2210  * i.e. we have a validate rule which matches every reply attribute.
2211  *
2212  * @todo this should be removed one we have sets and lists
2213  */
2216 
2217  fr_pair_list_foreach(filter, check) {
2218  /*
2219  * Were processing check attributes of a new type.
2220  */
2221  if (!ATTRIBUTE_EQ(last_check, check)) {
2222  /*
2223  * Record the start of the matching attributes in the pair list
2224  * For every other operator we require the match to be present
2225  */
2226  while ((match = fr_pair_list_next(list, match))) {
2227  if (fr_pair_matches_da(match, check->da)) break;
2228  }
2229  if (!match) {
2230  if (check->op == T_OP_CMP_FALSE) continue;
2231  goto mismatch;
2232  }
2233 
2234  last_check = check;
2235  } else {
2236  match = fr_pair_list_head(list);
2237  }
2238 
2239  /*
2240  * Now iterate over all attributes of the same type.
2241  */
2242  for (;
2243  ATTRIBUTE_EQ(match, check);
2244  match = fr_pair_list_next(list, match)) {
2245  switch (check->vp_type) {
2246  case FR_TYPE_STRUCTURAL:
2247  if (!fr_pair_validate_relaxed(failed, &check->vp_group, &match->vp_group)) goto mismatch;
2248  break;
2249 
2250  default:
2251  /*
2252  * This attribute passed the filter
2253  */
2254  if (!fr_pair_cmp(check, match)) {
2255  mismatch:
2256  if (failed) {
2257  failed[0] = check;
2258  failed[1] = match;
2259  }
2260  return false;
2261  }
2262  break;
2263  }
2264  }
2265  }
2266 
2267  return true;
2268 }
2269 
2270 /**
2271  *
2272  * @param[in] vp the pair to check
2273  * @return
2274  * - true the pair is immutable, or has an immutable child
2275  * - false the pair is not immutable, or has no immutable children.
2276  */
2278 {
2279  if (fr_type_is_leaf(vp->vp_type)) return vp->vp_immutable;
2280 
2281  fr_pair_list_foreach(&vp->vp_group, child) {
2282  if (fr_type_is_leaf(child->vp_type)) {
2283  if (child->vp_immutable) return true;
2284 
2285  continue;
2286  }
2287 
2288  if (fr_pair_immutable(child)) return true;
2289  }
2290 
2291  return false;
2292 }
2293 
2294 /** Steal a list of pairs to a new context
2295  *
2296  */
2297 void fr_pair_list_steal(TALLOC_CTX *ctx, fr_pair_list_t *list)
2298 {
2299  fr_pair_list_foreach(list, vp) {
2300  (void) fr_pair_steal(ctx, vp);
2301  }
2302 }
2303 
2304 /** Duplicate a list of pairs
2305  *
2306  * Copy all pairs from 'from' regardless of tag, attribute or vendor.
2307  *
2308  * @param[in] ctx for new #fr_pair_t (s) to be allocated in.
2309  * @param[in] to where to copy attributes to.
2310  * @param[in] from whence to copy #fr_pair_t (s).
2311  * @return
2312  * - >0 the number of attributes copied.
2313  * - 0 if no attributes copied.
2314  * - -1 on error.
2315  */
2316 int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
2317 {
2318  fr_pair_t *new_vp, *first_added = NULL;
2319  int cnt = 0;
2320 
2321  fr_pair_list_foreach(from, vp) {
2322  cnt++;
2323  PAIR_VERIFY_WITH_LIST(from, vp);
2324 
2325  new_vp = fr_pair_copy(ctx, vp);
2326  if (!new_vp) {
2327  fr_pair_order_list_talloc_free_to_tail(&to->order, first_added);
2328  return -1;
2329  }
2330 
2331  if (!first_added) first_added = new_vp;
2332  fr_pair_append(to, new_vp);
2333  }
2334 
2335  return cnt;
2336 }
2337 
2338 
2339 /** Copy the contents of a pair list to a set of value-boxes
2340  *
2341  * This function should be removed when the xlats use dcursors
2342  * of copying all of the boxes.
2343  *
2344  * @param[in] dst where boxes will be created
2345  * @param[in] from whence to copy #fr_pair_t (s).
2346  * @return
2347  * - >0 the number of boxes copied.
2348  * - 0 if no boxes copied.
2349  * - -1 on error.
2350  */
2352 {
2353  int cnt = 0;
2354  fr_value_box_t *value, *first_added = NULL;
2355 
2356  fr_assert(dst->type == FR_TYPE_GROUP);
2357 
2358  fr_pair_list_foreach(from, vp) {
2359  cnt++;
2360  PAIR_VERIFY_WITH_LIST(from, vp);
2361 
2362  if (fr_type_is_structural(vp->vp_type)) {
2363  value = fr_value_box_alloc(dst, FR_TYPE_GROUP, NULL);
2364  if (!value) goto fail;
2365 
2366  if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
2367  talloc_free(value);
2368  goto fail;
2369  }
2370 
2371  } else {
2372  value = fr_value_box_alloc(dst, vp->vp_type, vp->da);
2373  if (!value) {
2374  fail:
2375  fr_value_box_list_talloc_free_to_tail(&dst->vb_group, first_added);
2376  return -1;
2377  }
2378  fr_value_box_copy(value, value, &vp->data);
2379  }
2380 
2381  if (!first_added) first_added = value;
2382  fr_value_box_list_insert_tail(&dst->vb_group, value);
2383  }
2384 
2385  return cnt;
2386 }
2387 
2388 /** Duplicate pairs in a list matching the specified da
2389  *
2390  * Copy all pairs from 'from' matching the specified da.
2391  *
2392  * @param[in] ctx for new #fr_pair_t (s) to be allocated in.
2393  * @param[in] to where to copy attributes to.
2394  * @param[in] from whence to copy #fr_pair_t (s).
2395  * @param[in] da to match.
2396  * @param[in] count How many instances to copy.
2397  * Use 0 for all attributes.
2398  * @return
2399  * - >0 the number of attributes copied.
2400  * - 0 if no attributes copied.
2401  * - -1 on error.
2402  */
2403 int fr_pair_list_copy_by_da(TALLOC_CTX *ctx, fr_pair_list_t *to,
2404  fr_pair_list_t const *from, fr_dict_attr_t const *da, unsigned int count)
2405 {
2406  fr_pair_t *vp, *new_vp, *first_added = NULL;
2407  unsigned int cnt = 0;
2408 
2409  if (count == 0) count = UINT_MAX;
2410 
2411  if (unlikely(!da)) {
2412  fr_strerror_printf("No search attribute provided");
2413  return -1;
2414  }
2415 
2416  for (vp = fr_pair_list_head(from);
2417  vp && (cnt < count);
2418  vp = fr_pair_list_next(from, vp)) {
2419  PAIR_VERIFY_WITH_LIST(from, vp);
2420 
2421  if (!fr_pair_matches_da(vp, da)) continue;
2422 
2423  cnt++;
2424  new_vp = fr_pair_copy(ctx, vp);
2425  if (!new_vp) {
2426  fr_pair_order_list_talloc_free_to_tail(&to->order, first_added);
2427  return -1;
2428  }
2429 
2430  if (!first_added) first_added = new_vp;
2431  fr_pair_append(to, new_vp);
2432  }
2433 
2434  return cnt;
2435 }
2436 
2437 /** Duplicate pairs in a list where the da is a descendant of parent_da
2438  *
2439  * Copy all pairs from 'from' which are descendants of the specified 'parent_da'.
2440  * This is particularly useful for copying attributes of a particular vendor, where the vendor
2441  * da is passed as parent_da.
2442  *
2443  * @param[in] ctx for new #fr_pair_t (s) to be allocated in.
2444  * @param[in] to where to copy attributes to.
2445  * @param[in] from whence to copy #fr_pair_t (s).
2446  * @param[in] parent_da to match.
2447  * @return
2448  * - >0 one or more attributes were copied
2449  * - 0 if no attributes copied.
2450  * - -1 on error.
2451  */
2453  fr_pair_list_t const *from, fr_dict_attr_t const *parent_da)
2454 {
2455  fr_pair_t *tlv;
2456  bool found = false;
2457 
2458  if (!fr_type_is_structural(parent_da->type)) return -1;
2459 
2460  /*
2461  * Allow for nested attributes.
2462  */
2463  tlv = fr_pair_find_by_da(from, NULL, parent_da);
2464  if (tlv) {
2465  fr_pair_t *vp;
2466 
2467  vp = fr_pair_copy(ctx, tlv);
2468  if (!vp) return -1;
2469 
2470  fr_pair_append(to, vp);
2471 
2472  return 1;
2473  }
2474 
2475  fr_pair_list_foreach(from, vp) {
2476  fr_pair_t *new_vp;
2477 
2478  if (!fr_dict_attr_common_parent(parent_da, vp->da, true)) continue;
2479 
2480  new_vp = fr_pair_copy(ctx, vp);
2481  if (unlikely(!new_vp)) return -1;
2482 
2483  fr_pair_append(to, new_vp);
2484  found = true;
2485  }
2486 
2487  return found;
2488 }
2489 
2490 /** Duplicate a list of pairs starting at a particular item
2491  *
2492  * Copy all pairs from 'from' regardless of tag, attribute or vendor, starting at 'item'.
2493  *
2494  * @param[in] ctx for new #fr_pair_t (s) to be allocated in.
2495  * @param[in] to where to copy attributes to.
2496  * @param[in] from whence to copy #fr_pair_t (s).
2497  * @param[in] start first pair to start copying from.
2498  * @param[in] count How many instances to copy.
2499  * Use 0 for all attributes.
2500  * @return
2501  * - >0 the number of attributes copied.
2502  * - 0 if no attributes copied.
2503  * - -1 on error.
2504  */
2505 int fr_pair_sublist_copy(TALLOC_CTX *ctx, fr_pair_list_t *to,
2506  fr_pair_list_t const *from, fr_pair_t const *start, unsigned int count)
2507 {
2508  fr_pair_t const *vp;
2509  fr_pair_t *new_vp;
2510  unsigned int cnt = 0;
2511 
2512  if (!start) start = fr_pair_list_head(from);
2513 
2514  for (vp = start;
2515  vp && ((count == 0) || (cnt < count));
2516  vp = fr_pair_list_next(from, vp), cnt++) {
2517  PAIR_VERIFY_WITH_LIST(from, vp);
2518  new_vp = fr_pair_copy(ctx, vp);
2519  if (unlikely(!new_vp)) return -1;
2520  fr_pair_append(to, new_vp);
2521  }
2522 
2523  return cnt;
2524 }
2525 
2526 /** Free/zero out value (or children) of a given VP
2527  *
2528  * @param[in] vp to clear value from.
2529  */
2531 {
2532  fr_pair_t *child;
2533 
2534  switch (vp->vp_type) {
2535  default:
2536  fr_value_box_clear_value(&vp->data);
2537  break;
2538 
2539  case FR_TYPE_STRUCTURAL:
2540  if (!fr_pair_list_empty(&vp->vp_group)) return;
2541 
2542  while ((child = fr_pair_order_list_pop_tail(&vp->vp_group.order))) {
2543  fr_pair_value_clear(child);
2544  talloc_free(child);
2545  }
2546  break;
2547  }
2548 }
2549 
2550 /** Copy the value from one pair to another
2551  *
2552  * @param[out] dst where to copy the value to.
2553  * will clear assigned value.
2554  * @param[in] src where to copy the value from
2555  * Must have an assigned value.
2556  * @return
2557  * - 0 on success.
2558  * - -1 on failure.
2559  */
2561 {
2562  if (!fr_cond_assert(src->data.type != FR_TYPE_NULL)) return -1;
2563 
2564  if (dst->data.type != FR_TYPE_NULL) fr_value_box_clear_value(&dst->data);
2565  fr_value_box_copy(dst, &dst->data, &src->data);
2566 
2567  /*
2568  * If either source or destination is secret, then this value is secret.
2569  */
2570  dst->data.secret |= src->da->flags.secret | dst->da->flags.secret;
2571  return 0;
2572 }
2573 
2574 /** Convert string value to native attribute value
2575  *
2576  * @param[in] vp to assign value to.
2577  * @param[in] value string to convert. Binary safe for variable
2578  * length values if len is provided.
2579  * @param[in] inlen The length of the input string.
2580  * @param[in] uerules used to perform unescaping.
2581  * @param[in] tainted Whether the value came from a trusted source.
2582  * @return
2583  * - 0 on success.
2584  * - -1 on failure.
2585  */
2586 int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen,
2587  fr_sbuff_unescape_rules_t const *uerules, bool tainted)
2588 {
2589  /*
2590  * This is not yet supported because the rest of the APIs
2591  * to parse pair names, etc. don't yet enforce "inlen".
2592  * This is likely not a problem in practice, but we
2593  * haven't yet audited the uses of this function for that
2594  * behavior.
2595  */
2596  switch (vp->vp_type) {
2597  case FR_TYPE_STRUCTURAL:
2598  fr_strerror_printf("Attributes of type '%s' are not yet supported",
2599  fr_type_to_str(vp->vp_type));
2600  return -1;
2601 
2602  default:
2603  break;
2604  }
2605 
2606  /*
2607  * We presume that the input data is from a double quoted
2608  * string, and needs unescaping
2609  */
2610  if (fr_value_box_from_str(vp, &vp->data, vp->vp_type, vp->da,
2611  value, inlen,
2612  uerules,
2613  tainted) < 0) return -1;
2614 
2615  PAIR_VERIFY(vp);
2616 
2617  return 0;
2618 }
2619 
2620 /** Copy data into an "string" data type.
2621  *
2622  * @note vp->da must be of type FR_TYPE_STRING.
2623  *
2624  * @param[in,out] vp to update
2625  * @param[in] src data to copy
2626  * @param[in] tainted Whether the value came from a trusted source.
2627  * @return
2628  * - 0 on success.
2629  * - -1 on failure.
2630  */
2631 int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
2632 {
2633  int ret;
2634 
2635  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2636 
2637  fr_value_box_clear(&vp->data); /* Free any existing buffers */
2638  ret = fr_value_box_strdup(vp, &vp->data, vp->da, src, tainted);
2639  if (ret == 0) {
2640  PAIR_VERIFY(vp);
2641  }
2642 
2643  return ret;
2644 }
2645 
2646 /** Assign a buffer containing a nul terminated string to a vp, but don't copy it
2647  *
2648  * @param[in] vp to assign string to.
2649  * @param[in] src to copy string from.
2650  * @param[in] tainted Whether the value came from a trusted source.
2651  * @return
2652  * - 0 on success.
2653  * - -1 on failure.
2654  */
2655 int fr_pair_value_strdup_shallow(fr_pair_t *vp, char const *src, bool tainted)
2656 {
2657  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2658 
2659  fr_value_box_clear(&vp->data);
2660  fr_value_box_strdup_shallow(&vp->data, vp->da, src, tainted);
2661 
2662  PAIR_VERIFY(vp);
2663 
2664  return 0;
2665 }
2666 
2667 /** Trim the length of the string buffer to match the length of the C string
2668  *
2669  * @param[in,out] vp to trim.
2670  * @return
2671  * - 0 on success.
2672  * - -1 on failure.
2673  */
2675 {
2676  int ret;
2677 
2678  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2679 
2680  ret = fr_value_box_strtrim(vp, &vp->data);
2681  if (ret == 0) {
2682  PAIR_VERIFY(vp);
2683  }
2684 
2685  return ret;
2686 }
2687 
2688 /** Print data into an "string" data type.
2689  *
2690  * @note vp->da must be of type FR_TYPE_STRING.
2691  *
2692  * @param[in,out] vp to update
2693  * @param[in] fmt the format string
2694  */
2695 int fr_pair_value_aprintf(fr_pair_t *vp, char const *fmt, ...)
2696 {
2697  int ret;
2698  va_list ap;
2699 
2700  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2701 
2702  fr_value_box_clear(&vp->data);
2703  va_start(ap, fmt);
2704  ret = fr_value_box_vasprintf(vp, &vp->data, vp->da, false, fmt, ap);
2705  va_end(ap);
2706 
2707  if (ret == 0) {
2708  PAIR_VERIFY(vp);
2709  }
2710 
2711  return ret;
2712 }
2713 
2714 /** Pre-allocate a memory buffer for a "string" type value pair
2715  *
2716  * @note Will clear existing values (including buffers).
2717  *
2718  * @param[in,out] vp to update
2719  * @param[out] out If non-null will be filled with a pointer to the
2720  * new buffer.
2721  * @param[in] size of the data.
2722  * @param[in] tainted Whether the value came from a trusted source.
2723  * @return
2724  * - 0 on success.
2725  * - -1 on failure.
2726  */
2727 int fr_pair_value_bstr_alloc(fr_pair_t *vp, char **out, size_t size, bool tainted)
2728 {
2729  int ret;
2730 
2731  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2732 
2733  fr_value_box_clear(&vp->data); /* Free any existing buffers */
2734  ret = fr_value_box_bstr_alloc(vp, out, &vp->data, vp->da, size, tainted);
2735  if (ret == 0) {
2736  PAIR_VERIFY(vp);
2737  }
2738 
2739  return ret;
2740 }
2741 
2742 /** Change the length of a buffer for a "string" type value pair
2743  *
2744  * @param[in,out] vp to update
2745  * @param[out] out If non-null will be filled with a pointer to the
2746  * new buffer.
2747  * @param[in] size of the data.
2748  * @return
2749  * - 0 on success.
2750  * - -1 on failure.
2751  */
2752 int fr_pair_value_bstr_realloc(fr_pair_t *vp, char **out, size_t size)
2753 {
2754  int ret;
2755 
2756  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2757 
2758  ret = fr_value_box_bstr_realloc(vp, out, &vp->data, size);
2759  if (ret == 0) {
2760  PAIR_VERIFY(vp);
2761  }
2762 
2763  return ret;
2764 }
2765 
2766 /** Copy data into a "string" type value pair
2767  *
2768  * @note unlike the original strncpy, this function does not stop
2769  * if it finds \0 bytes embedded in the string.
2770  *
2771  * @note vp->da must be of type FR_TYPE_STRING.
2772  *
2773  * @param[in,out] vp to update.
2774  * @param[in] src data to copy.
2775  * @param[in] len of data to copy.
2776  * @param[in] tainted Whether the value came from a trusted source.
2777  * @return
2778  * - 0 on success.
2779  * - -1 on failure.
2780  */
2781 int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
2782 {
2783  int ret;
2784 
2785  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2786 
2787  fr_value_box_clear(&vp->data);
2788  ret = fr_value_box_bstrndup(vp, &vp->data, vp->da, src, len, tainted);
2789  if (ret == 0) {
2790  PAIR_VERIFY(vp);
2791  }
2792 
2793  return ret;
2794 }
2795 
2796 /** Copy a nul terminated talloced buffer a "string" type value pair
2797  *
2798  * The buffer must be \0 terminated, or an error will be returned.
2799  *
2800  * @param[in,out] vp to update.
2801  * @param[in] src a talloced nul terminated buffer.
2802  * @param[in] tainted Whether the value came from a trusted source.
2803  * @return
2804  * - 0 on success.
2805  * - -1 on failure.
2806  */
2807 int fr_pair_value_bstrdup_buffer(fr_pair_t *vp, char const *src, bool tainted)
2808 {
2809  int ret;
2810 
2811  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2812 
2813  fr_value_box_clear(&vp->data);
2814  ret = fr_value_box_bstrdup_buffer(vp, &vp->data, vp->da, src, tainted);
2815  if (ret == 0) {
2816  PAIR_VERIFY(vp);
2817  }
2818 
2819  return ret;
2820 }
2821 
2822 /** Assign a string to a "string" type value pair
2823  *
2824  * @param[in] vp to assign new buffer to.
2825  * @param[in] src a string.
2826  * @param[in] len of src.
2827  * @param[in] tainted Whether the value came from a trusted source.
2828  * @return
2829  * - 0 on success.
2830  * - -1 on failure.
2831  */
2832 int fr_pair_value_bstrndup_shallow(fr_pair_t *vp, char const *src, size_t len, bool tainted)
2833 {
2834  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2835 
2836  fr_value_box_clear(&vp->data);
2837  fr_value_box_bstrndup_shallow(&vp->data, vp->da, src, len, tainted);
2838  PAIR_VERIFY(vp);
2839 
2840  return 0;
2841 }
2842 
2843 /** Assign a string to a "string" type value pair
2844  *
2845  * @param[in] vp to assign new buffer to.
2846  * @param[in] src a string.
2847  * @param[in] tainted Whether the value came from a trusted source.
2848  * @return
2849  * - 0 on success.
2850  * - -1 on failure.
2851  */
2852 int fr_pair_value_bstrdup_buffer_shallow(fr_pair_t *vp, char const *src, bool tainted)
2853 {
2854  int ret;
2855 
2856  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2857 
2858  fr_value_box_clear(&vp->data);
2859  ret = fr_value_box_bstrdup_buffer_shallow(NULL, &vp->data, vp->da, src, tainted);
2860  if (ret == 0) {
2861  PAIR_VERIFY(vp);
2862  }
2863 
2864  return ret;
2865 }
2866 
2867 /** Append bytes from a buffer to an existing "string" type value pair
2868  *
2869  * @param[in,out] vp to update.
2870  * @param[in] src data to copy.
2871  * @param[in] len of data to copy.
2872  * @param[in] tainted Whether the value came from a trusted source.
2873  * @return
2874  * - 0 on success.
2875  * - -1 on failure.
2876  */
2877 int fr_pair_value_bstrn_append(fr_pair_t *vp, char const *src, size_t len, bool tainted)
2878 {
2879  int ret;
2880 
2881  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2882 
2883  ret = fr_value_box_bstrn_append(vp, &vp->data, src, len, tainted);
2884  if (ret == 0) {
2885  PAIR_VERIFY(vp);
2886  }
2887 
2888  return ret;
2889 }
2890 
2891 /** Append a talloced buffer to an existing "string" type value pair
2892  *
2893  * @param[in,out] vp to update.
2894  * @param[in] src a talloced nul terminated buffer.
2895  * @param[in] tainted Whether the value came from a trusted source.
2896  * @return
2897  * - 0 on success.
2898  * - -1 on failure.
2899  */
2900 int fr_pair_value_bstr_append_buffer(fr_pair_t *vp, char const *src, bool tainted)
2901 {
2902  int ret;
2903 
2904  if (!fr_cond_assert(vp->vp_type == FR_TYPE_STRING)) return -1;
2905 
2906  ret = fr_value_box_bstr_append_buffer(vp, &vp->data, src, tainted);
2907  if (ret == 0) {
2908  PAIR_VERIFY(vp);
2909  }
2910 
2911  return ret;
2912 }
2913 
2914 /** Pre-allocate a memory buffer for a "octets" type value pair
2915  *
2916  * @note Will clear existing values (including buffers).
2917  *
2918  * @param[in,out] vp to update
2919  * @param[out] out If non-null will be filled with a pointer to the
2920  * new buffer.
2921  * @param[in] size of the data.
2922  * @param[in] tainted Whether the value came from a trusted source.
2923  * @return
2924  * - 0 on success.
2925  * - -1 on failure.
2926  */
2927 int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
2928 {
2929  int ret;
2930 
2931  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
2932 
2933  fr_value_box_clear(&vp->data); /* Free any existing buffers */
2934  ret = fr_value_box_mem_alloc(vp, out, &vp->data, vp->da, size, tainted);
2935  if (ret == 0) {
2936  PAIR_VERIFY(vp);
2937  }
2938 
2939  return ret;
2940 }
2941 
2942 /** Change the length of a buffer for a "octets" type value pair
2943  *
2944  * @param[in,out] vp to update
2945  * @param[out] out If non-null will be filled with a pointer to the
2946  * new buffer.
2947  * @param[in] size of the data.
2948  * @return
2949  * - 0 on success.
2950  * - -1 on failure.
2951  */
2953 {
2954  int ret;
2955 
2956  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
2957 
2958  ret = fr_value_box_mem_realloc(vp, out, &vp->data, size);
2959  if (ret == 0) {
2960  PAIR_VERIFY(vp);
2961  }
2962 
2963  return ret;
2964 }
2965 
2966 /** Copy data into an "octets" data type.
2967  *
2968  * @note Will clear existing values (including buffers).
2969  *
2970  * @param[in,out] vp to update
2971  * @param[in] src data to copy
2972  * @param[in] len of the data.
2973  * @param[in] tainted Whether the value came from a trusted source.
2974  * @return
2975  * - 0 on success.
2976  * - -1 on failure.
2977  */
2978 int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
2979 {
2980  int ret;
2981 
2982  if (unlikely((len > 0) && !src)) {
2983  fr_strerror_printf("Invalid arguments to %s. Len > 0 (%zu) but src was NULL",
2984  __FUNCTION__, len);
2985  return -1;
2986  }
2987 
2988  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
2989 
2990  fr_value_box_clear_value(&vp->data); /* Free any existing buffers */
2991  ret = fr_value_box_memdup(vp, &vp->data, vp->da, src, len, tainted);
2992  if (ret == 0) PAIR_VERIFY(vp);
2993 
2994  return ret;
2995 }
2996 
2997 /** Copy data from a talloced buffer into an "octets" data type.
2998  *
2999  * @note Will clear existing values (including buffers).
3000  *
3001  * @param[in,out] vp to update
3002  * @param[in] src data to copy
3003  * @param[in] tainted Whether the value came from a trusted source.
3004  * @return
3005  * - 0 on success.
3006  * - -1 on failure.
3007  */
3008 int fr_pair_value_memdup_buffer(fr_pair_t *vp, uint8_t const *src, bool tainted)
3009 {
3010  int ret;
3011 
3012  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
3013 
3014  fr_value_box_clear(&vp->data); /* Free any existing buffers */
3015  ret = fr_value_box_memdup_buffer(vp, &vp->data, vp->da, src, tainted);
3016  if (ret == 0) {
3017  PAIR_VERIFY(vp);
3018  }
3019 
3020  return ret;
3021 }
3022 
3023 /** Assign a buffer to a "octets" type value pair
3024  *
3025  * @param[in] vp to assign new buffer to.
3026  * @param[in] src data to copy.
3027  * @param[in] len of src.
3028  * @param[in] tainted Whether the value came from a trusted source.
3029  * @return
3030  * - 0 on success.
3031  * - -1 on failure.
3032  */
3033 int fr_pair_value_memdup_shallow(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
3034 {
3035  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
3036 
3037  fr_value_box_clear(&vp->data);
3038  fr_value_box_memdup_shallow(&vp->data, vp->da, src, len, tainted);
3039  PAIR_VERIFY(vp);
3040 
3041  return 0;
3042 }
3043 
3044 /** Assign a talloced buffer to a "octets" type value pair
3045  *
3046  * @param[in] vp to assign new buffer to.
3047  * @param[in] src data to copy.
3048  * @param[in] tainted Whether the value came from a trusted source.
3049  * @return
3050  * - 0 on success.
3051  * - -1 on failure.
3052  */
3054 {
3055  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
3056 
3057  fr_value_box_clear(&vp->data);
3058  fr_value_box_memdup_buffer_shallow(NULL, &vp->data, vp->da, src, tainted);
3059  PAIR_VERIFY(vp);
3060 
3061  return 0;
3062 }
3063 
3064 
3065 /** Append bytes from a buffer to an existing "octets" type value pair
3066  *
3067  * @param[in,out] vp to update.
3068  * @param[in] src data to copy.
3069  * @param[in] len of data to copy.
3070  * @param[in] tainted Whether the value came from a trusted source.
3071  * @return
3072  * - 0 on success.
3073  * - -1 on failure.
3074  */
3075 int fr_pair_value_mem_append(fr_pair_t *vp, uint8_t *src, size_t len, bool tainted)
3076 {
3077  int ret;
3078 
3079  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
3080 
3081  ret = fr_value_box_mem_append(vp, &vp->data, src, len, tainted);
3082  if (ret == 0) {
3083  PAIR_VERIFY(vp);
3084  }
3085 
3086  return ret;
3087 }
3088 
3089 /** Append a talloced buffer to an existing "octets" type value pair
3090  *
3091  * @param[in,out] vp to update.
3092  * @param[in] src data to copy.
3093  * @param[in] tainted Whether the value came from a trusted source.
3094  * @return
3095  * - 0 on success.
3096  * - -1 on failure.
3097  */
3099 {
3100  int ret;
3101 
3102  if (!fr_cond_assert(vp->vp_type == FR_TYPE_OCTETS)) return -1;
3103 
3104  ret = fr_value_box_mem_append_buffer(vp, &vp->data, src, tainted);
3105  if (ret == 0) {
3106  PAIR_VERIFY(vp);
3107  }
3108 
3109  return ret;
3110 }
3111 
3112 /** Return a const buffer for an enum type attribute
3113  *
3114  * Where the vp type is numeric but does not have any enumv, or its value
3115  * does not map to an enumv, the integer value of the pair will be printed
3116  * to buff, and a pointer to buff will be returned.
3117  *
3118  * @param[in] vp to print.
3119  * @param[in] buff to print integer value to.
3120  * @return a talloced buffer.
3121  */
3122 char const *fr_pair_value_enum(fr_pair_t const *vp, char buff[20])
3123 {
3124  char const *str;
3125  fr_dict_enum_value_t const *enumv = NULL;
3126 
3127  if (!fr_box_is_numeric(&vp->data)) {
3128  fr_strerror_printf("Pair %s is not numeric", vp->da->name);
3129  return NULL;
3130  }
3131 
3132  if (vp->da->flags.has_value) switch (vp->vp_type) {
3133  case FR_TYPE_BOOL:
3134  return vp->vp_bool ? "yes" : "no";
3135 
3136  default:
3137  enumv = fr_dict_enum_by_value(vp->da, &vp->data);
3138  break;
3139  }
3140 
3141  if (!enumv) {
3143  str = buff;
3144  } else {
3145  str = enumv->name;
3146  }
3147 
3148  return str;
3149 }
3150 
3151 /** Get value box of a VP, optionally prefer enum value.
3152  *
3153  * Get the data value box of the given VP. If 'e' is set to 1 and the VP has an
3154  * enum value, this will be returned instead. Otherwise it will be set to the
3155  * value box of the VP itself.
3156  *
3157  * @param[out] out pointer to a value box.
3158  * @param[in] vp to print.
3159  * @return 1 if the enum value has been used, 0 otherwise, -1 on error.
3160  */
3162 {
3163  fr_dict_enum_value_t const *dv;
3164 
3165  if (vp->da && vp->da->flags.has_value &&
3166  (dv = fr_dict_enum_by_value(vp->da, &vp->data))) {
3167  *out = dv->value;
3168  return 1;
3169  }
3170 
3171  *out = &vp->data;
3172  return 0;
3173 }
3174 
3175 #ifdef WITH_VERIFY_PTR
3176 /*
3177  * Verify a fr_pair_t
3178  */
3179 void fr_pair_verify(char const *file, int line, fr_pair_list_t const *list, fr_pair_t const *vp)
3180 {
3182 
3183  if (!vp->da) {
3184  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t da pointer was NULL", file, line);
3185  }
3186 
3188  if (list) {
3189  fr_fatal_assert_msg(fr_pair_order_list_parent(vp) == &list->order,
3190  "CONSISTENCY CHECK FAILED %s[%u]: pair does not have the correct parentage "
3191  "at \"%s\"",
3192  file, line, vp->da->name);
3193  }
3194 
3195  /*
3196  * This field is only valid for non-structural pairs
3197  */
3198  if (!fr_type_is_structural(vp->vp_type)) {
3200 
3201  if (vp->data.enumv) fr_dict_attr_verify(file, line, vp->data.enumv);
3202 
3203  if (parent && !fr_dict_attr_can_contain(parent->da, vp->da)) {
3204  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" should be parented by %s, but is parented by %s",
3205  file, line, vp->da->name, vp->da->parent->name, parent->da->name);
3206  }
3207 
3208  } else {
3210 
3211  if (parent && (parent->vp_type != FR_TYPE_GROUP) && (parent->da == vp->da)) {
3212  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" structural (non-group) type contains itself",
3213  file, line, vp->da->name);
3214  }
3215 
3216  fr_pair_list_verify(file, line, vp, &vp->vp_group);
3217  }
3218 
3219  switch (vp->vp_type) {
3220  case FR_TYPE_OCTETS:
3221  {
3222  size_t len;
3223  TALLOC_CTX *parent;
3224 
3225  if (!vp->vp_octets) break; /* We might be in the middle of initialisation */
3226 
3227  if (!talloc_get_type(vp->vp_ptr, uint8_t)) {
3228  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" data buffer type should be "
3229  "uint8_t but is %s", file, line, vp->da->name, talloc_get_name(vp->vp_ptr));
3230  }
3231 
3232  len = talloc_array_length(vp->vp_octets);
3233  if (vp->vp_length > len) {
3234  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" length %zu is greater than "
3235  "uint8_t data buffer length %zu", file, line, vp->da->name, vp->vp_length, len);
3236  }
3237 
3238  parent = talloc_parent(vp->vp_ptr);
3239  if (parent != vp) {
3240  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" char buffer is not "
3241  "parented by fr_pair_t %p, instead parented by %p (%s)",
3242  file, line, vp->da->name,
3243  vp, parent, parent ? talloc_get_name(parent) : "NULL");
3244  }
3245  }
3246  break;
3247 
3248  case FR_TYPE_STRING:
3249  {
3250  size_t len;
3251  TALLOC_CTX *parent;
3252 
3253  if (!vp->vp_octets) break; /* We might be in the middle of initialisation */
3254 
3255  if (!talloc_get_type(vp->vp_ptr, char)) {
3256  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" data buffer type should be "
3257  "char but is %s", file, line, vp->da->name, talloc_get_name(vp->vp_ptr));
3258  }
3259 
3260  len = (talloc_array_length(vp->vp_strvalue) - 1);
3261  if (vp->vp_length > len) {
3262  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" length %zu is greater than "
3263  "char buffer length %zu", file, line, vp->da->name, vp->vp_length, len);
3264  }
3265 
3266  if (vp->vp_strvalue[vp->vp_length] != '\0') {
3267  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" char buffer not \\0 "
3268  "terminated", file, line, vp->da->name);
3269  }
3270 
3271  parent = talloc_parent(vp->vp_ptr);
3272  if (parent != vp) {
3273  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" char buffer is not "
3274  "parented by fr_pair_t %p, instead parented by %p (%s)",
3275  file, line, vp->da->name,
3276  vp, parent, parent ? talloc_get_name(parent) : "NULL");
3277  fr_fatal_assert_fail("0");
3278  }
3279  }
3280  break;
3281 
3282  case FR_TYPE_IPV4_ADDR:
3283  if (vp->vp_ip.af != AF_INET) {
3284  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" address family is not "
3285  "set correctly for IPv4 address. Expected %i got %i",
3286  file, line, vp->da->name,
3287  AF_INET, vp->vp_ip.af);
3288  }
3289  if (vp->vp_ip.prefix != 32) {
3290  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" address prefix "
3291  "set correctly for IPv4 address. Expected %i got %i",
3292  file, line, vp->da->name,
3293  32, vp->vp_ip.prefix);
3294  }
3295  break;
3296 
3297  case FR_TYPE_IPV6_ADDR:
3298  if (vp->vp_ip.af != AF_INET6) {
3299  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" address family is not "
3300  "set correctly for IPv6 address. Expected %i got %i",
3301  file, line, vp->da->name,
3302  AF_INET6, vp->vp_ip.af);
3303  }
3304  if (vp->vp_ip.prefix != 128) {
3305  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" address prefix "
3306  "set correctly for IPv6 address. Expected %i got %i",
3307  file, line, vp->da->name,
3308  128, vp->vp_ip.prefix);
3309  }
3310  break;
3311 
3312  case FR_TYPE_STRUCTURAL:
3313  {
3314  if (vp->vp_group.verified) break;
3315 
3316  fr_pair_list_foreach(&vp->vp_group, child) {
3317  TALLOC_CTX *parent = talloc_parent(child);
3318 
3320  "CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" should be parented "
3321  "by fr_pair_t \"%s\". Expected talloc parent %p (%s) got %p (%s)",
3322  file, line,
3323  child->da->name, vp->da->name,
3324  vp, talloc_get_name(vp),
3325  parent, talloc_get_name(parent));
3326 
3327  /*
3328  * Check if the child can be in the parent.
3329  */
3331  "CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t \"%s\" should be parented "
3332  "by fr_pair_t \"%s\", but it is instead parented by \"%s\"",
3333  file, line,
3334  child->da->name, child->da->parent->name, vp->da->name);
3335 
3336  fr_pair_verify(file, line, &vp->vp_group, child);
3337  }
3338 
3339  UNCONST(fr_pair_t *, vp)->vp_group.verified = true;
3340  }
3341  break;
3342 
3343  default:
3344  break;
3345  }
3346 
3347  if (vp->da->flags.is_unknown || vp->vp_raw) {
3349 
3350  } else {
3351  fr_dict_attr_t const *da;
3352 
3353  da = vp->da;
3354  if (da != vp->da) {
3355  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t "
3356  "dictionary pointer %p \"%s\" (%s) "
3357  "and global dictionary pointer %p \"%s\" (%s) differ",
3358  file, line, vp->da, vp->da->name,
3359  fr_type_to_str(vp->vp_type),
3360  da, da->name,
3361  fr_type_to_str(da->type));
3362  }
3363  }
3364 
3365  if (vp->vp_raw || vp->da->flags.is_unknown) {
3366  if ((vp->da->parent->type != FR_TYPE_VSA) && (vp->vp_type != FR_TYPE_VSA) && (vp->vp_type != FR_TYPE_OCTETS) && (vp->vp_type != FR_TYPE_TLV)) {
3367  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t (raw/unknown) attribute %p \"%s\" "
3368  "data type incorrect. Expected %s, got %s",
3369  file, line, vp->da, vp->da->name,
3371  fr_type_to_str(vp->vp_type));
3372  }
3373 
3374  } else if (fr_type_is_leaf(vp->vp_type) && (vp->vp_type != vp->da->type) &&
3375  !((vp->da->type == FR_TYPE_COMBO_IP_ADDR) && ((vp->vp_type == FR_TYPE_IPV4_ADDR) || (vp->vp_type == FR_TYPE_IPV6_ADDR))) &&
3376  !((vp->da->type == FR_TYPE_COMBO_IP_PREFIX) && ((vp->vp_type == FR_TYPE_IPV4_PREFIX) || (vp->vp_type == FR_TYPE_IPV6_PREFIX)))) {
3377  char data_type_int[10], da_type_int[10];
3378 
3379  snprintf(data_type_int, sizeof(data_type_int), "%i", vp->vp_type);
3380  snprintf(da_type_int, sizeof(da_type_int), "%i", vp->vp_type);
3381 
3382  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: fr_pair_t attribute %p \"%s\" "
3383  "data type (%s) does not match da type (%s)",
3384  file, line, vp->da, vp->da->name,
3385  fr_table_str_by_value(fr_type_table, vp->vp_type, data_type_int),
3386  fr_table_str_by_value(fr_type_table, vp->vp_type, da_type_int));
3387  }
3388 }
3389 
3390 /** Verify a pair list
3391  *
3392  * @param[in] file from which the verification is called
3393  * @param[in] line number in file
3394  * @param[in] expected talloc ctx pairs should have been allocated in
3395  * @param[in] list of fr_pair_ts to verify
3396  */
3397 void fr_pair_list_verify(char const *file, int line, TALLOC_CTX const *expected, fr_pair_list_t const *list)
3398 {
3399  fr_pair_t *slow, *fast;
3400  TALLOC_CTX *parent;
3401 
3402  if (fr_pair_list_empty(list)) return; /* Fast path */
3403 
3404  /*
3405  * Only verify the list if it has been modified.
3406  */
3407  if (list->verified) return;
3408 
3409  for (slow = fr_pair_list_head(list), fast = fr_pair_list_head(list);
3410  slow && fast;
3411  slow = fr_pair_list_next(list, slow), fast = fr_pair_list_next(list, fast)) {
3412  PAIR_VERIFY_WITH_LIST(list, slow);
3413 
3414  /*
3415  * Advances twice as fast as slow...
3416  */
3417  fast = fr_pair_list_next(list, fast);
3418  fr_fatal_assert_msg(fast != slow,
3419  "CONSISTENCY CHECK FAILED %s[%u]: Looping list found. Fast pointer hit "
3420  "slow pointer at \"%s\"",
3421  file, line, slow->da->name);
3422 
3423  parent = talloc_parent(slow);
3424  if (expected && (parent != expected)) {
3425  bad_parent:
3426  fr_log_talloc_report(expected);
3428 
3429  fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%u]: Expected fr_pair_t \"%s\" to be parented "
3430  "by %p (%s), instead parented by %p (%s)\n",
3431  file, line, slow->da->name,
3432  expected, talloc_get_name(expected),
3433  parent, parent ? talloc_get_name(parent) : "NULL");
3434  }
3435  }
3436 
3437  /*
3438  * Check the remaining pairs
3439  */
3440  for (; slow; slow = fr_pair_list_next(list, slow)) {
3441  PAIR_VERIFY_WITH_LIST(list, slow);
3442 
3443  parent = talloc_parent(slow);
3444  if (expected && (parent != expected)) goto bad_parent;
3445  }
3446 
3447  UNCONST(fr_pair_list_t *, list)->verified = true;
3448 }
3449 #endif
3450 
3451 /** Mark up a list of VPs as tainted.
3452  *
3453  */
3455 {
3456  if (fr_pair_list_empty(list)) return;
3457 
3458  fr_pair_list_foreach(list, vp) {
3459  PAIR_VERIFY_WITH_LIST(list, vp);
3460 
3461  switch (vp->vp_type) {
3462  case FR_TYPE_STRUCTURAL:
3463  fr_pair_list_tainted(&vp->vp_group);
3464  break;
3465 
3466  default:
3467  break;
3468  }
3469 
3470  vp->vp_tainted = true;
3471  }
3472 }
3473 
3474 /** Evaluation function for matching if vp matches a given da
3475  *
3476  * Can be used as a filter function for fr_dcursor_filter_next()
3477  *
3478  * @param item pointer to a fr_pair_t
3479  * @param uctx da to match
3480  *
3481  * @return true if the pair matches the da
3482  */
3483 bool fr_pair_matches_da(void const *item, void const *uctx)
3484 {
3485  fr_pair_t const *vp = item;
3486  fr_dict_attr_t const *da = uctx;
3487  return da == vp->da;
3488 }
3489 
3490 /** Find or allocate a parent attribute.
3491  *
3492  * The input da is somewhere down inside of the da hierarchy. We
3493  * need to recursively find or create parent VPs which match the
3494  * given da.
3495  *
3496  * We find (or add) the VP into the "in" list. Any newly created VP
3497  * is inserted before "next". Or if "next==NULL", at the tail of
3498  * "in".
3499  *
3500  * @param[in] in the parent vp to look in
3501  * @param[in] item if we create a new vp, insert it before this item
3502  * @param[in] da look for vps in the parent which match this da
3503  * @return
3504  * - NULL on OOM
3505  * - parent vp we've found or allocated.
3506  */
3508 {
3509  fr_pair_t *parent, *vp;
3510 
3511  /*
3512  * We should never be called with a leaf da.
3513  *
3514  * If we're asked to create children of a keyed
3515  * structure, just create the children in the parent.
3516  */
3517  if (!fr_type_is_structural(da->type)) {
3519  da = da->parent;
3520  }
3521 
3522  fr_assert(fr_type_is_structural(da->type));
3523 
3524  /*
3525  * We're looking for a parent in the root of the
3526  * dictionary. Find the relevant VP in the current
3527  * container.
3528  *
3529  * If it's not found, allocate it, and insert it into the
3530  * list. Note that we insert it before the given "item"
3531  * vp so that we don't loop over the newly created pair
3532  * as we're processing the list.
3533  */
3534  if (da->flags.is_root || (da->parent == in->da)) {
3535  return in;
3536  }
3537 
3538  /*
3539  * We're not at the root. Go find (or create) the parent
3540  * of this da.
3541  */
3542  parent = pair_alloc_parent(in, item, da->parent);
3543  if (!parent) return NULL;
3544 
3545  /*
3546  * We have the parent attribute, maybe it already
3547  * contains the da we're looking for?
3548  */
3549  vp = fr_pair_find_by_da(&parent->vp_group, NULL, da);
3550  if (vp) return vp;
3551 
3552  /*
3553  * Now that the entire set of parents has been created,
3554  * create the final VP. Make sure it's in the parent,
3555  * and return it.
3556  */
3557  vp = fr_pair_afrom_da(parent, da);
3558  if (!vp) return NULL;
3559 
3560  /*
3561  * If we are at the root, and have been provided with
3562  * an entry to insert before, then do that.
3563  */
3564  if (item && da->parent->flags.is_root) {
3565  fr_pair_insert_before(&parent->vp_group, item, vp);
3566  } else {
3567  fr_pair_append(&parent->vp_group, vp);
3568  }
3569  return vp;
3570 }
3571 
3572 /** Parse a list of VPs from a value box.
3573  *
3574  * @param[in] ctx to allocate new VPs in
3575  * @param[out] out list to add new pairs to
3576  * @param[in] dict to use in parsing
3577  * @param[in] box whose value is to be parsed
3578  */
3580 {
3581  fr_pair_parse_t root, relative;
3582 
3583  fr_assert(box->type == FR_TYPE_STRING);
3584 
3585  root = (fr_pair_parse_t) {
3586  .ctx = ctx,
3587  .da = fr_dict_root(dict),
3588  .list = out,
3589  .allow_crlf = true,
3590  .tainted = box->tainted,
3591  };
3592  relative = (fr_pair_parse_t) { };
3593 
3594  if (fr_pair_list_afrom_substr(&root, &relative, &FR_SBUFF_IN(box->vb_strvalue, box->vb_length)) < 0) {
3595  return;
3596  }
3597 }
3598 
3599 static const char spaces[] = " ";
3600 
3601 static void fprintf_pair_list(FILE *fp, fr_pair_list_t const *list, int depth)
3602 {
3603  fr_pair_list_foreach(list, vp) {
3604  fprintf(fp, "%.*s", depth, spaces);
3605 
3606  if (fr_type_is_leaf(vp->vp_type)) {
3607  fr_fprintf(fp, "%s %s %pV\n", vp->da->name, fr_tokens[vp->op], &vp->data);
3608  continue;
3609  }
3610 
3611  fprintf(fp, "%s = {\n", vp->da->name);
3612  fprintf_pair_list(fp, &vp->vp_group, depth + 1);
3613  fprintf(fp, "%.*s}\n", depth, spaces);
3614  }
3615 }
3616 
3617 void fr_fprintf_pair_list(FILE *fp, fr_pair_list_t const *list)
3618 {
3619  fprintf_pair_list(fp, list, 0);
3620 }
3621 
3622 /*
3623  * print.c doesn't include pair.h, and doing so causes too many knock-on effects.
3624  */
3625 void fr_fprintf_pair(FILE *fp, char const *msg, fr_pair_t const *vp)
3626 {
3627  if (msg) fputs(msg, fp);
3628 
3629  if (fr_type_is_leaf(vp->vp_type)) {
3630  fr_fprintf(fp, "%s %s %pV\n", vp->da->name, fr_tokens[vp->op], &vp->data);
3631  } else {
3632  fprintf(fp, "%s = {\n", vp->da->name);
3633  fprintf_pair_list(fp, &vp->vp_group, 1);
3634  fprintf(fp, "}\n");
3635  }
3636 }
int const char * file
Definition: acutest.h:702
va_end(args)
int n
Definition: acutest.h:577
log_entry msg
Definition: acutest.h:794
static int const char * fmt
Definition: acutest.h:573
int const char int line
Definition: acutest.h:702
va_start(args, fmt)
static fr_dict_t * dict
Definition: fuzzer.c:46
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define NDEBUG_UNUSED
Definition: build.h:324
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define unlikely(_x)
Definition: build.h:378
#define UNUSED
Definition: build.h:313
static void * _fr_dcursor_init(fr_dcursor_t *cursor, fr_dlist_head_t const *head, fr_dcursor_iter_t iter, fr_dcursor_iter_t peek, void const *iter_uctx, fr_dcursor_insert_t insert, fr_dcursor_remove_t remove, void const *mod_uctx, bool is_const)
Setup a cursor to iterate over attribute items in dlists.
Definition: dcursor.h:755
void *(* fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *uctx)
Callback for implementing custom iterators.
Definition: dcursor.h:51
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
int fr_log_talloc_report(TALLOC_CTX const *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition: debug.c:1120
#define fr_fatal_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:189
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition: debug.h:137
#define fr_fatal_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition: debug.h:182
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
static fr_dict_attr_t * fr_dict_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition: dict.h:428
fr_dict_attr_t const * fr_dict_attr_common_parent(fr_dict_attr_t const *a, fr_dict_attr_t const *b, bool is_ancestor)
Find a common ancestor that two TLV type attributes share.
Definition: dict_util.c:1631
void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
Definition: dict_util.c:4377
bool fr_dict_attr_can_contain(fr_dict_attr_t const *parent, fr_dict_attr_t const *child)
See if a structural da is allowed to contain another da.
Definition: dict_util.c:4464
fr_dict_enum_value_t * fr_dict_enum_by_value(fr_dict_attr_t const *da, fr_value_box_t const *value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict_util.c:2946
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_value_box_t const * value
Enum value (what name maps to).
Definition: dict.h:213
fr_dict_attr_t * fr_dict_unknown_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Copy a known or unknown attribute to produce an unknown attribute with the specified name.
Definition: dict_unknown.c:226
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict_util.c:2925
#define fr_dict_attr_is_key_field(_da)
Definition: dict.h:149
char const * name
Enum name.
Definition: dict.h:210
static fr_slen_t in
Definition: dict.h:645
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
Value of an enumerated attribute.
Definition: dict.h:209
Test enumeration values.
Definition: dict_test.h:92
unsigned int offset
Positive offset from start of structure to fr_dlist_t.
Definition: dlist.h:55
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
fr_dlist_t * next
Definition: dlist.h:43
fr_dlist_t entry
Struct holding the head and tail of the list.
Definition: dlist.h:52
Head of a doubly linked list.
Definition: dlist.h:51
talloc_free(reap)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition: lst.c:122
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_TLV
Contains nested attributes.
Definition: merged_model.c:118
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
Definition: merged_model.c:92
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_BOOL
A truth value.
Definition: merged_model.c:95
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
Definition: merged_model.c:121
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
Definition: merged_model.c:91
@ 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
unsigned char uint8_t
Definition: merged_model.c:30
static uint8_t depth(fr_minmax_heap_index_t i)
Definition: minmax_heap.c:83
void * memset_explicit(void *ptr, int ch, size_t len)
Definition: missing.c:620
bool fr_pair_matches_da(void const *item, void const *uctx)
Evaluation function for matching if vp matches a given da.
Definition: pair.c:3483
int fr_pair_insert_before(fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *to_add)
Add a VP before another VP.
Definition: pair.c:1401
int fr_pair_list_copy_by_da(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_dict_attr_t const *da, unsigned int count)
Duplicate pairs in a list matching the specified da.
Definition: pair.c:2403
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
static void pair_init_from_da(fr_pair_t *vp, fr_dict_attr_t const *da)
Continue initialising an fr_pair_t assigning a da.
Definition: pair.c:187
int fr_pair_value_bstrn_append(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Append bytes from a buffer to an existing "string" type value pair.
Definition: pair.c:2877
int fr_pair_list_cmp(fr_pair_list_t const *a, fr_pair_list_t const *b)
Determine equality of two lists.
Definition: pair.c:2044
int fr_pair_value_memdup_buffer(fr_pair_t *vp, uint8_t const *src, bool tainted)
Copy data from a talloced buffer into an "octets" data type.
Definition: pair.c:3008
unsigned int fr_pair_count_by_da(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Return the number of instances of a given da in the specified list.
Definition: pair.c:665
void fr_pair_list_tainted(fr_pair_list_t *list)
Mark up a list of VPs as tainted.
Definition: pair.c:3454
#define NOT_IN_THIS_LIST_MSG
Definition: pair.c:530
fr_pair_t * fr_pair_find_by_child_num_idx(fr_pair_list_t const *list, fr_dict_attr_t const *parent, unsigned int attr, unsigned int idx)
Find the pair with the matching child attribute at a given index.
Definition: pair.c:888
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
static void fprintf_pair_list(FILE *fp, fr_pair_list_t const *list, int depth)
Definition: pair.c:3601
int fr_pair_value_enum_box(fr_value_box_t const **out, fr_pair_t *vp)
Get value box of a VP, optionally prefer enum value.
Definition: pair.c:3161
int fr_pair_value_aprintf(fr_pair_t *vp, char const *fmt,...)
Print data into an "string" data type.
Definition: pair.c:2695
int fr_pair_delete_by_da_nested(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list, and prune any empty branches.
Definition: pair.c:1708
void fr_fprintf_pair_list(FILE *fp, fr_pair_list_t const *list)
Definition: pair.c:3617
fr_pair_t * fr_pair_alloc_null(TALLOC_CTX *ctx)
Dynamically allocate a new attribute with no fr_dict_attr_t assigned.
Definition: pair.c:167
int fr_pair_value_mem_append(fr_pair_t *vp, uint8_t *src, size_t len, bool tainted)
Append bytes from a buffer to an existing "octets" type value pair.
Definition: pair.c:3075
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
static int8_t pair_cmp_by_num(void const *a, void const *b)
Order attributes by their attribute number, and tag.
Definition: pair.c:1861
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
int fr_pair_steal_prepend(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
Change a vp's talloc ctx and insert it into a new list.
Definition: pair.c:564
static fr_pair_t * pair_alloc_parent(fr_pair_t *in, fr_pair_t *item, fr_dict_attr_t const *da)
Find or allocate a parent attribute.
Definition: pair.c:3507
int fr_pair_value_mem_append_buffer(fr_pair_t *vp, uint8_t *src, bool tainted)
Append a talloced buffer to an existing "octets" type value pair.
Definition: pair.c:3098
int fr_pair_value_memdup(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Copy data into an "octets" data type.
Definition: pair.c:2978
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
void fr_pair_validate_debug(fr_pair_t const *failed[2])
Write an error to the library errorbuff detailing the mismatch.
Definition: pair.c:2090
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition: pair.c:2631
static int _pair_list_dcursor_insert(fr_dlist_head_t *list, void *to_insert, UNUSED void *uctx)
Keep attr tree and sublists synced on cursor insert.
Definition: pair.c:968
int fr_pair_value_bstrdup_buffer_shallow(fr_pair_t *vp, char const *src, bool tainted)
Assign a string to a "string" type value pair.
Definition: pair.c:2852
void fr_pair_init_null(fr_pair_t *vp)
Initialise fields in an fr_pair_t without assigning a da.
Definition: pair.c:147
fr_pair_t * _fr_pair_dcursor_by_da_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dict_attr_t const *da, bool is_const)
Initialise a cursor that will return only attributes matching the specified fr_dict_attr_t.
Definition: pair.c:1138
int8_t fr_pair_cmp_by_parent_num(void const *a, void const *b)
Order attributes by their parent(s), attribute number, and tag.
Definition: pair.c:1918
fr_pair_t * fr_pair_find_by_child_num(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *parent, unsigned int attr)
Find the pair with the matching child attribute.
Definition: pair.c:862
int fr_pair_cmp(fr_pair_t const *a, fr_pair_t const *b)
Compare two pairs, using the operator from "a".
Definition: pair.c:1966
int fr_pair_value_bstrndup_shallow(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Assign a string to a "string" type value pair.
Definition: pair.c:2832
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
char const * fr_pair_value_enum(fr_pair_t const *vp, char buff[20])
Return a const buffer for an enum type attribute.
Definition: pair.c:3122
static void pair_init_null(fr_pair_t *vp)
Initialise fields in an fr_pair_t without assigning a da.
Definition: pair.c:133
void fr_pair_replace(fr_pair_list_t *list, fr_pair_t *to_replace, fr_pair_t *vp)
Replace a given VP.
Definition: pair.c:1434
int fr_pair_value_bstrdup_buffer(fr_pair_t *vp, char const *src, bool tainted)
Copy a nul terminated talloced buffer a "string" type value pair.
Definition: pair.c:2807
int fr_pair_update_by_da_parent(fr_pair_t *parent, fr_pair_t **out, fr_dict_attr_t const *da)
Return the first fr_pair_t matching the fr_dict_attr_t or alloc a new fr_pair_t and its subtree (and ...
Definition: pair.c:1591
int fr_pair_list_copy_by_ancestor(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_dict_attr_t const *parent_da)
Duplicate pairs in a list where the da is a descendant of parent_da.
Definition: pair.c:2452
static int _fr_pair_free(fr_pair_t *vp)
Free a fr_pair_t.
Definition: pair.c:69
fr_pair_t * fr_pair_delete(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list and free.
Definition: pair.c:1819
bool fr_pair_validate(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check.
Definition: pair.c:2125
int fr_pair_steal_append(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
Change a vp's talloc ctx and insert it into a new list.
Definition: pair.c:541
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition: pair.c:46
int fr_pair_value_mem_realloc(fr_pair_t *vp, uint8_t **out, size_t size)
Change the length of a buffer for a "octets" type value pair.
Definition: pair.c:2952
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
Definition: pair.c:462
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition: pair.c:366
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition: pair.c:2781
void fr_fprintf_pair(FILE *fp, char const *msg, fr_pair_t const *vp)
Definition: pair.c:3625
int fr_pair_value_bstr_alloc(fr_pair_t *vp, char **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "string" type value pair.
Definition: pair.c:2727
int fr_pair_value_bstr_append_buffer(fr_pair_t *vp, char const *src, bool tainted)
Append a talloced buffer to an existing "string" type value pair.
Definition: pair.c:2900
static void * fr_pair_iter_next_by_da(fr_dlist_head_t *list, void *current, void *uctx)
Iterate over pairs with a specified da.
Definition: pair.c:621
int fr_pair_value_bstr_realloc(fr_pair_t *vp, char **out, size_t size)
Change the length of a buffer for a "string" type value pair.
Definition: pair.c:2752
fr_pair_t * _fr_pair_dcursor_by_ancestor_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dict_attr_t const *da, bool is_const)
Initialise a cursor that will return only attributes descended from the specified fr_dict_attr_t.
Definition: pair.c:1157
bool fr_pair_immutable(fr_pair_t const *vp)
Definition: pair.c:2277
void fr_pair_value_clear(fr_pair_t *vp)
Free/zero out value (or children) of a given VP.
Definition: pair.c:2530
static void * _fr_pair_iter_next_value(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
Iterate over pairs.
Definition: pair.c:1195
fr_pair_list_t * fr_pair_children(fr_pair_t *vp)
Get the child list of a group.
Definition: pair.c:912
int fr_pair_append_by_da_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t, adding the parent attributes if required.
Definition: pair.c:1518
fr_pair_t * fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
Find a pair with a matching da at a given index.
Definition: pair.c:736
int fr_pair_sublist_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from, fr_pair_t const *start, unsigned int count)
Duplicate a list of pairs starting at a particular item.
Definition: pair.c:2505
static fr_dlist_head_t value_dlist
Definition: pair.c:1221
int fr_pair_delete_by_child_num(fr_pair_list_t *list, fr_dict_attr_t const *parent, unsigned int attr)
Delete matching pairs from the specified list.
Definition: pair.c:1803
int fr_pair_value_copy(fr_pair_t *dst, fr_pair_t *src)
Copy the value from one pair to another.
Definition: pair.c:2560
fr_pair_list_t * fr_pair_list_alloc(TALLOC_CTX *ctx)
Allocate a new pair list on the heap.
Definition: pair.c:117
int fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
Re-initialise an attribute with a different da.
Definition: pair.c:309
int fr_pair_steal(TALLOC_CTX *ctx, fr_pair_t *vp)
Steal one VP.
Definition: pair.c:516
static void * _fr_pair_iter_next_dcursor_value(UNUSED fr_dlist_head_t *list, void *current, void *uctx)
Iterate over pairs.
Definition: pair.c:1259
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:484
int fr_pair_value_memdup_shallow(fr_pair_t *vp, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a "octets" type value pair.
Definition: pair.c:3033
bool fr_pair_validate_relaxed(fr_pair_t const *failed[2], fr_pair_list_t *filter, fr_pair_list_t *list)
Uses fr_pair_cmp to verify all fr_pair_ts in list match the filter defined by check.
Definition: pair.c:2202
#define IN_A_LIST_MSG
Definition: pair.c:529
fr_pair_t * _fr_pair_dcursor_iter_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dcursor_iter_t iter, void const *uctx, bool is_const)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.c:1098
fr_pair_list_t * fr_pair_parent_list(fr_pair_t const *vp)
Return a pointer to the parent pair list.
Definition: pair.c:922
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
Definition: pair.c:765
int fr_pair_value_mem_alloc(fr_pair_t *vp, uint8_t **out, size_t size, bool tainted)
Pre-allocate a memory buffer for a "octets" type value pair.
Definition: pair.c:2927
int fr_pair_value_strtrim(fr_pair_t *vp)
Trim the length of the string buffer to match the length of the C string.
Definition: pair.c:2674
int fr_pair_insert_after(fr_pair_list_t *list, fr_pair_t *pos, fr_pair_t *to_add)
Add a VP after another VP.
Definition: pair.c:1368
int fr_pair_value_from_str(fr_pair_t *vp, char const *value, size_t inlen, fr_sbuff_unescape_rules_t const *uerules, bool tainted)
Convert string value to native attribute value.
Definition: pair.c:2586
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
static void * fr_pair_iter_next_by_ancestor(fr_dlist_head_t *list, void *current, void *uctx)
Iterate over pairs which are decedents of the specified da.
Definition: pair.c:644
static int _pair_list_dcursor_remove(NDEBUG_UNUSED fr_dlist_head_t *list, void *to_remove, UNUSED void *uctx)
Keep attr tree and sublists synced on cursor removal.
Definition: pair.c:993
void fr_pair_list_afrom_box(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_t const *dict, fr_value_box_t *box)
Parse a list of VPs from a value box.
Definition: pair.c:3579
fr_value_box_t * fr_pair_dcursor_nested_init(fr_dcursor_t *cursor, fr_dcursor_t *parent)
Initialises a special dcursor over another cursor which returns fr_pair_t, but we return fr_value_box...
Definition: pair.c:1293
void fr_pair_list_steal(TALLOC_CTX *ctx, fr_pair_list_t *list)
Steal a list of pairs to a new context.
Definition: pair.c:2297
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_list_iter_leaf(fr_pair_list_t *list, fr_pair_t *vp)
Iterates over the leaves of a list.
Definition: pair.c:1033
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
Definition: pair.c:588
fr_value_box_t * fr_pair_dcursor_value_init(fr_dcursor_t *cursor)
Initialises a special dcursor over a fr_pair_list_t, but which returns fr_value_box_t.
Definition: pair.c:1243
int8_t fr_pair_cmp_by_da(void const *a, void const *b)
Order attributes by their da, and tag.
Definition: pair.c:1841
static const char spaces[]
Definition: pair.c:3599
int fr_pair_value_memdup_buffer_shallow(fr_pair_t *vp, uint8_t const *src, bool tainted)
Assign a talloced buffer to a "octets" type value pair.
Definition: pair.c:3053
int fr_pair_value_strdup_shallow(fr_pair_t *vp, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a vp, but don't copy it.
Definition: pair.c:2655
int fr_pair_prepend_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 prepend)
Definition: pair.c:1488
fr_pair_t * _fr_pair_dcursor_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, bool is_const)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.c:1120
fr_pair_t * fr_pair_root_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
A special allocation function which disables child autofree.
Definition: pair.c:238
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
int fr_pair_list_copy_to_box(fr_value_box_t *dst, fr_pair_list_t *from)
Copy the contents of a pair list to a set of value-boxes.
Definition: pair.c:2351
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
struct fr_pair_parse_s fr_pair_parse_t
TALLOC_CTX * ctx
Definition: pair_legacy.h:43
ssize_t fr_fprintf(FILE *fp, char const *fmt,...)
Special version of fprintf which implements custom format specifiers.
Definition: print.c:899
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
Definition: proto.c:118
static rc_request_t * current
Definition: radclient-ng.c:97
#define check(_handle, _len_p)
static size_t min(size_t x, size_t y)
Definition: sbuff.c:135
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
Set of parsing rules for *unescape_until functions.
Definition: merged_model.c:163
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:689
return count
Definition: module.c:175
fr_assert(0)
fr_pair_t * vp
bool _CONST is_child
is a child of a VP
Definition: pair.h:55
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
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:253
#define talloc_get_type_abort_const
Definition: talloc.h:270
#define FR_TLIST_FUNCS(_name, _element_type, _element_entry)
Define type specific wrapper functions for tlists.
Definition: tlist.h:790
static fr_tlist_head_t * fr_tlist_head_from_dlist(fr_dlist_head_t *dlist_head)
Get a fr_tlist_head_t from a fr_dlist_head_t.
Definition: tlist.h:69
#define FR_TLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
Definition: tlist.h:769
char const * fr_tokens[T_TOKEN_LAST]
Definition: token.c:78
@ T_OP_CMP_TRUE
Definition: token.h:104
@ T_BARE_WORD
Definition: token.h:120
@ T_OP_EQ
Definition: token.h:83
@ T_OP_CMP_FALSE
Definition: token.h:105
@ T_OP_REG_EQ
Definition: token.h:102
@ T_OP_REG_NE
Definition: token.h:103
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
#define ATTRIBUTE_EQ(_x, _y)
Definition: pair.h:147
#define fr_pair_cmp_op(_op, _a, _b)
Compare two attributes using and operator.
Definition: pair.h:665
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
static fr_slen_t fr_pair_aprint(TALLOC_CTX *ctx, char **out, fr_dict_attr_t const *parent, fr_pair_t const *vp) 1(fr_pair_print
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_sort(fr_pair_list_t *list, fr_cmp_t cmp)
Sort a doubly linked list of fr_pair_ts using merge sort.
Definition: pair_inline.c:140
#define vp_group
Definition: pair.h:137
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition: pair.h:260
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
#define PAIR_VERIFY_WITH_LIST(_l, _x)
Definition: pair.h:191
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition: pair_print.c:40
fr_pair_t * fr_pair_list_prev(fr_pair_list_t const *list, fr_pair_t const *item))
Get the previous item in a valuepair list before a specific entry.
Definition: pair_inline.c:83
#define PAIR_LIST_VERIFY(_x)
Definition: pair.h:193
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
Definition: pair_inline.c:151
static fr_slen_t parent
Definition: pair.h:844
uint8_t depth
Deepest attribute in the stack.
Definition: proto.h:55
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Definition: proto.h:56
Structure for holding the stack of dictionary attributes being encoded.
Definition: proto.h:54
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition: strerror.c:577
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
Definition: strerror.h:84
#define fr_strerror_const(_msg)
Definition: strerror.h:223
fr_table_num_ordered_t const fr_type_table[]
Map data types to names representing those types.
Definition: types.c:31
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_group(_x)
Definition: types.h:355
#define fr_type_is_structural(_x)
Definition: types.h:371
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
#define fr_type_is_leaf(_x)
Definition: types.h:372
void fr_value_box_memdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, bool tainted)
Assign a talloced buffer to a box, but don't copy it.
Definition: value.c:4515
int fr_value_box_vasprintf(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, bool tainted, char const *fmt, va_list ap)
Print a formatted string using our internal printf wrapper and assign it to a value box.
Definition: value.c:3932
int fr_value_box_bstrn_append(TALLOC_CTX *ctx, fr_value_box_t *dst, char const *src, size_t len, bool tainted)
Append bytes from a buffer to an existing fr_value_box_t.
Definition: value.c:4233
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition: value.c:5264
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
Definition: value.c:3902
int fr_value_box_mem_append_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, uint8_t const *src, bool tainted)
Append a talloc buffer to an existing fr_value_box_t.
Definition: value.c:4586
int fr_value_box_mem_alloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Pre-allocate an octets buffer for filling by the caller.
Definition: value.c:4320
int fr_value_box_memdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, bool tainted)
Copy a talloced buffer to a fr_value_box_t.
Definition: value.c:4475
int fr_value_box_bstrdup_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated talloced buffer to a fr_value_box_t.
Definition: value.c:4157
int fr_value_box_mem_realloc(TALLOC_CTX *ctx, uint8_t **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition: value.c:4353
int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b)
Compare two values.
Definition: value.c:640
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3689
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition: value.c:3521
int fr_value_box_mem_append(TALLOC_CTX *ctx, fr_value_box_t *dst, uint8_t const *src, size_t len, bool tainted)
Append data to an existing fr_value_box_t.
Definition: value.c:4536
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition: value.c:4497
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition: value.c:3630
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition: value.c:3876
int fr_value_box_bstr_append_buffer(TALLOC_CTX *ctx, fr_value_box_t *dst, char const *src, bool tainted)
Append a talloced buffer to an existing fr_value_box_t.
Definition: value.c:4286
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:3985
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
Definition: value.c:4020
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition: value.c:3672
int fr_value_box_bstr_realloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, size_t len)
Change the length of a buffer already allocated to a value box.
Definition: value.c:4053
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition: value.c:4097
int fr_value_box_bstrdup_buffer_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a talloced buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:4202
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition: value.c:4181
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition: value.c:4417
#define fr_box_is_numeric(_x)
Definition: value.h:429
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static fr_slen_t data
Definition: value.h:1259
static size_t char fr_sbuff_t size_t inlen
Definition: value.h:984
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition: value.h:574
static size_t char ** out
Definition: value.h:984