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