1 /*
2 * pair.c Functions to handle VALUE_PAIRs
3 *
4 * Version: $Id: 146c82f95b551ed0f704ed5ba0814014fbc778b7 $
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * Copyright 2000,2006 The FreeRADIUS server project
21 */
22
23 RCSID("$Id: 146c82f95b551ed0f704ed5ba0814014fbc778b7 $")
24
25 #include <freeradius-devel/libradius.h>
26 #include <freeradius-devel/regex.h>
27
28 #include <ctype.h>
29
30 /** Free a VALUE_PAIR
31 *
32 * @note Do not call directly, use talloc_free instead.
33 *
34 * @param vp to free.
35 * @return 0
36 */
_fr_pair_free(VALUE_PAIR * vp)37 static int _fr_pair_free(VALUE_PAIR *vp) {
38 #ifndef NDEBUG
39 vp->vp_integer = 0xf4eef4ee;
40 #endif
41
42 #ifdef TALLOC_DEBUG
43 talloc_report_depth_cb(NULL, 0, -1, fr_talloc_verify_cb, NULL);
44 #endif
45 return 0;
46 }
47
fr_pair_alloc(TALLOC_CTX * ctx)48 VALUE_PAIR *fr_pair_alloc(TALLOC_CTX *ctx)
49 {
50 VALUE_PAIR *vp;
51
52 vp = talloc_zero(ctx, VALUE_PAIR);
53 if (!vp) {
54 fr_strerror_printf("Out of memory");
55 return NULL;
56 }
57
58 vp->op = T_OP_EQ;
59 vp->tag = TAG_ANY;
60 vp->type = VT_NONE;
61
62 talloc_set_destructor(vp, _fr_pair_free);
63
64 return vp;
65 }
66
67
68 /** Dynamically allocate a new attribute
69 *
70 * Allocates a new attribute and a new dictionary attr if no DA is provided.
71 *
72 * @param[in] ctx for allocated memory, usually a pointer to a RADIUS_PACKET
73 * @param[in] da Specifies the dictionary attribute to build the VP from.
74 * @return a new value pair or NULL if an error occurred.
75 */
fr_pair_afrom_da(TALLOC_CTX * ctx,DICT_ATTR const * da)76 VALUE_PAIR *fr_pair_afrom_da(TALLOC_CTX *ctx, DICT_ATTR const *da)
77 {
78 VALUE_PAIR *vp;
79
80 /*
81 * Caller must specify a da else we don't know what the attribute type is.
82 */
83 if (!da) {
84 fr_strerror_printf("Invalid arguments");
85 return NULL;
86 }
87
88 vp = fr_pair_alloc(ctx);
89 if (!vp) {
90 fr_strerror_printf("Out of memory");
91 return NULL;
92 }
93
94 /*
95 * Use the 'da' to initialize more fields.
96 */
97 vp->da = da;
98 vp->vp_length = da->flags.length;
99
100 return vp;
101 }
102
103 /** Create a new valuepair
104 *
105 * If attr and vendor match a dictionary entry then a VP with that DICT_ATTR
106 * will be returned.
107 *
108 * If attr or vendor are uknown will call dict_attruknown to create a dynamic
109 * DICT_ATTR of PW_TYPE_OCTETS.
110 *
111 * Which type of DICT_ATTR the VALUE_PAIR was created with can be determined by
112 * checking @verbatim vp->da->flags.is_unknown @endverbatim.
113 *
114 * @param[in] ctx for allocated memory, usually a pointer to a RADIUS_PACKET
115 * @param[in] attr number.
116 * @param[in] vendor number.
117 * @return the new valuepair or NULL on error.
118 */
fr_pair_afrom_num(TALLOC_CTX * ctx,unsigned int attr,unsigned int vendor)119 VALUE_PAIR *fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int attr, unsigned int vendor)
120 {
121 DICT_ATTR const *da;
122
123 da = dict_attrbyvalue(attr, vendor);
124 if (!da) return NULL;
125
126 return fr_pair_afrom_da(ctx, da);
127 }
128
129 /** Free memory used by a valuepair list.
130 *
131 * @todo TLV: needs to free all dependents of each VP freed.
132 */
fr_pair_list_free(VALUE_PAIR ** vps)133 void fr_pair_list_free(VALUE_PAIR **vps)
134 {
135 VALUE_PAIR *vp;
136 vp_cursor_t cursor;
137
138 if (!vps || !*vps) {
139 return;
140 }
141
142 for (vp = fr_cursor_init(&cursor, vps);
143 vp;
144 vp = fr_cursor_next(&cursor)) {
145 VERIFY_VP(vp);
146 talloc_free(vp);
147 }
148
149 *vps = NULL;
150 }
151
152 /** Mark malformed or unrecognised attributed as unknown
153 *
154 * @param vp to change DICT_ATTR of.
155 * @return 0 on success (or if already unknown) else -1 on error.
156 */
fr_pair_to_unknown(VALUE_PAIR * vp)157 int fr_pair_to_unknown(VALUE_PAIR *vp)
158 {
159 DICT_ATTR const *da;
160
161 VERIFY_VP(vp);
162 if (vp->da->flags.is_unknown) {
163 return 0;
164 }
165
166 da = dict_unknown_afrom_fields(vp, vp->da->attr, vp->da->vendor);
167 if (!da) {
168 return -1;
169 }
170
171 vp->da = da;
172
173 return 0;
174 }
175
176 /** Find the pair with the matching DAs
177 *
178 */
fr_pair_find_by_da(VALUE_PAIR * vp,DICT_ATTR const * da,int8_t tag)179 VALUE_PAIR *fr_pair_find_by_da(VALUE_PAIR *vp, DICT_ATTR const *da, int8_t tag)
180 {
181 vp_cursor_t cursor;
182
183 if(!fr_assert(da)) {
184 return NULL;
185 }
186
187 (void) fr_cursor_init(&cursor, &vp);
188 return fr_cursor_next_by_da(&cursor, da, tag);
189 }
190
191
192 /** Find the pair with the matching attribute
193 *
194 * @todo should take DAs and do a pointer comparison.
195 */
fr_pair_find_by_num(VALUE_PAIR * vp,unsigned int attr,unsigned int vendor,int8_t tag)196 VALUE_PAIR *fr_pair_find_by_num(VALUE_PAIR *vp, unsigned int attr, unsigned int vendor, int8_t tag)
197 {
198 vp_cursor_t cursor;
199
200 /* List head may be NULL if it contains no VPs */
201 if (!vp) return NULL;
202
203 VERIFY_LIST(vp, "");
204
205 (void) fr_cursor_init(&cursor, &vp);
206 return fr_cursor_next_by_num(&cursor, attr, vendor, tag);
207 }
208
209 /** Delete matching pairs
210 *
211 * Delete matching pairs from the attribute list.
212 *
213 * @param[in,out] first VP in list.
214 * @param[in] attr to match.
215 * @param[in] vendor to match.
216 * @param[in] tag to match. TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
217 *
218 * @todo should take DAs and do a point comparison.
219 */
fr_pair_delete_by_num(VALUE_PAIR ** first,unsigned int attr,unsigned int vendor,int8_t tag)220 void fr_pair_delete_by_num(VALUE_PAIR **first, unsigned int attr, unsigned int vendor, int8_t tag)
221 {
222 VALUE_PAIR *i, *next;
223 VALUE_PAIR **last = first;
224
225 for(i = *first; i; i = next) {
226 VERIFY_VP(i);
227 next = i->next;
228 if ((i->da->attr == attr) && (i->da->vendor == vendor) &&
229 (!i->da->flags.has_tag || TAG_EQ(tag, i->tag))) {
230 *last = next;
231 talloc_free(i);
232 } else {
233 last = &i->next;
234 }
235 }
236 }
237
238 /** Add a VP to the end of the list.
239 *
240 * Locates the end of 'first', and links an additional VP 'add' at the end.
241 *
242 * @param[in] first VP in linked list. Will add new VP to the end of this list.
243 * @param[in] add VP to add to list.
244 */
fr_pair_add(VALUE_PAIR ** first,VALUE_PAIR * add)245 void fr_pair_add(VALUE_PAIR **first, VALUE_PAIR *add)
246 {
247 VALUE_PAIR *i;
248
249 if (!add) return;
250
251 VERIFY_VP(add);
252
253 if (*first == NULL) {
254 *first = add;
255 return;
256 }
257
258 for (i = *first; i->next; i = i->next) {
259 #ifdef WITH_VERIFY_PTR
260 VERIFY_VP(i);
261 /*
262 * The same VP should never by added multiple times
263 * to the same list.
264 */
265 fr_assert(i != add);
266 #endif
267 }
268
269 i->next = add;
270 }
271
272 /** Add a VP to the start of the list.
273 *
274 * Links the new VP to 'first', then points 'first' at the new VP.
275 *
276 * @param[in] first VP in linked list. Will add new VP to the start of this list.
277 * @param[in] add VP to add to list.
278 */
fr_pair_prepend(VALUE_PAIR ** first,VALUE_PAIR * add)279 void fr_pair_prepend(VALUE_PAIR **first, VALUE_PAIR *add)
280 {
281 VALUE_PAIR *i;
282
283 if (!add) return;
284
285 VERIFY_VP(add);
286
287 if (*first == NULL) {
288 *first = add;
289 return;
290 }
291
292 /*
293 * Find the end of the list to be prepended
294 */
295 for (i = add; i->next; i = i->next) {
296 #ifdef WITH_VERIFY_PTR
297 VERIFY_VP(i);
298 /*
299 * The same VP should never by added multiple times
300 * to the same list.
301 */
302 fr_assert(*first != i);
303 #endif
304 }
305 i->next = *first;
306 *first = add;
307 }
308
309 /** Replace all matching VPs
310 *
311 * Walks over 'first', and replaces the first VP that matches 'replace'.
312 *
313 * @note Memory used by the VP being replaced will be freed.
314 * @note Will not work with unknown attributes.
315 *
316 * @param[in,out] first VP in linked list. Will search and replace in this list.
317 * @param[in] replace VP to replace.
318 */
fr_pair_replace(VALUE_PAIR ** first,VALUE_PAIR * replace)319 void fr_pair_replace(VALUE_PAIR **first, VALUE_PAIR *replace)
320 {
321 VALUE_PAIR *i, *next;
322 VALUE_PAIR **prev = first;
323
324 VERIFY_VP(replace);
325
326 if (*first == NULL) {
327 *first = replace;
328 return;
329 }
330
331 /*
332 * Not an empty list, so find item if it is there, and
333 * replace it. Note, we always replace the first one, and
334 * we ignore any others that might exist.
335 */
336 for(i = *first; i; i = next) {
337 VERIFY_VP(i);
338 next = i->next;
339
340 /*
341 * Found the first attribute, replace it,
342 * and return.
343 */
344 if ((i->da == replace->da) && (!i->da->flags.has_tag || TAG_EQ(replace->tag, i->tag))) {
345 *prev = replace;
346
347 /*
348 * Should really assert that replace->next == NULL
349 */
350 replace->next = next;
351 talloc_free(i);
352 return;
353 }
354
355 /*
356 * Point to where the attribute should go.
357 */
358 prev = &i->next;
359 }
360
361 /*
362 * If we got here, we didn't find anything to replace, so
363 * stopped at the last item, which we just append to.
364 */
365 *prev = replace;
366 }
367
fr_pair_cmp_by_da_tag(void const * a,void const * b)368 int8_t fr_pair_cmp_by_da_tag(void const *a, void const *b)
369 {
370 VALUE_PAIR const *my_a = a;
371 VALUE_PAIR const *my_b = b;
372
373 VERIFY_VP(my_a);
374 VERIFY_VP(my_b);
375
376 uint8_t cmp;
377
378 cmp = fr_pointer_cmp(my_a->da, my_b->da);
379 if (cmp != 0) return cmp;
380
381 if (my_a->tag < my_b->tag) return -1;
382
383 if (my_a->tag > my_b->tag) return 1;
384
385 return 0;
386 }
387
fr_pair_list_sort_split(VALUE_PAIR * source,VALUE_PAIR ** front,VALUE_PAIR ** back)388 static void fr_pair_list_sort_split(VALUE_PAIR *source, VALUE_PAIR **front, VALUE_PAIR **back)
389 {
390 VALUE_PAIR *fast;
391 VALUE_PAIR *slow;
392
393 /*
394 * Stopping condition - no more elements left to split
395 */
396 if (!source || !source->next) {
397 *front = source;
398 *back = NULL;
399
400 return;
401 }
402
403 /*
404 * Fast advances twice as fast as slow, so when it gets to the end,
405 * slow will point to the middle of the linked list.
406 */
407 slow = source;
408 fast = source->next;
409
410 while (fast) {
411 fast = fast->next;
412 if (fast) {
413 slow = slow->next;
414 fast = fast->next;
415 }
416 }
417
418 *front = source;
419 *back = slow->next;
420 slow->next = NULL;
421 }
422
fr_pair_list_sort_merge(VALUE_PAIR * a,VALUE_PAIR * b,fr_cmp_t cmp)423 static VALUE_PAIR *fr_pair_list_sort_merge(VALUE_PAIR *a, VALUE_PAIR *b, fr_cmp_t cmp)
424 {
425 VALUE_PAIR *result = NULL;
426
427 if (!a) return b;
428 if (!b) return a;
429
430 /*
431 * Compare the DICT_ATTRs and tags
432 */
433 if (cmp(a, b) <= 0) {
434 result = a;
435 result->next = fr_pair_list_sort_merge(a->next, b, cmp);
436 } else {
437 result = b;
438 result->next = fr_pair_list_sort_merge(a, b->next, cmp);
439 }
440
441 return result;
442 }
443
444 /** Sort a linked list of VALUE_PAIRs using merge sort
445 *
446 * @param[in,out] vps List of VALUE_PAIRs to sort.
447 * @param[in] cmp to sort with
448 */
fr_pair_list_sort(VALUE_PAIR ** vps,fr_cmp_t cmp)449 void fr_pair_list_sort(VALUE_PAIR **vps, fr_cmp_t cmp)
450 {
451 VALUE_PAIR *head = *vps;
452 VALUE_PAIR *a;
453 VALUE_PAIR *b;
454
455 /*
456 * If there's 0-1 elements it must already be sorted.
457 */
458 if (!head || !head->next) {
459 return;
460 }
461
462 fr_pair_list_sort_split(head, &a, &b); /* Split into sublists */
463 fr_pair_list_sort(&a, cmp); /* Traverse left */
464 fr_pair_list_sort(&b, cmp); /* Traverse right */
465
466 /*
467 * merge the two sorted lists together
468 */
469 *vps = fr_pair_list_sort_merge(a, b, cmp);
470 }
471
472 /** Write an error to the library errorbuff detailing the mismatch
473 *
474 * Retrieve output with fr_strerror();
475 *
476 * @todo add thread specific talloc contexts.
477 *
478 * @param ctx a hack until we have thread specific talloc contexts.
479 * @param failed pair of attributes which didn't match.
480 */
fr_pair_validate_debug(TALLOC_CTX * ctx,VALUE_PAIR const * failed[2])481 void fr_pair_validate_debug(TALLOC_CTX *ctx, VALUE_PAIR const *failed[2])
482 {
483 VALUE_PAIR const *filter = failed[0];
484 VALUE_PAIR const *list = failed[1];
485
486 char *value, *str;
487
488 (void) fr_strerror(); /* Clear any existing messages */
489
490 if (!fr_assert(!(!filter && !list))) return;
491
492 if (!list) {
493 if (!filter) return;
494 fr_strerror_printf("Attribute \"%s\" not found in list", filter->da->name);
495 return;
496 }
497
498 if (!filter || (filter->da != list->da)) {
499 fr_strerror_printf("Attribute \"%s\" not found in filter", list->da->name);
500 return;
501 }
502
503 if (!TAG_EQ(filter->tag, list->tag)) {
504 fr_strerror_printf("Attribute \"%s\" tag \"%i\" didn't match filter tag \"%i\"",
505 list->da->name, list->tag, filter->tag);
506 return;
507 }
508
509
510 value = vp_aprints_value(ctx, list, '"');
511 str = vp_aprints(ctx, filter, '"');
512
513 fr_strerror_printf("Attribute value \"%s\" didn't match filter: %s", value, str);
514
515 talloc_free(str);
516 talloc_free(value);
517
518 return;
519 }
520
521 /** Uses fr_pair_cmp to verify all VALUE_PAIRs in list match the filter defined by check
522 *
523 * @note will sort both filter and list in place.
524 *
525 * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
526 * May be NULL.
527 * @param filter attributes to check list against.
528 * @param list attributes, probably a request or reply
529 */
fr_pair_validate(VALUE_PAIR const * failed[2],VALUE_PAIR * filter,VALUE_PAIR * list)530 bool fr_pair_validate(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
531 {
532 vp_cursor_t filter_cursor;
533 vp_cursor_t list_cursor;
534
535 VALUE_PAIR *check, *match;
536
537 if (!filter && !list) {
538 return true;
539 }
540
541 /*
542 * This allows us to verify the sets of validate and reply are equal
543 * i.e. we have a validate rule which matches every reply attribute.
544 *
545 * @todo this should be removed one we have sets and lists
546 */
547 fr_pair_list_sort(&filter, fr_pair_cmp_by_da_tag);
548 fr_pair_list_sort(&list, fr_pair_cmp_by_da_tag);
549
550 check = fr_cursor_init(&filter_cursor, &filter);
551 match = fr_cursor_init(&list_cursor, &list);
552 while (match || check) {
553 /*
554 * Lists are of different lengths
555 */
556 if (!match || !check) goto mismatch;
557
558 /*
559 * The lists are sorted, so if the first
560 * attributes aren't of the same type, then we're
561 * done.
562 */
563 if (!ATTRIBUTE_EQ(check, match)) goto mismatch;
564
565 /*
566 * They're of the same type, but don't have the
567 * same values. This is a problem.
568 *
569 * Note that the RFCs say that for attributes of
570 * the same type, order is important.
571 */
572 if (fr_pair_cmp(check, match) != 1) goto mismatch;
573
574 check = fr_cursor_next(&filter_cursor);
575 match = fr_cursor_next(&list_cursor);
576 }
577
578 return true;
579
580 mismatch:
581 if (failed) {
582 failed[0] = check;
583 failed[1] = match;
584 }
585 return false;
586 }
587
588 /** Uses fr_pair_cmp to verify all VALUE_PAIRs in list match the filter defined by check
589 *
590 * @note will sort both filter and list in place.
591 *
592 * @param failed pointer to an array to write the pointers of the filter/list attributes that didn't match.
593 * May be NULL.
594 * @param filter attributes to check list against.
595 * @param list attributes, probably a request or reply
596 */
fr_pair_validate_relaxed(VALUE_PAIR const * failed[2],VALUE_PAIR * filter,VALUE_PAIR * list)597 bool fr_pair_validate_relaxed(VALUE_PAIR const *failed[2], VALUE_PAIR *filter, VALUE_PAIR *list)
598 {
599 vp_cursor_t filter_cursor;
600 vp_cursor_t list_cursor;
601
602 VALUE_PAIR *check, *last_check = NULL, *match = NULL;
603
604 if (!filter && !list) {
605 return true;
606 }
607
608 /*
609 * This allows us to verify the sets of validate and reply are equal
610 * i.e. we have a validate rule which matches every reply attribute.
611 *
612 * @todo this should be removed one we have sets and lists
613 */
614 fr_pair_list_sort(&filter, fr_pair_cmp_by_da_tag);
615 fr_pair_list_sort(&list, fr_pair_cmp_by_da_tag);
616
617 fr_cursor_init(&list_cursor, &list);
618 for (check = fr_cursor_init(&filter_cursor, &filter);
619 check;
620 check = fr_cursor_next(&filter_cursor)) {
621 /*
622 * Were processing check attributes of a new type.
623 */
624 if (!ATTRIBUTE_EQ(last_check, check)) {
625 /*
626 * Record the start of the matching attributes in the pair list
627 * For every other operator we require the match to be present
628 */
629 match = fr_cursor_next_by_da(&list_cursor, check->da, check->tag);
630 if (!match) {
631 if (check->op == T_OP_CMP_FALSE) continue;
632 goto mismatch;
633 }
634
635 fr_cursor_init(&list_cursor, &match);
636 last_check = check;
637 }
638
639 /*
640 * Now iterate over all attributes of the same type.
641 */
642 for (match = fr_cursor_first(&list_cursor);
643 ATTRIBUTE_EQ(match, check);
644 match = fr_cursor_next(&list_cursor)) {
645 /*
646 * This attribute passed the filter
647 */
648 if (!fr_pair_cmp(check, match)) goto mismatch;
649 }
650 }
651
652 return true;
653
654 mismatch:
655 if (failed) {
656 failed[0] = check;
657 failed[1] = match;
658 }
659 return false;
660 }
661
662 /** Copy a single valuepair
663 *
664 * Allocate a new valuepair and copy the da from the old vp.
665 *
666 * @param[in] ctx for talloc
667 * @param[in] vp to copy.
668 * @return a copy of the input VP or NULL on error.
669 */
fr_pair_copy(TALLOC_CTX * ctx,VALUE_PAIR const * vp)670 VALUE_PAIR *fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
671 {
672 VALUE_PAIR *n;
673
674 if (!vp) return NULL;
675
676 VERIFY_VP(vp);
677
678 n = fr_pair_afrom_da(ctx, vp->da);
679 if (!n) return NULL;
680
681 memcpy(n, vp, sizeof(*n));
682
683 /*
684 * If the DA is unknown, steal "n" to "ctx". This does
685 * nothing for "n", but will also copy the unknown "da".
686 */
687 if (n->da->flags.is_unknown) {
688 fr_pair_steal(ctx, n);
689 }
690
691 n->next = NULL;
692
693 /*
694 * If it's an xlat, copy the raw string and return early,
695 * so we don't pre-expand or otherwise mangle the VALUE_PAIR.
696 */
697 if (vp->type == VT_XLAT) {
698 n->value.xlat = talloc_typed_strdup(n, n->value.xlat);
699 return n;
700 }
701
702 switch (vp->da->type) {
703 case PW_TYPE_OCTETS:
704 n->vp_octets = NULL; /* else fr_pair_value_memcpy will free vp's value */
705 fr_pair_value_memcpy(n, vp->vp_octets, n->vp_length);
706 break;
707
708 case PW_TYPE_STRING:
709 n->vp_strvalue = NULL; /* else pairstrnpy will free vp's value */
710 fr_pair_value_bstrncpy(n, vp->vp_strvalue, n->vp_length);
711 break;
712
713 default:
714 break;
715 }
716
717 return n;
718 }
719
720 /** Copy a pairlist.
721 *
722 * Copy all pairs from 'from' regardless of tag, attribute or vendor.
723 *
724 * @param[in] ctx for new VALUE_PAIRs to be allocated in.
725 * @param[in] from whence to copy VALUE_PAIRs.
726 * @return the head of the new VALUE_PAIR list or NULL on error.
727 */
fr_pair_list_copy(TALLOC_CTX * ctx,VALUE_PAIR * from)728 VALUE_PAIR *fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
729 {
730 vp_cursor_t src, dst;
731
732 VALUE_PAIR *out = NULL, *vp;
733
734 fr_cursor_init(&dst, &out);
735 for (vp = fr_cursor_init(&src, &from);
736 vp;
737 vp = fr_cursor_next(&src)) {
738 VERIFY_VP(vp);
739 vp = fr_pair_copy(ctx, vp);
740 if (!vp) {
741 fr_pair_list_free(&out);
742 return NULL;
743 }
744 fr_cursor_insert(&dst, vp); /* fr_pair_list_copy sets next pointer to NULL */
745 }
746
747 return out;
748 }
749
750 /** Copy matching pairs
751 *
752 * Copy pairs of a matching attribute number, vendor number and tag from the
753 * the input list to a new list, and returns the head of this list.
754 *
755 * @param[in] ctx for talloc
756 * @param[in] from whence to copy VALUE_PAIRs.
757 * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
758 * will match (and therefore copy) only VSAs.
759 * If attribute 0 and vendor 0 will match (and therefore copy) all
760 * attributes.
761 * @param[in] vendor to match.
762 * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
763 * @return the head of the new VALUE_PAIR list or NULL on error.
764 */
fr_pair_list_copy_by_num(TALLOC_CTX * ctx,VALUE_PAIR * from,unsigned int attr,unsigned int vendor,int8_t tag)765 VALUE_PAIR *fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from,
766 unsigned int attr, unsigned int vendor, int8_t tag)
767 {
768 vp_cursor_t src, dst;
769
770 VALUE_PAIR *out = NULL, *vp;
771
772 fr_cursor_init(&dst, &out);
773 for (vp = fr_cursor_init(&src, &from);
774 vp;
775 vp = fr_cursor_next(&src)) {
776 VERIFY_VP(vp);
777
778 if (vp->da->flags.has_tag && !TAG_EQ(tag, vp->tag)) {
779 continue;
780 }
781
782 /*
783 * Attr/vendor of 0 means "move them all".
784 * It's better than "fr_pair_copy(foo,bar);bar=NULL"
785 */
786 if ((attr == 0) && (vendor == 0)) {
787 goto do_copy;
788 }
789
790 /*
791 * vendor=0, attr = PW_VENDOR_SPECIFIC means
792 * "match any vendor attribute".
793 */
794 if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
795 /*
796 * It's a VSA: copy it over.
797 */
798 if (vp->da->vendor != 0) goto do_copy;
799
800 /*
801 * It's Vendor-Specific: copy it over.
802 */
803 if (vp->da->attr == attr) goto do_copy;
804
805 /*
806 * It's not a VSA: ignore it.
807 */
808 continue;
809 }
810
811 if ((vp->da->attr != attr) || (vp->da->vendor != vendor)) {
812 continue;
813 }
814
815 do_copy:
816 vp = fr_pair_copy(ctx, vp);
817 if (!vp) {
818 fr_pair_list_free(&out);
819 return NULL;
820 }
821 fr_cursor_insert(&dst, vp);
822 }
823
824 return out;
825 }
826
827 /** Steal one VP
828 *
829 * @param[in] ctx to move VALUE_PAIR into
830 * @param[in] vp VALUE_PAIR to move into the new context.
831 */
fr_pair_steal(TALLOC_CTX * ctx,VALUE_PAIR * vp)832 void fr_pair_steal(TALLOC_CTX *ctx, VALUE_PAIR *vp)
833 {
834 (void) talloc_steal(ctx, vp);
835
836 /*
837 * The DA may be unknown. If we're stealing the VPs to a
838 * different context, copy the unknown DA. We use the VP
839 * as a context here instead of "ctx", so that when the
840 * VP is freed, so is the DA.
841 *
842 * Since we have no introspection into OTHER VPs using
843 * the same DA, we can't have multiple VPs use the same
844 * DA. So we might as well tie it to this VP.
845 */
846 if (vp->da->flags.is_unknown) {
847 DICT_ATTR *da;
848 char *p;
849 size_t size;
850
851 size = talloc_get_size(vp->da);
852
853 p = talloc_zero_array(vp, char, size);
854 da = (DICT_ATTR *) p;
855 talloc_set_type(p, DICT_ATTR);
856 memcpy(da, vp->da, size);
857 vp->da = da;
858 }
859 }
860
861 /** Move pairs from source list to destination list respecting operator
862 *
863 * @note This function does some additional magic that's probably not needed
864 * in most places. Consider using radius_pairmove in server code.
865 *
866 * @note fr_pair_list_free should be called on the head of the source list to free
867 * unmoved attributes (if they're no longer needed).
868 *
869 * @note Does not respect tags when matching.
870 *
871 * @param[in] ctx for talloc
872 * @param[in,out] to destination list.
873 * @param[in,out] from source list.
874 * @param[in] op operator for move.
875 *
876 * @see radius_pairmove
877 */
fr_pair_list_move(TALLOC_CTX * ctx,VALUE_PAIR ** to,VALUE_PAIR ** from,FR_TOKEN op)878 void fr_pair_list_move(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, FR_TOKEN op)
879 {
880 VALUE_PAIR *i, *found;
881 VALUE_PAIR *head_new, **tail_new;
882 VALUE_PAIR *head_prepend;
883 VALUE_PAIR **tail_from;
884
885 if (!to || !from || !*from) return;
886
887 /*
888 * We're editing the "to" list while we're adding new
889 * attributes to it. We don't want the new attributes to
890 * be edited, so we create an intermediate list to hold
891 * them during the editing process.
892 */
893 head_new = NULL;
894 tail_new = &head_new;
895
896 /*
897 * Any attributes that are requested to be prepended
898 * are added to a temporary list here
899 */
900 head_prepend = NULL;
901
902 /*
903 * We're looping over the "from" list, moving some
904 * attributes out, but leaving others in place.
905 */
906 tail_from = from;
907 while ((i = *tail_from) != NULL) {
908 VALUE_PAIR *j;
909
910 VERIFY_VP(i);
911
912 /*
913 * We never move Fall-Through.
914 */
915 if (!i->da->vendor && i->da->attr == PW_FALL_THROUGH) {
916 tail_from = &(i->next);
917 continue;
918 }
919
920 /*
921 * Unlike previous versions, we treat all other
922 * attributes as normal. i.e. there's no special
923 * treatment for passwords or Hint.
924 */
925
926 switch (i->op) {
927 /*
928 * Anything else are operators which
929 * shouldn't occur. We ignore them, and
930 * leave them in place.
931 */
932 default:
933 tail_from = &(i->next);
934 continue;
935
936 /*
937 * Add it to the "to" list, but only if
938 * it doesn't already exist.
939 */
940 case T_OP_EQ:
941 found = fr_pair_find_by_da(*to, i->da, TAG_ANY);
942 if (!found) goto do_add;
943
944 tail_from = &(i->next);
945 continue;
946
947 /*
948 * Add it to the "to" list, and delete any attribute
949 * of the same vendor/attr which already exists.
950 */
951 case T_OP_SET:
952 found = fr_pair_find_by_da(*to, i->da, TAG_ANY);
953 if (!found) goto do_add;
954
955 /*
956 * Do NOT call fr_pair_delete_by_num() here,
957 * due to issues with re-writing
958 * "request->username".
959 *
960 * Everybody calls fr_pair_move, and
961 * expects it to work. We can't
962 * update request->username here,
963 * so instead we over-write the
964 * vp that it's pointing to.
965 */
966 switch (found->da->type) {
967 default:
968 j = found->next;
969 memcpy(found, i, sizeof(*found));
970 found->next = j;
971 break;
972
973 case PW_TYPE_OCTETS:
974 fr_pair_value_memsteal(found, i->vp_octets);
975 i->vp_octets = NULL;
976 break;
977
978 case PW_TYPE_STRING:
979 fr_pair_value_strsteal(found, i->vp_strvalue);
980 i->vp_strvalue = NULL;
981 found->tag = i->tag;
982 break;
983 }
984
985 /*
986 * Delete *all* of the attributes
987 * of the same number.
988 */
989 fr_pair_delete_by_num(&found->next,
990 found->da->attr,
991 found->da->vendor, TAG_ANY);
992
993 /*
994 * Remove this attribute from the
995 * "from" list.
996 */
997 *tail_from = i->next;
998 i->next = NULL;
999 fr_pair_list_free(&i);
1000 continue;
1001
1002 /*
1003 * Move it from the old list and add it
1004 * to the new list.
1005 */
1006 case T_OP_ADD:
1007 do_add:
1008 *tail_from = i->next;
1009 i->next = NULL;
1010 *tail_new = i;
1011 fr_pair_steal(ctx, i);
1012 tail_new = &(i->next);
1013 continue;
1014 case T_OP_PREPEND:
1015 i->next = head_prepend;
1016 head_prepend = i;
1017 fr_pair_steal(ctx, i);
1018 continue;
1019 }
1020 } /* loop over the "from" list. */
1021
1022 /*
1023 * If the op parameter was prepend, add the "new" list
1024 * attributes first as those whose individual operator
1025 * is prepend should be prepended to the resulting list
1026 */
1027 if (op == T_OP_PREPEND) {
1028 fr_pair_prepend(to, head_new);
1029 }
1030
1031 /*
1032 * If there are any items in the prepend list prepend
1033 * it to the "to" list
1034 */
1035 fr_pair_prepend(to, head_prepend);
1036
1037 /*
1038 * If the op parameter was not prepend, take the "new"
1039 * list, and append it to the "to" list.
1040 */
1041 if (op != T_OP_PREPEND) {
1042 fr_pair_add(to, head_new);
1043 }
1044 }
1045
1046 /** Move matching pairs between VALUE_PAIR lists
1047 *
1048 * Move pairs of a matching attribute number, vendor number and tag from the
1049 * the input list to the output list.
1050 *
1051 * @note fr_pair_list_free should be called on the head of the old list to free unmoved
1052 attributes (if they're no longer needed).
1053 *
1054 * @param[in] ctx for talloc
1055 * @param[in,out] to destination list.
1056 * @param[in,out] from source list.
1057 * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
1058 * will match (and therefore copy) only VSAs.
1059 * If attribute 0 and vendor 0 will match (and therefore copy) all
1060 * attributes.
1061 * @param[in] vendor to match.
1062 * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
1063 * @param[in] move if set to "true", VPs are moved. If set to "false", VPs are copied, and the old one deleted.
1064 */
fr_pair_list_move_by_num_internal(TALLOC_CTX * ctx,VALUE_PAIR ** to,VALUE_PAIR ** from,unsigned int attr,unsigned int vendor,int8_t tag,bool move)1065 static void fr_pair_list_move_by_num_internal(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
1066 unsigned int attr, unsigned int vendor, int8_t tag,
1067 bool move)
1068 {
1069 VALUE_PAIR *to_tail, *i, *next, *this;
1070 VALUE_PAIR *iprev = NULL;
1071
1072 /*
1073 * Find the last pair in the "to" list and put it in "to_tail".
1074 *
1075 * @todo: replace the "if" with "VALUE_PAIR **tail"
1076 */
1077 if (*to != NULL) {
1078 to_tail = *to;
1079 for(i = *to; i; i = i->next) {
1080 VERIFY_VP(i);
1081 to_tail = i;
1082 }
1083 } else
1084 to_tail = NULL;
1085
1086 /*
1087 * Attr/vendor of 0 means "move them all".
1088 * It's better than "fr_pair_add(foo,bar);bar=NULL"
1089 */
1090 if ((vendor == 0) && (attr == 0)) {
1091 if (*to) {
1092 to_tail->next = *from;
1093 } else {
1094 *to = *from;
1095 }
1096
1097 for (i = *from; i; i = i->next) {
1098 fr_pair_steal(ctx, i);
1099 }
1100
1101 *from = NULL;
1102 return;
1103 }
1104
1105 for(i = *from; i; i = next) {
1106 VERIFY_VP(i);
1107 next = i->next;
1108
1109 if (i->da->flags.has_tag && !TAG_EQ(tag, i->tag)) {
1110 iprev = i;
1111 continue;
1112 }
1113
1114 /*
1115 * vendor=0, attr = PW_VENDOR_SPECIFIC means
1116 * "match any vendor attribute".
1117 */
1118 if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
1119 /*
1120 * It's a VSA: move it over.
1121 */
1122 if (i->da->vendor != 0) goto move;
1123
1124 /*
1125 * It's Vendor-Specific: move it over.
1126 */
1127 if (i->da->attr == attr) goto move;
1128
1129 /*
1130 * It's not a VSA: ignore it.
1131 */
1132 iprev = i;
1133 continue;
1134 }
1135
1136 /*
1137 * If it isn't an exact match, ignore it.
1138 */
1139 if (!((i->da->vendor == vendor) && (i->da->attr == attr))) {
1140 iprev = i;
1141 continue;
1142 }
1143
1144 move:
1145 /*
1146 * Remove the attribute from the "from" list.
1147 */
1148 if (iprev)
1149 iprev->next = next;
1150 else
1151 *from = next;
1152
1153 if (move) {
1154 this = i;
1155 } else {
1156 this = fr_pair_copy(ctx, i);
1157 }
1158
1159 /*
1160 * Add the attribute to the "to" list.
1161 */
1162 if (to_tail)
1163 to_tail->next = this;
1164 else
1165 *to = this;
1166 to_tail = this;
1167 this->next = NULL;
1168
1169 if (move) {
1170 fr_pair_steal(ctx, i);
1171 } else {
1172 talloc_free(i);
1173 }
1174 }
1175 }
1176
1177
1178 /** Move matching pairs between VALUE_PAIR lists
1179 *
1180 * Move pairs of a matching attribute number, vendor number and tag from the
1181 * the input list to the output list.
1182 *
1183 * @note pairs which are moved have their parent changed to ctx.
1184 *
1185 * @note fr_pair_list_free should be called on the head of the old list to free unmoved
1186 attributes (if they're no longer needed).
1187 *
1188 * @param[in] ctx for talloc
1189 * @param[in,out] to destination list.
1190 * @param[in,out] from source list.
1191 * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
1192 * will match (and therefore copy) only VSAs.
1193 * If attribute 0 and vendor 0 will match (and therefore copy) all
1194 * attributes.
1195 * @param[in] vendor to match.
1196 * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
1197 */
fr_pair_list_move_by_num(TALLOC_CTX * ctx,VALUE_PAIR ** to,VALUE_PAIR ** from,unsigned int attr,unsigned int vendor,int8_t tag)1198 void fr_pair_list_move_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
1199 unsigned int attr, unsigned int vendor, int8_t tag)
1200 {
1201 fr_pair_list_move_by_num_internal(ctx, to, from, attr, vendor, tag, true);
1202 }
1203
1204
1205 /** Copy / delete matching pairs between VALUE_PAIR lists
1206 *
1207 * Move pairs of a matching attribute number, vendor number and tag from the
1208 * the input list to the output list. Like fr_pair_list_move_by_num(), but
1209 * instead does copy / delete.
1210 *
1211 * @note The pair is NOT reparented. It is copied and deleted.
1212 *
1213 * @note fr_pair_list_free should be called on the head of the old list to free unmoved
1214 attributes (if they're no longer needed).
1215 *
1216 * @param[in] ctx for talloc
1217 * @param[in,out] to destination list.
1218 * @param[in,out] from source list.
1219 * @param[in] attr to match. If attribute PW_VENDOR_SPECIFIC and vendor 0,
1220 * will match (and therefore copy) only VSAs.
1221 * If attribute 0 and vendor 0 will match (and therefore copy) all
1222 * attributes.
1223 * @param[in] vendor to match.
1224 * @param[in] tag to match, TAG_ANY matches any tag, TAG_NONE matches tagless VPs.
1225 */
fr_pair_list_mcopy_by_num(TALLOC_CTX * ctx,VALUE_PAIR ** to,VALUE_PAIR ** from,unsigned int attr,unsigned int vendor,int8_t tag)1226 void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from,
1227 unsigned int attr, unsigned int vendor, int8_t tag)
1228 {
1229 fr_pair_list_move_by_num_internal(ctx, to, from, attr, vendor, tag, false);
1230 }
1231
1232
1233 /** Convert string value to native attribute value
1234 *
1235 * @param vp to assign value to.
1236 * @param value string to convert. Binary safe for variable length values if len is provided.
1237 * @param inlen may be < 0 in which case strlen(len) is used to determine length, else inline
1238 * should be the length of the string or sub string to parse.
1239 * @return 0 on success -1 on error.
1240 */
fr_pair_value_from_str(VALUE_PAIR * vp,char const * value,size_t inlen)1241 int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t inlen)
1242 {
1243 ssize_t ret;
1244 PW_TYPE type;
1245 VERIFY_VP(vp);
1246
1247 if (!value) return -1;
1248
1249 type = vp->da->type;
1250
1251 /*
1252 * We presume that the input data is from a double quoted
1253 * string, and needs escaping
1254 */
1255 ret = value_data_from_str(vp, &vp->data, &type, vp->da, value, inlen, '"');
1256 if (ret < 0) return -1;
1257
1258 /*
1259 * If we parsed to a different type than the DA associated with
1260 * the VALUE_PAIR we now need to fixup the DA.
1261 */
1262 if (type != vp->da->type) {
1263 DICT_ATTR const *da;
1264
1265 da = dict_attrbytype(vp->da->attr, vp->da->vendor, type);
1266 if (!da) {
1267 fr_strerror_printf("Cannot find %s variant of attribute \"%s\"",
1268 fr_int2str(dict_attr_types, type, "<INVALID>"), vp->da->name);
1269 return -1;
1270 }
1271 vp->da = da;
1272 }
1273
1274 vp->vp_length = ret;
1275 vp->type = VT_DATA;
1276
1277 VERIFY_VP(vp);
1278
1279 return 0;
1280 }
1281
1282 /** Use simple heuristics to create an VALUE_PAIR from an unknown address string
1283 *
1284 * If a DICT_ATTR is not provided for the address type, parsing will fail with
1285 * and error.
1286 *
1287 * @param ctx to allocate VP in.
1288 * @param value IPv4/IPv6 address/prefix string.
1289 * @param ipv4 dictionary attribute to use for an IPv4 address.
1290 * @param ipv6 dictionary attribute to use for an IPv6 address.
1291 * @param ipv4_prefix dictionary attribute to use for an IPv4 prefix.
1292 * @param ipv6_prefix dictionary attribute to use for an IPv6 prefix.
1293 * @return NULL on error, or new VALUE_PAIR.
1294 */
fr_pair_afrom_ip_str(TALLOC_CTX * ctx,char const * value,DICT_ATTR * ipv4,DICT_ATTR * ipv6,DICT_ATTR * ipv4_prefix,DICT_ATTR * ipv6_prefix)1295 VALUE_PAIR *fr_pair_afrom_ip_str(TALLOC_CTX *ctx, char const *value, DICT_ATTR *ipv4, DICT_ATTR *ipv6,
1296 DICT_ATTR *ipv4_prefix, DICT_ATTR *ipv6_prefix)
1297 {
1298 VALUE_PAIR *vp;
1299 DICT_ATTR *da = NULL;
1300
1301 if (!fr_assert(ipv4 || ipv6 || ipv4_prefix || ipv6_prefix)) {
1302 return NULL;
1303 }
1304
1305 /* No point in repeating the work of fr_pair_value_from_str */
1306 if (strchr(value, ':')) {
1307 if (strchr(value, '/')) {
1308 da = ipv6_prefix;
1309 goto finish;
1310 }
1311
1312 da = ipv6;
1313 goto finish;
1314 }
1315
1316 if (strchr(value, '/')) {
1317 da = ipv4_prefix;
1318 goto finish;
1319 }
1320
1321 if (ipv4) {
1322 da = ipv4;
1323 goto finish;
1324 }
1325
1326 fr_strerror_printf("Invalid IP value specified, allowed types are %s%s%s%s",
1327 ipv4 ? "ipaddr " : "", ipv6 ? "ipv6addr " : "",
1328 ipv4_prefix ? "ipv4prefix " : "", ipv6_prefix ? "ipv6prefix" : "");
1329
1330 finish:
1331 vp = fr_pair_afrom_da(ctx, da);
1332 if (!vp) return NULL;
1333 if (fr_pair_value_from_str(vp, value, -1) < 0) {
1334 talloc_free(vp);
1335 return NULL;
1336 }
1337
1338 return vp;
1339 }
1340
1341
1342 /** Create a valuepair from an ASCII attribute and value
1343 *
1344 * Where the attribute name is in the form:
1345 * - Attr-%d
1346 * - Attr-%d.%d.%d...
1347 * - Vendor-%d-Attr-%d
1348 * - VendorName-Attr-%d
1349 *
1350 * @param ctx for talloc
1351 * @param attribute name to parse.
1352 * @param value to parse (must be a hex string).
1353 * @param op to assign to new valuepair.
1354 * @return new valuepair or NULL on error.
1355 */
fr_pair_make_unknown(TALLOC_CTX * ctx,char const * attribute,char const * value,FR_TOKEN op)1356 static VALUE_PAIR *fr_pair_make_unknown(TALLOC_CTX *ctx,
1357 char const *attribute, char const *value,
1358 FR_TOKEN op)
1359 {
1360 VALUE_PAIR *vp, *vp2;
1361 DICT_ATTR const *da;
1362
1363 uint8_t *data;
1364 size_t size;
1365 ssize_t len;
1366
1367 vp = fr_pair_alloc(ctx);
1368 if (!vp) return NULL;
1369
1370 vp->da = dict_unknown_afrom_str(vp, attribute);
1371 if (!vp->da) {
1372 talloc_free(vp);
1373 return NULL;
1374 }
1375
1376 /*
1377 * No value. Nothing more to do.
1378 */
1379 if (!value) return vp;
1380
1381 /*
1382 * Unknown attributes MUST be of type 'octets'
1383 */
1384 if (strncasecmp(value, "0x", 2) != 0) {
1385 fr_strerror_printf("Unknown attribute \"%s\" requires a hex "
1386 "string, not \"%s\"", attribute, value);
1387 talloc_free(vp);
1388 return NULL;
1389 }
1390
1391 /*
1392 * Convert the hex data to binary.
1393 */
1394 size = strlen(value + 2);
1395
1396 vp->vp_length = size >> 1;
1397 vp->vp_octets = data = talloc_array(vp, uint8_t, vp->vp_length);
1398 vp->type = VT_DATA;
1399 vp->op = (op == 0) ? T_OP_EQ : op;
1400
1401 if (fr_hex2bin(data, vp->vp_length, value + 2, size) != vp->vp_length) {
1402 fr_strerror_printf("Invalid hex string");
1403 talloc_free(vp);
1404 return NULL;
1405 }
1406
1407 /*
1408 * It's still unknown, return it as-is.
1409 */
1410 da = dict_attrbyvalue(vp->da->attr, vp->da->vendor);
1411 if (!da) return vp;
1412
1413 /*
1414 * It MIGHT be known. See if we can decode the raw data
1415 * into a valid attribute.
1416 */
1417 len = data2vp(ctx, NULL, NULL, NULL, da,
1418 vp->vp_octets, vp->vp_length, vp->vp_length,
1419 &vp2);
1420 if (len <= 0) return vp;
1421
1422 /*
1423 * It's still unknown. Return the original VP.
1424 */
1425 if (vp2->da->flags.is_unknown) {
1426 fr_pair_list_free(&vp2);
1427 return vp;
1428 }
1429
1430 /*
1431 * Didn't parse all of it. Return the "unknown" one.
1432 *
1433 * FIXME: it COULD have parsed 2 attributes and
1434 * then not the third, so returning 2 "knowns"
1435 * and 1 "unknown" is likely preferable.
1436 */
1437 if ((size_t) len < vp->vp_length) {
1438 fr_pair_list_free(&vp2);
1439 return vp;
1440 }
1441
1442 fr_pair_list_free(&vp);
1443 return vp2;
1444 }
1445
1446
1447 /** Create a VALUE_PAIR from ASCII strings
1448 *
1449 * Converts an attribute string identifier (with an optional tag qualifier)
1450 * and value string into a VALUE_PAIR.
1451 *
1452 * The string value is parsed according to the type of VALUE_PAIR being created.
1453 *
1454 * @param[in] ctx for talloc
1455 * @param[in] vps list where the attribute will be added (optional)
1456 * @param[in] attribute name.
1457 * @param[in] value attribute value (may be NULL if value will be set later).
1458 * @param[in] op to assign to new VALUE_PAIR.
1459 * @return a new VALUE_PAIR.
1460 */
fr_pair_make(TALLOC_CTX * ctx,VALUE_PAIR ** vps,char const * attribute,char const * value,FR_TOKEN op)1461 VALUE_PAIR *fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps,
1462 char const *attribute, char const *value, FR_TOKEN op)
1463 {
1464 DICT_ATTR const *da;
1465 VALUE_PAIR *vp;
1466 char *tc, *ts;
1467 int8_t tag;
1468 bool found_tag;
1469 char buffer[256];
1470 char const *attrname = attribute;
1471
1472 /*
1473 * Check for tags in 'Attribute:Tag' format.
1474 */
1475 found_tag = false;
1476 tag = TAG_ANY;
1477
1478 ts = strrchr(attribute, ':');
1479 if (ts && !ts[1]) {
1480 fr_strerror_printf("Invalid tag for attribute %s", attribute);
1481 return NULL;
1482 }
1483
1484 if (ts && ts[1]) {
1485 strlcpy(buffer, attribute, sizeof(buffer));
1486 attrname = buffer;
1487 ts = strrchr(attrname, ':');
1488 if (!ts) return NULL;
1489
1490 /* Colon found with something behind it */
1491 if (ts[1] == '*' && ts[2] == 0) {
1492 /* Wildcard tag for check items */
1493 tag = TAG_ANY;
1494 *ts = '\0';
1495 } else if ((ts[1] >= '0') && (ts[1] <= '9')) {
1496 /* It's not a wild card tag */
1497 tag = strtol(ts + 1, &tc, 0);
1498 if (tc && !*tc && TAG_VALID_ZERO(tag))
1499 *ts = '\0';
1500 else tag = TAG_ANY;
1501 } else {
1502 fr_strerror_printf("Invalid tag for attribute %s", attribute);
1503 return NULL;
1504 }
1505 found_tag = true;
1506 }
1507
1508 /*
1509 * It's not found in the dictionary, so we use
1510 * another method to create the attribute.
1511 */
1512 da = dict_attrbyname(attrname);
1513 if (!da) {
1514 vp = fr_pair_make_unknown(ctx, attrname, value, op);
1515 if (vp && vps) fr_pair_add(vps, vp);
1516 return vp;
1517 }
1518
1519 /* Check for a tag in the 'Merit' format of:
1520 * :Tag:Value. Print an error if we already found
1521 * a tag in the Attribute.
1522 */
1523
1524 if (value && (*value == ':' && da->flags.has_tag)) {
1525 /* If we already found a tag, this is invalid */
1526 if(found_tag) {
1527 fr_strerror_printf("Duplicate tag %s for attribute %s",
1528 value, da->name);
1529 DEBUG("Duplicate tag %s for attribute %s\n",
1530 value, da->name);
1531 return NULL;
1532 }
1533 /* Colon found and attribute allows a tag */
1534 if (value[1] == '*' && value[2] == ':') {
1535 /* Wildcard tag for check items */
1536 tag = TAG_ANY;
1537 value += 3;
1538 } else {
1539 /* Real tag */
1540 tag = strtol(value + 1, &tc, 0);
1541 if (tc && *tc==':' && TAG_VALID_ZERO(tag))
1542 value = tc + 1;
1543 else tag = 0;
1544 }
1545 }
1546
1547 vp = fr_pair_afrom_da(ctx, da);
1548 if (!vp) return NULL;
1549 vp->op = (op == 0) ? T_OP_EQ : op;
1550 vp->tag = tag;
1551
1552 switch (vp->op) {
1553 case T_OP_CMP_TRUE:
1554 case T_OP_CMP_FALSE:
1555 vp->vp_strvalue = NULL;
1556 vp->vp_length = 0;
1557 value = NULL; /* ignore it! */
1558 break;
1559
1560 /*
1561 * Regular expression comparison of integer attributes
1562 * does a STRING comparison of the names of their
1563 * integer attributes.
1564 */
1565 case T_OP_REG_EQ: /* =~ */
1566 case T_OP_REG_NE: /* !~ */
1567 {
1568 #ifndef HAVE_REGEX
1569 fr_strerror_printf("Regular expressions are not supported");
1570 return NULL;
1571 #else
1572 ssize_t slen;
1573 regex_t *preg;
1574
1575 /*
1576 * Someone else will fill in the value.
1577 */
1578 if (!value) break;
1579
1580 talloc_free(vp);
1581
1582 slen = regex_compile(ctx, &preg, value, strlen(value), false, false, false, true);
1583 if (slen <= 0) {
1584 fr_strerror_printf("Error at offset %zu compiling regex for %s: %s", -slen,
1585 attribute, fr_strerror());
1586 return NULL;
1587 }
1588 talloc_free(preg);
1589
1590 vp = fr_pair_make(ctx, NULL, attribute, NULL, op);
1591 if (!vp) return NULL;
1592
1593 if (fr_pair_mark_xlat(vp, value) < 0) {
1594 talloc_free(vp);
1595 return NULL;
1596 }
1597
1598 value = NULL; /* ignore it */
1599 break;
1600 #endif
1601 }
1602 default:
1603 break;
1604 }
1605
1606 /*
1607 * We allow this for stupidity, but it's really a bad idea.
1608 */
1609 if (vp->da->type == PW_TYPE_TLV) {
1610 ssize_t len;
1611 DICT_ATTR const *unknown;
1612 VALUE_PAIR *head = NULL;
1613 VALUE_PAIR **tail = &head;
1614
1615 if (!value) {
1616 talloc_free(vp);
1617 return NULL;
1618 }
1619
1620 unknown = dict_unknown_afrom_fields(vp, vp->da->attr, vp->da->vendor);
1621 if (!unknown) {
1622 talloc_free(vp);
1623 return NULL;
1624 }
1625
1626 vp->da = unknown;
1627
1628 /*
1629 * Parse it as an unknown type, i.e. octets.
1630 */
1631 if (fr_pair_value_from_str(vp, value, -1) < 0) {
1632 talloc_free(vp);
1633 return NULL;
1634 }
1635
1636 /*
1637 * It's badly formatted. Treat it as unknown.
1638 */
1639 if (rad_tlv_ok(vp->vp_octets, vp->vp_length, 1, 1) < 0) {
1640 goto do_add;
1641 }
1642
1643 /*
1644 * Decode the TLVs
1645 */
1646 len = rad_data2vp_tlvs(ctx, NULL, NULL, NULL, da, vp->vp_octets,
1647 vp->vp_length, tail);
1648 if (len < 0) {
1649 goto do_add;
1650 }
1651
1652 talloc_free(vp);
1653 vp = head;
1654 goto do_add;
1655 }
1656
1657 /*
1658 * FIXME: if (strcasecmp(attribute, vp->da->name) != 0)
1659 * then the user MAY have typed in the attribute name
1660 * as Vendor-%d-Attr-%d, and the value MAY be octets.
1661 *
1662 * We probably want to fix fr_pair_value_from_str to accept
1663 * octets as values for any attribute.
1664 */
1665 if (value && (fr_pair_value_from_str(vp, value, -1) < 0)) {
1666 talloc_free(vp);
1667 return NULL;
1668 }
1669
1670 do_add:
1671 if (vps) fr_pair_add(vps, vp);
1672 return vp;
1673 }
1674
1675 /** Mark a valuepair for xlat expansion
1676 *
1677 * Copies xlat source (unprocessed) string to valuepair value,
1678 * and sets value type.
1679 *
1680 * @param vp to mark for expansion.
1681 * @param value to expand.
1682 * @return 0 if marking succeeded or -1 if vp already had a value, or OOM.
1683 */
fr_pair_mark_xlat(VALUE_PAIR * vp,char const * value)1684 int fr_pair_mark_xlat(VALUE_PAIR *vp, char const *value)
1685 {
1686 char *raw;
1687
1688 /*
1689 * valuepair should not already have a value.
1690 */
1691 if (vp->type != VT_NONE) {
1692 fr_strerror_printf("Pair already has a value");
1693 return -1;
1694 }
1695
1696 raw = talloc_typed_strdup(vp, value);
1697 if (!raw) {
1698 fr_strerror_printf("Out of memory");
1699 return -1;
1700 }
1701
1702 vp->type = VT_XLAT;
1703 vp->value.xlat = raw;
1704 vp->vp_length = 0;
1705
1706 return 0;
1707 }
1708
1709
1710 /** Read a single valuepair from a buffer, and advance the pointer
1711 *
1712 * Returns T_EOL if end of line was encountered.
1713 *
1714 * @param[in,out] ptr to read from and update.
1715 * @param[out] raw The struct to write the raw VALUE_PAIR to.
1716 * @return the last token read.
1717 */
fr_pair_raw_from_str(char const ** ptr,VALUE_PAIR_RAW * raw)1718 FR_TOKEN fr_pair_raw_from_str(char const **ptr, VALUE_PAIR_RAW *raw)
1719 {
1720 char const *p;
1721 char *q;
1722 FR_TOKEN ret = T_INVALID, next, quote;
1723 char buf[8];
1724
1725 if (!ptr || !*ptr || !raw) {
1726 fr_strerror_printf("Invalid arguments");
1727 return T_INVALID;
1728 }
1729
1730 /*
1731 * Skip leading spaces
1732 */
1733 p = *ptr;
1734 while ((*p == ' ') || (*p == '\t')) p++;
1735
1736 if (!*p) {
1737 fr_strerror_printf("No token read where we expected "
1738 "an attribute name");
1739 return T_INVALID;
1740 }
1741
1742 if (*p == '#') return T_HASH;
1743
1744 /*
1745 * Try to get the attribute name.
1746 */
1747 q = raw->l_opand;
1748 *q = '\0';
1749 while (*p) {
1750 uint8_t const *t = (uint8_t const *) p;
1751
1752 if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
1753 too_long:
1754 fr_strerror_printf("Attribute name too long");
1755 return T_INVALID;
1756 }
1757
1758 /*
1759 * This is arguably easier than trying to figure
1760 * out which operators come after the attribute
1761 * name. Yes, our "lexer" is bad.
1762 */
1763 if (!dict_attr_allowed_chars[(unsigned int) *t]) {
1764 break;
1765 }
1766
1767 /*
1768 * Attribute:=value is NOT
1769 *
1770 * Attribute:
1771 * =
1772 * value
1773 */
1774 if ((*p == ':') && (!isdigit((int) p[1]))) {
1775 break;
1776 }
1777
1778 *(q++) = *(p++);
1779 }
1780
1781 /*
1782 * Haven't found any valid characters in the name.
1783 */
1784 if (!*raw->l_opand) {
1785 fr_strerror_printf("Invalid attribute name");
1786 return T_INVALID;
1787 }
1788
1789 /*
1790 * Look for tag (:#). This is different from :=, which
1791 * is an operator.
1792 */
1793 if ((*p == ':') && (isdigit((int) p[1]))) {
1794 if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
1795 goto too_long;
1796 }
1797 *(q++) = *(p++);
1798
1799 while (isdigit((int) *p)) {
1800 if (q >= (raw->l_opand + sizeof(raw->l_opand))) {
1801 goto too_long;
1802 }
1803 *(q++) = *(p++);
1804 }
1805 }
1806
1807 *q = '\0';
1808 *ptr = p;
1809
1810 /* Now we should have an operator here. */
1811 raw->op = gettoken(ptr, buf, sizeof(buf), false);
1812 if (raw->op < T_EQSTART || raw->op > T_EQEND) {
1813 fr_strerror_printf("Expecting operator");
1814
1815 return T_INVALID;
1816 }
1817
1818 /*
1819 * Read value. Note that empty string values are allowed
1820 */
1821 quote = gettoken(ptr, raw->r_opand, sizeof(raw->r_opand), false);
1822 if (quote == T_EOL) {
1823 fr_strerror_printf("Failed to get value");
1824
1825 return T_INVALID;
1826 }
1827
1828 /*
1829 * Peek at the next token. Must be T_EOL, T_COMMA, or T_HASH
1830 */
1831 p = *ptr;
1832
1833 next = gettoken(&p, buf, sizeof(buf), false);
1834 switch (next) {
1835 case T_HASH:
1836 next = T_EOL;
1837 break;
1838
1839 case T_EOL:
1840 break;
1841
1842 case T_COMMA:
1843 *ptr = p;
1844 break;
1845
1846 default:
1847 fr_strerror_printf("Expected end of line or comma");
1848 return T_INVALID;
1849 }
1850 ret = next;
1851
1852 switch (quote) {
1853 /*
1854 * Perhaps do xlat's
1855 */
1856 case T_DOUBLE_QUOTED_STRING:
1857 /*
1858 * Only report as double quoted if it contained valid
1859 * a valid xlat expansion.
1860 */
1861 p = strchr(raw->r_opand, '%');
1862 if (p && (p[1] == '{')) {
1863 raw->quote = quote;
1864 } else {
1865 raw->quote = T_SINGLE_QUOTED_STRING;
1866 }
1867
1868 break;
1869
1870 case T_SINGLE_QUOTED_STRING:
1871 case T_BACK_QUOTED_STRING:
1872 case T_BARE_WORD:
1873 raw->quote = quote;
1874 break;
1875
1876 default:
1877 fr_strerror_printf("Failed to find expected value on right hand side in %s", raw->l_opand);
1878 return T_INVALID;
1879 }
1880
1881 return ret;
1882 }
1883
1884 /** Read one line of attribute/value pairs into a list.
1885 *
1886 * The line may specify multiple attributes separated by commas.
1887 *
1888 * @note If the function returns T_INVALID, an error has occurred and
1889 * @note the valuepair list should probably be freed.
1890 *
1891 * @param ctx for talloc
1892 * @param buffer to read valuepairs from.
1893 * @param list where the parsed VALUE_PAIRs will be appended.
1894 * @return the last token parsed, or T_INVALID
1895 */
fr_pair_list_afrom_str(TALLOC_CTX * ctx,char const * buffer,VALUE_PAIR ** list)1896 FR_TOKEN fr_pair_list_afrom_str(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **list)
1897 {
1898 VALUE_PAIR *vp, *head, **tail;
1899 char const *p;
1900 FR_TOKEN last_token = T_INVALID;
1901 VALUE_PAIR_RAW raw;
1902
1903 /*
1904 * We allow an empty line.
1905 */
1906 if (buffer[0] == 0) {
1907 return T_EOL;
1908 }
1909
1910 head = NULL;
1911 tail = &head;
1912
1913 p = buffer;
1914 do {
1915 raw.l_opand[0] = '\0';
1916 raw.r_opand[0] = '\0';
1917
1918 last_token = fr_pair_raw_from_str(&p, &raw);
1919
1920 /*
1921 * JUST a hash. Don't try to create a VP.
1922 * Let the caller determine if an empty list is OK.
1923 */
1924 if (last_token == T_HASH) {
1925 last_token = T_EOL;
1926 break;
1927 }
1928 if (last_token == T_INVALID) break;
1929
1930 if (raw.quote == T_DOUBLE_QUOTED_STRING) {
1931 vp = fr_pair_make(ctx, NULL, raw.l_opand, NULL, raw.op);
1932 if (!vp) {
1933 last_token = T_INVALID;
1934 break;
1935 }
1936 if (fr_pair_mark_xlat(vp, raw.r_opand) < 0) {
1937 talloc_free(vp);
1938 last_token = T_INVALID;
1939 break;
1940 }
1941 } else {
1942 vp = fr_pair_make(ctx, NULL, raw.l_opand, raw.r_opand, raw.op);
1943 if (!vp) {
1944 last_token = T_INVALID;
1945 break;
1946 }
1947 }
1948
1949 *tail = vp;
1950 tail = &((*tail)->next);
1951 } while (*p && (last_token == T_COMMA));
1952
1953 if (last_token == T_INVALID) {
1954 fr_pair_list_free(&head);
1955 } else {
1956 fr_pair_add(list, head);
1957 }
1958
1959 /*
1960 * And return the last token which we read.
1961 */
1962 return last_token;
1963 }
1964
1965 /*
1966 * Read valuepairs from the fp up to End-Of-File.
1967 */
fr_pair_list_afrom_file(TALLOC_CTX * ctx,VALUE_PAIR ** out,FILE * fp,bool * pfiledone)1968 int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone)
1969 {
1970 char buf[8192];
1971 FR_TOKEN last_token = T_EOL;
1972
1973 vp_cursor_t cursor;
1974
1975 VALUE_PAIR *vp = NULL;
1976 fr_cursor_init(&cursor, out);
1977
1978 while (fgets(buf, sizeof(buf), fp) != NULL) {
1979 /*
1980 * If we get a '\n' by itself, we assume that's
1981 * the end of that VP
1982 */
1983 if (buf[0] == '\n') {
1984 if (vp) {
1985 *pfiledone = false;
1986 return 0;
1987 }
1988 continue;
1989 }
1990
1991 /*
1992 * Comments get ignored
1993 */
1994 if (buf[0] == '#') continue;
1995
1996 /*
1997 * Read all of the attributes on the current line.
1998 */
1999 vp = NULL;
2000 last_token = fr_pair_list_afrom_str(ctx, buf, &vp);
2001 if (!vp) {
2002 if (last_token != T_EOL) goto error;
2003 break;
2004 }
2005
2006 fr_cursor_merge(&cursor, vp);
2007 buf[0] = '\0';
2008 }
2009 *pfiledone = true;
2010
2011 return 0;
2012
2013 error:
2014 *pfiledone = false;
2015 vp = fr_cursor_first(&cursor);
2016 if (vp) fr_pair_list_free(&vp);
2017
2018 return -1;
2019 }
2020
2021 /** Compare two pairs, using the operator from "a"
2022 *
2023 * i.e. given two attributes, it does:
2024 *
2025 * (b->data) (a->operator) (a->data)
2026 *
2027 * e.g. "foo" != "bar"
2028 *
2029 * @param[in] a the first attribute
2030 * @param[in] b the second attribute
2031 * @return 1 if true, 0 if false, -1 on error.
2032 */
fr_pair_cmp(VALUE_PAIR * a,VALUE_PAIR * b)2033 int fr_pair_cmp(VALUE_PAIR *a, VALUE_PAIR *b)
2034 {
2035 if (!a) return -1;
2036
2037 VERIFY_VP(a);
2038 if (b) VERIFY_VP(b);
2039
2040 switch (a->op) {
2041 case T_OP_CMP_TRUE:
2042 return (b != NULL);
2043
2044 case T_OP_CMP_FALSE:
2045 return (b == NULL);
2046
2047 /*
2048 * a is a regex, compile it, print b to a string,
2049 * and then do string comparisons.
2050 */
2051 case T_OP_REG_EQ:
2052 case T_OP_REG_NE:
2053 #ifndef HAVE_REGEX
2054 return -1;
2055 #else
2056 if (!b) return false;
2057
2058 {
2059 ssize_t slen;
2060 regex_t *preg;
2061 char *value;
2062
2063 if (!fr_assert(a->da->type == PW_TYPE_STRING)) return -1;
2064
2065 slen = regex_compile(NULL, &preg, a->value.xlat, talloc_array_length(a->value.xlat) - 1, false, false, false, true);
2066 if (slen <= 0) {
2067 fr_strerror_printf("Error at offset %zu compiling regex for %s: %s",
2068 -slen, a->da->name, fr_strerror());
2069 return -1;
2070 }
2071 value = vp_aprints_value(NULL, b, '\0');
2072 if (!value) {
2073 talloc_free(preg);
2074 return -1;
2075 }
2076
2077 /*
2078 * Don't care about substring matches, oh well...
2079 */
2080 slen = regex_exec(preg, value, talloc_array_length(value) - 1, NULL, NULL);
2081 talloc_free(preg);
2082 talloc_free(value);
2083
2084 if (slen < 0) return -1;
2085 if (a->op == T_OP_REG_EQ) return (int)slen;
2086 return !slen;
2087 }
2088 #endif
2089
2090 default: /* we're OK */
2091 if (!b) return false;
2092 break;
2093 }
2094
2095 return fr_pair_cmp_op(a->op, b, a);
2096 }
2097
2098 /** Determine equality of two lists
2099 *
2100 * This is useful for comparing lists of attributes inserted into a binary tree.
2101 *
2102 * @param a first list of VALUE_PAIRs.
2103 * @param b second list of VALUE_PAIRs.
2104 * @return -1 if a < b, 0 if the two lists are equal, 1 if a > b, -2 on error.
2105 */
fr_pair_list_cmp(VALUE_PAIR * a,VALUE_PAIR * b)2106 int fr_pair_list_cmp(VALUE_PAIR *a, VALUE_PAIR *b)
2107 {
2108 vp_cursor_t a_cursor, b_cursor;
2109 VALUE_PAIR *a_p, *b_p;
2110 int ret;
2111
2112 for (a_p = fr_cursor_init(&a_cursor, &a), b_p = fr_cursor_init(&b_cursor, &b);
2113 a_p && b_p;
2114 a_p = fr_cursor_next(&a_cursor), b_p = fr_cursor_next(&b_cursor)) {
2115 /* Same VP, no point doing expensive checks */
2116 if (a_p == b_p) {
2117 continue;
2118 }
2119
2120 if (a_p->da < b_p->da) {
2121 return -1;
2122 }
2123 if (a_p->da > b_p->da) {
2124 return 1;
2125 }
2126
2127 if (a_p->tag < b_p->tag) {
2128 return -1;
2129 }
2130 if (a_p->tag > b_p->tag) {
2131 return 1;
2132 }
2133
2134 ret = value_data_cmp(a_p->da->type, &a_p->data, a_p->vp_length,
2135 b_p->da->type, &b_p->data, b_p->vp_length);
2136 if (ret != 0) {
2137 fr_assert(ret >= -1); /* Comparison error */
2138 return ret;
2139 }
2140 }
2141
2142 if (!a_p && !b_p) {
2143 return 0;
2144 }
2145
2146 if (!a_p) {
2147 return -1;
2148 }
2149
2150 /* if(!b_p) */
2151 return 1;
2152 }
2153
2154 /** Set the type of the VALUE_PAIR value buffer to match it's DICT_ATTR
2155 *
2156 * @param vp to fixup.
2157 */
fr_pair_value_set_type(VALUE_PAIR * vp)2158 static void fr_pair_value_set_type(VALUE_PAIR *vp)
2159 {
2160 if (!vp->data.ptr) return;
2161
2162 switch (vp->da->type) {
2163 case PW_TYPE_OCTETS:
2164 talloc_set_type(vp->data.ptr, uint8_t);
2165 return;
2166
2167 case PW_TYPE_STRING:
2168 talloc_set_type(vp->data.ptr, char);
2169 return;
2170
2171 default:
2172 return;
2173 }
2174 }
2175
2176 /** Copy data into an "octets" data type.
2177 *
2178 * @param[in,out] vp to update
2179 * @param[in] src data to copy
2180 * @param[in] size of the data, may be 0 in which case previous value will be freed.
2181 */
fr_pair_value_memcpy(VALUE_PAIR * vp,uint8_t const * src,size_t size)2182 void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t size)
2183 {
2184 uint8_t *p = NULL, *q;
2185
2186 VERIFY_VP(vp);
2187
2188 if (size > 0) {
2189 p = talloc_memdup(vp, src, size);
2190 if (!p) return;
2191 talloc_set_type(p, uint8_t);
2192 }
2193
2194 memcpy(&q, &vp->vp_octets, sizeof(q));
2195 TALLOC_FREE(q);
2196
2197 vp->vp_octets = p;
2198 vp->vp_length = size;
2199
2200 if (size > 0) fr_pair_value_set_type(vp);
2201 }
2202
2203 /** Reparent an allocated octet buffer to a VALUE_PAIR
2204 *
2205 * @param[in,out] vp to update
2206 * @param[in] src buffer to steal.
2207 */
fr_pair_value_memsteal(VALUE_PAIR * vp,uint8_t const * src)2208 void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
2209 {
2210 uint8_t *q;
2211
2212 VERIFY_VP(vp);
2213
2214 memcpy(&q, &vp->vp_octets, sizeof(q));
2215 talloc_free(q);
2216
2217 vp->vp_octets = talloc_steal(vp, src);
2218 vp->type = VT_DATA;
2219 vp->vp_length = talloc_array_length(vp->vp_strvalue);
2220 fr_pair_value_set_type(vp);
2221 }
2222
2223 /** Reparent an allocated char buffer to a VALUE_PAIR
2224 *
2225 * @param[in,out] vp to update
2226 * @param[in] src buffer to steal.
2227 */
fr_pair_value_strsteal(VALUE_PAIR * vp,char const * src)2228 void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
2229 {
2230 uint8_t *q;
2231
2232 VERIFY_VP(vp);
2233
2234 memcpy(&q, &vp->vp_octets, sizeof(q));
2235 talloc_free(q);
2236
2237 vp->vp_strvalue = talloc_steal(vp, src);
2238 vp->type = VT_DATA;
2239 vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
2240 fr_pair_value_set_type(vp);
2241 }
2242
2243 /** Copy data into an "string" data type.
2244 *
2245 * @param[in,out] vp to update
2246 * @param[in] src data to copy
2247 */
fr_pair_value_strcpy(VALUE_PAIR * vp,char const * src)2248 void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
2249 {
2250 char *p, *q;
2251
2252 VERIFY_VP(vp);
2253
2254 p = talloc_strdup(vp, src);
2255
2256 if (!p) return;
2257
2258 memcpy(&q, &vp->vp_strvalue, sizeof(q));
2259 talloc_free(q);
2260
2261 vp->vp_strvalue = p;
2262 vp->type = VT_DATA;
2263 vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
2264 fr_pair_value_set_type(vp);
2265 }
2266
2267 /** Copy data into an "string" data type.
2268 *
2269 * @note unlike the original strncpy, this function does not stop
2270 * if it finds \0 bytes embedded in the string.
2271 *
2272 * @param[in,out] vp to update.
2273 * @param[in] src data to copy.
2274 * @param[in] len of data to copy.
2275 */
fr_pair_value_bstrncpy(VALUE_PAIR * vp,void const * src,size_t len)2276 void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
2277 {
2278 char *p, *q;
2279
2280 VERIFY_VP(vp);
2281
2282 p = talloc_array(vp, char, len + 1);
2283 if (!p) return;
2284
2285 memcpy(p, src, len); /* embdedded \0 safe */
2286 p[len] = '\0';
2287
2288 memcpy(&q, &vp->vp_strvalue, sizeof(q));
2289 talloc_free(q);
2290
2291 vp->vp_strvalue = p;
2292 vp->type = VT_DATA;
2293 vp->vp_length = len;
2294 fr_pair_value_set_type(vp);
2295 }
2296
2297 /** Print data into an "string" data type.
2298 *
2299 * @param[in,out] vp to update
2300 * @param[in] fmt the format string
2301 */
fr_pair_value_sprintf(VALUE_PAIR * vp,char const * fmt,...)2302 void fr_pair_value_sprintf(VALUE_PAIR *vp, char const *fmt, ...)
2303 {
2304 va_list ap;
2305 char *p, *q;
2306
2307 VERIFY_VP(vp);
2308
2309 va_start(ap, fmt);
2310 p = talloc_vasprintf(vp, fmt, ap);
2311 va_end(ap);
2312
2313 if (!p) return;
2314
2315 memcpy(&q, &vp->vp_strvalue, sizeof(q));
2316 talloc_free(q);
2317
2318 vp->vp_strvalue = p;
2319 vp->type = VT_DATA;
2320
2321 vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
2322 fr_pair_value_set_type(vp);
2323 }
2324
2325 #ifdef WITH_VERIFY_PTR
2326 /*
2327 * Verify a VALUE_PAIR
2328 */
fr_pair_verify(char const * file,int line,VALUE_PAIR const * vp)2329 inline void fr_pair_verify(char const *file, int line, VALUE_PAIR const *vp)
2330 {
2331 if (!vp) {
2332 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR pointer was NULL", file, line);
2333 fr_assert(0);
2334 fr_exit_now(1);
2335 }
2336
2337 (void) talloc_get_type_abort(vp, VALUE_PAIR);
2338
2339 if (!vp->da) {
2340 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR da pointer was NULL", file, line);
2341 fr_assert(0);
2342 fr_exit_now(1);
2343 }
2344
2345 if (vp->data.ptr) switch (vp->da->type) {
2346 case PW_TYPE_OCTETS:
2347 {
2348 size_t len;
2349 TALLOC_CTX *parent;
2350
2351 if (!talloc_get_type(vp->data.ptr, uint8_t)) {
2352 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
2353 "uint8_t but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
2354 (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
2355 }
2356
2357 len = talloc_array_length(vp->vp_octets);
2358 if (vp->vp_length > len) {
2359 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
2360 "uint8_t data buffer length %zu\n", file, line, vp->da->name, vp->vp_length, len);
2361 fr_assert(0);
2362 fr_exit_now(1);
2363 }
2364
2365 parent = talloc_parent(vp->data.ptr);
2366 if (parent != vp) {
2367 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
2368 "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
2369 file, line, vp->da->name,
2370 vp, parent, parent ? talloc_get_name(parent) : "NULL");
2371 fr_assert(0);
2372 fr_exit_now(1);
2373 }
2374 }
2375 break;
2376
2377 case PW_TYPE_STRING:
2378 {
2379 size_t len;
2380 TALLOC_CTX *parent;
2381
2382 if (!talloc_get_type(vp->data.ptr, char)) {
2383 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
2384 "char but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
2385 (void) talloc_get_type_abort(vp->data.ptr, char);
2386 }
2387
2388 len = (talloc_array_length(vp->vp_strvalue) - 1);
2389 if (vp->vp_length > len) {
2390 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
2391 "char buffer length %zu\n", file, line, vp->da->name, vp->vp_length, len);
2392 fr_assert(0);
2393 fr_exit_now(1);
2394 }
2395
2396 if (vp->vp_strvalue[vp->vp_length] != '\0') {
2397 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer not \\0 "
2398 "terminated\n", file, line, vp->da->name);
2399 fr_assert(0);
2400 fr_exit_now(1);
2401 }
2402
2403 parent = talloc_parent(vp->data.ptr);
2404 if (parent != vp) {
2405 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
2406 "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
2407 file, line, vp->da->name,
2408 vp, parent, parent ? talloc_get_name(parent) : "NULL");
2409 fr_assert(0);
2410 fr_exit_now(1);
2411 }
2412 }
2413 break;
2414
2415 default:
2416 break;
2417 }
2418
2419 if (vp->da->flags.is_unknown) {
2420 (void) talloc_get_type_abort(vp->da, DICT_ATTR);
2421 } else {
2422 DICT_ATTR const *da;
2423
2424 /*
2425 * Attribute may be present with multiple names
2426 */
2427 da = dict_attrbyname(vp->da->name);
2428 if (!da) {
2429 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR attribute %p \"%s\" (%s) "
2430 "not found in global dictionary",
2431 file, line, vp->da, vp->da->name,
2432 fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
2433 fr_assert(0);
2434 fr_exit_now(1);
2435 }
2436
2437 if (da->type == PW_TYPE_COMBO_IP_ADDR) {
2438 da = dict_attrbytype(vp->da->attr, vp->da->vendor, vp->da->type);
2439 if (!da) {
2440 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR attribute %p \"%s\" "
2441 "variant (%s) not found in global dictionary",
2442 file, line, vp->da, vp->da->name,
2443 fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"));
2444 fr_assert(0);
2445 fr_exit_now(1);
2446 }
2447 }
2448
2449
2450 if (da != vp->da) {
2451 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR "
2452 "dictionary pointer %p \"%s\" (%s) "
2453 "and global dictionary pointer %p \"%s\" (%s) differ",
2454 file, line, vp->da, vp->da->name,
2455 fr_int2str(dict_attr_types, vp->da->type, "<INVALID>"),
2456 da, da->name, fr_int2str(dict_attr_types, da->type, "<INVALID>"));
2457 fr_assert(0);
2458 fr_exit_now(1);
2459 }
2460 }
2461 }
2462
2463 /*
2464 * Verify a pair list
2465 */
fr_pair_list_verify(char const * file,int line,TALLOC_CTX * expected,VALUE_PAIR * vps,char const * name)2466 void fr_pair_list_verify(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps, char const *name)
2467 {
2468 vp_cursor_t cursor;
2469 VALUE_PAIR *vp;
2470 TALLOC_CTX *parent;
2471
2472 for (vp = fr_cursor_init(&cursor, &vps);
2473 vp;
2474 vp = fr_cursor_next(&cursor)) {
2475 VERIFY_VP(vp);
2476
2477 parent = talloc_parent(vp);
2478 if (expected && (parent != expected)) {
2479 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Expected VALUE_PAIR \"%s\" to be parented "
2480 "by %p (%s) name %s, instead parented by %p (%s)\n",
2481 file, line, vp->da->name,
2482 expected, talloc_get_name(expected), name,
2483 parent, parent ? talloc_get_name(parent) : "NULL");
2484
2485 fr_log_talloc_report(expected);
2486 if (parent) fr_log_talloc_report(parent);
2487
2488 fr_assert(0);
2489 fr_exit_now(1);
2490 }
2491
2492 }
2493 }
2494 #endif
2495