The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
calc.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: efa54e8a18513b795641ff2f17231e946e3fce24 $
19 *
20 * @file src/lib/util/calc.c
21 * @brief Functions to perform calculations on leaf values
22 *
23 * @copyright 2021 Network RADIUS SAS (legal@networkradius.com)
24 */
25
26RCSID("$Id: efa54e8a18513b795641ff2f17231e946e3fce24 $")
27
28#include <freeradius-devel/util/strerror.h>
29#include <freeradius-devel/util/regex.h>
30#include <math.h>
31#include "calc.h"
32
33#define swap(_a, _b) do { __typeof__ (_a) _tmp = _a; _a = _b; _b = _tmp; } while (0)
34
35#define ERR_ZERO (-5)
36#define ERR_UNDERFLOW (-4)
37#define ERR_OVERFLOW (-3)
38#define ERR_INVALID (-2)
39
40#define COERCE(_vb, _box, _type, _enumv) do { \
41 if (_vb->type != _type) { \
42 if (fr_value_box_cast(NULL, &_box, _type, _enumv, _vb) < 0) return -1; \
43 _vb = &_box; \
44 } \
45 } while (0)
46
47#define COERCE_A(_type, _enumv) COERCE(a, one, _type, _enumv)
48#define COERCE_B(_type, _enumv) COERCE(b, two, _type, _enumv)
49
50/** Updates type (a,b) -> c
51 *
52 * Note that we MUST have a less than b here. Otherwise there will
53 * be two entries for the same upcast, and the entries may get out of
54 * sync.
55 *
56 * These upcasts are for operations.
57 *
58 *
59 * If one side is a string and the other isn't, then we try to parse
60 * the string as the type of the other side.
61 *
62 * If one side is an octets type and the other isn't, then we try to
63 * parse the octets as the type of the other side.
64 */
65static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = {
66 /*
67 * string / octets -> octets
68 */
69 [FR_TYPE_STRING] = {
72 },
73
74 [FR_TYPE_OCTETS] = {
76 },
77
79 /*
80 * ipaddr + int --> prefix (generally only "and")
81 */
83
84 /*
85 * 192.168.0.255 - 192.168.0.1 -> int64
86 */
88 },
89
90 /*
91 * IPv6 mod IPv6 -> ????
92 */
95 },
96
97 /*
98 * Prefix + int --> ipaddr
99 */
104
106
111
113
118
121 },
122
126
128
133
135
140
143 },
144
148
150
155
157
162
165 },
166
169
174
176
181
184 },
185
186 /*
187 * Bools and to pretty much any numerical type result in
188 * the other integer.
189 */
190 [FR_TYPE_BOOL] = {
192
195
200
202
204
209
211
214 },
215
216 /*
217 * Various ints get cast to the next highest size which
218 * can hold their values.
219 */
220 [FR_TYPE_UINT8] = {
223
228
230
232
237
239
242 },
243
244 [FR_TYPE_UINT16] = {
247
251
253
255
260
262
265 },
266
267 [FR_TYPE_UINT32] = {
270
273
275
277
282
284
287 },
288
289 [FR_TYPE_UINT64] = {
292
295
297
299
301
304 },
305
306 [FR_TYPE_SIZE] = {
308
313
315
318 },
319
320 [FR_TYPE_DATE] = {
322
327
330
333 },
334
335 /*
336 * Signed ints
337 */
338 [FR_TYPE_INT8] = {
341
346
348
351 },
352
353 [FR_TYPE_INT16] = {
356
360
363 },
364
365 [FR_TYPE_INT32] = {
368
370
373 },
374
375 [FR_TYPE_INT64] = {
378
380
384 },
385
388
390
393 },
394
395 [FR_TYPE_FLOAT32] = {
397
400 },
401
402 [FR_TYPE_FLOAT64] = {
405 },
406};
407
408/** Updates type (a,b) -> c
409 *
410 * Note that we MUST have a less than b here. Otherwise there will
411 * be two entries for the same upcast, and the entries may get out of
412 * sync.
413 *
414 * These upcasts are for comparisons. In some cases, we can promote
415 * one data type to another, and then compare them. However, this is
416 * not always possible.
417 *
418 * If one side is a string and the other isn't, then we try to parse
419 * the string as the type of the other side.
420 *
421 * If one side is an octets type and the other isn't, then we try to
422 * parse the octets as the type of the other side.
423 *
424 * @todo - check this table against fr_type_promote()
425 */
426static const fr_type_t upcast_cmp[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = {
427 [FR_TYPE_STRING] = {
429 },
430
434
436
439
442
444 },
445
449
451
453 },
454
458
460
463 },
464
468
470 },
471
472 [FR_TYPE_IFID] = {
475 },
476
479 },
480
481 [FR_TYPE_ETHERNET] = {
484 },
485
486 /*
487 * Bools compared to pretty much any numerical type
488 * result in the other integer.
489 */
490 [FR_TYPE_BOOL] = {
493
498
500
502
507
509
512 },
513
514 /*
515 * Integers of the same sign get cast to the larger of
516 * the data type. Integers of different signs get cast
517 * to a *different* data type which can hold all values
518 * from both sides.
519 */
520 [FR_TYPE_UINT8] = {
523
527
529
531
536
538
541 },
542
543 [FR_TYPE_UINT16] = {
546
549
551
553
558
560
563 },
564
565 [FR_TYPE_UINT32] = {
568
570
572
574
579
581
584 },
585
586 [FR_TYPE_UINT64] = {
589
591
593
595
598 },
599
600 [FR_TYPE_SIZE] = {
602
607
610 },
611
612 [FR_TYPE_DATE] = {
614
619
621
624 },
625
626 /*
627 * Signed ints
628 */
629 [FR_TYPE_INT8] = {
632
636
638
641 },
642
643 [FR_TYPE_INT16] = {
646
649
652 },
653
654 [FR_TYPE_INT32] = {
657
659
662 },
663
664 [FR_TYPE_INT64] = {
667
669 },
670
673
676 },
677
678 [FR_TYPE_FLOAT32] = {
680
682 },
683
684 [FR_TYPE_FLOAT64] = {
686 },
687};
688
697
699{
700 fr_strerror_printf("Cannot perform mathematical operations on data type %s",
702 return -1;
703}
704
705static int handle_result(fr_type_t type, fr_token_t op, int rcode)
706{
707 if (rcode == ERR_ZERO) {
708 fr_strerror_const("Cannot divide by zero.");
709
710 } else if (rcode == ERR_UNDERFLOW) {
711 fr_strerror_printf("Value underflows '%s' when calculating result.",
713
714 } else if (rcode == ERR_OVERFLOW) {
715 fr_strerror_printf("Value overflows '%s' when calculating result.",
717
718 } else if (rcode == ERR_INVALID) {
719 fr_strerror_printf("Invalid assignment operator '%s' for result type '%s'.",
720 fr_tokens[op],
722 }
723
724 return rcode;
725}
726
727static int calc_bool(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
728{
729 fr_value_box_t one, two;
730
731 fr_assert(dst->type == FR_TYPE_BOOL);
732
733 COERCE_A(FR_TYPE_BOOL, NULL);
734 COERCE_B(FR_TYPE_BOOL, NULL);
735
736 switch (op) {
737 case T_ADD:
738 /*
739 * 1+1 = 2, which isn't a valid boolean value.
740 */
741 if (a->vb_bool & b->vb_bool) return ERR_OVERFLOW;
742
743 dst->vb_bool = a->vb_bool | b->vb_bool;
744 break;
745
746 case T_SUB:
747 /*
748 * 0-1 = -1, which isn't a valid boolean value.
749 */
750 if (a->vb_bool < b->vb_bool) return ERR_UNDERFLOW;
751
752 dst->vb_bool = a->vb_bool - b->vb_bool;
753 break;
754
755 case T_MUL: /* MUL is just AND here! */
756 case T_AND:
757 dst->vb_bool = a->vb_bool & b->vb_bool;
758 break;
759
760 case T_OR:
761 dst->vb_bool = a->vb_bool | b->vb_bool;
762 break;
763
764 case T_XOR:
765 dst->vb_bool = a->vb_bool ^ b->vb_bool;
766 break;
767
768 default:
769 return ERR_INVALID;
770 }
771
772 return 0;
773}
774
775static int calc_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
776{
777 fr_value_box_t one, two;
778 bool overflow;
779 int64_t when;
780
781 fr_assert(dst->type == FR_TYPE_DATE);
782
783 if ((a->type == FR_TYPE_DATE) && (b->type == FR_TYPE_DATE)) {
784 fr_strerror_const("Cannot perform operation on two values of type 'date'. One value must be a number.");
785 return -1;
786 }
787
788 fr_assert(!dst->enumv); /* unix time is always seconds */
789
790 /*
791 * Cast dates to time delta, do the conversions.
792 */
795
796 switch (op) {
797 case T_ADD:
798 if (!fr_add(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_OVERFLOW;
799
800 dst->vb_date = fr_unix_time_from_integer(&overflow, when, FR_TIME_RES_NSEC);
801 if (overflow) return ERR_OVERFLOW;
802 break;
803
804 case T_SUB:
805 if (!fr_sub(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_UNDERFLOW;
806
807 dst->vb_date = fr_unix_time_from_integer(&overflow, when, FR_TIME_RES_NSEC);
808 if (overflow) return ERR_UNDERFLOW;
809 break;
810
811 default:
812 return ERR_INVALID; /* invalid operator */
813 }
814
815 return 0;
816}
817
818static int calc_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
819{
820 fr_value_box_t one, two;
821 int64_t when;
822
823 fr_assert(dst->type == FR_TYPE_TIME_DELTA);
824
825 /*
826 * We can subtract two dates to get a time delta, but we
827 * cannot add two dates to get a time delta.
828 */
829 if ((a->type == FR_TYPE_DATE) && (b->type == FR_TYPE_DATE)) {
830 if (op != T_SUB) {
831 fr_strerror_const("Cannot perform operation on two values of type 'date'.");
832 return -1;
833 }
834 }
835
836 /*
837 * date % (time_delta) 1d --> time_delta
838 */
839 if (op == T_MOD) {
840 /*
841 * We MUST specify date ranges as a time delta, not as an integer. And it must be a
842 * positive time delta.
843 */
844 if ((b->type != FR_TYPE_TIME_DELTA) || !fr_time_delta_ispos(b->vb_time_delta)) {
845 return ERR_INVALID;
846 }
847
848 dst->vb_time_delta = fr_time_delta_wrap(fr_unix_time_unwrap(a->vb_date) % fr_time_delta_unwrap(b->vb_time_delta));
849 return 0;
850 }
851
852 /*
853 * Unix times are always converted 1-1 to our internal
854 * TIME_DELTA.
855 *
856 * We cast the inputs based on the destination time resolution. So "5ms + 5" = "10ms".
857 */
858 COERCE_A(FR_TYPE_TIME_DELTA, dst->enumv);
859
860 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
861 /*
862 * Don't touch the RHS.
863 */
864 fr_assert(b->type == FR_TYPE_UINT32);
865
866 } else {
867 COERCE_B(FR_TYPE_TIME_DELTA, dst->enumv);
868 }
869
870 switch (op) {
871 case T_ADD:
872 if (!fr_add(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_OVERFLOW;
873 dst->vb_time_delta = fr_time_delta_wrap(when);
874 break;
875
876 case T_SUB:
877 if (!fr_sub(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_UNDERFLOW;
878 dst->vb_time_delta = fr_time_delta_wrap(when);
879 break;
880
881 case T_RSHIFT:
882 if (b->vb_uint32 >= 64) return ERR_UNDERFLOW;
883
884 when = fr_time_delta_unwrap(a->vb_time_delta) >> b->vb_uint32;
885 dst->vb_time_delta = fr_time_delta_wrap(when);
886 break;
887
888 case T_LSHIFT:
889 if (b->vb_uint32 >= 64) return ERR_OVERFLOW;
890
891 when = fr_time_delta_unwrap(a->vb_time_delta) << b->vb_uint32;
892 dst->vb_time_delta = fr_time_delta_wrap(when);
893 break;
894
895 default:
896 return ERR_INVALID; /* invalid operator */
897 }
898
899 return 0;
900
901}
902
903static int calc_octets(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
904{
905 uint8_t *buf;
906 size_t len;
907 fr_value_box_t one = {};
908 fr_value_box_t two = {};
909
910 fr_assert(dst->type == FR_TYPE_OCTETS);
911
912 COERCE_A(FR_TYPE_OCTETS, dst->enumv);
913
914 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
915 /*
916 * Don't touch the RHS.
917 */
918 fr_assert(b->type == FR_TYPE_UINT32);
919
920 } else {
921 COERCE_B(FR_TYPE_OCTETS, dst->enumv);
922 }
923
924 len = a->vb_length + b->vb_length;
925
926 switch (op) {
927 case T_ADD: /* dst = a . b */
928 buf = talloc_array(ctx, uint8_t, len);
929 if (!buf) {
930 oom:
931 fr_strerror_const("Out of memory");
932 return -1;
933 }
934
935 memcpy(buf, a->vb_octets, a->vb_length);
936 memcpy(buf + a->vb_length, b->vb_octets, b->vb_length);
937
938 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, a->tainted | b->tainted);
939 break;
940
941 case T_SUB:
942 /*
943 * The inverse of add!
944 */
945 if (a->vb_length < b->vb_length) {
946 fr_strerror_const("Suffix to remove is longer than input string.");
947 return -1;
948 }
949
950 if (memcmp(a->vb_octets + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
951 fr_strerror_const("Suffix to remove is not a suffix of the input string.");
952 return -1;
953 }
954
955 len = a->vb_length - b->vb_length;
956 buf = talloc_array(ctx, uint8_t, len);
957 if (!buf) goto oom;
958
959 memcpy(buf, a->vb_strvalue, len);
960
961 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, a->tainted | b->tainted);
962 break;
963
964 case T_AND:
965 if (a->vb_length != b->vb_length) {
966 length_error:
967 fr_strerror_const("Cannot perform operation on strings of different length");
968 return -1;
969 }
970
971 buf = talloc_array(ctx, uint8_t, a->vb_length);
972 if (!buf) goto oom;
973
974 for (len = 0; len < a->vb_length; len++) {
975 buf[len] = a->vb_octets[len] & b->vb_octets[len];
976 }
977
978 fr_value_box_memdup_shallow(dst, dst->enumv, buf, a->vb_length, a->tainted | b->tainted);
979 break;
980
981 case T_OR:
982 if (a->vb_length != b->vb_length) goto length_error;
983
984 buf = talloc_array(ctx, uint8_t, a->vb_length);
985 if (!buf) goto oom;
986
987 for (len = 0; len < a->vb_length; len++) {
988 buf[len] = a->vb_octets[len] | b->vb_octets[len];
989 }
990
991 fr_value_box_memdup_shallow(dst, dst->enumv, buf, a->vb_length, a->tainted | b->tainted);
992 break;
993
994 case T_XOR:
995 if (a->vb_length != b->vb_length) goto length_error;
996
997 buf = talloc_array(ctx, uint8_t, a->vb_length);
998 if (!buf) goto oom;
999
1000 for (len = 0; len < a->vb_length; len++) {
1001 buf[len] = a->vb_octets[len] ^ b->vb_octets[len];
1002 }
1003
1004 fr_value_box_memdup_shallow(dst, dst->enumv, buf, a->vb_length, a->tainted | b->tainted);
1005 break;
1006
1007 case T_RSHIFT:
1008 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1009
1010 len = a->vb_length - b->vb_uint32;
1011 buf = talloc_array(ctx, uint8_t, len);
1012 if (!buf) goto oom;
1013
1014 memcpy(buf, a->vb_octets, len);
1015
1016 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, a->tainted);
1017 break;
1018
1019 case T_LSHIFT:
1020 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1021
1022 len = a->vb_length - b->vb_uint32;
1023
1024 buf = talloc_array(ctx, uint8_t, len);
1025 if (!buf) goto oom;
1026
1027 memcpy(buf, a->vb_octets + b->vb_uint32, len);
1028
1029 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, a->tainted);
1030 break;
1031
1032 default:
1033 return ERR_INVALID; /* invalid operator */
1034 }
1035
1036 if (a == &one) fr_value_box_clear_value(&one);
1037 if (b == &two) fr_value_box_clear_value(&two);
1038
1039 return 0;
1040}
1041
1042static int calc_string(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
1043{
1044 char *buf;
1045 size_t len;
1046 fr_value_box_t one = {};
1047 fr_value_box_t two = {};
1048
1049 fr_assert(dst->type == FR_TYPE_STRING);
1050
1051 COERCE_A(FR_TYPE_STRING, dst->enumv);
1052
1053 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1054 /*
1055 * Don't touch the RHS.
1056 */
1057 fr_assert(b->type == FR_TYPE_UINT32);
1058
1059 } else {
1060 COERCE_B(FR_TYPE_STRING, dst->enumv);
1061 }
1062
1063 len = a->vb_length + b->vb_length;
1064
1065 switch (op) {
1066 case T_ADD:
1067 buf = talloc_array(ctx, char, len + 1);
1068 if (!buf) {
1069 oom:
1070 fr_strerror_const("Out of memory");
1071 return -1;
1072 }
1073
1074 len = a->vb_length + b->vb_length;
1075 memcpy(buf, a->vb_strvalue, a->vb_length);
1076 memcpy(buf + a->vb_length, b->vb_strvalue, b->vb_length);
1077 buf[len] = '\0';
1078
1079 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, a->tainted | b->tainted);
1080 break;
1081
1082 case T_XOR: /* is prepend for strings */
1083 buf = talloc_array(ctx, char, len + 1);
1084 if (!buf) goto oom;
1085
1086 len = a->vb_length + b->vb_length;
1087 memcpy(buf, b->vb_strvalue, b->vb_length);
1088 memcpy(buf + b->vb_length, a->vb_strvalue, a->vb_length);
1089 buf[len] = '\0';
1090
1091 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, a->tainted | b->tainted);
1092 break;
1093
1094 case T_SUB:
1095 /*
1096 * The inverse of add!
1097 */
1098 if (a->vb_length < b->vb_length) {
1099 fr_strerror_const("Suffix to remove is longer than input string");
1100 return -1;
1101 }
1102
1103 if (memcmp(a->vb_strvalue + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
1104 fr_strerror_const("Suffix to remove is not a suffix of the input string");
1105 return -1;
1106 }
1107
1108 len = a->vb_length - b->vb_length;
1109 buf = talloc_array(ctx, char, len + 1);
1110 if (!buf) goto oom;
1111
1112 memcpy(buf, a->vb_strvalue, len);
1113 buf[len] = '\0';
1114
1115 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, a->tainted | b->tainted);
1116 break;
1117
1118 case T_RSHIFT:
1119 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1120
1121 len = a->vb_length - b->vb_uint32;
1122 buf = talloc_array(ctx, char, len + 1);
1123 if (!buf) goto oom;
1124
1125 memcpy(buf, a->vb_strvalue, len);
1126 buf[len] = '\0';
1127
1128 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, a->tainted);
1129 break;
1130
1131 case T_LSHIFT:
1132 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1133
1134 len = a->vb_length - b->vb_uint32;
1135
1136 buf = talloc_array(ctx, char, len + 1);
1137 if (!buf) goto oom;
1138
1139 memcpy(buf, a->vb_strvalue + b->vb_uint32, len);
1140 buf[len] = '\0';
1141
1142 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, a->tainted);
1143 break;
1144
1145 default:
1146 return ERR_INVALID; /* invalid operator */
1147 }
1148
1149 if (a == &one) fr_value_box_clear_value(&one);
1150 if (b == &two) fr_value_box_clear_value(&two);
1151
1152 return 0;
1153}
1154
1156{
1157 switch (in->type) {
1158 default:
1159 fr_strerror_printf("Cannot operate on ipaddr and %s",
1160 fr_type_to_str(in->type));
1161 return -1;
1162
1164 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_addr;
1165
1166 fr_value_box_init(out, FR_TYPE_IPV4_ADDR, NULL, in->tainted);
1167 out->vb_ip = in->vb_ip;
1168 break;
1169
1171 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_prefix;
1172
1173 fr_value_box_init(out, FR_TYPE_IPV4_PREFIX, NULL, in->tainted);
1174 out->vb_ip = in->vb_ip;
1175 break;
1176
1178 case FR_TYPE_IPV4_ADDR:
1179 fr_value_box_copy(NULL, out, in);
1180 break;
1181
1182 case FR_TYPE_IPV6_ADDR:
1184 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_ADDR, NULL, in) < 0) return -1;
1185 break;
1186
1188 cast_ipv6_prefix:
1189 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_PREFIX, NULL, in) < 0) return -1;
1190 break;
1191
1192 /*
1193 * All of these get mashed to 32-bits. The cast
1194 * operation will check bounds (both negative and
1195 * positive) on the run-time values.
1196 */
1197 case FR_TYPE_BOOL:
1198
1199 case FR_TYPE_UINT8:
1200 case FR_TYPE_UINT16:
1201 case FR_TYPE_UINT32:
1202 case FR_TYPE_UINT64:
1203
1204 case FR_TYPE_SIZE:
1205
1206 case FR_TYPE_INT8:
1207 case FR_TYPE_INT16:
1208 case FR_TYPE_INT32:
1209 case FR_TYPE_INT64:
1210
1211 case FR_TYPE_FLOAT32:
1212 case FR_TYPE_FLOAT64:
1213 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT32, NULL, in) < 0) return -1;
1214 break;
1215 }
1216
1217 return 0;
1218}
1219
1220static int calc_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1221{
1222 fr_value_box_t one, two;
1223 fr_value_box_t *a, *b;
1224
1225 fr_assert((dst->type == FR_TYPE_IPV4_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1226
1227 if (cast_ipv4_addr(&one, in1) < 0) return -1;
1228 a = &one;
1229
1230 if (cast_ipv4_addr(&two, in2) < 0) return -1;
1231 b = &two;
1232
1233 switch (op) {
1234 case T_ADD:
1235 case T_OR:
1236 /*
1237 * For simplicity, make sure that the prefix is first.
1238 */
1239 if (b->type == FR_TYPE_IPV4_PREFIX) swap(a,b);
1240
1241 /*
1242 * We can only add something to a prefix, and
1243 * that something has to be a number. The cast
1244 * operation already ensured that the number is
1245 * uint32, and is at least vaguely within the
1246 * allowed range.
1247 */
1248 if (a->type != FR_TYPE_IPV4_PREFIX) return ERR_INVALID;
1249
1250 if (b->type != FR_TYPE_UINT32) return ERR_INVALID;
1251
1252 /*
1253 * Trying to add a number outside of the given prefix. That's not allowed.
1254 */
1255 if (b->vb_uint32 >= (((uint32_t) 1) << (32 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1256
1257 dst->vb_ip.af = AF_INET;
1258 dst->vb_ip.addr.v4.s_addr = htonl(ntohl(a->vb_ip.addr.v4.s_addr) | b->vb_uint32);
1259 dst->vb_ip.prefix = 32;
1260 break;
1261
1262 default:
1263 return ERR_INVALID;
1264 }
1265
1266 return 0;
1267}
1268
1269static int calc_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
1270{
1271 int prefix;
1272 fr_value_box_t one, two, tmp;
1273
1274 fr_assert((dst->type == FR_TYPE_IPV4_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1275
1276 switch (op) {
1277 case T_AND:
1278 if (fr_type_is_integer(a->type)) {
1279 if (fr_value_box_cast(NULL, &one, FR_TYPE_UINT32, NULL, a) < 0) return -1;
1280
1281 a = &one;
1282 swap(a,b);
1283
1284 } else if (fr_type_is_integer(b->type)) {
1285 if (fr_value_box_cast(NULL, &two, FR_TYPE_UINT32, NULL, b) < 0) return -1;
1286 b = &two;
1287
1288 } else {
1289 fr_strerror_const("Invalid input types for ipv4prefix");
1290 return -1;
1291 }
1292
1293 switch (a->type) {
1294 case FR_TYPE_IPV6_ADDR:
1295 if (fr_value_box_cast(NULL, &tmp, FR_TYPE_IPV4_ADDR, NULL, a) < 0) return -1;
1296 break;
1297
1298 case FR_TYPE_IPV4_ADDR:
1299 break;
1300
1301 default:
1302 fr_strerror_printf("Invalid input data type '%s' for logical 'and'",
1303 fr_type_to_str(a->type));
1304
1305 return -1;
1306 }
1307
1308 if (b->vb_uint32 == 0) { /* set everything to zero */
1309 dst->vb_ip.addr.v4.s_addr = 0;
1310 prefix = 0;
1311
1312 } else if ((~b->vb_uint32) == 0) { /* all 1's */
1313 dst->vb_ip.addr.v4.s_addr = a->vb_ip.addr.v4.s_addr;
1314 prefix = 32;
1315
1316 } else {
1317 uint32_t mask;
1318
1319 mask = ~b->vb_uint32; /* 0xff00 -> 0x00ff */
1320 mask++; /* 0x00ff -> 0x0100 */
1321 if ((mask & b->vb_uint32) != mask) {
1322 fr_strerror_printf("Invalid network mask '0x%08x'", b->vb_uint32);
1323 return -1;
1324 }
1325
1326 mask = 0xfffffffe;
1327 prefix = 31;
1328
1329 while (prefix > 0) {
1330 if (mask == b->vb_uint32) break;
1331
1332 prefix--;
1333 /* coverity[overflow_const] */
1334 mask <<= 1;
1335 }
1336 fr_assert(prefix > 0);
1337
1338 dst->vb_ip.addr.v4.s_addr = htonl(ntohl(a->vb_ip.addr.v4.s_addr) & b->vb_uint32);
1339 }
1340
1341 dst->vb_ip.af = AF_INET;
1342 dst->vb_ip.prefix = prefix;
1343 break;
1344
1345 default:
1346 return ERR_INVALID;
1347 }
1348
1349 return 0;
1350}
1351
1353{
1354 switch (in->type) {
1355 default:
1356 fr_strerror_printf("Cannot operate on ipv6addr and %s",
1357 fr_type_to_str(in->type));
1358 return -1;
1359
1361 if (in->vb_ip.af == AF_INET) goto cast_ipv4_addr;
1362
1363 fr_value_box_init(out, FR_TYPE_IPV4_ADDR, NULL, in->tainted);
1364 out->vb_ip = in->vb_ip;
1365 break;
1366
1368 if (in->vb_ip.af == AF_INET) goto cast_ipv4_prefix;
1369
1370 fr_value_box_init(out, FR_TYPE_IPV4_PREFIX, NULL, in->tainted);
1371 out->vb_ip = in->vb_ip;
1372 break;
1373
1374
1376 case FR_TYPE_IPV6_ADDR:
1377 fr_value_box_copy(NULL, out, in);
1378 break;
1379
1380 case FR_TYPE_IPV4_ADDR:
1382 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_ADDR, NULL, in) < 0) return -1;
1383 break;
1384
1386 cast_ipv4_prefix:
1387 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_PREFIX, NULL, in) < 0) return -1;
1388 break;
1389
1390 /*
1391 * All of these get mashed to 64-bits. The cast
1392 * operation will check bounds (both negative and
1393 * positive) on the run-time values.
1394 */
1395 case FR_TYPE_BOOL:
1396
1397 case FR_TYPE_UINT8:
1398 case FR_TYPE_UINT16:
1399 case FR_TYPE_UINT32:
1400 case FR_TYPE_UINT64:
1401
1402 case FR_TYPE_SIZE:
1403
1404 case FR_TYPE_INT8:
1405 case FR_TYPE_INT16:
1406 case FR_TYPE_INT32:
1407 case FR_TYPE_INT64:
1408
1409 case FR_TYPE_FLOAT32:
1410 case FR_TYPE_FLOAT64:
1411 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT64, NULL, in) < 0) return -1;
1412 break;
1413 }
1414
1415 return 0;
1416}
1417
1418static int calc_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1419{
1420 fr_value_box_t one, two;
1421 fr_value_box_t *a, *b;
1422 int i;
1423 uint64_t mask;
1424
1425 fr_assert((dst->type == FR_TYPE_IPV6_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1426
1427 if (cast_ipv6_addr(&one, in1) < 0) return -1;
1428 a = &one;
1429
1430 if (cast_ipv6_addr(&two, in2) < 0) return -1;
1431 b = &two;
1432
1433 switch (op) {
1434 case T_ADD:
1435 /*
1436 * For simplicity, make sure that the prefix is first.
1437 */
1438 if (b->type == FR_TYPE_IPV6_PREFIX) swap(a,b);
1439
1440 /*
1441 * We can only add something to a prefix, and
1442 * that something has to be a number. The cast
1443 * operation already ensured that the number is
1444 * uint32, and is at least vaguely within the
1445 * allowed range.
1446 */
1447 if (a->type != FR_TYPE_IPV6_PREFIX) return ERR_INVALID;
1448
1449 if (b->type != FR_TYPE_UINT64) return ERR_INVALID;
1450
1451 /*
1452 * If we're adding a UINT64, the prefix can't be shorter than 64.
1453 */
1454 if (a->vb_ip.prefix <= 64) return ERR_OVERFLOW;
1455
1456 /*
1457 * Trying to add a number outside of the given prefix. That's not allowed.
1458 */
1459 if (b->vb_uint64 >= (((uint64_t) 1) << (128 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1460
1461 /*
1462 * Add in the relevant low bits.
1463 */
1464 mask = b->vb_uint64;
1465 for (i = 15; i >= ((a->vb_ip.prefix + 7) >> 3); i--) {
1466 dst->vb_ip.addr.v6.s6_addr[i] |= mask & 0xff;
1467 mask >>= 8;
1468 }
1469
1470 dst->vb_ip.af = AF_INET6;
1471 dst->vb_ip.prefix = 0;
1472 dst->vb_ip.scope_id = a->vb_ip.scope_id;
1473 break;
1474
1475 default:
1476 return ERR_INVALID;
1477 }
1478
1479 return 0;
1480}
1481
1482static int get_ipv6_prefix(uint8_t const *in)
1483{
1484 int i, j, prefix;
1485
1486 prefix = 128;
1487 for (i = 15; i >= 0; i--) {
1488 if (!in[i]) {
1489 prefix -= 8;
1490 continue;
1491 }
1492
1493 for (j = 0; j < 8; j++) {
1494 if ((in[i] & (1 << j)) == 0) {
1495 prefix--;
1496 continue;
1497 }
1498 return prefix;
1499 }
1500 }
1501
1502 return prefix;
1503}
1504
1505static int calc_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
1506{
1507 int i, prefix = 128;
1508 uint8_t const *pa, *pb;
1509 uint8_t *pdst;
1510
1511 fr_assert((dst->type == FR_TYPE_IPV6_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1512
1513 if (a->type == FR_TYPE_OCTETS) {
1514 if (a->vb_length != (128 / 8)) {
1515 fr_strerror_printf("Invalid length %zu for octets network mask", a->vb_length);
1516 return -1;
1517 }
1518 pa = a->vb_octets;
1519 prefix = get_ipv6_prefix(pa);
1520
1521 } else if (a->type == FR_TYPE_IPV6_ADDR) {
1522 pa = (const uint8_t *) &a->vb_ip.addr.v6.s6_addr;
1523
1524 } else {
1525 return ERR_INVALID;
1526 }
1527
1528 if (b->type == FR_TYPE_OCTETS) {
1529 if (b->vb_length != (128 / 8)) {
1530 fr_strerror_printf("Invalid length %zu for octets network mask", b->vb_length);
1531 return -1;
1532 }
1533 pb = b->vb_octets;
1534 prefix = get_ipv6_prefix(pb);
1535
1536 } else if (a->type == FR_TYPE_IPV6_ADDR) {
1537 pb = (const uint8_t *) &b->vb_ip.addr.v6;
1538
1539 } else {
1540 return ERR_INVALID;
1541 }
1542
1543 switch (op) {
1544 case T_AND:
1545 fr_value_box_init(dst, FR_TYPE_IPV6_PREFIX, NULL, a->tainted | b->tainted);
1546 pdst = (uint8_t *) &dst->vb_ip.addr.v6;
1547
1548 for (i = 0; i < 16; i++) {
1549 pdst[i] = pa[i] & pb[i];
1550 }
1551
1552 dst->vb_ip.af = AF_INET6;
1553 dst->vb_ip.prefix = prefix;
1554 break;
1555
1556 default:
1557 return ERR_INVALID;
1558 }
1559
1560 return 0;
1561}
1562
1563#define is_ipv6(_x) (((_x)->type == FR_TYPE_IPV6_ADDR) || ((_x)->type == FR_TYPE_IPV6_PREFIX) || ((((_x)->type == FR_TYPE_COMBO_IP_ADDR) || ((_x)->type == FR_TYPE_COMBO_IP_PREFIX)) && ((_x)->vb_ip.af == AF_INET6)))
1564
1565static int calc_combo_ip_addr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1566{
1567 /*
1568 * IPv6 is better than IPv4!
1569 */
1570 if (is_ipv6(in1) || is_ipv6(in2)) {
1571 return calc_ipv6_addr(ctx, dst, in1, op, in2);
1572 }
1573
1574 return calc_ipv4_addr(ctx, dst, in1, op, in2);
1575}
1576
1577static int calc_combo_ip_prefix(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1578{
1579 if (is_ipv6(in1) || is_ipv6(in2)) {
1580 return calc_ipv6_prefix(ctx, dst, in1, op, in2);
1581 }
1582
1583 return calc_ipv4_prefix(ctx, dst, in1, op, in2);
1584}
1585
1586
1587static int calc_float32(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1588{
1589 fr_value_box_t one, two;
1590 fr_value_box_t const *a = in1;
1591 fr_value_box_t const *b = in2;
1592
1593 fr_assert(dst->type == FR_TYPE_FLOAT32);
1594
1595 /*
1596 * Intermediate calculations are done using increased precision.
1597 */
1600
1601 switch (op) {
1602 case T_ADD:
1603 dst->vb_float32 = a->vb_float64 + b->vb_float64;
1604 break;
1605
1606 case T_SUB:
1607 dst->vb_float32 = a->vb_float64 - b->vb_float64;
1608 break;
1609
1610 case T_MUL:
1611 dst->vb_float32 = a->vb_float64 * b->vb_float64;
1612 break;
1613
1614 case T_DIV:
1615 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1616
1617 dst->vb_float32 = a->vb_float64 / b->vb_float64;
1618 break;
1619
1620 case T_MOD:
1621 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1622
1623 dst->vb_float32 = fmod(a->vb_float64, b->vb_float64);
1624 break;
1625
1626 default:
1627 return ERR_INVALID;
1628 }
1629
1630 return 0;
1631
1632}
1633
1634static int calc_float64(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1635{
1636 fr_value_box_t one, two;
1637 fr_value_box_t const *a = in1;
1638 fr_value_box_t const *b = in2;
1639
1640 fr_assert(dst->type == FR_TYPE_FLOAT64);
1641
1644
1645 switch (op) {
1646 case T_ADD:
1647 dst->vb_float64 = a->vb_float64 + b->vb_float64;
1648 break;
1649
1650 case T_SUB:
1651 dst->vb_float64 = a->vb_float64 - b->vb_float64;
1652 break;
1653
1654 case T_MUL:
1655 dst->vb_float64 = a->vb_float64 * b->vb_float64;
1656 break;
1657
1658 case T_DIV:
1659 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1660
1661 dst->vb_float64 = a->vb_float64 / b->vb_float64;
1662 break;
1663
1664 case T_MOD:
1665 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1666
1667 dst->vb_float64 = fmod(a->vb_float64, b->vb_float64);
1668 break;
1669
1670 default:
1671 return ERR_INVALID;
1672 }
1673
1674 return 0;
1675
1676}
1677
1678/*
1679 * Do all intermediate operations on 64-bit numbers.
1680 */
1681static int calc_uint64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1682{
1683 fr_value_box_t one, two, result;
1684 fr_value_box_t const *a = in1;
1685 fr_value_box_t const *b = in2;
1686
1687 fr_value_box_init(&result, FR_TYPE_UINT64, NULL, a->tainted | b->tainted);
1688
1689 COERCE_A(FR_TYPE_UINT64, NULL);
1690
1691 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1692 /*
1693 * Don't touch the RHS.
1694 */
1695 fr_assert(b->type == FR_TYPE_UINT32);
1696
1697 } else {
1698 COERCE_B(FR_TYPE_UINT64, dst->enumv);
1699 }
1700
1701 switch (op) {
1702 case T_ADD:
1703 if (!fr_add(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1704 break;
1705
1706 case T_SUB:
1707 if (!fr_sub(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_UNDERFLOW;
1708 break;
1709
1710 case T_MUL:
1711 if (!fr_multiply(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1712 break;
1713
1714 case T_DIV:
1715 if (b->vb_uint64 == 0) return ERR_ZERO;
1716
1717 result.vb_uint64 = a->vb_uint64 / b->vb_uint64;
1718 break;
1719
1720 case T_MOD:
1721 if (b->vb_uint64 == 0) return ERR_ZERO;
1722
1723 result.vb_uint64 = a->vb_uint64 % in2->vb_uint64;
1724 break;
1725
1726 case T_AND:
1727 result.vb_uint64 = a->vb_uint64 & b->vb_uint64;
1728 break;
1729
1730 case T_OR:
1731 result.vb_uint64 = a->vb_uint64 | b->vb_uint64;
1732 break;
1733
1734 case T_XOR:
1735 result.vb_uint64 = a->vb_uint64 ^ b->vb_uint64;
1736 break;
1737
1738 case T_RSHIFT:
1739 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_UNDERFLOW;
1740
1741 result.vb_uint64 = a->vb_uint64 >> b->vb_uint32;
1742 break;
1743
1744 case T_LSHIFT:
1745 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_OVERFLOW;
1746
1747 result.vb_uint64 = a->vb_uint64 << b->vb_uint32;
1748 break;
1749
1750 default:
1751 return ERR_INVALID;
1752 }
1753
1754 /*
1755 * Once we're done, cast the result to the final data type.
1756 */
1757 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1758
1759 return 0;
1760}
1761
1762/*
1763 * Same as above, except uint64 -> int64. These functions should be kept in sync!
1764 */
1765static int calc_int64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
1766{
1767 fr_value_box_t one, two, result;
1768 fr_value_box_t const *a = in1;
1769 fr_value_box_t const *b = in2;
1770
1771 fr_value_box_init(&result, FR_TYPE_INT64, NULL, a->tainted | b->tainted);
1772
1773 COERCE_A(FR_TYPE_INT64, NULL);
1774
1775 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1776 /*
1777 * Don't touch the RHS.
1778 */
1779 fr_assert(b->type == FR_TYPE_UINT32);
1780
1781 } else {
1782 COERCE_B(FR_TYPE_INT64, dst->enumv);
1783 }
1784
1785 switch (op) {
1786 case T_ADD:
1787 if (!fr_add(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1788 break;
1789
1790 case T_SUB:
1791 if (!fr_sub(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_UNDERFLOW;
1792 break;
1793
1794 case T_MUL:
1795 if (!fr_multiply(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1796 break;
1797
1798 case T_DIV:
1799 if (b->vb_int64 == 0) return ERR_ZERO;
1800
1801 result.vb_int64 = a->vb_int64 / b->vb_int64;
1802 break;
1803
1804 case T_MOD:
1805 if (b->vb_int64 == 0) return ERR_ZERO;
1806
1807 result.vb_int64 = a->vb_int64 % in2->vb_int64;
1808 break;
1809
1810 case T_AND:
1811 result.vb_int64 = a->vb_int64 & b->vb_int64;
1812 break;
1813
1814 case T_OR:
1815 result.vb_int64 = a->vb_int64 | b->vb_int64;
1816 break;
1817
1818 case T_XOR:
1819 result.vb_int64 = a->vb_int64 ^ b->vb_int64;
1820 break;
1821
1822 case T_RSHIFT:
1823 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_UNDERFLOW;
1824
1825 result.vb_int64 = a->vb_int64 >> b->vb_uint32;
1826 break;
1827
1828 case T_LSHIFT:
1829 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_OVERFLOW;
1830
1831 result.vb_int64 = a->vb_int64 << b->vb_uint32;
1832 break;
1833
1834 default:
1835 return ERR_INVALID;
1836 }
1837
1838 /*
1839 * Once we're done, cast the result to the final data type.
1840 */
1841 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1842
1843 return 0;
1844}
1845
1846typedef int (*fr_binary_op_t)(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b);
1847
1848/** Map output type to its associated function
1849 *
1850 */
1884
1885/** Calculate DST = A OP B
1886 *
1887 * The result is written to DST only *after* it has been calculated.
1888 * So it's safe to pass DST as either A or B. DST should already exist.
1889 *
1890 * This function should arguably not take comparison operators, but
1891 * whatever. The "promote types" code is the same for all of the
1892 * binary operations, so we might as well just have one function.
1893 */
1894int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
1895{
1896 int rcode = -1;
1897 fr_value_box_t one, two;
1899 fr_binary_op_t func;
1900
1901 if ((hint != FR_TYPE_NULL) && !fr_type_is_leaf(hint)) return invalid_type(hint);
1902
1903 /*
1904 * Casting to structural types should be a parse error,
1905 * and not a run-time calculation error.
1906 */
1907 if (!fr_type_is_leaf(a->type)) return invalid_type(a->type);
1908 if (!fr_type_is_leaf(b->type)) return invalid_type(b->type);
1909
1910 /*
1911 * === and !== also check types. If the types are
1912 * different, it's a failure. Otherwise they revert to == and !=.
1913 */
1914 switch (op) {
1915 case T_OP_CMP_EQ_TYPE:
1916 if (a->type != b->type) {
1917 mismatch_type:
1918 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
1919 dst->vb_bool = false;
1920 return 0;
1921 }
1922 op = T_OP_CMP_EQ;
1923 break;
1924
1925 case T_OP_CMP_NE_TYPE:
1926 if (a->type != b->type) goto mismatch_type;
1927
1928 op = T_OP_NE;
1929 break;
1930
1931 case T_OP_REG_EQ:
1932 case T_OP_REG_NE:
1933 if (b->type != FR_TYPE_STRING) {
1934 fr_strerror_const("Invalid type for regular expression");
1935 return -1;
1936 }
1937
1938 rcode = fr_regex_cmp_op(op, a, b);
1939 if (rcode < 0) return rcode;
1940
1941 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
1942 dst->vb_bool = (rcode != 0);
1943 return 0;
1944
1945 default:
1946 break;
1947 }
1948
1951
1952 /*
1953 * We don't know what the output type should be. Try to
1954 * guess based on a variety of factors.
1955 */
1956 if (hint == FR_TYPE_NULL) do {
1957 /*
1958 * All kinds of special cases :(
1959 *
1960 * date1 - date2 --> time_delta
1961 *
1962 * time_delta * FOO --> float64, because time_delta is _printed_ as a floating point
1963 * number. And this is the least surprising thing to do.
1964 */
1965 if ((op == T_SUB) && (a->type == b->type) && (a->type == FR_TYPE_DATE)) {
1966 hint = FR_TYPE_TIME_DELTA;
1967 break;
1968 }
1969
1970 if (op == T_MUL) {
1971 if (a->type == FR_TYPE_TIME_DELTA) {
1972 hint = upcast_op[FR_TYPE_FLOAT64][b->type];
1973 if (hint == FR_TYPE_NULL) hint = upcast_op[b->type][FR_TYPE_FLOAT64];
1974
1975 } else if (b->type == FR_TYPE_TIME_DELTA) {
1976 hint = upcast_op[a->type][FR_TYPE_FLOAT64];
1977 if (hint == FR_TYPE_NULL) hint = upcast_op[FR_TYPE_FLOAT64][a->type];
1978 }
1979
1980 if (hint != FR_TYPE_NULL) break;
1981 }
1982
1983 /*
1984 * date % time_delta --> time_delta
1985 */
1986 if ((op == T_MOD) && (a->type == FR_TYPE_DATE)) {
1987 hint = FR_TYPE_TIME_DELTA;
1988 break;
1989 }
1990
1991 switch (op) {
1992 case T_OP_CMP_EQ:
1993 case T_OP_NE:
1994 case T_OP_GE:
1995 case T_OP_GT:
1996 case T_OP_LE:
1997 case T_OP_LT:
1998 /*
1999 * Comparison operators always return
2000 * "bool".
2001 */
2002 hint = FR_TYPE_BOOL;
2003 break;
2004
2005 case T_AND:
2006 /*
2007 * Get mask from IP + number
2008 */
2009 if ((a->type == FR_TYPE_IPV4_ADDR) || (b->type == FR_TYPE_IPV4_ADDR)) {
2010 hint = FR_TYPE_IPV4_PREFIX;
2011 break;
2012 }
2013
2014 if ((a->type == FR_TYPE_IPV6_ADDR) || (b->type == FR_TYPE_IPV6_ADDR)) {
2015 hint = FR_TYPE_IPV6_PREFIX;
2016 break;
2017 }
2019
2020 case T_OR:
2021 case T_ADD:
2022 case T_SUB:
2023 case T_MUL:
2024 case T_DIV:
2025 case T_MOD:
2026 case T_XOR:
2027 /*
2028 * Try to "up-cast" the types. This is
2029 * so that we can take (for example)
2030 * uint8 + uint16, and have the output as
2031 * uint16.
2032 *
2033 * There must be only one entry per [a,b]
2034 * pairing. That way we're sure that [a,b]==[b,a]
2035 */
2036 hint = upcast_op[a->type][b->type];
2037 if (hint == FR_TYPE_NULL) {
2038 hint = upcast_op[b->type][a->type];
2039 } else if (a->type != b->type) {
2040 fr_assert(upcast_op[b->type][a->type] == FR_TYPE_NULL);
2041 }
2042
2043 /*
2044 * No idea what to do. :(
2045 */
2046 if (hint == FR_TYPE_NULL) {
2047 fr_strerror_printf("Invalid operation on data types - '%s' %s '%s'",
2048 fr_type_to_str(a->type), fr_tokens[op], fr_type_to_str(b->type));
2049 goto done;
2050 }
2051
2052 break;
2053
2054 /*
2055 * The RHS MUST be a numerical type. We don't need to do any upcasting here.
2056 *
2057 * @todo - the output type could be larger than the input type, if the shift is
2058 * more than the input type can handle. e.g. uint8 << 4 could result in uint16
2059 */
2060 case T_LSHIFT:
2061 if (!fr_type_is_integer(a->type)) {
2062 return handle_result(a->type, T_LSHIFT, ERR_INVALID);
2063 }
2064
2065 if (fr_type_is_signed(a->type)) {
2066 hint = FR_TYPE_INT64;
2067 break;
2068 }
2069 hint = FR_TYPE_UINT64;
2070 break;
2071
2072 case T_RSHIFT:
2073 hint = a->type;
2074 break;
2075
2076 default:
2077 return handle_result(a->type, op, ERR_INVALID);
2078 }
2079 } while (0);
2080
2081 /*
2082 * Now that we've figured out the correct types, perform the operation.
2083 */
2084 switch (op) {
2085 case T_OP_CMP_EQ:
2086 case T_OP_NE:
2087 case T_OP_GE:
2088 case T_OP_GT:
2089 case T_OP_LE:
2090 case T_OP_LT:
2091 if (hint != FR_TYPE_BOOL) {
2092 fr_strerror_printf("Invalid destination type '%s' for comparison operator",
2093 fr_type_to_str(hint));
2094 goto done;
2095 }
2096
2097 /*
2098 * Convert the types to ones which are comparable.
2099 */
2100 if (a->type != b->type) {
2101 fr_dict_attr_t const *enumv = NULL;
2102
2103 /*
2104 * If we're doing comparisons and one of them has an enum, and the other is an
2105 * enum name, then use the enum name to convert the string to the other type.
2106 *
2107 * We can then do type-specific comparisons.
2108 */
2109 if ((a->type == FR_TYPE_STRING) && b->enumv) {
2110 enumv = b->enumv;
2111 hint = b->type;
2112
2113 } else if ((b->type == FR_TYPE_STRING) && a->enumv) {
2114 enumv = a->enumv;
2115 hint = a->type;
2116
2117 } else {
2118 /*
2119 * Try to "up-cast" the types. This is so that we can take (for example)
2120 * uint8 < uint16, and have it make sense.
2121 *
2122 * There must be only one entry per [a,b] pairing. That way we're sure
2123 * that [a,b]==[b,a]
2124 */
2125 hint = upcast_cmp[a->type][b->type];
2126 if (hint == FR_TYPE_NULL) {
2127 hint = upcast_cmp[b->type][a->type];
2128 } else {
2129 fr_assert(upcast_cmp[b->type][a->type] == FR_TYPE_NULL);
2130 }
2131
2132 /*
2133 * time_deltas have a scale in the enumv, but default to "seconds" if
2134 * there's no scale. As a result, if we compare time_delta(ms) to integer,
2135 * then the integer is interpreted as seconds, and the scale is wrong.
2136 *
2137 * The solution is to use the appropriate scale.
2138 */
2139 if (hint == a->type) enumv = a->enumv;
2140 if (hint == b->type) enumv = b->enumv;
2141
2142 if (hint == FR_TYPE_NULL) {
2143 fr_strerror_printf("Cannot compare incompatible types (%s)... %s (%s)...",
2144 fr_type_to_str(a->type),
2145 fr_tokens[op],
2146 fr_type_to_str(b->type));
2147 goto done;
2148 }
2149 }
2150
2151 /*
2152 * Cast them to the appropriate type, which may be different from either of the
2153 * inputs.
2154 */
2155 if (a->type != hint) {
2156 if (fr_value_box_cast(NULL, &one, hint, enumv, a) < 0) goto done;
2157 a = &one;
2158 }
2159
2160 if (b->type != hint) {
2161 if (fr_value_box_cast(NULL, &two, hint, enumv, b) < 0) goto done;
2162 b = &two;
2163 }
2164 }
2165
2166 rcode = fr_value_box_cmp_op(op, a, b);
2167 if (rcode < 0) goto done;
2168
2169 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false);
2170 dst->vb_bool = (rcode > 0);
2171 break;
2172
2173 /*
2174 * For shifts, the RHS value MUST be an integer. There's no reason to have it as
2175 * anything other than an 8-bit field.
2176 */
2177 case T_LSHIFT:
2178 case T_RSHIFT:
2179 if (b->type != FR_TYPE_UINT32) {
2180 if (fr_value_box_cast(ctx, &two, FR_TYPE_UINT32, NULL, b) < 0) {
2181 fr_strerror_printf("Cannot parse shift value as integer - %s",
2182 fr_strerror());
2183 goto done;
2184 }
2185 b = &two;
2186 }
2188
2189 case T_ADD:
2190 case T_SUB:
2191 case T_MUL:
2192 case T_DIV:
2193 case T_MOD:
2194 case T_AND:
2195 case T_OR:
2196 case T_XOR:
2197 fr_assert(hint != FR_TYPE_NULL);
2198
2199 func = calc_type[hint];
2200 if (!func) {
2201 fr_strerror_printf("Cannot perform any operations for destination type %s",
2202 fr_type_to_str(hint));
2203 rcode = -1;
2204 break;
2205 }
2206
2207 /*
2208 * It's OK to use one of the inputs as the
2209 * output. In order to ensure that nothing bad
2210 * happens, we use an intermediate value-box.
2211 */
2212 fr_value_box_init(&out, hint, NULL, false);
2213
2214 rcode = func(ctx, &out, a, op, b); /* not calc_type[hint], to shut up clang */
2215 if (rcode < 0) goto done;
2216
2217 fr_value_box_copy_shallow(NULL, dst, &out);
2218 dst->tainted = a->tainted | b->tainted;
2219 break;
2220
2221 default:
2222 rcode = ERR_INVALID;
2223 break;
2224 }
2225
2226done:
2229
2230 return handle_result(hint, op, rcode);
2231}
2232
2233/** Calculate DST = OP { A, B, C, ... }
2234 *
2235 * The result is written to DST only *after* it has been calculated.
2236 * So it's safe to pass DST as one of the inputs. DST should already
2237 * exist.
2238 */
2240{
2241 fr_value_box_t out, *vb;
2242 fr_binary_op_t calc;
2243
2244 if (group->type != FR_TYPE_GROUP) {
2245 fr_strerror_const("Invalid type passed to multivalue calculation");
2246 return -1;
2247 }
2248
2251 fr_strerror_printf("Invalid operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2252 return -1;
2253 }
2254
2255 if (type == FR_TYPE_STRING) {
2256 fr_sbuff_t *sbuff;
2257 bool secret = false;
2258 bool tainted = false;
2259
2260 if (op != T_ADD) goto invalid_type;
2261
2262 FR_SBUFF_TALLOC_THREAD_LOCAL(&sbuff, 1024, (1 << 16));
2263
2264 if (fr_value_box_list_concat_as_string(&tainted, &secret, sbuff, UNCONST(fr_value_box_list_t *, &group->vb_group),
2265 NULL, 0, NULL, FR_VALUE_BOX_LIST_NONE, 0, false) < 0) return -1;
2266
2267 if (fr_value_box_bstrndup(ctx, dst, NULL, fr_sbuff_start(sbuff), fr_sbuff_used(sbuff), tainted) < 0) return -1;
2268
2270
2271 return 0;
2272 }
2273
2274 if (type == FR_TYPE_OCTETS) {
2275 fr_dbuff_t *dbuff;
2276 bool secret = false;
2277 bool tainted = false;
2278
2279 if (op != T_ADD) goto invalid_type;
2280
2281 FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, (1 << 16));
2282
2283 if (fr_value_box_list_concat_as_octets(&tainted, &secret, dbuff, UNCONST(fr_value_box_list_t *, &group->vb_group), NULL, 0, FR_VALUE_BOX_LIST_NONE, false) < 0) return -1;
2284
2285 if (fr_value_box_memdup(ctx, dst, NULL, fr_dbuff_start(dbuff), fr_dbuff_used(dbuff), tainted) < 0) return -1;
2286
2288
2289 return 0;
2290 }
2291
2292 /*
2293 * Can't add or multiply booleans.
2294 */
2295 if ((type == FR_TYPE_BOOL) && !((op == T_AND) || (op == T_OR) || (op == T_XOR))) goto unsupported;
2296
2297 switch (op) {
2298 case T_ADD:
2299 case T_MUL:
2300 case T_AND:
2301 case T_OR:
2302 case T_XOR:
2303 break;
2304
2305 default:
2306 goto invalid_type;
2307 }
2308
2309 /*
2310 * Strings and octets are different.
2311 */
2312 if (!fr_type_is_numeric(type)) {
2313 unsupported:
2314 fr_strerror_printf("Not yet supported operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2315 return -1;
2316 }
2317
2318 switch (type) {
2319 case FR_TYPE_UINT8:
2320 case FR_TYPE_UINT16:
2321 case FR_TYPE_UINT32:
2322 case FR_TYPE_UINT64:
2323 calc = calc_uint64;
2324 break;
2325
2326 case FR_TYPE_INT8:
2327 case FR_TYPE_INT16:
2328 case FR_TYPE_INT32:
2329 case FR_TYPE_INT64:
2330 calc = calc_int64;
2331 break;
2332
2333 case FR_TYPE_TIME_DELTA:
2334 if ((op != T_ADD) && (op != T_SUB)) goto invalid_type;
2335 calc = calc_time_delta;
2336 break;
2337
2338 case FR_TYPE_FLOAT32:
2339 calc = calc_float32;
2340 break;
2341
2342 case FR_TYPE_FLOAT64:
2343 calc = calc_float64;
2344 break;
2345
2346 default:
2347 goto unsupported;
2348 }
2349
2350 vb = fr_value_box_list_head(&group->vb_group);
2351 if (!vb) {
2352 fr_strerror_printf("Empty input is invalid");
2353 return -1;
2354 }
2355
2356 if (fr_value_box_cast(ctx, &out, type, NULL, vb) < 0) return -1;
2357
2358 while ((vb = fr_value_box_list_next(&group->vb_group, vb)) != NULL) {
2359 int rcode;
2360 fr_value_box_t box;
2361
2362 if (vb->type == type) {
2363 rcode = calc(ctx, &out, &out, op, vb);
2364 if (rcode < 0) return rcode;
2365
2366 } else {
2367 if (fr_value_box_cast(ctx, &box, type, NULL, vb) < 0) return -1;
2368
2369 rcode = calc(ctx, &out, &out, op, &box);
2370 if (rcode < 0) return rcode;
2371 }
2372 }
2373
2374 return fr_value_box_copy(ctx, dst, &out);
2375}
2376
2377
2378#define T(_x) [T_OP_ ## _x ## _EQ] = T_ ## _x
2379
2381 T(ADD),
2382 T(SUB),
2383 T(MUL),
2384 T(DIV),
2385 T(AND),
2386 T(OR),
2387 T(XOR),
2388 T(RSHIFT),
2389 T(LSHIFT),
2390};
2391
2392/** Calculate DST OP SRC
2393 *
2394 * e.g. "foo += bar".
2395 *
2396 * This is done by doing some sanity checks, and then just calling
2397 * the "binary operation" function.
2398 */
2400{
2401 int rcode;
2402
2403 if (!fr_type_is_leaf(dst->type)) return invalid_type(dst->type);
2404 if (!fr_type_is_leaf(src->type)) return invalid_type(src->type);
2405
2406 if (dst->immutable) {
2407 fr_strerror_printf("Cannot modify immutable value");
2408 return -1;
2409 }
2410
2411 /*
2412 * These operators are included here for testing and completeness. But see comments in
2413 * fr_edit_list_apply_pair_assignment() for what the caller should be doing.
2414 */
2415 if ((op == T_OP_EQ) || (op == T_OP_SET)) {
2416 /*
2417 * Allow for unintentional mistakes.
2418 */
2419 if (src == dst) return 0;
2420
2422 return fr_value_box_cast(ctx, dst, dst->type, dst->enumv, src); /* cast, as the RHS might not (yet) be the same! */
2423 }
2424
2425 if (assignment2op[op] == T_INVALID) {
2426 return handle_result(dst->type, op, ERR_INVALID);
2427 }
2428 op = assignment2op[op];
2429
2430 /*
2431 * Just call the binary op function. It already ensures that (a) the inputs are "const", and (b)
2432 * the output is over-written only at the final step.
2433 */
2434 if (src->type != FR_TYPE_GROUP) {
2435 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, src);
2436
2437 } else {
2438 fr_value_box_t *vb = NULL;
2439
2440 /*
2441 * If the RHS is a group, then we loop over the group recursively, doing the operation.
2442 */
2443 rcode = 0; /* in case group is empty */
2444
2445 while ((vb = fr_value_box_list_next(&src->vb_group, vb)) != NULL) {
2446 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, vb);
2447 if (rcode < 0) break;
2448 }
2449 }
2450
2451 if (rcode < 0) return handle_result(dst->type, op, rcode);
2452
2453 return 0;
2454}
2455
2456/** Calculate unary operations
2457 *
2458 * e.g. "foo++", or "-foo".
2459 */
2460int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
2461{
2462 int rcode = -1;
2463 fr_value_box_t one;
2464
2465 if (!fr_type_is_numeric(src->type)) return invalid_type(src->type);
2466
2467 if (dst->immutable) {
2468 fr_strerror_printf("Cannot modify immutable value");
2469 return -1;
2470 }
2471
2472 if (op == T_OP_INCRM) {
2473 /*
2474 * Add 1 or subtract 1 means RHS is always 1.
2475 */
2476 fr_value_box_init(&one, src->type, NULL, false);
2477 switch (src->type) {
2478 case FR_TYPE_UINT8:
2479 one.vb_uint8 = 1;
2480 break;
2481
2482 case FR_TYPE_UINT16:
2483 one.vb_uint16 = 1;
2484 break;
2485
2486 case FR_TYPE_UINT32:
2487 one.vb_uint32 = 1;
2488 break;
2489
2490 case FR_TYPE_UINT64:
2491 one.vb_uint64 = 1;
2492 break;
2493
2494 case FR_TYPE_SIZE:
2495 one.vb_size = 1;
2496 break;
2497
2498 case FR_TYPE_INT8:
2499 one.vb_int8 = 1;
2500 break;
2501
2502 case FR_TYPE_INT16:
2503 one.vb_int16 = 1;
2504 break;
2505
2506 case FR_TYPE_INT32:
2507 one.vb_int32 = 1;
2508 break;
2509
2510 case FR_TYPE_INT64:
2511 one.vb_int64 = 1;
2512 break;
2513
2514 case FR_TYPE_FLOAT32:
2515 one.vb_float32 = 1;
2516 break;
2517
2518 case FR_TYPE_FLOAT64:
2519 one.vb_float64 = 1;
2520 break;
2521
2522 default:
2523 fr_assert(0);
2524 return -1;
2525 }
2526
2527 rcode = fr_value_calc_binary_op(ctx, dst, src->type, src, T_ADD, &one);
2528 return handle_result(dst->type, op, rcode);
2529
2530 } else if (op == T_COMPLEMENT) {
2531 if (dst != src) fr_value_box_init(dst, src->type, src->enumv, src->tainted);
2532
2533#undef COMP
2534#define COMP(_type, _field) case FR_TYPE_ ## _type: dst->vb_ ##_field = (_field ## _t) ~src->vb_ ##_field; break
2535 switch (src->type) {
2536 COMP(UINT8, uint8);
2537 COMP(UINT16, uint16);
2538 COMP(UINT32, uint32);
2539 COMP(UINT64, uint64);
2540 COMP(SIZE, size);
2541
2542 COMP(INT8, int8);
2543 COMP(INT16, int16);
2544 COMP(INT32, int32);
2545 COMP(INT64, int64);
2546
2547 default:
2548 goto invalid;
2549 }
2550
2551 return 0;
2552
2553 } else if (op == T_SUB) {
2554 fr_type_t type = src->type;
2555
2556 if ((dst != src) && !fr_type_is_signed(src->type)) {
2557 type = upcast_unsigned[src->type];
2558
2559 if (type == FR_TYPE_NULL) {
2560 type = src->type; /* hope for the best */
2561 }
2562 }
2563
2564 fr_value_box_init(&one, type, NULL, src->tainted); /* init to zero */
2565 rcode = fr_value_calc_binary_op(ctx, dst, type, &one, T_SUB, src);
2566
2567 return handle_result(dst->type, op, rcode);
2568
2569 } else if (op == T_NOT) {
2570 bool value = fr_value_box_is_truthy(src);
2571
2572 fr_value_box_clear(dst);
2573 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2574 dst->vb_bool = !value;
2575
2576 return 0;
2577
2578 } else {
2579 invalid:
2580 return handle_result(src->type, op, ERR_INVALID);
2581 }
2582
2583}
2584
2585/** Apply a set of operations in order to create an output box.
2586 *
2587 */
2588int fr_value_calc_list_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op, fr_value_box_list_t const *list)
2589{
2590 /*
2591 * For octets and string and prepend / append, figure out
2592 * first how long the output is, create a string that
2593 * long, and then loop assigning the values. Doing it
2594 * this way avoids a lot of intermediate garbage.
2595 */
2596 if (fr_type_is_variable_size(box->type)) {
2597 bool tainted = false;
2598 int rcode;
2599 size_t len = 0;
2600 uint8_t *str, *p;
2601 fr_value_box_t src;
2602
2603 fr_value_box_list_foreach(list, a) {
2604 if (a->type != box->type) {
2605 len = 0;
2606 break;
2607 }
2608
2609 len += a->vb_length;
2610 }
2611
2612 if (!len) goto brute_force;
2613
2614 if (box->type == FR_TYPE_STRING) {
2615 str = talloc_array(ctx, uint8_t, len);
2616 if (!str) return -1;
2617 } else {
2618 str = talloc_array(ctx, uint8_t, len + 1);
2619 if (!str) return -1;
2620
2621 str[len] = '\0';
2622 }
2623
2624 p = str;
2625 fr_value_box_list_foreach(list, a) {
2626 memcpy(p, a->vb_octets, a->vb_length);
2627 p += a->vb_length;
2628 tainted |= a->tainted;
2629 }
2630
2631 if (box->type == FR_TYPE_STRING) {
2632 fr_value_box_bstrndup_shallow(&src, NULL, (char const *) str, len, tainted);
2633 } else {
2634 fr_value_box_memdup_shallow(&src, NULL, str, len, tainted);
2635 }
2636
2637 rcode = fr_value_calc_binary_op(ctx, box, box->type, box, op, &src);
2638 talloc_free(str);
2639 return rcode;
2640 }
2641
2642brute_force:
2643 fr_value_box_list_foreach(list, a) {
2644 if (fr_value_calc_binary_op(ctx, box, box->type, box, op, a) < 0) return -1;
2645 }
2646
2647 return 0;
2648}
2649
2650/*
2651 * Empty lists are empty:
2652 *
2653 * {}
2654 * {{}}
2655 * {''}
2656 * {{},''}
2657 *
2658 * etc.
2659 */
2660static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
2661{
2663 switch (item->type) {
2664 default:
2665 return false;
2666
2667 case FR_TYPE_GROUP:
2668 if (!fr_value_calc_list_empty(&item->vb_group)) return false;
2669 break;
2670
2671 case FR_TYPE_STRING:
2672 case FR_TYPE_OCTETS:
2673 if (item->vb_length != 0) return false;
2674 break;
2675 }
2676 }
2677
2678 return true;
2679}
2680
2681
2682/*
2683 * Loop over input lists, calling fr_value_calc_binary_op()
2684 *
2685 * This implementation is arguably wrong... it should be checking individual entries in list1 against individual entries in list2.
2686 * Instead, it checks if ANY entry in list1 matches ANY entry in list2.
2687 */
2688int fr_value_calc_list_cmp(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_list_t const *list1, fr_token_t op, fr_value_box_list_t const *list2)
2689{
2690 int rcode;
2691 bool invert = false;
2692 bool a_empty, b_empty;
2693
2694 /*
2695 * v3 hack. != really means !( ... == ... )
2696 */
2697 if (op == T_OP_NE) {
2698 invert = true;
2699 op = T_OP_CMP_EQ;
2700 }
2701
2702 /*
2703 * It's annoying when the debug prints out cmp({},{}) and says "not equal".
2704 *
2705 * What's happening behind the scenes is that one side is an empty value-box group, such as when
2706 * an xlat expansion fails. And the other side is an empty string. If we believe that strings
2707 * are actually sets of characters, then {}=='', and we're all OK
2708 */
2709 a_empty = fr_value_box_list_empty(list1) || fr_value_calc_list_empty(list1);
2710 b_empty = fr_value_box_list_empty(list2) || fr_value_calc_list_empty(list2);
2711
2712 /*
2713 * Both lists are empty, they should be equal when checked for equality.
2714 */
2715 if (a_empty && b_empty) {
2716 switch (op) {
2717 case T_OP_CMP_EQ:
2718 case T_OP_LE:
2719 case T_OP_GE:
2720 invert = !invert;
2721 break;
2722
2723 default:
2724 break;
2725 }
2726
2727 goto done;
2728 }
2729
2730 /*
2731 * Emulate v3. :(
2732 */
2733 fr_value_box_list_foreach(list1, a) {
2734 fr_value_box_list_foreach(list2, b) {
2735 rcode = fr_value_calc_binary_op(ctx, dst, FR_TYPE_BOOL, a, op, b);
2736 if (rcode < 0) return rcode;
2737
2738 /*
2739 * No match: keep looking for a match.
2740 */
2741 fr_assert(dst->type == FR_TYPE_BOOL);
2742 if (!dst->vb_bool) continue;
2743
2744 /*
2745 * Found a match, we're done.
2746 */
2747 dst->vb_bool = !invert;
2748 return 0;
2749 }
2750 }
2751
2752 /*
2753 * No match,
2754 */
2755done:
2756 fr_value_box_clear(dst);
2757 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2758 dst->vb_bool = invert;
2759 return 0;
2760}
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:167
#define RCSID(id)
Definition build.h:483
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:322
#define UNUSED
Definition build.h:315
static int calc_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:775
static const fr_type_t upcast_cmp[FR_TYPE_MAX+1][FR_TYPE_MAX+1]
Updates type (a,b) -> c.
Definition calc.c:426
static int calc_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1220
static int get_ipv6_prefix(uint8_t const *in)
Definition calc.c:1482
static const fr_binary_op_t calc_type[FR_TYPE_MAX+1]
Map output type to its associated function.
Definition calc.c:1851
static int calc_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1418
static int invalid_type(fr_type_t type)
Definition calc.c:698
#define ERR_UNDERFLOW
Definition calc.c:36
static const fr_type_t upcast_op[FR_TYPE_MAX+1][FR_TYPE_MAX+1]
Updates type (a,b) -> c.
Definition calc.c:65
#define ERR_ZERO
Definition calc.c:35
static int calc_float32(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1587
#define COERCE_A(_type, _enumv)
Definition calc.c:47
static int calc_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:1269
static const fr_type_t upcast_unsigned[FR_TYPE_MAX+1]
Definition calc.c:689
static int calc_uint64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1681
static int calc_octets(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:903
static int calc_combo_ip_addr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1565
static int calc_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:1505
static int cast_ipv6_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1352
static int handle_result(fr_type_t type, fr_token_t op, int rcode)
Definition calc.c:705
static int calc_int64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1765
static int calc_bool(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:727
static int calc_string(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:1042
int fr_value_calc_list_cmp(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_list_t const *list1, fr_token_t op, fr_value_box_list_t const *list2)
Definition calc.c:2688
#define ERR_INVALID
Definition calc.c:38
#define swap(_a, _b)
Definition calc.c:33
int fr_value_calc_list_op(TALLOC_CTX *ctx, fr_value_box_t *box, fr_token_t op, fr_value_box_list_t const *list)
Apply a set of operations in order to create an output box.
Definition calc.c:2588
static int calc_combo_ip_prefix(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1577
static int calc_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:818
int(* fr_binary_op_t)(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Definition calc.c:1846
static int cast_ipv4_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1155
static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
Definition calc.c:2660
static int calc_float64(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
Definition calc.c:1634
int fr_value_calc_nary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_token_t op, fr_value_box_t const *group)
Calculate DST = OP { A, B, C, ... }.
Definition calc.c:2239
#define is_ipv6(_x)
Definition calc.c:1563
#define COERCE_B(_type, _enumv)
Definition calc.c:48
static const fr_token_t assignment2op[T_TOKEN_LAST]
Definition calc.c:2380
int fr_value_calc_assignment_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate DST OP SRC.
Definition calc.c:2399
int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Calculate DST = A OP B.
Definition calc.c:1894
#define ERR_OVERFLOW
Definition calc.c:37
#define COMP(_type, _field)
int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate unary operations.
Definition calc.c:2460
#define T(_x)
Definition calc.c:2378
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
Definition dbuff.h:767
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:898
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition dbuff.h:556
static fr_slen_t in
Definition dict.h:822
Test enumeration values.
Definition dict_test.h:92
talloc_free(reap)
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:122
#define fr_sub(_out, _a, _b)
Subtracts two integers.
Definition math.h:140
#define fr_add(_out, _a, _b)
Adds two integers.
Definition math.h:129
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
Definition math.h:118
fr_type_t
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
unsigned int uint32_t
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:38
static char * secret
static bool done
Definition radclient.c:80
static uint32_t mask
Definition rbmonkey.c:39
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_aka_sim_id_type_t type
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_delta_ispos(_a)
Definition time.h:290
@ FR_TIME_RES_NSEC
Definition time.h:60
static fr_unix_time_t fr_unix_time_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
Definition time.h:411
static uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
Definition time.h:161
char const * fr_tokens[T_TOKEN_LAST]
Definition token.c:78
enum fr_token fr_token_t
@ T_AND
Definition token.h:55
@ T_INVALID
Definition token.h:39
@ T_SUB
Definition token.h:52
@ T_RSHIFT
Definition token.h:62
@ T_NOT
Definition token.h:57
@ T_XOR
Definition token.h:58
@ T_DIV
Definition token.h:54
@ T_MOD
Definition token.h:60
@ T_OP_EQ
Definition token.h:83
@ T_COMPLEMENT
Definition token.h:59
@ T_ADD
Definition token.h:51
@ T_OP_SET
Definition token.h:84
@ T_OP_NE
Definition token.h:97
@ T_LSHIFT
Definition token.h:63
@ T_OP_REG_EQ
Definition token.h:102
@ T_OP_CMP_EQ_TYPE
Definition token.h:107
@ T_OP_CMP_EQ
Definition token.h:106
@ T_OP_INCRM
Definition token.h:113
@ T_MUL
Definition token.h:53
@ T_OP_LE
Definition token.h:100
@ T_OP_CMP_NE_TYPE
Definition token.h:108
@ T_OP_GE
Definition token.h:98
@ T_OP_GT
Definition token.h:99
@ T_OP_LT
Definition token.h:101
@ T_OP_REG_NE
Definition token.h:103
@ T_OR
Definition token.h:56
#define T_TOKEN_LAST
Definition token.h:129
int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two boxes using an operator.
Definition regex.c:1360
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:554
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_variable_size(_x)
Definition types.h:367
#define fr_type_is_structural(_x)
Definition types.h:371
#define fr_type_is_numeric(_x)
Definition types.h:361
#define fr_type_is_signed(_x)
Definition types.h:362
#define fr_type_is_leaf(_x)
Definition types.h:372
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:433
#define fr_type_is_integer(_x)
Definition types.h:360
ssize_t fr_value_box_list_concat_as_octets(bool *tainted, bool *secret, fr_dbuff_t *dbuff, fr_value_box_list_t *list, uint8_t const *sep, size_t sep_len, fr_value_box_list_action_t proc_action, bool flatten)
Concatenate a list of value boxes together.
Definition value.c:5677
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3352
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:3740
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
Definition value.c:929
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:6326
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition value.c:4548
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition value.c:3834
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3681
ssize_t fr_value_box_list_concat_as_string(bool *tainted, bool *secret, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
Definition value.c:5584
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:3723
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
Definition value.c:4148
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition value.c:4232
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
Definition value.c:4468
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
Definition value.h:216
static void fr_value_box_set_secret(fr_value_box_t *box, bool secret)
Definition value.h:1080
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:593
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:587
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:206
static size_t char ** out
Definition value.h:997