1 /*
2  * value.c	Functions to handle value_data_t
3  *
4  * Version:	$Id: 05d42e269a476576bdce1501894e0e4a6d67dae8 $
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 2014 The FreeRADIUS server project
21  */
22 
23 RCSID("$Id: 05d42e269a476576bdce1501894e0e4a6d67dae8 $")
24 
25 #include <freeradius-devel/libradius.h>
26 #include <ctype.h>
27 
28 /** Compare two values
29  *
30  * @param[in] a_type of data to compare.
31  * @param[in] a_len of data to compare.
32  * @param[in] a Value to compare.
33  * @param[in] b_type of data to compare.
34  * @param[in] b_len of data to compare.
35  * @param[in] b Value to compare.
36  * @return -1 if a is less than b, 0 if both are equal, 1 if a is more than b, < -1 on error.
37  */
value_data_cmp(PW_TYPE a_type,value_data_t const * a,size_t a_len,PW_TYPE b_type,value_data_t const * b,size_t b_len)38 int value_data_cmp(PW_TYPE a_type, value_data_t const *a, size_t a_len,
39 		   PW_TYPE b_type, value_data_t const *b, size_t b_len)
40 {
41 	int compare = 0;
42 
43 	if (a_type != b_type) {
44 		fr_strerror_printf("Can't compare values of different types");
45 		return -2;
46 	}
47 
48 	/*
49 	 *	After doing the previous check for special comparisons,
50 	 *	do the per-type comparison here.
51 	 */
52 	switch (a_type) {
53 	case PW_TYPE_ABINARY:
54 	case PW_TYPE_OCTETS:
55 	case PW_TYPE_STRING:	/* We use memcmp to be \0 safe */
56 	{
57 		size_t length;
58 
59 		if (a_len < b_len) {
60 			length = a_len;
61 		} else {
62 			length = b_len;
63 		}
64 
65 		if (length) {
66 			compare = memcmp(a->octets, b->octets, length);
67 			if (compare != 0) break;
68 		}
69 
70 		/*
71 		 *	Contents are the same.  The return code
72 		 *	is therefore the difference in lengths.
73 		 *
74 		 *	i.e. "0x00" is smaller than "0x0000"
75 		 */
76 		compare = a_len - b_len;
77 	}
78 		break;
79 
80 		/*
81 		 *	Short-hand for simplicity.
82 		 */
83 #define CHECK(_type) if (a->_type < b->_type)   { compare = -1; \
84 		} else if (a->_type > b->_type) { compare = +1; }
85 
86 	case PW_TYPE_BOOLEAN:	/* this isn't a RADIUS type, and shouldn't really ever be used */
87 	case PW_TYPE_BYTE:
88 		CHECK(byte);
89 		break;
90 
91 
92 	case PW_TYPE_SHORT:
93 		CHECK(ushort);
94 		break;
95 
96 	case PW_TYPE_DATE:
97 		CHECK(date);
98 		break;
99 
100 	case PW_TYPE_INTEGER:
101 		CHECK(integer);
102 		break;
103 
104 	case PW_TYPE_SIGNED:
105 		CHECK(sinteger);
106 		break;
107 
108 	case PW_TYPE_INTEGER64:
109 		CHECK(integer64);
110 		break;
111 
112 	case PW_TYPE_ETHERNET:
113 		compare = memcmp(a->ether, b->ether, sizeof(a->ether));
114 		break;
115 
116 	case PW_TYPE_IPV4_ADDR: {
117 			uint32_t a_int, b_int;
118 
119 			a_int = ntohl(a->ipaddr.s_addr);
120 			b_int = ntohl(b->ipaddr.s_addr);
121 			if (a_int < b_int) {
122 				compare = -1;
123 			} else if (a_int > b_int) {
124 				compare = +1;
125 			}
126 		}
127 		break;
128 
129 	case PW_TYPE_IPV6_ADDR:
130 		compare = memcmp(&a->ipv6addr, &b->ipv6addr, sizeof(a->ipv6addr));
131 		break;
132 
133 	case PW_TYPE_IPV6_PREFIX:
134 		compare = memcmp(a->ipv6prefix, b->ipv6prefix, sizeof(a->ipv6prefix));
135 		break;
136 
137 	case PW_TYPE_IPV4_PREFIX:
138 		compare = memcmp(a->ipv4prefix, b->ipv4prefix, sizeof(a->ipv4prefix));
139 		break;
140 
141 	case PW_TYPE_IFID:
142 		compare = memcmp(a->ifid, b->ifid, sizeof(a->ifid));
143 		break;
144 
145 	/*
146 	 *	Na of the types below should be in the REQUEST
147 	 */
148 	case PW_TYPE_INVALID:		/* We should never see these */
149 	case PW_TYPE_COMBO_IP_ADDR:		/* This should have been converted into IPADDR/IPV6ADDR */
150 	case PW_TYPE_COMBO_IP_PREFIX:		/* This should have been converted into IPADDR/IPV6ADDR */
151 	case PW_TYPE_TLV:
152 	case PW_TYPE_EXTENDED:
153 	case PW_TYPE_LONG_EXTENDED:
154 	case PW_TYPE_EVS:
155 	case PW_TYPE_VSA:
156 	case PW_TYPE_TIMEVAL:
157 	case PW_TYPE_MAX:
158 		fr_assert(0);	/* unknown type */
159 		return -2;
160 
161 	/*
162 	 *	Do NOT add a default here, as new types are added
163 	 *	static analysis will warn us they're not handled
164 	 */
165 	}
166 
167 	if (compare > 0) {
168 		return 1;
169 	} else if (compare < 0) {
170 		return -1;
171 	}
172 	return 0;
173 }
174 
175 /*
176  *	We leverage the fact that IPv4 and IPv6 prefixes both
177  *	have the same format:
178  *
179  *	reserved, prefix-len, data...
180  */
value_data_cidr_cmp_op(FR_TOKEN op,int bytes,uint8_t a_net,uint8_t const * a,uint8_t b_net,uint8_t const * b)181 static int value_data_cidr_cmp_op(FR_TOKEN op, int bytes,
182 				  uint8_t a_net, uint8_t const *a,
183 				  uint8_t b_net, uint8_t const *b)
184 {
185 	int i, common;
186 	uint32_t mask;
187 
188 	/*
189 	 *	Handle the case of netmasks being identical.
190 	 */
191 	if (a_net == b_net) {
192 		int compare;
193 
194 		compare = memcmp(a, b, bytes);
195 
196 		/*
197 		 *	If they're identical return true for
198 		 *	identical.
199 		 */
200 		if ((compare == 0) &&
201 		    ((op == T_OP_CMP_EQ) ||
202 		     (op == T_OP_LE) ||
203 		     (op == T_OP_GE))) {
204 			return true;
205 		}
206 
207 		/*
208 		 *	Everything else returns false.
209 		 *
210 		 *	10/8 == 24/8  --> false
211 		 *	10/8 <= 24/8  --> false
212 		 *	10/8 >= 24/8  --> false
213 		 */
214 		return false;
215 	}
216 
217 	/*
218 	 *	Netmasks are different.  That limits the
219 	 *	possible results, based on the operator.
220 	 */
221 	switch (op) {
222 	case T_OP_CMP_EQ:
223 		return false;
224 
225 	case T_OP_NE:
226 		return true;
227 
228 	case T_OP_LE:
229 	case T_OP_LT:	/* 192/8 < 192.168/16 --> false */
230 		if (a_net < b_net) {
231 			return false;
232 		}
233 		break;
234 
235 	case T_OP_GE:
236 	case T_OP_GT:	/* 192/16 > 192.168/8 --> false */
237 		if (a_net > b_net) {
238 			return false;
239 		}
240 		break;
241 
242 	default:
243 		return false;
244 	}
245 
246 	if (a_net < b_net) {
247 		common = a_net;
248 	} else {
249 		common = b_net;
250 	}
251 
252 	/*
253 	 *	Do the check byte by byte.  If the bytes are
254 	 *	identical, it MAY be a match.  If they're different,
255 	 *	it is NOT a match.
256 	 */
257 	i = 0;
258 	while (i < bytes) {
259 		/*
260 		 *	All leading bytes are identical.
261 		 */
262 		if (common == 0) return true;
263 
264 		/*
265 		 *	Doing bitmasks takes more work.
266 		 */
267 		if (common < 8) break;
268 
269 		if (a[i] != b[i]) return false;
270 
271 		common -= 8;
272 		i++;
273 		continue;
274 	}
275 
276 	mask = 1;
277 	mask <<= (8 - common);
278 	mask--;
279 	mask = ~mask;
280 
281 	if ((a[i] & mask) == ((b[i] & mask))) {
282 		return true;
283 	}
284 
285 	return false;
286 }
287 
288 /** Compare two attributes using an operator
289  *
290  * @param[in] op to use in comparison.
291  * @param[in] a_type of data to compare.
292  * @param[in] a_len of data to compare.
293  * @param[in] a Value to compare.
294  * @param[in] b_type of data to compare.
295  * @param[in] b_len of data to compare.
296  * @param[in] b Value to compare.
297  * @return 1 if true, 0 if false, -1 on error.
298  */
value_data_cmp_op(FR_TOKEN op,PW_TYPE a_type,value_data_t const * a,size_t a_len,PW_TYPE b_type,value_data_t const * b,size_t b_len)299 int value_data_cmp_op(FR_TOKEN op,
300 		      PW_TYPE a_type, value_data_t const *a, size_t a_len,
301 		      PW_TYPE b_type, value_data_t const *b, size_t b_len)
302 {
303 	int compare = 0;
304 
305 	if (!a || !b) return -1;
306 
307 	switch (a_type) {
308 	case PW_TYPE_IPV4_ADDR:
309 		switch (b_type) {
310 		case PW_TYPE_IPV4_ADDR:		/* IPv4 and IPv4 */
311 			goto cmp;
312 
313 		case PW_TYPE_IPV4_PREFIX:	/* IPv4 and IPv4 Prefix */
314 			return value_data_cidr_cmp_op(op, 4, 32, (uint8_t const *) &a->ipaddr,
315 						      b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
316 
317 		default:
318 			fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
319 			return -1;
320 		}
321 
322 	case PW_TYPE_IPV4_PREFIX:		/* IPv4 and IPv4 Prefix */
323 		switch (b_type) {
324 		case PW_TYPE_IPV4_ADDR:
325 			return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
326 						    (uint8_t const *) &a->ipv4prefix[2],
327 						    32, (uint8_t const *) &b->ipaddr);
328 
329 		case PW_TYPE_IPV4_PREFIX:	/* IPv4 Prefix and IPv4 Prefix */
330 			return value_data_cidr_cmp_op(op, 4, a->ipv4prefix[1],
331 						    (uint8_t const *) &a->ipv4prefix[2],
332 						    b->ipv4prefix[1], (uint8_t const *) &b->ipv4prefix[2]);
333 
334 		default:
335 			fr_strerror_printf("Cannot compare IPv4 with IPv6 address");
336 			return -1;
337 		}
338 
339 	case PW_TYPE_IPV6_ADDR:
340 		switch (b_type) {
341 		case PW_TYPE_IPV6_ADDR:		/* IPv6 and IPv6 */
342 			goto cmp;
343 
344 		case PW_TYPE_IPV6_PREFIX:	/* IPv6 and IPv6 Preifx */
345 			return value_data_cidr_cmp_op(op, 16, 128, (uint8_t const *) &a->ipv6addr,
346 						      b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
347 
348 		default:
349 			fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
350 			return -1;
351 		}
352 
353 	case PW_TYPE_IPV6_PREFIX:
354 		switch (b_type) {
355 		case PW_TYPE_IPV6_ADDR:		/* IPv6 Prefix and IPv6 */
356 			return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
357 						      (uint8_t const *) &a->ipv6prefix[2],
358 						      128, (uint8_t const *) &b->ipv6addr);
359 
360 		case PW_TYPE_IPV6_PREFIX:	/* IPv6 Prefix and IPv6 */
361 			return value_data_cidr_cmp_op(op, 16, a->ipv6prefix[1],
362 						      (uint8_t const *) &a->ipv6prefix[2],
363 						      b->ipv6prefix[1], (uint8_t const *) &b->ipv6prefix[2]);
364 
365 		default:
366 			fr_strerror_printf("Cannot compare IPv6 with IPv4 address");
367 			return -1;
368 		}
369 
370 	default:
371 	cmp:
372 		compare = value_data_cmp(a_type, a, a_len,
373 					 b_type, b, b_len);
374 		if (compare < -1) {	/* comparison error */
375 			return -1;
376 		}
377 	}
378 
379 	/*
380 	 *	Now do the operator comparison.
381 	 */
382 	switch (op) {
383 	case T_OP_CMP_EQ:
384 		return (compare == 0);
385 
386 	case T_OP_NE:
387 		return (compare != 0);
388 
389 	case T_OP_LT:
390 		return (compare < 0);
391 
392 	case T_OP_GT:
393 		return (compare > 0);
394 
395 	case T_OP_LE:
396 		return (compare <= 0);
397 
398 	case T_OP_GE:
399 		return (compare >= 0);
400 
401 	default:
402 		return 0;
403 	}
404 }
405 
406 static char const hextab[] = "0123456789abcdef";
407 
408 /** Convert string value to a value_data_t type
409  *
410  * @param[in] ctx to alloc strings in.
411  * @param[out] dst where to write parsed value.
412  * @param[in,out] src_type of value data to create/type of value created.
413  * @param[in] src_enumv DICT_ATTR with string aliases for integer values.
414  * @param[in] src String to convert. Binary safe for variable length values if len is provided.
415  * @param[in] src_len may be < 0 in which case strlen(len) is used to determine length, else src_len
416  *	  should be the length of the string or sub string to parse.
417  * @param[in] quote quotation character used to drive de-escaping
418  * @return length of data written to out or -1 on parse error.
419  */
value_data_from_str(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE * src_type,DICT_ATTR const * src_enumv,char const * src,ssize_t src_len,char quote)420 ssize_t value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst,
421 			    PW_TYPE *src_type, DICT_ATTR const *src_enumv,
422 			    char const *src, ssize_t src_len, char quote)
423 {
424 	DICT_VALUE	*dval;
425 	size_t		len;
426 	ssize_t		ret;
427 	char		buffer[256];
428 
429 	if (!src) return -1;
430 
431 	len = (src_len < 0) ? strlen(src) : (size_t)src_len;
432 
433 	/*
434 	 *	Set size for all fixed length attributes.
435 	 */
436 	ret = dict_attr_sizes[*src_type][1];	/* Max length */
437 
438 	/*
439 	 *	It's a variable ret src_type so we just alloc a new buffer
440 	 *	of size len and copy.
441 	 */
442 	switch (*src_type) {
443 	case PW_TYPE_STRING:
444 	{
445 		char		*p, *buff;
446 		char const	*q;
447 		int		x;
448 
449 		buff = p = talloc_bstrndup(ctx, src, len);
450 
451 		/*
452 		 *	No de-quoting.  Just copy the string.
453 		 */
454 		if (!quote) {
455 			ret = len;
456 			dst->strvalue = buff;
457 			goto finish;
458 		}
459 
460 		/*
461 		 *	Do escaping for single quoted strings.  Only
462 		 *	single quotes get escaped.  Everything else is
463 		 *	left as-is.
464 		 */
465 		if (quote == '\'') {
466 			q = p;
467 
468 			while (q < (buff + len)) {
469 				/*
470 				 *	The quotation character is escaped.
471 				 */
472 				if ((q[0] == '\\') &&
473 				    (q[1] == quote)) {
474 					*(p++) = quote;
475 					q += 2;
476 					continue;
477 				}
478 
479 				/*
480 				 *	Two backslashes get mangled to one.
481 				 */
482 				if ((q[0] == '\\') &&
483 				    (q[1] == '\\')) {
484 					*(p++) = '\\';
485 					q += 2;
486 					continue;
487 				}
488 
489 				/*
490 				 *	Not escaped, just copy it over.
491 				 */
492 				*(p++) = *(q++);
493 			}
494 
495 			*p = '\0';
496 			ret = p - buff;
497 
498 			/* Shrink the buffer to the correct size */
499 			dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
500 			goto finish;
501 		}
502 
503 		/*
504 		 *	It's "string" or `string`, do all standard
505 		 *	escaping.
506 		 */
507 		q = p;
508 		while (q < (buff + len)) {
509 			char c = *q++;
510 
511 			if ((c == '\\') && (q >= (buff + len))) {
512 				fr_strerror_printf("Invalid escape at end of string");
513 				talloc_free(buff);
514 				return -1;
515 			}
516 
517 			/*
518 			 *	Fix up \X -> ... the binary form of it.
519 			 */
520 			if (c == '\\') {
521 				switch (*q) {
522 				case 'r':
523 					c = '\r';
524 					q++;
525 					break;
526 
527 				case 'n':
528 					c = '\n';
529 					q++;
530 					break;
531 
532 				case 't':
533 					c = '\t';
534 					q++;
535 					break;
536 
537 				case '\\':
538 					c = '\\';
539 					q++;
540 					break;
541 
542 				default:
543 					/*
544 					 *	\" --> ", but only inside of double quoted strings, etc.
545 					 */
546 					if (*q == quote) {
547 						c = quote;
548 						q++;
549 						break;
550 					}
551 
552 					/*
553 					 *	\000 --> binary zero character
554 					 */
555 					if ((q[0] >= '0') &&
556 					    (q[0] <= '9') &&
557 					    (q[1] >= '0') &&
558 					    (q[1] <= '9') &&
559 					    (q[2] >= '0') &&
560 					    (q[2] <= '9') &&
561 					    (sscanf(q, "%3o", &x) == 1)) {
562 						c = x;
563 						q += 3;
564 					}
565 
566 					/*
567 					 *	Else It's not a recognised escape sequence DON'T
568 					 *	consume the backslash. This is identical
569 					 *	behaviour to bash and most other things that
570 					 *	use backslash escaping.
571 					 */
572 				}
573 			}
574 
575 			*p++ = c;
576 		}
577 
578 		*p = '\0';
579 		ret = p - buff;
580 		dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
581 	}
582 		goto finish;
583 
584 	case PW_TYPE_VSA:
585 		fr_strerror_printf("Must use 'Attr-26 = ...' instead of 'Vendor-Specific = ...'");
586 		return -1;
587 
588 	/* raw octets: 0x01020304... */
589 #ifndef WITH_ASCEND_BINARY
590 	do_octets:
591 #endif
592 	case PW_TYPE_OCTETS:
593 	{
594 		uint8_t	*p;
595 
596 		/*
597 		 *	No 0x prefix, just copy verbatim.
598 		 */
599 		if ((len < 2) || (strncasecmp(src, "0x", 2) != 0)) {
600 			dst->octets = talloc_memdup(ctx, (uint8_t const *)src, len);
601 			talloc_set_type(dst->octets, uint8_t);
602 			ret = len;
603 			goto finish;
604 		}
605 
606 		len -= 2;
607 
608 		/*
609 		 *	Invalid.
610 		 */
611 		if ((len & 0x01) != 0) {
612 			fr_strerror_printf("Length of Hex String is not even, got %zu bytes", len);
613 			return -1;
614 		}
615 
616 		ret = len >> 1;
617 		p = talloc_array(ctx, uint8_t, ret);
618 		if (fr_hex2bin(p, ret, src + 2, len) != (size_t)ret) {
619 			talloc_free(p);
620 			fr_strerror_printf("Invalid hex data");
621 			return -1;
622 		}
623 
624 		dst->octets = p;
625 	}
626 		goto finish;
627 
628 	case PW_TYPE_ABINARY:
629 #ifdef WITH_ASCEND_BINARY
630 		if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) {
631 			ssize_t bin;
632 
633 			if (len > ((sizeof(dst->filter) + 1) * 2)) {
634 				fr_strerror_printf("Hex data is too large for ascend filter");
635 				return -1;
636 			}
637 
638 			bin = fr_hex2bin((uint8_t *) &dst->filter, ret, src + 2, len - 2);
639 			if (bin < ret) {
640 				memset(((uint8_t *) &dst->filter) + bin, 0, ret - bin);
641 			}
642 		} else {
643 			if (ascend_parse_filter(dst, src, len) < 0 ) {
644 				/* Allow ascend_parse_filter's strerror to bubble up */
645 				return -1;
646 			}
647 		}
648 
649 		ret = sizeof(dst->filter);
650 		goto finish;
651 #else
652 		/*
653 		 *	If Ascend binary is NOT defined,
654 		 *	then fall through to raw octets, so that
655 		 *	the user can at least make them by hand...
656 		 */
657 	 	goto do_octets;
658 #endif
659 
660 	/* don't use this! */
661 	case PW_TYPE_TLV:
662 		fr_strerror_printf("Cannot parse TLV");
663 		return -1;
664 
665 	case PW_TYPE_IPV4_ADDR:
666 	{
667 		fr_ipaddr_t addr;
668 
669 		if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
670 
671 		/*
672 		 *	We allow v4 addresses to have a /32 suffix as some databases (PostgreSQL)
673 		 *	print them this way.
674 		 */
675 		if (addr.prefix != 32) {
676 			fr_strerror_printf("Invalid IPv4 mask length \"/%i\".  Only \"/32\" permitted "
677 					   "for non-prefix types", addr.prefix);
678 			return -1;
679 		}
680 
681 		dst->ipaddr.s_addr = addr.ipaddr.ip4addr.s_addr;
682 	}
683 		goto finish;
684 
685 	case PW_TYPE_IPV4_PREFIX:
686 	{
687 		fr_ipaddr_t addr;
688 
689 		if (fr_pton4(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
690 
691 		dst->ipv4prefix[1] = addr.prefix;
692 		memcpy(&dst->ipv4prefix[2], &addr.ipaddr.ip4addr.s_addr, sizeof(dst->ipv4prefix) - 2);
693 	}
694 		goto finish;
695 
696 	case PW_TYPE_IPV6_ADDR:
697 	{
698 		fr_ipaddr_t addr;
699 
700 		if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
701 
702 		/*
703 		 *	We allow v6 addresses to have a /128 suffix as some databases (PostgreSQL)
704 		 *	print them this way.
705 		 */
706 		if (addr.prefix != 128) {
707 			fr_strerror_printf("Invalid IPv6 mask length \"/%i\".  Only \"/128\" permitted "
708 					   "for non-prefix types", addr.prefix);
709 			return -1;
710 		}
711 
712 		memcpy(&dst->ipv6addr, addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6addr));
713 	}
714 		goto finish;
715 
716 	case PW_TYPE_IPV6_PREFIX:
717 	{
718 		fr_ipaddr_t addr;
719 
720 		if (fr_pton6(&addr, src, src_len, fr_hostname_lookups, false) < 0) return -1;
721 
722 		dst->ipv6prefix[1] = addr.prefix;
723 		memcpy(&dst->ipv6prefix[2], addr.ipaddr.ip6addr.s6_addr, sizeof(dst->ipv6prefix) - 2);
724 	}
725 		goto finish;
726 
727 	default:
728 		break;
729 	}
730 
731 	/*
732 	 *	It's a fixed size src_type, copy to a temporary buffer and
733 	 *	\0 terminate if insize >= 0.
734 	 */
735 	if (src_len > 0) {
736 		if (len >= sizeof(buffer)) {
737 			fr_strerror_printf("Temporary buffer too small");
738 			return -1;
739 		}
740 
741 		memcpy(buffer, src, src_len);
742 		buffer[src_len] = '\0';
743 		src = buffer;
744 	}
745 
746 	switch (*src_type) {
747 	case PW_TYPE_BYTE:
748 	{
749 		char *p;
750 		unsigned int i;
751 
752 		/*
753 		 *	Note that ALL integers are unsigned!
754 		 */
755 		i = fr_strtoul(src, &p);
756 
757 		/*
758 		 *	Look for the named src for the given
759 		 *	attribute.
760 		 */
761 		if (src_enumv && *p && !is_whitespace(p)) {
762 			if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
763 				fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
764 						   src, src_enumv->name);
765 				return -1;
766 			}
767 
768 			dst->byte = dval->value;
769 		} else {
770 			if (i > 255) {
771 				fr_strerror_printf("Byte value \"%s\" is larger than 255", src);
772 				return -1;
773 			}
774 
775 			dst->byte = i;
776 		}
777 		break;
778 	}
779 
780 	case PW_TYPE_SHORT:
781 	{
782 		char *p;
783 		unsigned int i;
784 
785 		/*
786 		 *	Note that ALL integers are unsigned!
787 		 */
788 		i = fr_strtoul(src, &p);
789 
790 		/*
791 		 *	Look for the named src for the given
792 		 *	attribute.
793 		 */
794 		if (src_enumv && *p && !is_whitespace(p)) {
795 			if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
796 				fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
797 						   src, src_enumv->name);
798 				return -1;
799 			}
800 
801 			dst->ushort = dval->value;
802 		} else {
803 			if (i > 65535) {
804 				fr_strerror_printf("Short value \"%s\" is larger than 65535", src);
805 				return -1;
806 			}
807 
808 			dst->ushort = i;
809 		}
810 		break;
811 	}
812 
813 	case PW_TYPE_INTEGER:
814 	{
815 		char *p;
816 		unsigned int i;
817 
818 		/*
819 		 *	Note that ALL integers are unsigned!
820 		 */
821 		i = fr_strtoul(src, &p);
822 
823 		/*
824 		 *	Look for the named src for the given
825 		 *	attribute.
826 		 */
827 		if (src_enumv && *p && !is_whitespace(p)) {
828 			if ((dval = dict_valbyname(src_enumv->attr, src_enumv->vendor, src)) == NULL) {
829 				fr_strerror_printf("Unknown or invalid value \"%s\" for attribute %s",
830 						   src, src_enumv->name);
831 				return -1;
832 			}
833 
834 			dst->integer = dval->value;
835 		} else {
836 			/*
837 			 *	Value is always within the limits
838 			 */
839 			dst->integer = i;
840 		}
841 	}
842 		break;
843 
844 	case PW_TYPE_INTEGER64:
845 	{
846 		uint64_t i;
847 
848 		/*
849 		 *	Note that ALL integers are unsigned!
850 		 */
851 		if (sscanf(src, "%" PRIu64, &i) != 1) {
852 			fr_strerror_printf("Failed parsing \"%s\" as unsigned 64bit integer", src);
853 			return -1;
854 		}
855 		dst->integer64 = i;
856 	}
857 		break;
858 
859 	case PW_TYPE_DATE:
860 	{
861 		/*
862 		 *	time_t may be 64 bits, whule vp_date MUST be 32-bits.  We need an
863 		 *	intermediary variable to handle the conversions.
864 		 */
865 		time_t date;
866 		struct tm tm = { 0 };
867 		char *end;
868 
869 		/*
870 		 *	Try to parse dates via locale-specific names,
871 		 *	using the same format string as strftime(),
872 		 *	below.
873 		 *
874 		 *	If that fails (e.g. unix dates as integer),
875 		 *	then we fall back to our parsing routine,
876 		 *	which is much more forgiving.
877 		 */
878 		end = strptime(src, "%b %e %Y %H:%M:%S %Z", &tm);
879 		if (end && (*end == '\0')) {
880 			date = mktime(&tm);
881 
882 		} else if (fr_get_time(src, &date) < 0) {
883 			fr_strerror_printf("failed to parse time string \"%s\"", src);
884 			return -1;
885 		}
886 
887 		dst->date = date;
888 	}
889 
890 		break;
891 
892 	case PW_TYPE_IFID:
893 		if (ifid_aton(src, (void *) dst->ifid) == NULL) {
894 			fr_strerror_printf("Failed to parse interface-id string \"%s\"", src);
895 			return -1;
896 		}
897 		break;
898 
899 	case PW_TYPE_ETHERNET:
900 	{
901 		char const *c1, *c2, *cp;
902 		size_t p_len = 0;
903 
904 		/*
905 		 *	Convert things which are obviously integers to Ethernet addresses
906 		 *
907 		 *	We assume the number is the bigendian representation of the
908 		 *	ethernet address.
909 		 */
910 		if (is_integer(src)) {
911 			uint64_t integer = htonll(atoll(src));
912 
913 			memcpy(dst->ether, &integer, sizeof(dst->ether));
914 			break;
915 		}
916 
917 		cp = src;
918 		while (*cp) {
919 			if (cp[1] == ':') {
920 				c1 = hextab;
921 				c2 = memchr(hextab, tolower((int) cp[0]), 16);
922 				cp += 2;
923 			} else if ((cp[1] != '\0') && ((cp[2] == ':') || (cp[2] == '\0'))) {
924 				c1 = memchr(hextab, tolower((int) cp[0]), 16);
925 				c2 = memchr(hextab, tolower((int) cp[1]), 16);
926 				cp += 2;
927 				if (*cp == ':') cp++;
928 			} else {
929 				c1 = c2 = NULL;
930 			}
931 			if (!c1 || !c2 || (p_len >= sizeof(dst->ether))) {
932 				fr_strerror_printf("failed to parse Ethernet address \"%s\"", src);
933 				return -1;
934 			}
935 			dst->ether[p_len] = ((c1-hextab)<<4) + (c2-hextab);
936 			p_len++;
937 		}
938 	}
939 		break;
940 
941 	/*
942 	 *	Crazy polymorphic (IPv4/IPv6) attribute src_type for WiMAX.
943 	 *
944 	 *	We try and make is saner by replacing the original
945 	 *	da, with either an IPv4 or IPv6 da src_type.
946 	 *
947 	 *	These are not dynamic da, and will have the same vendor
948 	 *	and attribute as the original.
949 	 */
950 	case PW_TYPE_COMBO_IP_ADDR:
951 	{
952 		if (inet_pton(AF_INET6, src, &dst->ipv6addr) > 0) {
953 			*src_type = PW_TYPE_IPV6_ADDR;
954 			ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][1]; /* size of IPv6 address */
955 		} else {
956 			fr_ipaddr_t ipaddr;
957 
958 			if (ip_hton(&ipaddr, AF_INET, src, false) < 0) {
959 				fr_strerror_printf("Failed to find IPv4 address for %s", src);
960 				return -1;
961 			}
962 
963 			*src_type = PW_TYPE_IPV4_ADDR;
964 			dst->ipaddr.s_addr = ipaddr.ipaddr.ip4addr.s_addr;
965 			ret = dict_attr_sizes[PW_TYPE_COMBO_IP_ADDR][0]; /* size of IPv4 address */
966 		}
967 	}
968 		break;
969 
970 	case PW_TYPE_SIGNED:
971 		/* Damned code for 1 WiMAX attribute */
972 		dst->sinteger = (int32_t)strtol(src, NULL, 10);
973 		break;
974 
975 	/*
976 	 *  Anything else.
977 	 */
978 	default:
979 		fr_strerror_printf("Unknown attribute type %d", *src_type);
980 		return -1;
981 	}
982 
983 finish:
984 	return ret;
985 }
986 
987 /** Performs byte order reversal for types that need it
988  *
989  */
value_data_hton(value_data_t * dst,PW_TYPE dst_type,void const * src,size_t src_len)990 static ssize_t value_data_hton(value_data_t *dst, PW_TYPE dst_type, void const *src, size_t src_len)
991 {
992 	size_t dst_len;
993 	uint8_t *dst_ptr;
994 
995 	/* 8 byte integers */
996 	switch (dst_type) {
997 	case PW_TYPE_INTEGER64:
998 		dst_len = sizeof(dst->integer64);
999 
1000 		if (src_len < dst_len) {
1001 		too_small:
1002 			fr_strerror_printf("Source is too small to cast to destination type");
1003 			return -1;
1004 		}
1005 
1006 		dst->integer64 = htonll(*(uint64_t const *)src);
1007 		break;
1008 
1009 	/* 4 byte integers */
1010 	case PW_TYPE_INTEGER:
1011 	case PW_TYPE_DATE:
1012 	case PW_TYPE_SIGNED:
1013 		dst_len = sizeof(dst->integer);
1014 
1015 		if (src_len < dst_len) goto too_small;
1016 
1017 		dst->integer = htonl(*(uint32_t const *)src);
1018 		break;
1019 
1020 	/* 2 byte integers */
1021 	case PW_TYPE_SHORT:
1022 		dst_len = sizeof(dst->ushort);
1023 
1024 		if (src_len < dst_len) goto too_small;
1025 
1026 		dst->ushort = htons(*(uint16_t const *)src);
1027 		break;
1028 
1029 	/* 1 byte integer */
1030 	case PW_TYPE_BYTE:
1031 		dst_len = sizeof(dst->byte);
1032 
1033 		if (src_len < dst_len) goto too_small;
1034 
1035 		dst->byte = *(uint8_t const *)src;
1036 		break;
1037 
1038 	case PW_TYPE_IPV4_ADDR:
1039 		dst_len = 4;
1040 		dst_ptr = (uint8_t *) &dst->ipaddr.s_addr;
1041 
1042 	copy:
1043 		/*
1044 		 *	Not enough information, die.
1045 		 */
1046 		if (src_len < dst_len) goto too_small;
1047 
1048 		/*
1049 		 *	Copy only as much as we need from the source.
1050 		 */
1051 		memcpy(dst_ptr, src, dst_len);
1052 		break;
1053 
1054 	case PW_TYPE_ABINARY:
1055 		dst_len = sizeof(dst->filter);
1056 		dst_ptr = (uint8_t *) dst->filter;
1057 
1058 		/*
1059 		 *	Too little data is OK here.
1060 		 */
1061 		if (src_len < dst_len) {
1062 			memcpy(dst_ptr, src, src_len);
1063 			memset(dst_ptr + src_len, 0, dst_len - src_len);
1064 			break;
1065 		}
1066 		goto copy;
1067 
1068 	case PW_TYPE_IFID:
1069 		dst_len = sizeof(dst->ifid);
1070 		dst_ptr = (uint8_t *) dst->ifid;
1071 		goto copy;
1072 
1073 	case PW_TYPE_IPV6_ADDR:
1074 		dst_len = sizeof(dst->ipv6addr);
1075 		dst_ptr = (uint8_t *) dst->ipv6addr.s6_addr;
1076 		goto copy;
1077 
1078 	case PW_TYPE_IPV4_PREFIX:
1079 		dst_len = sizeof(dst->ipv4prefix);
1080 		dst_ptr = (uint8_t *) dst->ipv4prefix;
1081 
1082 		if (src_len < dst_len) goto too_small;
1083 		if ((((uint8_t const *)src)[1] & 0x3f) > 32) return -1;
1084 		goto copy;
1085 
1086 	case PW_TYPE_IPV6_PREFIX:
1087 		dst_len = sizeof(dst->ipv6prefix);
1088 		dst_ptr = (uint8_t *) dst->ipv6prefix;
1089 
1090 		/*
1091 		 *	Smaller IPv6 prefixes are OK, too, so long as
1092 		 *	they're not too short.
1093 		 */
1094 		if (src_len < 2) goto too_small;
1095 
1096 		/*
1097 		 *	Prefix is too long.
1098 		 */
1099 		if (((uint8_t const *)src)[1] > 128) return -1;
1100 
1101 		if (src_len < dst_len) {
1102 			memcpy(dst_ptr, src, src_len);
1103 			memset(dst_ptr + src_len, 0, dst_len - src_len);
1104 			break;
1105 		}
1106 
1107 		goto copy;
1108 
1109 	case PW_TYPE_ETHERNET:
1110 		dst_len = sizeof(dst->ether);
1111 		dst_ptr = (uint8_t *) dst->ether;
1112 		goto copy;
1113 
1114 	default:
1115 		fr_strerror_printf("Invalid cast to %s",
1116 				   fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1117 		return -1;	/* can't do it */
1118 	}
1119 
1120 	return dst_len;
1121 }
1122 
1123 /** Convert one type of value_data_t to another
1124  *
1125  * @note This should be the canonical function used to convert between data types.
1126  *
1127  * @param ctx to allocate buffers in (usually the same as dst)
1128  * @param dst Where to write result of casting.
1129  * @param dst_type to cast to.
1130  * @param dst_enumv Enumerated values used to converts strings to integers.
1131  * @param src_type to cast from.
1132  * @param src_enumv Enumerated values used to convert integers to strings.
1133  * @param src Input data.
1134  * @param src_len Input data len.
1135  * @return the length of data in the dst or -1 on error.
1136  */
value_data_cast(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE dst_type,DICT_ATTR const * dst_enumv,PW_TYPE src_type,DICT_ATTR const * src_enumv,value_data_t const * src,size_t src_len)1137 ssize_t value_data_cast(TALLOC_CTX *ctx, value_data_t *dst,
1138 			PW_TYPE dst_type, DICT_ATTR const *dst_enumv,
1139 			PW_TYPE src_type, DICT_ATTR const *src_enumv,
1140 			value_data_t const *src, size_t src_len)
1141 {
1142 	ssize_t dst_len;
1143 
1144 	if (!fr_assert(dst_type != src_type)) {
1145 		fr_strerror_printf("Types do not match");
1146 		return -1;
1147 	}
1148 
1149 	/*
1150 	 *	Deserialise a value_data_t
1151 	 */
1152 	if (src_type == PW_TYPE_STRING) {
1153 		return value_data_from_str(ctx, dst, &dst_type, dst_enumv, src->strvalue, src_len, '\0');
1154 	}
1155 
1156 	/*
1157 	 *	Converts the src data to octets with no processing.
1158 	 */
1159 	if (dst_type == PW_TYPE_OCTETS) {
1160 		dst_len = value_data_hton(dst, src_type, src, src_len);
1161 		if (dst_len < 0) return -1;
1162 
1163 		dst->octets = talloc_memdup(ctx, dst, dst_len);
1164 		talloc_set_type(dst->octets, uint8_t);
1165 		return dst_len;
1166 	}
1167 
1168 	/*
1169 	 *	Serialise a value_data_t
1170 	 */
1171 	if (dst_type == PW_TYPE_STRING) {
1172 		dst->strvalue = value_data_aprints(ctx, src_type, src_enumv, src, src_len, '\0');
1173 		return talloc_array_length(dst->strvalue) - 1;
1174 	}
1175 
1176 	if ((src_type == PW_TYPE_IFID) &&
1177 	    (dst_type == PW_TYPE_INTEGER64)) {
1178 		memcpy(&dst->integer64, src->ifid, sizeof(src->ifid));
1179 		dst->integer64 = htonll(dst->integer64);
1180 	fixed_length:
1181 		return dict_attr_sizes[dst_type][0];
1182 	}
1183 
1184 	if ((src_type == PW_TYPE_INTEGER64) &&
1185 	    (dst_type == PW_TYPE_ETHERNET)) {
1186 		uint8_t array[8];
1187 		uint64_t i;
1188 
1189 		i = htonll(src->integer64);
1190 		memcpy(array, &i, 8);
1191 
1192 		/*
1193 		 *	For OUIs in the DB.
1194 		 */
1195 		if ((array[0] != 0) || (array[1] != 0)) return -1;
1196 
1197 		memcpy(dst->ether, &array[2], 6);
1198 		goto fixed_length;
1199 	}
1200 
1201 	/*
1202 	 *	For integers, we allow the casting of a SMALL type to
1203 	 *	a larger type, but not vice-versa.
1204 	 */
1205 	if (dst_type == PW_TYPE_INTEGER64) {
1206 		switch (src_type) {
1207 		case PW_TYPE_BYTE:
1208 			dst->integer64 = src->byte;
1209 			break;
1210 
1211 		case PW_TYPE_SHORT:
1212 			dst->integer64 = src->ushort;
1213 			break;
1214 
1215 		case PW_TYPE_INTEGER:
1216 			dst->integer64 = src->integer;
1217 			break;
1218 
1219 		case PW_TYPE_DATE:
1220 			dst->integer64 = src->date;
1221 			break;
1222 
1223 		case PW_TYPE_OCTETS:
1224 			goto do_octets;
1225 
1226 		default:
1227 		invalid_cast:
1228 			fr_strerror_printf("Invalid cast from %s to %s",
1229 					   fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1230 					   fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1231 			return -1;
1232 
1233 		}
1234 		goto fixed_length;
1235 	}
1236 
1237 	/*
1238 	 *	We can cast LONG integers to SHORTER ones, so long
1239 	 *	as the long one is on the LHS.
1240 	 */
1241 	if (dst_type == PW_TYPE_INTEGER) {
1242 		switch (src_type) {
1243 		case PW_TYPE_BYTE:
1244 			dst->integer = src->byte;
1245 			break;
1246 
1247 		case PW_TYPE_SHORT:
1248 			dst->integer = src->ushort;
1249 			break;
1250 
1251 		case PW_TYPE_DATE:
1252 			dst->integer = src->date;
1253 			break;
1254 
1255 		case PW_TYPE_IPV4_ADDR:
1256 			dst->integer = ntohl(src->ipaddr.s_addr);
1257 			break;
1258 
1259 		case PW_TYPE_OCTETS:
1260 			goto do_octets;
1261 
1262 		default:
1263 			goto invalid_cast;
1264 		}
1265 		goto fixed_length;
1266 	}
1267 
1268 	if (dst_type == PW_TYPE_SHORT) {
1269 		switch (src_type) {
1270 		case PW_TYPE_BYTE:
1271 			dst->ushort = src->byte;
1272 			break;
1273 
1274 		case PW_TYPE_OCTETS:
1275 			goto do_octets;
1276 
1277 		default:
1278 			goto invalid_cast;
1279 		}
1280 		goto fixed_length;
1281 	}
1282 
1283 	/*
1284 	 *	We can cast integers less that < INT_MAX to signed
1285 	 */
1286 	if (dst_type == PW_TYPE_SIGNED) {
1287 		switch (src_type) {
1288 		case PW_TYPE_BYTE:
1289 			dst->sinteger = src->byte;
1290 			break;
1291 
1292 		case PW_TYPE_SHORT:
1293 			dst->sinteger = src->ushort;
1294 			break;
1295 
1296 		case PW_TYPE_INTEGER:
1297 			if (src->integer > INT_MAX) {
1298 				fr_strerror_printf("Invalid cast: From integer to signed.  integer value %u is larger "
1299 						   "than max signed int and would overflow", src->integer);
1300 				return -1;
1301 			}
1302 			dst->sinteger = (int)src->integer;
1303 			break;
1304 
1305 		case PW_TYPE_INTEGER64:
1306 			if (src->integer > INT_MAX) {
1307 				fr_strerror_printf("Invalid cast: From integer64 to signed.  integer64 value %" PRIu64
1308 						   " is larger than max signed int and would overflow", src->integer64);
1309 				return -1;
1310 			}
1311 			dst->sinteger = (int)src->integer64;
1312 			break;
1313 
1314 		case PW_TYPE_OCTETS:
1315 			goto do_octets;
1316 
1317 		default:
1318 			goto invalid_cast;
1319 		}
1320 		goto fixed_length;
1321 	}
1322 	/*
1323 	 *	Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
1324 	 *
1325 	 *	For prefix to ipaddress conversions, we assume that the host portion has already
1326 	 *	been zeroed out.
1327 	 *
1328 	 *	We allow casts from v6 to v4 if the v6 address has the correct mapping prefix.
1329 	 *
1330 	 *	We only allow casts from prefixes to addresses if the prefix is the the length of
1331 	 *	the address, e.g. 32 for ipv4 128 for ipv6.
1332 	 */
1333 	{
1334 		/*
1335 		 *	10 bytes of 0x00 2 bytes of 0xff
1336 		 */
1337 		static uint8_t const v4_v6_map[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1338 						     0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
1339 
1340 		switch (dst_type) {
1341 		case PW_TYPE_IPV4_ADDR:
1342 			switch (src_type) {
1343 			case PW_TYPE_IPV6_ADDR:
1344 				if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1345 				bad_v6_prefix_map:
1346 					fr_strerror_printf("Invalid cast from %s to %s.  No IPv4-IPv6 mapping prefix",
1347 							   fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1348 							   fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1349 					return -1;
1350 				}
1351 
1352 				memcpy(&dst->ipaddr, &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1353 				       sizeof(dst->ipaddr));
1354 				goto fixed_length;
1355 
1356 			case PW_TYPE_IPV4_PREFIX:
1357 				if (src->ipv4prefix[1] != 32) {
1358 				bad_v4_prefix_len:
1359 					fr_strerror_printf("Invalid cast from %s to %s.  Only /32 prefixes may be "
1360 							   "cast to IP address types",
1361 							   fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1362 							   fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1363 					return -1;
1364 				}
1365 
1366 				memcpy(&dst->ipaddr, &src->ipv4prefix[2], sizeof(dst->ipaddr));
1367 				goto fixed_length;
1368 
1369 			case PW_TYPE_IPV6_PREFIX:
1370 				if (src->ipv6prefix[1] != 128) {
1371 				bad_v6_prefix_len:
1372 					fr_strerror_printf("Invalid cast from %s to %s.  Only /128 prefixes may be "
1373 							   "cast to IP address types",
1374 							   fr_int2str(dict_attr_types, src_type, "<INVALID>"),
1375 							   fr_int2str(dict_attr_types, dst_type, "<INVALID>"));
1376 					return -1;
1377 				}
1378 				if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1379 					goto bad_v6_prefix_map;
1380 				}
1381 				memcpy(&dst->ipaddr, &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1382 				       sizeof(dst->ipaddr));
1383 				goto fixed_length;
1384 
1385 			default:
1386 				break;
1387 			}
1388 			break;
1389 
1390 		case PW_TYPE_IPV6_ADDR:
1391 			switch (src_type) {
1392 			case PW_TYPE_IPV4_ADDR:
1393 				/* Add the v4/v6 mapping prefix */
1394 				memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1395 				memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipaddr,
1396 				       sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1397 
1398 				goto fixed_length;
1399 
1400 			case PW_TYPE_IPV4_PREFIX:
1401 				if (src->ipv4prefix[1] != 32) goto bad_v4_prefix_len;
1402 
1403 				/* Add the v4/v6 mapping prefix */
1404 				memcpy(dst->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map));
1405 				memcpy(&dst->ipv6addr.s6_addr[sizeof(v4_v6_map)], &src->ipv4prefix[2],
1406 				       sizeof(dst->ipv6addr.s6_addr) - sizeof(v4_v6_map));
1407 				goto fixed_length;
1408 
1409 			case PW_TYPE_IPV6_PREFIX:
1410 				if (src->ipv4prefix[1] != 128) goto bad_v6_prefix_len;
1411 
1412 				memcpy(dst->ipv6addr.s6_addr, &src->ipv6prefix[2], sizeof(dst->ipv6addr.s6_addr));
1413 				goto fixed_length;
1414 
1415 			default:
1416 				break;
1417 			}
1418 			break;
1419 
1420 		case PW_TYPE_IPV4_PREFIX:
1421 			switch (src_type) {
1422 			case PW_TYPE_IPV4_ADDR:
1423 				memcpy(&dst->ipv4prefix[2], &src->ipaddr, sizeof(dst->ipv4prefix) - 2);
1424 				dst->ipv4prefix[0] = 0;
1425 				dst->ipv4prefix[1] = 32;
1426 				goto fixed_length;
1427 
1428 			case PW_TYPE_IPV6_ADDR:
1429 				if (memcmp(src->ipv6addr.s6_addr, v4_v6_map, sizeof(v4_v6_map)) != 0) {
1430 					goto bad_v6_prefix_map;
1431 				}
1432 				memcpy(&dst->ipv4prefix[2], &src->ipv6addr.s6_addr[sizeof(v4_v6_map)],
1433 				       sizeof(dst->ipv4prefix) - 2);
1434 				dst->ipv4prefix[0] = 0;
1435 				dst->ipv4prefix[1] = 32;
1436 				goto fixed_length;
1437 
1438 			case PW_TYPE_IPV6_PREFIX:
1439 				if (memcmp(&src->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map)) != 0) {
1440 					goto bad_v6_prefix_map;
1441 				}
1442 
1443 				/*
1444 				 *	Prefix must be >= 96 bits. If it's < 96 bytes and the
1445 				 *	above check passed, the v6 address wasn't masked
1446 				 *	correctly when it was packet into a value_data_t.
1447 				 */
1448 				if (!fr_assert(src->ipv6prefix[1] >= (sizeof(v4_v6_map) * 8))) return -1;
1449 
1450 				memcpy(&dst->ipv4prefix[2], &src->ipv6prefix[2 + sizeof(v4_v6_map)],
1451 				       sizeof(dst->ipv4prefix) - 2);
1452 				dst->ipv4prefix[0] = 0;
1453 				dst->ipv4prefix[1] = src->ipv6prefix[1] - (sizeof(v4_v6_map) * 8);
1454 				goto fixed_length;
1455 
1456 			default:
1457 				break;
1458 			}
1459 			break;
1460 
1461 		case PW_TYPE_IPV6_PREFIX:
1462 			switch (src_type) {
1463 			case PW_TYPE_IPV4_ADDR:
1464 				/* Add the v4/v6 mapping prefix */
1465 				memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1466 				memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipaddr,
1467 				       (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1468 				dst->ipv6prefix[0] = 0;
1469 				dst->ipv6prefix[1] = 128;
1470 				goto fixed_length;
1471 
1472 			case PW_TYPE_IPV4_PREFIX:
1473 				/* Add the v4/v6 mapping prefix */
1474 				memcpy(&dst->ipv6prefix[2], v4_v6_map, sizeof(v4_v6_map));
1475 				memcpy(&dst->ipv6prefix[2 + sizeof(v4_v6_map)], &src->ipv4prefix[2],
1476 				       (sizeof(dst->ipv6prefix) - 2) - sizeof(v4_v6_map));
1477 				dst->ipv6prefix[0] = 0;
1478 				dst->ipv6prefix[1] = (sizeof(v4_v6_map) * 8) + src->ipv4prefix[1];
1479 				goto fixed_length;
1480 
1481 			case PW_TYPE_IPV6_ADDR:
1482 				memcpy(&dst->ipv6prefix[2], &src->ipv6addr, sizeof(dst->ipv6prefix) - 2);
1483 				dst->ipv6prefix[0] = 0;
1484 				dst->ipv6prefix[1] = 128;
1485 				goto fixed_length;
1486 
1487 			default:
1488 				break;
1489 			}
1490 
1491 			break;
1492 
1493 		default:
1494 			break;
1495 		}
1496 	}
1497 
1498 	/*
1499 	 *	The attribute we've found has to have a size which is
1500 	 *	compatible with the type of the destination cast.
1501 	 */
1502 	if ((src_len < dict_attr_sizes[dst_type][0]) ||
1503 	    (src_len > dict_attr_sizes[dst_type][1])) {
1504 	    	char const *src_type_name;
1505 
1506 	    	src_type_name =  fr_int2str(dict_attr_types, src_type, "<INVALID>");
1507 		fr_strerror_printf("Invalid cast from %s to %s. Length should be between %zu and %zu but is %zu",
1508 				   src_type_name,
1509 				   fr_int2str(dict_attr_types, dst_type, "<INVALID>"),
1510 				   dict_attr_sizes[dst_type][0], dict_attr_sizes[dst_type][1],
1511 				   src_len);
1512 		return -1;
1513 	}
1514 
1515 	if (src_type == PW_TYPE_OCTETS) {
1516 	do_octets:
1517 		return value_data_hton(dst, dst_type, src->octets, src_len);
1518 	}
1519 
1520 	/*
1521 	 *	Convert host order to network byte order.
1522 	 */
1523 	if ((dst_type == PW_TYPE_IPV4_ADDR) &&
1524 	    ((src_type == PW_TYPE_INTEGER) ||
1525 	     (src_type == PW_TYPE_DATE) ||
1526 	     (src_type == PW_TYPE_SIGNED))) {
1527 		dst->ipaddr.s_addr = htonl(src->integer);
1528 
1529 	} else if ((src_type == PW_TYPE_IPV4_ADDR) &&
1530 		   ((dst_type == PW_TYPE_INTEGER) ||
1531 		    (dst_type == PW_TYPE_DATE) ||
1532 		    (dst_type == PW_TYPE_SIGNED))) {
1533 		dst->integer = htonl(src->ipaddr.s_addr);
1534 
1535 	} else {		/* they're of the same byte order */
1536 		memcpy(&dst, &src, src_len);
1537 	}
1538 
1539 	return src_len;
1540 }
1541 
1542 /** Copy value data verbatim duplicating any buffers
1543  *
1544  * @param ctx To allocate buffers in.
1545  * @param dst Where to copy value_data to.
1546  * @param src_type Type of src.
1547  * @param src Where to copy value_data from.
1548  * @param src_len Where
1549  */
value_data_copy(TALLOC_CTX * ctx,value_data_t * dst,PW_TYPE src_type,const value_data_t * src,size_t src_len)1550 ssize_t value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE src_type,
1551 			const value_data_t *src, size_t src_len)
1552 {
1553 	switch (src_type) {
1554 	default:
1555 		memcpy(dst, src, sizeof(*src));
1556 		break;
1557 
1558 	case PW_TYPE_STRING:
1559 		dst->strvalue = talloc_bstrndup(ctx, src->strvalue, src_len);
1560 		if (!dst->strvalue) return -1;
1561 		break;
1562 
1563 	case PW_TYPE_OCTETS:
1564 		dst->octets = talloc_memdup(ctx, src->octets, src_len);
1565 		talloc_set_type(dst->strvalue, uint8_t);
1566 		if (!dst->octets) return -1;
1567 		break;
1568 	}
1569 
1570 	return src_len;
1571 }
1572 
1573 
1574 
1575 /** Print one attribute value to a string
1576  *
1577  */
value_data_aprints(TALLOC_CTX * ctx,PW_TYPE type,DICT_ATTR const * enumv,value_data_t const * data,size_t inlen,char quote)1578 char *value_data_aprints(TALLOC_CTX *ctx,
1579 			 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1580 			 size_t inlen, char quote)
1581 {
1582 	char *p = NULL;
1583 	unsigned int i;
1584 
1585 	switch (type) {
1586 	case PW_TYPE_STRING:
1587 	{
1588 		size_t len, ret;
1589 
1590 		if (!quote) {
1591 			p = talloc_bstrndup(ctx, data->strvalue, inlen);
1592 			if (!p) return NULL;
1593 			talloc_set_type(p, char);
1594 			return p;
1595 		}
1596 
1597 		/* Gets us the size of the buffer we need to alloc */
1598 		len = fr_prints_len(data->strvalue, inlen, quote);
1599 		p = talloc_array(ctx, char, len);
1600 		if (!p) return NULL;
1601 
1602 		ret = fr_prints(p, len, data->strvalue, inlen, quote);
1603 		if (!fr_assert(ret == (len - 1))) {
1604 			talloc_free(p);
1605 			return NULL;
1606 		}
1607 		break;
1608 	}
1609 
1610 	case PW_TYPE_INTEGER:
1611 		i = data->integer;
1612 		goto print_int;
1613 
1614 	case PW_TYPE_SHORT:
1615 		i = data->ushort;
1616 		goto print_int;
1617 
1618 	case PW_TYPE_BYTE:
1619 		i = data->byte;
1620 
1621 	print_int:
1622 	{
1623 		DICT_VALUE const *dv;
1624 
1625 		if (enumv && (dv = dict_valbyattr(enumv->attr, enumv->vendor, i))) {
1626 			p = talloc_typed_strdup(ctx, dv->name);
1627 		} else {
1628 			p = talloc_typed_asprintf(ctx, "%u", i);
1629 		}
1630 	}
1631 		break;
1632 
1633 	case PW_TYPE_SIGNED:
1634 		p = talloc_typed_asprintf(ctx, "%d", data->sinteger);
1635 		break;
1636 
1637 	case PW_TYPE_INTEGER64:
1638 		p = talloc_typed_asprintf(ctx, "%" PRIu64 , data->integer64);
1639 		break;
1640 
1641 	case PW_TYPE_ETHERNET:
1642 		p = talloc_typed_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
1643 					  data->ether[0], data->ether[1],
1644 					  data->ether[2], data->ether[3],
1645 					  data->ether[4], data->ether[5]);
1646 		break;
1647 
1648 	case PW_TYPE_ABINARY:
1649 #ifdef WITH_ASCEND_BINARY
1650 		p = talloc_array(ctx, char, 128);
1651 		if (!p) return NULL;
1652 		print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
1653 		break;
1654 #else
1655 		  /* FALL THROUGH */
1656 #endif
1657 
1658 	case PW_TYPE_OCTETS:
1659 		p = talloc_array(ctx, char, 2 + 1 + inlen * 2);
1660 		if (!p) return NULL;
1661 		p[0] = '0';
1662 		p[1] = 'x';
1663 
1664 		fr_bin2hex(p + 2, data->octets, inlen);
1665 		p[2 + (inlen * 2)] = '\0';
1666 		break;
1667 
1668 	case PW_TYPE_DATE:
1669 	{
1670 		time_t t;
1671 		struct tm s_tm;
1672 
1673 		t = data->date;
1674 
1675 		p = talloc_zero_array(ctx, char, 64);
1676 		strftime(p, 63, "%b %e %Y %H:%M:%S %Z",
1677 			 localtime_r(&t, &s_tm));
1678 		break;
1679 	}
1680 
1681 	/*
1682 	 *	We need to use the proper inet_ntop functions for IP
1683 	 *	addresses, else the output might not match output of
1684 	 *	other functions, which makes testing difficult.
1685 	 *
1686 	 *	An example is tunnelled ipv4 in ipv6 addresses.
1687 	 */
1688 	case PW_TYPE_IPV4_ADDR:
1689 	case PW_TYPE_IPV4_PREFIX:
1690 	{
1691 		char buff[INET_ADDRSTRLEN  + 4]; // + /prefix
1692 
1693 		buff[0] = '\0';
1694 		value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1695 
1696 		p = talloc_typed_strdup(ctx, buff);
1697 	}
1698 	break;
1699 
1700 	case PW_TYPE_IPV6_ADDR:
1701 	case PW_TYPE_IPV6_PREFIX:
1702 	{
1703 		char buff[INET6_ADDRSTRLEN + 4]; // + /prefix
1704 
1705 		buff[0] = '\0';
1706 		value_data_prints(buff, sizeof(buff), type, enumv, data, inlen, '\0');
1707 
1708 		p = talloc_typed_strdup(ctx, buff);
1709 	}
1710 	break;
1711 
1712 	case PW_TYPE_IFID:
1713 		p = talloc_typed_asprintf(ctx, "%x:%x:%x:%x",
1714 					  (data->ifid[0] << 8) | data->ifid[1],
1715 					  (data->ifid[2] << 8) | data->ifid[3],
1716 					  (data->ifid[4] << 8) | data->ifid[5],
1717 					  (data->ifid[6] << 8) | data->ifid[7]);
1718 		break;
1719 
1720 	case PW_TYPE_BOOLEAN:
1721 		p = talloc_typed_strdup(ctx, data->byte ? "yes" : "no");
1722 		break;
1723 
1724 	/*
1725 	 *	Don't add default here
1726 	 */
1727 	case PW_TYPE_INVALID:
1728 	case PW_TYPE_COMBO_IP_ADDR:
1729 	case PW_TYPE_COMBO_IP_PREFIX:
1730 	case PW_TYPE_TLV:
1731 	case PW_TYPE_EXTENDED:
1732 	case PW_TYPE_LONG_EXTENDED:
1733 	case PW_TYPE_EVS:
1734 	case PW_TYPE_VSA:
1735 	case PW_TYPE_TIMEVAL:
1736 	case PW_TYPE_MAX:
1737 		fr_assert(0);
1738 		return NULL;
1739 	}
1740 
1741 	return p;
1742 }
1743 
1744 
1745 /** Print the value of an attribute to a string
1746  *
1747  * @note return value should be checked with is_truncated.
1748  * @note Will always \0 terminate unless outlen == 0.
1749  *
1750  * @param out Where to write the printed version of the attribute value.
1751  * @param outlen Length of the output buffer.
1752  * @param type of data being printed.
1753  * @param enumv Enumerated string values for integer types.
1754  * @param data to print.
1755  * @param inlen Length of data.
1756  * @param quote char to escape in string output.
1757  * @return  the number of bytes written to the out buffer, or a number >= outlen if truncation has occurred.
1758  */
value_data_prints(char * out,size_t outlen,PW_TYPE type,DICT_ATTR const * enumv,value_data_t const * data,ssize_t inlen,char quote)1759 size_t value_data_prints(char *out, size_t outlen,
1760 			 PW_TYPE type, DICT_ATTR const *enumv, value_data_t const *data,
1761 			 ssize_t inlen, char quote)
1762 {
1763 	DICT_VALUE	*v;
1764 	char		buf[1024];	/* Interim buffer to use with poorly behaved printing functions */
1765 	char const	*a = NULL;
1766 	char		*p = out;
1767 	time_t		t;
1768 	struct tm	s_tm;
1769 	unsigned int	i;
1770 
1771 	size_t		len = 0, freespace = outlen;
1772 
1773 	if (!data) return 0;
1774 	if (outlen == 0) return inlen;
1775 
1776 	*out = '\0';
1777 
1778 	p = out;
1779 
1780 	switch (type) {
1781 	case PW_TYPE_STRING:
1782 
1783 		/*
1784 		 *	Ensure that WE add the quotation marks around the string.
1785 		 */
1786 		if (quote) {
1787 			if (freespace < 3) return inlen + 2;
1788 
1789 			*p++ = quote;
1790 			freespace--;
1791 
1792 			len = fr_prints(p, freespace, data->strvalue, inlen, quote);
1793 			/* always terminate the quoted string with another quote */
1794 			if (len >= (freespace - 1)) {
1795 				/* Use out not p as we're operating on the entire buffer */
1796 				out[outlen - 2] = (char) quote;
1797 				out[outlen - 1] = '\0';
1798 				return len + 2;
1799 			}
1800 			p += len;
1801 			freespace -= len;
1802 
1803 			*p++ = (char) quote;
1804 			freespace--;
1805 			*p = '\0';
1806 
1807 			return len + 2;
1808 		}
1809 
1810 		return fr_prints(out, outlen, data->strvalue, inlen, quote);
1811 
1812 	case PW_TYPE_INTEGER:
1813 		i = data->integer;
1814 		goto print_int;
1815 
1816 	case PW_TYPE_SHORT:
1817 		i = data->ushort;
1818 		goto print_int;
1819 
1820 	case PW_TYPE_BYTE:
1821 		i = data->byte;
1822 
1823 print_int:
1824 		/* Normal, non-tagged attribute */
1825 		if (enumv && (v = dict_valbyattr(enumv->attr, enumv->vendor, i)) != NULL) {
1826 			a = v->name;
1827 			len = strlen(a);
1828 		} else {
1829 			/* should never be truncated */
1830 			len = snprintf(buf, sizeof(buf), "%u", i);
1831 			a = buf;
1832 		}
1833 		break;
1834 
1835 	case PW_TYPE_INTEGER64:
1836 		return snprintf(out, outlen, "%" PRIu64, data->integer64);
1837 
1838 	case PW_TYPE_DATE:
1839 		t = data->date;
1840 		if (quote > 0) {
1841 			len = strftime(buf, sizeof(buf) - 1, "%%%b %e %Y %H:%M:%S %Z%%", localtime_r(&t, &s_tm));
1842 			buf[0] = (char) quote;
1843 			buf[len - 1] = (char) quote;
1844 			buf[len] = '\0';
1845 		} else {
1846 			len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z", localtime_r(&t, &s_tm));
1847 		}
1848 		a = buf;
1849 		break;
1850 
1851 	case PW_TYPE_SIGNED: /* Damned code for 1 WiMAX attribute */
1852 		len = snprintf(buf, sizeof(buf), "%d", data->sinteger);
1853 		a = buf;
1854 		break;
1855 
1856 	case PW_TYPE_IPV4_ADDR:
1857 		a = inet_ntop(AF_INET, &(data->ipaddr), buf, sizeof(buf));
1858 		len = strlen(buf);
1859 		break;
1860 
1861 	case PW_TYPE_ABINARY:
1862 #ifdef WITH_ASCEND_BINARY
1863 		print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, inlen, quote);
1864 		a = buf;
1865 		len = strlen(buf);
1866 		break;
1867 #else
1868 	/* FALL THROUGH */
1869 #endif
1870 	case PW_TYPE_OCTETS:
1871 	case PW_TYPE_TLV:
1872 	{
1873 		size_t binlen;
1874 		size_t hexlen;
1875 
1876 		binlen = inlen;
1877 		hexlen = (binlen * 2) + 2; /* NOT accounting for trailing NUL */
1878 
1879 		/*
1880 		 *	If the buffer is too small, put something into
1881 		 *	it, and return how much we should have written
1882 		 *
1883 		 *	0 + x + H + H + NUL = 5
1884 		 */
1885 		if (freespace < 5) {
1886 			switch (freespace) {
1887 			case '4':
1888 			case '3':
1889 				out[0] = '0';
1890 				out[1] = 'x';
1891 				out[2] = '\0';
1892 				return hexlen;
1893 
1894 			case 2:
1895 				*out = '0';
1896 				out++;
1897 				/* FALL-THROUGH */
1898 
1899 			case 1:
1900 				*out = '\0';
1901 				break;
1902 
1903 			case 0:
1904 				break;
1905 			}
1906 
1907 			return hexlen;
1908 		}
1909 
1910 		/*
1911 		 *	The output buffer is at least 5 bytes, we haev
1912 		 *	room for '0xHH' plus a trailing NUL byte.
1913 		 */
1914 		out[0] = '0';
1915 		out[1] = 'x';
1916 
1917 		/*
1918 		 *	Get maximum number of bytes we can encode
1919 		 *	given freespace, ensuring we account for '0',
1920 		 *	'x', and the trailing NUL in the buffer.
1921 		 *
1922 		 *	Note that we can't have "freespace = 0" after
1923 		 *	this, as 'freespace' has to be at least 5.
1924 		 */
1925 		freespace -= 3;
1926 		freespace /= 2;
1927 		if (binlen > freespace) {
1928 			binlen = freespace;
1929 		}
1930 
1931 		fr_bin2hex(out + 2, data->octets, binlen);
1932 		return hexlen;
1933 	}
1934 
1935 	case PW_TYPE_IFID:
1936 		a = ifid_ntoa(buf, sizeof(buf), data->ifid);
1937 		len = strlen(buf);
1938 		break;
1939 
1940 	case PW_TYPE_IPV6_ADDR:
1941 		a = inet_ntop(AF_INET6, &data->ipv6addr, buf, sizeof(buf));
1942 		len = strlen(buf);
1943 		break;
1944 
1945 	case PW_TYPE_IPV6_PREFIX:
1946 	{
1947 		struct in6_addr addr;
1948 
1949 		/*
1950 		 *	Alignment issues.
1951 		 */
1952 		memcpy(&addr, &(data->ipv6prefix[2]), sizeof(addr));
1953 
1954 		a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
1955 		if (a) {
1956 			p = buf;
1957 
1958 			len = strlen(buf);
1959 			p += len;
1960 			len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) data->ipv6prefix[1]);
1961 		}
1962 	}
1963 		break;
1964 
1965 	case PW_TYPE_IPV4_PREFIX:
1966 	{
1967 		struct in_addr addr;
1968 
1969 		/*
1970 		 *	Alignment issues.
1971 		 */
1972 		memcpy(&addr, &(data->ipv4prefix[2]), sizeof(addr));
1973 
1974 		a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
1975 		if (a) {
1976 			p = buf;
1977 
1978 			len = strlen(buf);
1979 			p += len;
1980 			len += snprintf(p, sizeof(buf) - len, "/%u", (unsigned int) (data->ipv4prefix[1] & 0x3f));
1981 		}
1982 	}
1983 		break;
1984 
1985 	case PW_TYPE_ETHERNET:
1986 		return snprintf(out, outlen, "%02x:%02x:%02x:%02x:%02x:%02x",
1987 				data->ether[0], data->ether[1],
1988 				data->ether[2], data->ether[3],
1989 				data->ether[4], data->ether[5]);
1990 
1991 	/*
1992 	 *	Don't add default here
1993 	 */
1994 	case PW_TYPE_INVALID:
1995 	case PW_TYPE_COMBO_IP_ADDR:
1996 	case PW_TYPE_COMBO_IP_PREFIX:
1997 	case PW_TYPE_EXTENDED:
1998 	case PW_TYPE_LONG_EXTENDED:
1999 	case PW_TYPE_EVS:
2000 	case PW_TYPE_VSA:
2001 	case PW_TYPE_TIMEVAL:
2002 	case PW_TYPE_BOOLEAN:
2003 	case PW_TYPE_MAX:
2004 		fr_assert(0);
2005 		*out = '\0';
2006 		return 0;
2007 	}
2008 
2009 	if (a) strlcpy(out, a, outlen);
2010 
2011 	return len;	/* Return the number of bytes we would of written (for truncation detection) */
2012 }
2013 
2014