The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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 */
24RCSID("$Id: db7c30bfd739ea4cff1e9d23cb433bd046366e60 $")
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
36FR_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) {
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
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 */
133static 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 */
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 */
187static 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 */
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
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 */
283fr_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
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 */
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 */
371fr_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
380 if (!da) {
381 fr_dict_attr_t *unknown;
382
384 if (!unknown) {
386 return NULL;
387 }
388 da = unknown;
389 }
390
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 */
408fr_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 */
489fr_pair_t *fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
490{
491 fr_pair_t *n;
492
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 */
521int 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 */
546int 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 */
569int 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 */
593int 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
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
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 */
626static 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 */
649static void *fr_pair_iter_next_by_ancestor(fr_dlist_head_t *list, void *current, void *uctx)
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 */
670unsigned 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 */
741fr_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
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
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 */
973static 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
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 */
998static 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 */
1064next_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
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 */
1200static void *_fr_pair_iter_next_value(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
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,
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;
1267 fr_dcursor_t *parent = uctx;
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 */
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 */
1466int 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 */
1493int 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 */
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
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 */
1844int8_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 */
1864static 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 */
1921int8_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 */
1969int 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 %zd 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);
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 */
2093void 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 */
2128bool 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
2188mismatch:
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 */
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 */
2300void 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 */
2319int 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++;
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++;
2364
2365 if (fr_type_is_structural(vp->vp_type)) {
2367 if (!value) goto fail;
2368
2369 if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
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 */
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)) {
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 */
2508int 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++) {
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:
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 */
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 */
2634int 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 */
2658int 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 */
2698int 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 */
2730int 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 */
2755int 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 */
2784int 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 */
2810int 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 */
2835int 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 */
2855int 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 */
2880int 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 */
2903int 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 */
2930int 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 */
2981int 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 */
3011int 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 */
3036int 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 */
3078int 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 */
3125char 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 */
3176void 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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");
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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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[%d]: 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), "%u", vp->vp_type);
3373 snprintf(da_type_int, sizeof(da_type_int), "%u", vp->vp_type);
3374
3375 fr_fatal_assert_fail("CONSISTENCY CHECK FAILED %s[%d]: 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 */
3390void 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[%d]: 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[%d]: 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) {
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 */
3476bool 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
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 */
3572void fr_pair_list_afrom_box(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_t const *dict, fr_value_box_t *box)
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
3592static const char spaces[] = " ";
3593
3594static 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
3610void 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 */
3618void 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)
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:483
#define NDEBUG_UNUSED
Definition build.h:326
#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:112
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
static size_t min(size_t x, size_t y)
Definition dbuff.c:66
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:288
void *(* fr_dcursor_iter_t)(fr_dlist_head_t *list, void *to_eval, void *uctx)
Callback for implementing custom iterators.
Definition dcursor.h:51
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:337
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
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
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_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
static fr_dict_attr_t * fr_dict_attr_unknown_copy(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Definition dict.h:553
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.
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:580
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_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:231
void fr_dict_attr_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
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:153
char const * name
Enum name.
Definition dict.h:228
static fr_slen_t in
Definition dict.h:824
Value of an enumerated attribute.
Definition dict.h:227
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
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
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
Head of a doubly linked list.
Definition dlist.h:51
talloc_free(reap)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:122
fr_type_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
long int ssize_t
unsigned char uint8_t
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
#define check(_handle, _len_p)
Definition bio.c:44
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_list_parent(fr_pair_list_t const *list)
Return a pointer to the parent pair which contains this list.
Definition pair.c:956
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
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
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
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
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
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 void * _fr_pair_iter_next_value(fr_dlist_head_t *list, void *current, UNUSED void *uctx)
Iterate over pairs.
Definition pair.c:1200
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
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
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
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
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_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
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_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(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
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_cmp(fr_pair_t const *a, fr_pair_t const *b)
Compare two pairs, using the operator from "a".
Definition pair.c:1969
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_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
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_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
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
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
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
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
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
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
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
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_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
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_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
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
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
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_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
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
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
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_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
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
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
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:489
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
#define IN_A_LIST_MSG
Definition pair.c:534
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
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
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
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
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_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
Definition pair.c:1314
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
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_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
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_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_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
Definition pair.c:593
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_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
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
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_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
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.
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 fr_assert(_expr)
Definition rad_assert.h:38
static rc_request_t * current
#define FR_SBUFF_IN(_start, _len_or_end)
#define FR_SBUFF_OUT(_start, _len_or_end)
Set of parsing rules for *unescape_until functions.
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_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
#define FR_TLIST_HEAD(_name)
Expands to the type name used for the head wrapper structure.
Definition tlist.h:769
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
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
#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
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.
#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.
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 vp_group
Definition pair.h:137
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
#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.
#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:53
#define PAIR_LIST_VERIFY(_x)
Definition pair.h:194
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
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
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
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
#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
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
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