The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
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: 51ce99633871f7ed8e785139d9ca67c0da7e1816 $
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: 51ce99633871f7ed8e785139d9ca67c0da7e1816 $")
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 fr_value_box_safety_copy(&_box, _vb); \
44 _vb = &_box; \
45 } \
46 } while (0)
47
48#define COERCE_A(_type, _enumv) COERCE(a, one, _type, _enumv)
49#define COERCE_B(_type, _enumv) COERCE(b, two, _type, _enumv)
50
51/** Updates type (a,b) -> c
52 *
53 * Note that we MUST have a less than b here. Otherwise there will
54 * be two entries for the same upcast, and the entries may get out of
55 * sync.
56 *
57 * These upcasts are for operations.
58 *
59 *
60 * If one side is a string and the other isn't, then we try to parse
61 * the string as the type of the other side.
62 *
63 * If one side is an octets type and the other isn't, then we try to
64 * parse the octets as the type of the other side.
65 */
66static const fr_type_t upcast_op[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = {
67 /*
68 * string / octets -> octets
69 */
70 [FR_TYPE_STRING] = {
73 },
74
75 [FR_TYPE_OCTETS] = {
77 },
78
80 /*
81 * ipaddr + int --> prefix (generally only "and")
82 */
84
85 /*
86 * 192.168.0.255 - 192.168.0.1 -> int64
87 */
89 },
90
91 /*
92 * IPv6 mod IPv6 -> ????
93 */
96 },
97
98 /*
99 * Prefix + int --> ipaddr
100 */
105
107
112
114
119
122 },
123
127
129
134
136
141
144 },
145
149
151
156
158
163
166 },
167
170
175
177
182
185 },
186
187 /*
188 * Bools and to pretty much any numerical type result in
189 * the other integer.
190 */
191 [FR_TYPE_BOOL] = {
193
196
201
203
205
210
212
215 },
216
217 /*
218 * Various ints get cast to the next highest size which
219 * can hold their values.
220 */
221 [FR_TYPE_UINT8] = {
224
229
231
233
238
240
243 },
244
245 [FR_TYPE_UINT16] = {
248
252
254
256
261
263
266 },
267
268 [FR_TYPE_UINT32] = {
271
274
276
278
283
285
288 },
289
290 [FR_TYPE_UINT64] = {
293
296
298
300
302
305 },
306
307 [FR_TYPE_SIZE] = {
309
314
316
319 },
320
321 [FR_TYPE_DATE] = {
323
328
331
334 },
335
336 /*
337 * Signed ints
338 */
339 [FR_TYPE_INT8] = {
342
347
349
352 },
353
354 [FR_TYPE_INT16] = {
357
361
364 },
365
366 [FR_TYPE_INT32] = {
369
371
374 },
375
376 [FR_TYPE_INT64] = {
379
381
385 },
386
389
391
394 },
395
396 [FR_TYPE_FLOAT32] = {
398
401 },
402
403 [FR_TYPE_FLOAT64] = {
406 },
407};
408
409/** Updates type (a,b) -> c
410 *
411 * Note that we MUST have a less than b here. Otherwise there will
412 * be two entries for the same upcast, and the entries may get out of
413 * sync.
414 *
415 * These upcasts are for comparisons. In some cases, we can promote
416 * one data type to another, and then compare them. However, this is
417 * not always possible.
418 *
419 * If one side is a string and the other isn't, then we try to parse
420 * the string as the type of the other side.
421 *
422 * If one side is an octets type and the other isn't, then we try to
423 * parse the octets as the type of the other side.
424 *
425 * @todo - check this table against fr_type_promote()
426 */
427static const fr_type_t upcast_cmp[FR_TYPE_MAX + 1][FR_TYPE_MAX + 1] = {
428 [FR_TYPE_STRING] = {
430 },
431
435
437
440
443
445 },
446
450
452
454 },
455
459
461
464 },
465
469
471 },
472
473 [FR_TYPE_IFID] = {
476 },
477
480 },
481
482 [FR_TYPE_ETHERNET] = {
485 },
486
487 /*
488 * Bools compared to pretty much any numerical type
489 * result in the other integer.
490 */
491 [FR_TYPE_BOOL] = {
494
499
501
503
508
510
513 },
514
515 /*
516 * Integers of the same sign get cast to the larger of
517 * the data type. Integers of different signs get cast
518 * to a *different* data type which can hold all values
519 * from both sides.
520 */
521 [FR_TYPE_UINT8] = {
524
528
530
532
537
539
542 },
543
544 [FR_TYPE_UINT16] = {
547
550
552
554
559
561
564 },
565
566 [FR_TYPE_UINT32] = {
569
571
573
575
580
582
585 },
586
587 [FR_TYPE_UINT64] = {
590
592
594
596
599 },
600
601 [FR_TYPE_SIZE] = {
603
608
611 },
612
613 [FR_TYPE_DATE] = {
615
620
622
625 },
626
627 /*
628 * Signed ints
629 */
630 [FR_TYPE_INT8] = {
633
637
639
642 },
643
644 [FR_TYPE_INT16] = {
647
650
653 },
654
655 [FR_TYPE_INT32] = {
658
660
663 },
664
665 [FR_TYPE_INT64] = {
668
670 },
671
674
677 },
678
679 [FR_TYPE_FLOAT32] = {
681
683 },
684
685 [FR_TYPE_FLOAT64] = {
687 },
688};
689
698
700{
701 fr_strerror_printf("Cannot perform mathematical operations on data type %s",
703 return -1;
704}
705
706static int handle_result(fr_type_t type, fr_token_t op, int rcode)
707{
708 if (rcode == ERR_ZERO) {
709 fr_strerror_const("Cannot divide by zero.");
710
711 } else if (rcode == ERR_UNDERFLOW) {
712 fr_strerror_printf("Value underflows '%s' when calculating result.",
714
715 } else if (rcode == ERR_OVERFLOW) {
716 fr_strerror_printf("Value overflows '%s' when calculating result.",
718
719 } else if (rcode == ERR_INVALID) {
720 fr_strerror_printf("Invalid assignment operator '%s' for result type '%s'.",
721 fr_tokens[op],
723 }
724
725 return rcode;
726}
727
728static 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)
729{
730 fr_value_box_t one, two;
731
732 fr_assert(dst->type == FR_TYPE_BOOL);
733
734 COERCE_A(FR_TYPE_BOOL, NULL);
735 COERCE_B(FR_TYPE_BOOL, NULL);
736
737 switch (op) {
738 case T_ADD:
739 /*
740 * 1+1 = 2, which isn't a valid boolean value.
741 */
742 if (a->vb_bool & b->vb_bool) return ERR_OVERFLOW;
743
744 dst->vb_bool = a->vb_bool | b->vb_bool;
745 break;
746
747 case T_SUB:
748 /*
749 * 0-1 = -1, which isn't a valid boolean value.
750 */
751 if (a->vb_bool < b->vb_bool) return ERR_UNDERFLOW;
752
753 dst->vb_bool = a->vb_bool - b->vb_bool;
754 break;
755
756 case T_MUL: /* MUL is just AND here! */
757 case T_AND:
758 dst->vb_bool = a->vb_bool & b->vb_bool;
759 break;
760
761 case T_OR:
762 dst->vb_bool = a->vb_bool | b->vb_bool;
763 break;
764
765 case T_XOR:
766 dst->vb_bool = a->vb_bool ^ b->vb_bool;
767 break;
768
769 default:
770 return ERR_INVALID;
771 }
772
773 return 0;
774}
775
776static 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)
777{
778 fr_value_box_t one, two;
779 bool overflow;
780 int64_t when;
781
782 fr_assert(dst->type == FR_TYPE_DATE);
783
784 if ((a->type == FR_TYPE_DATE) && (b->type == FR_TYPE_DATE)) {
785 fr_strerror_const("Cannot perform operation on two values of type 'date'. One value must be a number.");
786 return -1;
787 }
788
789 fr_assert(!dst->enumv); /* unix time is always seconds */
790
791 /*
792 * Cast dates to time delta, do the conversions.
793 */
796
797 switch (op) {
798 case T_ADD:
799 if (!fr_add(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_OVERFLOW;
800
802 if (overflow) return ERR_OVERFLOW;
803 break;
804
805 case T_SUB:
806 if (!fr_sub(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_UNDERFLOW;
807
809 if (overflow) return ERR_UNDERFLOW;
810 break;
811
812 default:
813 return ERR_INVALID; /* invalid operator */
814 }
815
816 return 0;
817}
818
819static 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)
820{
821 fr_value_box_t one, two;
822 int64_t when;
823
824 fr_assert(dst->type == FR_TYPE_TIME_DELTA);
825
826 /*
827 * We can subtract two dates to get a time delta, but we
828 * cannot add two dates to get a time delta.
829 */
830 if ((a->type == FR_TYPE_DATE) && (b->type == FR_TYPE_DATE)) {
831 if (op != T_SUB) {
832 fr_strerror_const("Cannot perform operation on two values of type 'date'.");
833 return -1;
834 }
835 }
836
837 /*
838 * date % (time_delta) 1d --> time_delta
839 */
840 if (op == T_MOD) {
841 /*
842 * We MUST specify date ranges as a time delta, not as an integer. And it must be a
843 * positive time delta.
844 */
845 if ((b->type != FR_TYPE_TIME_DELTA) || !fr_time_delta_ispos(b->vb_time_delta)) {
846 return ERR_INVALID;
847 }
848
849 dst->vb_time_delta = fr_time_delta_wrap(fr_unix_time_unwrap(a->vb_date) % fr_time_delta_unwrap(b->vb_time_delta));
850 return 0;
851 }
852
853 /*
854 * Unix times are always converted 1-1 to our internal
855 * TIME_DELTA.
856 *
857 * We cast the inputs based on the destination time resolution. So "5ms + 5" = "10ms".
858 */
859 COERCE_A(FR_TYPE_TIME_DELTA, dst->enumv);
860
861 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
862 /*
863 * Don't touch the RHS.
864 */
865 fr_assert(b->type == FR_TYPE_UINT32);
866
867 } else {
868 COERCE_B(FR_TYPE_TIME_DELTA, dst->enumv);
869 }
870
871 switch (op) {
872 case T_ADD:
873 if (!fr_add(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_OVERFLOW;
874 dst->vb_time_delta = fr_time_delta_wrap(when);
875 break;
876
877 case T_SUB:
878 if (!fr_sub(&when, fr_time_delta_unwrap(a->vb_time_delta), fr_time_delta_unwrap(b->vb_time_delta))) return ERR_UNDERFLOW;
879 dst->vb_time_delta = fr_time_delta_wrap(when);
880 break;
881
882 case T_RSHIFT:
883 if (b->vb_uint32 >= 64) return ERR_UNDERFLOW;
884
885 when = fr_time_delta_unwrap(a->vb_time_delta) >> b->vb_uint32;
886 dst->vb_time_delta = fr_time_delta_wrap(when);
887 break;
888
889 case T_LSHIFT:
890 if (b->vb_uint32 >= 64) return ERR_OVERFLOW;
891
892 when = fr_time_delta_unwrap(a->vb_time_delta) << b->vb_uint32;
893 dst->vb_time_delta = fr_time_delta_wrap(when);
894 break;
895
896 default:
897 return ERR_INVALID; /* invalid operator */
898 }
899
900 return 0;
901
902}
903
904static 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)
905{
906 uint8_t *buf, *p;
907 size_t i, len;
908 fr_value_box_t one = {};
909 fr_value_box_t two = {};
910
911 fr_assert(dst->type == FR_TYPE_OCTETS);
912
913 COERCE_A(FR_TYPE_OCTETS, dst->enumv);
914#ifdef __clang_analyzer__
915 /*
916 * The clang analyser does not see fr_value_box_cast() fill in
917 * the box, and reports every copy out of the box as a NULL
918 * pointer.
919 */
920 if (!a->vb_octets) return -1;
921#endif
922
923 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
924 /*
925 * Don't touch the RHS.
926 */
927 fr_assert(b->type == FR_TYPE_UINT32);
928
929 } else if (op == T_MUL) {
931
933
934 } else {
935 COERCE_B(FR_TYPE_OCTETS, dst->enumv);
936#ifdef __clang_analyzer__
937 if (!b->vb_octets) return -1; /* As for a->vb_octets, above */
938#endif
939 }
940
941 len = a->vb_length + b->vb_length;
942
943 switch (op) {
944 case T_ADD: /* dst = a . b */
945 buf = talloc_array(ctx, uint8_t, len);
946 if (!buf) {
947 oom:
948 fr_strerror_const("Out of memory");
949 return -1;
950 }
951
952 memcpy(buf, a->vb_octets, a->vb_length);
953 memcpy(buf + a->vb_length, b->vb_octets, b->vb_length);
954
955 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
958 break;
959
960 case T_SUB:
961 /*
962 * The inverse of add!
963 */
964 if (a->vb_length < b->vb_length) {
965 fr_strerror_const("Suffix to remove is longer than input string.");
966 return -1;
967 }
968
969 if (memcmp(a->vb_octets + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
970 fr_strerror_const("Suffix to remove is not a suffix of the input string.");
971 return -1;
972 }
973
974 len = a->vb_length - b->vb_length;
975 buf = talloc_array(ctx, uint8_t, len);
976 if (!buf) goto oom;
977
978 memcpy(buf, a->vb_strvalue, len);
979
980 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
982 break;
983
984 case T_AND:
985 if (a->vb_length != b->vb_length) {
986 length_error:
987 fr_strerror_const("Cannot perform operation on strings of different length");
988 return -1;
989 }
990
991 buf = talloc_array(ctx, uint8_t, a->vb_length);
992 if (!buf) goto oom;
993
994 for (len = 0; len < a->vb_length; len++) {
995 buf[len] = a->vb_octets[len] & b->vb_octets[len];
996 }
997
998 set_result:
999 fr_value_box_memdup_shallow(dst, dst->enumv, buf, a->vb_length, false);
1002 break;
1003
1004 case T_OR:
1005 if (a->vb_length != b->vb_length) goto length_error;
1006
1007 buf = talloc_array(ctx, uint8_t, a->vb_length);
1008 if (!buf) goto oom;
1009
1010 for (len = 0; len < a->vb_length; len++) {
1011 buf[len] = a->vb_octets[len] | b->vb_octets[len];
1012 }
1013 goto set_result;
1014
1015 case T_XOR:
1016 if (a->vb_length != b->vb_length) goto length_error;
1017
1018 buf = talloc_array(ctx, uint8_t, a->vb_length);
1019 if (!buf) goto oom;
1020
1021 for (len = 0; len < a->vb_length; len++) {
1022 buf[len] = a->vb_octets[len] ^ b->vb_octets[len];
1023 }
1024
1025 goto set_result;
1026
1027 case T_RSHIFT:
1028 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1029
1030 len = a->vb_length - b->vb_uint32;
1031 buf = talloc_array(ctx, uint8_t, len);
1032 if (!buf) goto oom;
1033
1034 memcpy(buf, a->vb_octets, len);
1035
1036 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1038 break;
1039
1040 case T_LSHIFT:
1041 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1042
1043 len = a->vb_length - b->vb_uint32;
1044
1045 buf = talloc_array(ctx, uint8_t, len);
1046 if (!buf) goto oom;
1047
1048 memcpy(buf, a->vb_octets + b->vb_uint32, len);
1049
1050 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1052 break;
1053
1054 case T_MUL:
1055 /*
1056 * 0 * 0 = 0
1057 */
1058 if (!b->vb_uint64 || !a->vb_length) {
1059 fr_value_box_memdup(ctx, dst, dst->enumv, (const uint8_t *) "", 0, false);
1061 break;
1062 }
1063
1064 if (b->vb_uint64 > 256) return ERR_OVERFLOW;
1065 if (a->vb_length > 16) return ERR_OVERFLOW;
1066
1067 len = a->vb_length * b->vb_uint64;
1068
1069 buf = talloc_array(ctx, uint8_t, len);
1070 if (!buf) goto oom;
1071
1072 for (i = 0, p = buf; i < b->vb_uint64; i++, p += a->vb_length) {
1073 memcpy(p, a->vb_octets, a->vb_length);
1074 }
1075
1076 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1078 break;
1079
1080 default:
1081 return ERR_INVALID; /* invalid operator */
1082 }
1083
1084 if (a == &one) fr_value_box_clear_value(&one);
1085 if (b == &two) fr_value_box_clear_value(&two);
1086
1087 return 0;
1088}
1089
1090static 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)
1091{
1092 char *buf, *p;
1093 size_t i, len;
1094 fr_value_box_t one = {};
1095 fr_value_box_t two = {};
1096
1097 fr_assert(dst->type == FR_TYPE_STRING);
1098
1099 COERCE_A(FR_TYPE_STRING, dst->enumv);
1100#ifdef __clang_analyzer__
1101 /*
1102 * The clang analyser does not see fr_value_box_cast() fill in
1103 * the box, and reports every copy out of the box as a NULL
1104 * pointer.
1105 */
1106 if (!a->vb_strvalue) return -1;
1107#endif
1108
1109 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1110 /*
1111 * Don't touch the RHS.
1112 */
1113 fr_assert(b->type == FR_TYPE_UINT32);
1114
1115 } else if (op == T_MUL) {
1117
1118 COERCE_B(FR_TYPE_UINT64, NULL);
1119
1120 } else {
1121 COERCE_B(FR_TYPE_STRING, dst->enumv);
1122#ifdef __clang_analyzer__
1123 if (!b->vb_strvalue) return -1; /* As for a->vb_strvalue, above */
1124#endif
1125 }
1126
1127 len = a->vb_length + b->vb_length;
1128
1129 switch (op) {
1130 case T_ADD:
1131 buf = talloc_array(ctx, char, len + 1);
1132 if (!buf) {
1133 oom:
1134 fr_strerror_const("Out of memory");
1135 return -1;
1136 }
1137
1138 len = a->vb_length + b->vb_length;
1139 memcpy(buf, a->vb_strvalue, a->vb_length);
1140 memcpy(buf + a->vb_length, b->vb_strvalue, b->vb_length);
1141 buf[len] = '\0';
1142
1143 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1146 break;
1147
1148 case T_XOR: /* is prepend for strings */
1149 buf = talloc_array(ctx, char, len + 1);
1150 if (!buf) goto oom;
1151
1152 len = a->vb_length + b->vb_length;
1153 memcpy(buf, b->vb_strvalue, b->vb_length);
1154 memcpy(buf + b->vb_length, a->vb_strvalue, a->vb_length);
1155 buf[len] = '\0';
1156
1157 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1160 break;
1161
1162 case T_SUB:
1163 /*
1164 * The inverse of add!
1165 */
1166 if (a->vb_length < b->vb_length) {
1167 fr_strerror_const("Suffix to remove is longer than input string");
1168 return -1;
1169 }
1170
1171 if (memcmp(a->vb_strvalue + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
1172 fr_strerror_const("Right side of substract is not a suffix of the input string");
1173 return -1;
1174 }
1175
1176 len = a->vb_length - b->vb_length;
1177 buf = talloc_array(ctx, char, len + 1);
1178 if (!buf) goto oom;
1179
1180 memcpy(buf, a->vb_strvalue, len);
1181 buf[len] = '\0';
1182
1183 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1185 break;
1186
1187 case T_RSHIFT:
1188 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1189
1190 len = a->vb_length - b->vb_uint32;
1191 buf = talloc_array(ctx, char, len + 1);
1192 if (!buf) goto oom;
1193
1194 memcpy(buf, a->vb_strvalue, len);
1195 buf[len] = '\0';
1196
1197 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1199 break;
1200
1201 case T_LSHIFT:
1202 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1203
1204 len = a->vb_length - b->vb_uint32;
1205
1206 buf = talloc_array(ctx, char, len + 1);
1207 if (!buf) goto oom;
1208
1209 memcpy(buf, a->vb_strvalue + b->vb_uint32, len);
1210 buf[len] = '\0';
1211
1212 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1214 break;
1215
1216 case T_MUL:
1217 /*
1218 * 0 * 0 = 0
1219 */
1220 if (!b->vb_uint64 || !a->vb_length) {
1221 fr_value_box_strdup(ctx, dst, dst->enumv, "", false);
1223 break;
1224 }
1225
1226 if (b->vb_uint64 > 256) return ERR_OVERFLOW;
1227 if (a->vb_length > 16) return ERR_OVERFLOW;
1228
1229 len = a->vb_length * b->vb_uint64;
1230
1231 buf = talloc_array(ctx, char, len + 1);
1232 if (!buf) goto oom;
1233
1234 for (i = 0, p = buf; i < b->vb_uint64; i++, p += a->vb_length) {
1235 memcpy(p, a->vb_strvalue, a->vb_length);
1236 }
1237 *p = '\0';
1238
1239 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1241 break;
1242
1243 default:
1244 return ERR_INVALID; /* invalid operator */
1245 }
1246
1247 if (a == &one) fr_value_box_clear_value(&one);
1248 if (b == &two) fr_value_box_clear_value(&two);
1249
1250 return 0;
1251}
1252
1254{
1255 switch (in->type) {
1256 default:
1257 fr_strerror_printf("Cannot operate on ipaddr and %s",
1258 fr_type_to_str(in->type));
1259 return -1;
1260
1262 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_addr;
1263
1264 fr_value_box_init(out, FR_TYPE_IPV4_ADDR, NULL, in->tainted);
1265 out->vb_ip = in->vb_ip;
1266 break;
1267
1269 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_prefix;
1270
1271 fr_value_box_init(out, FR_TYPE_IPV4_PREFIX, NULL, in->tainted);
1272 out->vb_ip = in->vb_ip;
1273 break;
1274
1276 case FR_TYPE_IPV4_ADDR:
1277 if (unlikely(fr_value_box_copy(NULL, out, in) < 0)) return -1;
1278 break;
1279
1280 case FR_TYPE_IPV6_ADDR:
1282 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_ADDR, NULL, in) < 0) return -1;
1283 break;
1284
1286 cast_ipv6_prefix:
1287 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_PREFIX, NULL, in) < 0) return -1;
1288 break;
1289
1290 /*
1291 * All of these get mashed to 32-bits. The cast
1292 * operation will check bounds (both negative and
1293 * positive) on the run-time values.
1294 */
1295 case FR_TYPE_BOOL:
1296
1297 case FR_TYPE_UINT8:
1298 case FR_TYPE_UINT16:
1299 case FR_TYPE_UINT32:
1300 case FR_TYPE_UINT64:
1301
1302 case FR_TYPE_SIZE:
1303
1304 case FR_TYPE_INT8:
1305 case FR_TYPE_INT16:
1306 case FR_TYPE_INT32:
1307 case FR_TYPE_INT64:
1308
1309 case FR_TYPE_FLOAT32:
1310 case FR_TYPE_FLOAT64:
1311 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT32, NULL, in) < 0) return -1;
1312 break;
1313 }
1314
1315 return 0;
1316}
1317
1318static 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)
1319{
1320 fr_value_box_t one, two;
1321 fr_value_box_t *a, *b;
1322
1323 fr_assert((dst->type == FR_TYPE_IPV4_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1324
1325 if (cast_ipv4_addr(&one, in1) < 0) return -1;
1326 a = &one;
1327
1328 if (cast_ipv4_addr(&two, in2) < 0) return -1;
1329 b = &two;
1330
1331 switch (op) {
1332 case T_ADD:
1333 case T_OR:
1334 /*
1335 * For simplicity, make sure that the prefix is first.
1336 */
1337 if (b->type == FR_TYPE_IPV4_PREFIX) swap(a,b);
1338
1339 /*
1340 * We can only add something to a prefix, and
1341 * that something has to be a number. The cast
1342 * operation already ensured that the number is
1343 * uint32, and is at least vaguely within the
1344 * allowed range.
1345 */
1346 if (a->type != FR_TYPE_IPV4_PREFIX) return ERR_INVALID;
1347
1348 if (b->type != FR_TYPE_UINT32) return ERR_INVALID;
1349
1350 /*
1351 * Trying to add a number outside of the given prefix. That's not allowed.
1352 */
1353 if (b->vb_uint32 >= (((uint32_t) 1) << (32 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1354
1355 dst->vb_ip.af = AF_INET;
1356 dst->vb_ipv4addr = htonl(ntohl(a->vb_ipv4addr) | b->vb_uint32);
1357 dst->vb_ip.prefix = 32;
1360 break;
1361
1362 default:
1363 return ERR_INVALID;
1364 }
1365
1366 return 0;
1367}
1368
1369static 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)
1370{
1371 int prefix;
1372 fr_value_box_t one, two, tmp;
1373
1374 fr_assert((dst->type == FR_TYPE_IPV4_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1375
1376 switch (op) {
1377 case T_AND:
1378 if (fr_type_is_integer(a->type)) {
1379 if (fr_value_box_cast(NULL, &one, FR_TYPE_UINT32, NULL, a) < 0) return -1;
1380
1381 a = &one;
1382 swap(a, b);
1383
1384 } else if (fr_type_is_integer(b->type)) {
1385 if (fr_value_box_cast(NULL, &two, FR_TYPE_UINT32, NULL, b) < 0) return -1;
1386 b = &two;
1387
1388 } else {
1389 fr_strerror_const("Invalid input types for ipv4prefix");
1390 return -1;
1391 }
1392
1393 switch (a->type) {
1394 case FR_TYPE_IPV6_ADDR:
1395 if (fr_value_box_cast(NULL, &tmp, FR_TYPE_IPV4_ADDR, NULL, a) < 0) return -1;
1396 a = &tmp;
1397 break;
1398
1399 case FR_TYPE_IPV4_ADDR:
1401 break;
1402
1403 default:
1404 fr_strerror_printf("Invalid input data type '%s' for logical 'and'",
1405 fr_type_to_str(a->type));
1406
1407 return -1;
1408 }
1409
1410 if (b->vb_uint32 == 0) { /* set everything to zero */
1411 dst->vb_ipv4addr = 0;
1412 prefix = 0;
1413
1414 } else if ((~b->vb_uint32) == 0) { /* all 1's */
1415 dst->vb_ipv4addr = a->vb_ipv4addr;
1416 prefix = 32;
1417
1418 } else {
1419 uint32_t mask;
1420
1421 mask = ~b->vb_uint32; /* 0xff00 -> 0x00ff */
1422 mask++; /* 0x00ff -> 0x0100 */
1423 if ((mask & b->vb_uint32) != mask) {
1424 fr_strerror_printf("Invalid network mask '0x%08x'", b->vb_uint32);
1425 return -1;
1426 }
1427
1428 mask = 0xfffffffe;
1429 prefix = 31;
1430
1431 while (prefix > 0) {
1432 if (mask == b->vb_uint32) break;
1433
1434 prefix--;
1435 mask <<= 1;
1436 }
1437 fr_assert(prefix > 0);
1438
1439 dst->vb_ipv4addr = htonl(ntohl(a->vb_ipv4addr) & b->vb_uint32);
1440 }
1441
1442 dst->vb_ip.af = AF_INET;
1443 dst->vb_ip.prefix = prefix;
1444 break;
1445
1446 default:
1447 return ERR_INVALID;
1448 }
1449
1450 return 0;
1451}
1452
1454{
1455 switch (in->type) {
1456 default:
1457 fr_strerror_printf("Cannot operate on ipv6addr and %s",
1458 fr_type_to_str(in->type));
1459 return -1;
1460
1462 if (in->vb_ip.af == AF_INET) goto cast_ipv4_addr;
1463
1464 fr_assert(in->vb_ip.af == AF_INET6);
1465 fr_value_box_init(out, FR_TYPE_IPV6_ADDR, NULL, in->tainted);
1466 out->vb_ip = in->vb_ip;
1467 break;
1468
1470 if (in->vb_ip.af == AF_INET) goto cast_ipv4_prefix;
1471
1472 fr_assert(in->vb_ip.af == AF_INET6);
1473 fr_value_box_init(out, FR_TYPE_IPV6_PREFIX, NULL, in->tainted);
1474 out->vb_ip = in->vb_ip;
1475 break;
1476
1477
1479 case FR_TYPE_IPV6_ADDR:
1480 if (unlikely(fr_value_box_copy(NULL, out, in) < 0)) return -1;
1481 break;
1482
1483 case FR_TYPE_IPV4_ADDR:
1485 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_ADDR, NULL, in) < 0) return -1;
1486 break;
1487
1489 cast_ipv4_prefix:
1490 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_PREFIX, NULL, in) < 0) return -1;
1491 break;
1492
1493 /*
1494 * All of these get mashed to 64-bits. The cast
1495 * operation will check bounds (both negative and
1496 * positive) on the run-time values.
1497 */
1498 case FR_TYPE_BOOL:
1499
1500 case FR_TYPE_UINT8:
1501 case FR_TYPE_UINT16:
1502 case FR_TYPE_UINT32:
1503 case FR_TYPE_UINT64:
1504
1505 case FR_TYPE_SIZE:
1506
1507 case FR_TYPE_INT8:
1508 case FR_TYPE_INT16:
1509 case FR_TYPE_INT32:
1510 case FR_TYPE_INT64:
1511
1512 case FR_TYPE_FLOAT32:
1513 case FR_TYPE_FLOAT64:
1514 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT64, NULL, in) < 0) return -1;
1515 break;
1516 }
1517
1518 return 0;
1519}
1520
1521static 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)
1522{
1523 fr_value_box_t one, two;
1524 fr_value_box_t *a, *b;
1525 int i;
1526 uint64_t mask;
1527
1528 fr_assert((dst->type == FR_TYPE_IPV6_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1529
1530 if (cast_ipv6_addr(&one, in1) < 0) return -1;
1531 a = &one;
1532
1533 if (cast_ipv6_addr(&two, in2) < 0) return -1;
1534 b = &two;
1535
1536 switch (op) {
1537 case T_ADD:
1538 case T_OR:
1539 /*
1540 * For simplicity, make sure that the prefix is first.
1541 */
1542 if (b->type == FR_TYPE_IPV6_PREFIX) swap(a, b);
1543
1544 /*
1545 * We can only add something to a prefix, and
1546 * that something has to be a number. The cast
1547 * operation already ensured that the number is
1548 * uint64, and is at least vaguely within the
1549 * allowed range.
1550 */
1551 if (a->type != FR_TYPE_IPV6_PREFIX) return ERR_INVALID;
1552
1553 if (b->type != FR_TYPE_UINT64) return ERR_INVALID;
1554
1555 /*
1556 * If we're adding a UINT64, the prefix can't be shorter than 64.
1557 */
1558 if (a->vb_ip.prefix <= 64) return ERR_OVERFLOW;
1559
1560 /*
1561 * Trying to add a number outside of the given prefix. That's not allowed.
1562 */
1563 if (b->vb_uint64 >= (((uint64_t) 1) << (128 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1564
1565 /*
1566 * Add in the relevant low bits.
1567 */
1568 memcpy(&dst->vb_ipv6addr, a->vb_ipv6addr, sizeof(dst->vb_ipv6addr));
1569 mask = b->vb_uint64;
1570 for (i = 15; i >= ((a->vb_ip.prefix + 7) >> 3); i--) {
1571 dst->vb_ipv6addr[i] |= mask & 0xff;
1572 mask >>= 8;
1573 }
1574
1575 dst->vb_ip.af = AF_INET6;
1576 dst->vb_ip.prefix = 128;
1577 dst->vb_ip.scope_id = a->vb_ip.scope_id;
1579 break;
1580
1581 default:
1582 return ERR_INVALID;
1583 }
1584
1585 return 0;
1586}
1587
1588static int get_ipv6_prefix(uint8_t const *in)
1589{
1590 int i, j, prefix;
1591
1592 prefix = 128;
1593 for (i = 15; i >= 0; i--) {
1594 if (!in[i]) {
1595 prefix -= 8;
1596 continue;
1597 }
1598
1599 for (j = 0; j < 8; j++) {
1600 if ((in[i] & (1 << j)) == 0) {
1601 prefix--;
1602 continue;
1603 }
1604 return prefix;
1605 }
1606 }
1607
1608 return prefix;
1609}
1610
1611static 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)
1612{
1613 int i, prefix = 128;
1614 uint8_t const *pa, *pb;
1615 uint8_t *pdst;
1616
1617 fr_assert((dst->type == FR_TYPE_IPV6_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1618
1619 if (a->type == FR_TYPE_OCTETS) {
1620 if (a->vb_length != (128 / 8)) {
1621 fr_strerror_printf("Invalid length %zu for octets network mask", a->vb_length);
1622 return -1;
1623 }
1624 pa = a->vb_octets;
1625 prefix = get_ipv6_prefix(pa);
1626
1627 } else if (a->type == FR_TYPE_IPV6_ADDR) {
1628 pa = (const uint8_t *) &a->vb_ipv6addr;
1629
1630 } else {
1631 return ERR_INVALID;
1632 }
1633
1634 if (b->type == FR_TYPE_OCTETS) {
1635 if (b->vb_length != (128 / 8)) {
1636 fr_strerror_printf("Invalid length %zu for octets network mask", b->vb_length);
1637 return -1;
1638 }
1639 pb = b->vb_octets;
1640 prefix = get_ipv6_prefix(pb);
1641
1642 } else if (b->type == FR_TYPE_IPV6_ADDR) {
1643 pb = (const uint8_t *) &b->vb_ip.addr.v6;
1644
1645 } else {
1646 return ERR_INVALID;
1647 }
1648
1649 switch (op) {
1650 case T_AND:
1651 fr_value_box_init(dst, FR_TYPE_IPV6_PREFIX, NULL, false);
1652 pdst = (uint8_t *) &dst->vb_ip.addr.v6;
1653
1654 for (i = 0; i < 16; i++) {
1655 pdst[i] = pa[i] & pb[i];
1656 }
1657
1658 dst->vb_ip.af = AF_INET6;
1659 dst->vb_ip.prefix = prefix;
1662 break;
1663
1664 default:
1665 return ERR_INVALID;
1666 }
1667
1668 return 0;
1669}
1670
1671#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)))
1672
1673static 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)
1674{
1675 /*
1676 * IPv6 is better than IPv4!
1677 */
1678 if (is_ipv6(in1) || is_ipv6(in2)) {
1679 return calc_ipv6_addr(ctx, dst, in1, op, in2);
1680 }
1681
1682 return calc_ipv4_addr(ctx, dst, in1, op, in2);
1683}
1684
1685static 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)
1686{
1687 if (is_ipv6(in1) || is_ipv6(in2)) {
1688 return calc_ipv6_prefix(ctx, dst, in1, op, in2);
1689 }
1690
1691 return calc_ipv4_prefix(ctx, dst, in1, op, in2);
1692}
1693
1694
1695static 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)
1696{
1697 fr_value_box_t one, two;
1698 fr_value_box_t const *a = in1;
1699 fr_value_box_t const *b = in2;
1700
1701 fr_assert(dst->type == FR_TYPE_FLOAT32);
1702
1703 /*
1704 * Intermediate calculations are done using increased precision.
1705 */
1708
1709 switch (op) {
1710 case T_ADD:
1711 dst->vb_float32 = a->vb_float64 + b->vb_float64;
1712 break;
1713
1714 case T_SUB:
1715 dst->vb_float32 = a->vb_float64 - b->vb_float64;
1716 break;
1717
1718 case T_MUL:
1719 dst->vb_float32 = a->vb_float64 * b->vb_float64;
1720 break;
1721
1722 case T_DIV:
1723 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1724
1725 dst->vb_float32 = a->vb_float64 / b->vb_float64;
1726 break;
1727
1728 case T_MOD:
1729 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1730
1731 dst->vb_float32 = fmod(a->vb_float64, b->vb_float64);
1732 break;
1733
1734 default:
1735 return ERR_INVALID;
1736 }
1737
1740
1741 return 0;
1742
1743}
1744
1745static 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)
1746{
1747 fr_value_box_t one, two;
1748 fr_value_box_t const *a = in1;
1749 fr_value_box_t const *b = in2;
1750
1751 fr_assert(dst->type == FR_TYPE_FLOAT64);
1752
1755
1756 switch (op) {
1757 case T_ADD:
1758 dst->vb_float64 = a->vb_float64 + b->vb_float64;
1759 break;
1760
1761 case T_SUB:
1762 dst->vb_float64 = a->vb_float64 - b->vb_float64;
1763 break;
1764
1765 case T_MUL:
1766 dst->vb_float64 = a->vb_float64 * b->vb_float64;
1767 break;
1768
1769 case T_DIV:
1770 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1771
1772 dst->vb_float64 = a->vb_float64 / b->vb_float64;
1773 break;
1774
1775 case T_MOD:
1776 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1777
1778 dst->vb_float64 = fmod(a->vb_float64, b->vb_float64);
1779 break;
1780
1781 default:
1782 return ERR_INVALID;
1783 }
1784
1787
1788 return 0;
1789}
1790
1791/*
1792 * Do all intermediate operations on 64-bit numbers.
1793 */
1794static 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)
1795{
1796 fr_value_box_t one, two, result;
1797 fr_value_box_t const *a = in1;
1798 fr_value_box_t const *b = in2;
1799
1800 fr_value_box_init(&result, FR_TYPE_UINT64, NULL, a->tainted | b->tainted);
1801
1802 COERCE_A(FR_TYPE_UINT64, NULL);
1803
1804 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1805 /*
1806 * Don't touch the RHS.
1807 */
1808 fr_assert(b->type == FR_TYPE_UINT32);
1809
1810 } else {
1811 COERCE_B(FR_TYPE_UINT64, dst->enumv);
1812 }
1813
1814 switch (op) {
1815 case T_ADD:
1816 if (!fr_add(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1817 break;
1818
1819 case T_SUB:
1820 if (!fr_sub(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_UNDERFLOW;
1821 break;
1822
1823 case T_MUL:
1824 if (!fr_multiply(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1825 break;
1826
1827 case T_DIV:
1828 if (b->vb_uint64 == 0) return ERR_ZERO;
1829
1830 result.vb_uint64 = a->vb_uint64 / b->vb_uint64;
1831 break;
1832
1833 case T_MOD:
1834 if (b->vb_uint64 == 0) return ERR_ZERO;
1835
1836 result.vb_uint64 = a->vb_uint64 % b->vb_uint64;
1837 break;
1838
1839 case T_AND:
1840 result.vb_uint64 = a->vb_uint64 & b->vb_uint64;
1841 break;
1842
1843 case T_OR:
1844 result.vb_uint64 = a->vb_uint64 | b->vb_uint64;
1845 break;
1846
1847 case T_XOR:
1848 result.vb_uint64 = a->vb_uint64 ^ b->vb_uint64;
1849 break;
1850
1851 case T_RSHIFT:
1852 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_UNDERFLOW;
1853
1854 result.vb_uint64 = a->vb_uint64 >> b->vb_uint32;
1855 break;
1856
1857 case T_LSHIFT:
1858 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_OVERFLOW;
1859
1860 result.vb_uint64 = a->vb_uint64 << b->vb_uint32;
1861 break;
1862
1863 default:
1864 return ERR_INVALID;
1865 }
1866
1867 /*
1868 * Once we're done, cast the result to the final data type.
1869 */
1870 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1871
1874
1875 return 0;
1876}
1877
1878/*
1879 * Same as above, except uint64 -> int64. These functions should be kept in sync!
1880 */
1881static 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)
1882{
1883 fr_value_box_t one, two, result;
1884 fr_value_box_t const *a = in1;
1885 fr_value_box_t const *b = in2;
1886
1887 fr_value_box_init(&result, FR_TYPE_INT64, NULL, a->tainted | b->tainted);
1888
1889 COERCE_A(FR_TYPE_INT64, NULL);
1890
1891 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1892 /*
1893 * Don't touch the RHS.
1894 */
1895 fr_assert(b->type == FR_TYPE_UINT32);
1896
1897 } else {
1898 COERCE_B(FR_TYPE_INT64, dst->enumv);
1899 }
1900
1901 switch (op) {
1902 case T_ADD:
1903 if (!fr_add(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1904 break;
1905
1906 case T_SUB:
1907 if (!fr_sub(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_UNDERFLOW;
1908 break;
1909
1910 case T_MUL:
1911 if (!fr_multiply(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1912 break;
1913
1914 case T_DIV:
1915 if (b->vb_int64 == 0) return ERR_ZERO;
1916
1917 result.vb_int64 = a->vb_int64 / b->vb_int64;
1918 break;
1919
1920 case T_MOD:
1921 if (b->vb_int64 == 0) return ERR_ZERO;
1922
1923 result.vb_int64 = a->vb_int64 % b->vb_int64;
1924 break;
1925
1926 case T_AND:
1927 result.vb_int64 = a->vb_int64 & b->vb_int64;
1928 break;
1929
1930 case T_OR:
1931 result.vb_int64 = a->vb_int64 | b->vb_int64;
1932 break;
1933
1934 case T_XOR:
1935 result.vb_int64 = a->vb_int64 ^ b->vb_int64;
1936 break;
1937
1938 case T_RSHIFT:
1939 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_UNDERFLOW;
1940
1941 result.vb_int64 = a->vb_int64 >> b->vb_uint32;
1942 break;
1943
1944 case T_LSHIFT:
1945 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_OVERFLOW;
1946
1947 result.vb_int64 = a->vb_int64 << b->vb_uint32;
1948 break;
1949
1950 default:
1951 return ERR_INVALID;
1952 }
1953
1954 /*
1955 * Once we're done, cast the result to the final data type.
1956 */
1957 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1958
1961
1962 return 0;
1963}
1964
1965typedef 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);
1966
1967/** Map output type to its associated function
1968 *
1969 */
2003
2004/** Calculate DST = A OP B
2005 *
2006 * The result is written to DST only *after* it has been calculated.
2007 * So it's safe to pass DST as either A or B. DST should already exist.
2008 *
2009 * This function should arguably not take comparison operators, but
2010 * whatever. The "promote types" code is the same for all of the
2011 * binary operations, so we might as well just have one function.
2012 */
2013int 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)
2014{
2015 int rcode = -1;
2016 fr_value_box_t one, two;
2018 fr_binary_op_t func;
2019
2020 if ((hint != FR_TYPE_NULL) && !fr_type_is_leaf(hint)) return invalid_type(hint);
2021
2022 /*
2023 * Casting to structural types should be a parse error,
2024 * and not a run-time calculation error.
2025 */
2026 if (!fr_type_is_leaf(a->type)) return invalid_type(a->type);
2027 if (!fr_type_is_leaf(b->type)) return invalid_type(b->type);
2028
2031
2032 /*
2033 * === and !== also check types. If the types are
2034 * different, it's a failure. Otherwise they revert to == and !=.
2035 */
2036 switch (op) {
2037 case T_OP_CMP_EQ_TYPE:
2038 if (a->type != b->type) {
2039 mismatch_type:
2040 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
2041 dst->vb_bool = false;
2042 return 0;
2043 }
2044 op = T_OP_CMP_EQ;
2045 break;
2046
2047 case T_OP_CMP_NE_TYPE:
2048 if (a->type != b->type) goto mismatch_type;
2049
2050 op = T_OP_NE;
2051 break;
2052
2053 case T_OP_REG_EQ:
2054 case T_OP_REG_NE:
2055 if (b->type != FR_TYPE_STRING) {
2056 fr_strerror_const("Invalid type for regular expression");
2057 return -1;
2058 }
2059
2060 rcode = fr_regex_cmp_op(op, a, b);
2061 if (rcode < 0) return rcode;
2062
2063 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
2064 dst->vb_bool = (rcode != 0);
2065 return 0;
2066
2067 default:
2068 break;
2069 }
2070
2073
2074 /*
2075 * We don't know what the output type should be. Try to
2076 * guess based on a variety of factors.
2077 */
2078 if (hint == FR_TYPE_NULL) do {
2079 /*
2080 * All kinds of special cases :(
2081 *
2082 * date1 - date2 --> time_delta
2083 *
2084 * time_delta * FOO --> float64, because time_delta is _printed_ as a floating point
2085 * number. And this is the least surprising thing to do.
2086 */
2087 if ((op == T_SUB) && (a->type == b->type) && (a->type == FR_TYPE_DATE)) {
2088 hint = FR_TYPE_TIME_DELTA;
2089 break;
2090 }
2091
2092 if (op == T_MUL) {
2093 if (a->type == FR_TYPE_TIME_DELTA) {
2094 hint = upcast_op[FR_TYPE_FLOAT64][b->type];
2095 if (hint == FR_TYPE_NULL) hint = upcast_op[b->type][FR_TYPE_FLOAT64];
2096
2097 } else if (b->type == FR_TYPE_TIME_DELTA) {
2098 hint = upcast_op[a->type][FR_TYPE_FLOAT64];
2099 if (hint == FR_TYPE_NULL) hint = upcast_op[FR_TYPE_FLOAT64][a->type];
2100 }
2101
2102 if ((a->type == FR_TYPE_STRING) &&
2103 (fr_type_is_integer_except_bool(b->type))) {
2104 hint = FR_TYPE_STRING;
2105 }
2106
2107 if ((a->type == FR_TYPE_OCTETS) &&
2108 (fr_type_is_integer_except_bool(b->type))) {
2109 hint = FR_TYPE_OCTETS;
2110 }
2111
2112 if (hint != FR_TYPE_NULL) break;
2113 }
2114
2115 /*
2116 * date % time_delta --> time_delta
2117 */
2118 if ((op == T_MOD) && (a->type == FR_TYPE_DATE)) {
2119 hint = FR_TYPE_TIME_DELTA;
2120 break;
2121 }
2122
2123 switch (op) {
2124 case T_OP_CMP_EQ:
2125 case T_OP_NE:
2126 case T_OP_GE:
2127 case T_OP_GT:
2128 case T_OP_LE:
2129 case T_OP_LT:
2130 /*
2131 * Comparison operators always return
2132 * "bool".
2133 */
2134 hint = FR_TYPE_BOOL;
2135 break;
2136
2137 case T_AND:
2138 /*
2139 * Get mask from IP + number
2140 */
2141 if ((a->type == FR_TYPE_IPV4_ADDR) || (b->type == FR_TYPE_IPV4_ADDR)) {
2142 hint = FR_TYPE_IPV4_PREFIX;
2143 break;
2144 }
2145
2146 if ((a->type == FR_TYPE_IPV6_ADDR) || (b->type == FR_TYPE_IPV6_ADDR)) {
2147 hint = FR_TYPE_IPV6_PREFIX;
2148 break;
2149 }
2151
2152 case T_OR:
2153 case T_ADD:
2154 case T_SUB:
2155 case T_MUL:
2156 case T_DIV:
2157 case T_MOD:
2158 case T_XOR:
2159 /*
2160 * Try to "up-cast" the types. This is
2161 * so that we can take (for example)
2162 * uint8 + uint16, and have the output as
2163 * uint16.
2164 *
2165 * There must be only one entry per [a,b]
2166 * pairing. That way we're sure that [a,b]==[b,a]
2167 */
2168 hint = upcast_op[a->type][b->type];
2169 if (hint == FR_TYPE_NULL) {
2170 hint = upcast_op[b->type][a->type];
2171 } else if (a->type != b->type) {
2172 fr_assert(upcast_op[b->type][a->type] == FR_TYPE_NULL);
2173 }
2174
2175 /*
2176 * No idea what to do. :(
2177 */
2178 if (hint == FR_TYPE_NULL) {
2179 fr_strerror_printf("Invalid operation on data types - '%s' %s '%s'",
2180 fr_type_to_str(a->type), fr_tokens[op], fr_type_to_str(b->type));
2181 goto done;
2182 }
2183
2184 break;
2185
2186 /*
2187 * The RHS MUST be a numerical type. We don't need to do any upcasting here.
2188 *
2189 * @todo - the output type could be larger than the input type, if the shift is
2190 * more than the input type can handle. e.g. uint8 << 4 could result in uint16
2191 */
2192 case T_LSHIFT:
2193 if (!fr_type_is_integer(a->type)) {
2194 return handle_result(a->type, T_LSHIFT, ERR_INVALID);
2195 }
2196
2197 if (fr_type_is_signed(a->type)) {
2198 hint = FR_TYPE_INT64;
2199 break;
2200 }
2201 hint = FR_TYPE_UINT64;
2202 break;
2203
2204 case T_RSHIFT:
2205 hint = a->type;
2206 break;
2207
2208 default:
2209 return handle_result(a->type, op, ERR_INVALID);
2210 }
2211 } while (0);
2212
2213 /*
2214 * Now that we've figured out the correct types, perform the operation.
2215 */
2216 switch (op) {
2217 case T_OP_CMP_EQ:
2218 case T_OP_NE:
2219 case T_OP_GE:
2220 case T_OP_GT:
2221 case T_OP_LE:
2222 case T_OP_LT:
2223 if (hint != FR_TYPE_BOOL) {
2224 fr_strerror_printf("Invalid destination type '%s' for comparison operator",
2225 fr_type_to_str(hint));
2226 goto done;
2227 }
2228
2229 /*
2230 * Convert the types to ones which are comparable.
2231 */
2232 if (a->type != b->type) {
2233 fr_dict_attr_t const *enumv = NULL;
2234
2235 /*
2236 * If we're doing comparisons and one of them has an enum, and the other is an
2237 * enum name, then use the enum name to convert the string to the other type.
2238 *
2239 * We can then do type-specific comparisons.
2240 */
2241 if ((a->type == FR_TYPE_STRING) && b->enumv) {
2242 enumv = b->enumv;
2243 hint = b->type;
2244
2245 } else if ((b->type == FR_TYPE_STRING) && a->enumv) {
2246 enumv = a->enumv;
2247 hint = a->type;
2248
2249 } else {
2250 /*
2251 * Try to "up-cast" the types. This is so that we can take (for example)
2252 * uint8 < uint16, and have it make sense.
2253 *
2254 * There must be only one entry per [a,b] pairing. That way we're sure
2255 * that [a,b]==[b,a]
2256 */
2257 hint = upcast_cmp[a->type][b->type];
2258 if (hint == FR_TYPE_NULL) {
2259 hint = upcast_cmp[b->type][a->type];
2260 } else {
2261 fr_assert(upcast_cmp[b->type][a->type] == FR_TYPE_NULL);
2262 }
2263
2264 /*
2265 * time_deltas have a scale in the enumv, but default to "seconds" if
2266 * there's no scale. As a result, if we compare time_delta(ms) to integer,
2267 * then the integer is interpreted as seconds, and the scale is wrong.
2268 *
2269 * The solution is to use the appropriate scale.
2270 */
2271 if (hint == a->type) enumv = a->enumv;
2272 if (hint == b->type) enumv = b->enumv;
2273
2274 if (hint == FR_TYPE_NULL) {
2275 fr_strerror_printf("Cannot compare incompatible types (%s)... %s (%s)...",
2276 fr_type_to_str(a->type),
2277 fr_tokens[op],
2278 fr_type_to_str(b->type));
2279 goto done;
2280 }
2281 }
2282
2283 /*
2284 * Cast them to the appropriate type, which may be different from either of the
2285 * inputs.
2286 */
2287 if (a->type != hint) {
2288 if (fr_value_box_cast(NULL, &one, hint, enumv, a) < 0) goto done;
2289 a = &one;
2291 }
2292
2293 if (b->type != hint) {
2294 if (fr_value_box_cast(NULL, &two, hint, enumv, b) < 0) goto done;
2295 b = &two;
2297 }
2298 }
2299
2300 rcode = fr_value_box_cmp_op(op, a, b);
2301 if (rcode < 0) goto done;
2302
2303 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false);
2304 dst->vb_bool = (rcode > 0);
2305 break;
2306
2307 /*
2308 * For shifts, the RHS value MUST be an integer. There's no reason to have it as
2309 * anything other than an 8-bit field.
2310 */
2311 case T_LSHIFT:
2312 case T_RSHIFT:
2313 if (b->type != FR_TYPE_UINT32) {
2314 if (fr_value_box_cast(ctx, &two, FR_TYPE_UINT32, NULL, b) < 0) {
2315 fr_strerror_const_push("Cannot parse shift value as integer");
2316 goto done;
2317 }
2318 b = &two;
2319 }
2321
2322 case T_ADD:
2323 case T_SUB:
2324 case T_MUL:
2325 case T_DIV:
2326 case T_MOD:
2327 case T_AND:
2328 case T_OR:
2329 case T_XOR:
2330 fr_assert(hint != FR_TYPE_NULL);
2331
2332 func = calc_type[hint];
2333 if (!func) {
2334 fr_strerror_printf("Cannot perform any operations for destination type %s",
2335 fr_type_to_str(hint));
2336 rcode = -1;
2337 break;
2338 }
2339
2340 /*
2341 * It's OK to use one of the inputs as the
2342 * output. In order to ensure that nothing bad
2343 * happens, we use an intermediate value-box.
2344 */
2345 fr_value_box_init(&out, hint, NULL, false);
2346
2347 rcode = func(ctx, &out, a, op, b); /* not calc_type[hint], to shut up clang */
2348 if (rcode < 0) goto done;
2349
2350 fr_value_box_copy_shallow(NULL, dst, &out);
2351 dst->tainted = a->tainted | b->tainted;
2352 break;
2353
2354 default:
2355 rcode = ERR_INVALID;
2356 break;
2357 }
2358
2359done:
2362
2363 return handle_result(hint, op, rcode);
2364}
2365
2366/** Calculate DST = OP { A, B, C, ... }
2367 *
2368 * The result is written to DST only *after* it has been calculated.
2369 * So it's safe to pass DST as one of the inputs. DST should already
2370 * exist.
2371 */
2373{
2374 fr_value_box_t out, *vb;
2375 fr_binary_op_t calc;
2376
2377 if (group->type != FR_TYPE_GROUP) {
2378 fr_strerror_const("Invalid type passed to multivalue calculation");
2379 return -1;
2380 }
2381
2384 fr_strerror_printf("Invalid operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2385 return -1;
2386 }
2387
2388 if (type == FR_TYPE_STRING) {
2389 fr_sbuff_t *sbuff;
2391
2392 if (op != T_ADD) goto invalid_type;
2393
2394 FR_SBUFF_TALLOC_THREAD_LOCAL(&sbuff, 1024, (1 << 16));
2395
2396 if (fr_value_box_list_concat_as_string(&safety, sbuff, UNCONST(fr_value_box_list_t *, &group->vb_group),
2397 NULL, 0, NULL, FR_VALUE_BOX_LIST_NONE, FR_VALUE_BOX_SAFE_FOR_ANY, false) < 0) return -1;
2398
2399 if (fr_value_box_bstrndup(ctx, dst, NULL, fr_sbuff_start(sbuff), fr_sbuff_used(sbuff), false) < 0) return -1;
2400 fr_value_box_safety_set(dst, &safety);
2401 return 0;
2402 }
2403
2404 if (type == FR_TYPE_OCTETS) {
2405 fr_dbuff_t *dbuff;
2407
2408 if (op != T_ADD) goto invalid_type;
2409
2410 FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, (1 << 16));
2411
2412 if (fr_value_box_list_concat_as_octets(&safety, dbuff, UNCONST(fr_value_box_list_t *, &group->vb_group), NULL, 0, FR_VALUE_BOX_LIST_NONE, false) < 0) return -1;
2413
2414 if (fr_value_box_memdup(ctx, dst, NULL, fr_dbuff_start(dbuff), fr_dbuff_used(dbuff), false) < 0) return -1;
2415 fr_value_box_safety_set(dst, &safety);
2416
2417 return 0;
2418 }
2419
2420 /*
2421 * Can't add or multiply booleans.
2422 */
2423 if ((type == FR_TYPE_BOOL) && !((op == T_AND) || (op == T_OR) || (op == T_XOR))) goto unsupported;
2424
2425 switch (op) {
2426 case T_ADD:
2427 case T_MUL:
2428 case T_AND:
2429 case T_OR:
2430 case T_XOR:
2431 break;
2432
2433 default:
2434 goto invalid_type;
2435 }
2436
2437 /*
2438 * Strings and octets are different.
2439 */
2440 if (!fr_type_is_numeric(type)) {
2441 unsupported:
2442 fr_strerror_printf("Not yet supported operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2443 return -1;
2444 }
2445
2446 switch (type) {
2447 case FR_TYPE_UINT8:
2448 case FR_TYPE_UINT16:
2449 case FR_TYPE_UINT32:
2450 case FR_TYPE_UINT64:
2451 calc = calc_uint64;
2452 break;
2453
2454 case FR_TYPE_INT8:
2455 case FR_TYPE_INT16:
2456 case FR_TYPE_INT32:
2457 case FR_TYPE_INT64:
2458 calc = calc_int64;
2459 break;
2460
2461 case FR_TYPE_TIME_DELTA:
2462 if ((op != T_ADD) && (op != T_SUB)) goto invalid_type;
2463 calc = calc_time_delta;
2464 break;
2465
2466 case FR_TYPE_FLOAT32:
2467 calc = calc_float32;
2468 break;
2469
2470 case FR_TYPE_FLOAT64:
2471 calc = calc_float64;
2472 break;
2473
2474 default:
2475 goto unsupported;
2476 }
2477
2478 vb = fr_value_box_list_head(&group->vb_group);
2479 if (!vb) {
2480 fr_strerror_printf("Empty input is invalid");
2481 return -1;
2482 }
2483
2484 if (fr_value_box_cast(ctx, &out, type, NULL, vb) < 0) return -1;
2485
2486 while ((vb = fr_value_box_list_next(&group->vb_group, vb)) != NULL) {
2487 int rcode;
2488 fr_value_box_t box;
2489
2490 if (vb->type == type) {
2491 rcode = calc(ctx, &out, &out, op, vb);
2492 if (rcode < 0) return rcode;
2493
2494 } else {
2495 if (fr_value_box_cast(ctx, &box, type, NULL, vb) < 0) return -1;
2496
2497 rcode = calc(ctx, &out, &out, op, &box);
2498 if (rcode < 0) return rcode;
2499 }
2500 }
2501
2502 return fr_value_box_copy(ctx, dst, &out);
2503}
2504
2505
2506#define T(_x) [T_OP_ ## _x ## _EQ] = T_ ## _x
2507
2509 T(ADD),
2510 T(SUB),
2511 T(MUL),
2512 T(DIV),
2513 T(AND),
2514 T(OR),
2515 T(XOR),
2516 T(RSHIFT),
2517 T(LSHIFT),
2518};
2519
2520/** Calculate DST OP SRC
2521 *
2522 * e.g. "foo += bar".
2523 *
2524 * This is done by doing some sanity checks, and then just calling
2525 * the "binary operation" function.
2526 */
2528{
2529 int rcode;
2530
2531 if (!fr_type_is_leaf(dst->type)) return invalid_type(dst->type);
2532 if (!fr_type_is_leaf(src->type)) return invalid_type(src->type);
2533
2534 if (dst->immutable) {
2535 fr_strerror_printf("Cannot modify immutable value");
2536 return -1;
2537 }
2538
2539 /*
2540 * These operators are included here for testing and completeness. But see comments in
2541 * fr_edit_list_apply_pair_assignment() for what the caller should be doing.
2542 */
2543 if ((op == T_OP_EQ) || (op == T_OP_SET)) {
2544 /*
2545 * Allow for unintentional mistakes.
2546 */
2547 if (src == dst) return 0;
2548
2550 return fr_value_box_cast(ctx, dst, dst->type, dst->enumv, src); /* cast, as the RHS might not (yet) be the same! */
2551 }
2552
2553 if (assignment2op[op] == T_INVALID) {
2554 return handle_result(dst->type, op, ERR_INVALID);
2555 }
2556 op = assignment2op[op];
2557
2558 /*
2559 * Just call the binary op function. It already ensures that (a) the inputs are "const", and (b)
2560 * the output is over-written only at the final step.
2561 */
2562 if (src->type != FR_TYPE_GROUP) {
2563 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, src);
2564
2565 } else {
2566 fr_value_box_t *vb = NULL;
2567
2568 /*
2569 * If the RHS is a group, then we loop over the group recursively, doing the operation.
2570 */
2571 rcode = 0; /* in case group is empty */
2572
2573 while ((vb = fr_value_box_list_next(&src->vb_group, vb)) != NULL) {
2574 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, vb);
2575 if (rcode < 0) break;
2576 }
2577 }
2578
2579 if (rcode < 0) return handle_result(dst->type, op, rcode);
2580
2581 return 0;
2582}
2583
2584/** Calculate unary operations
2585 *
2586 * e.g. "foo++", or "-foo".
2587 */
2588int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
2589{
2590 int rcode = -1;
2591 fr_value_box_t one;
2592
2593 if (!fr_type_is_numeric(src->type)) return invalid_type(src->type);
2594
2595 if (dst->immutable) {
2596 fr_strerror_printf("Cannot modify immutable value");
2597 return -1;
2598 }
2599
2600 if (op == T_OP_INCRM) {
2601 /*
2602 * Add 1 or subtract 1 means RHS is always 1.
2603 */
2604 fr_value_box_init(&one, src->type, NULL, false);
2605 switch (src->type) {
2606 case FR_TYPE_UINT8:
2607 one.vb_uint8 = 1;
2608 break;
2609
2610 case FR_TYPE_UINT16:
2611 one.vb_uint16 = 1;
2612 break;
2613
2614 case FR_TYPE_UINT32:
2615 one.vb_uint32 = 1;
2616 break;
2617
2618 case FR_TYPE_UINT64:
2619 one.vb_uint64 = 1;
2620 break;
2621
2622 case FR_TYPE_SIZE:
2623 one.vb_size = 1;
2624 break;
2625
2626 case FR_TYPE_INT8:
2627 one.vb_int8 = 1;
2628 break;
2629
2630 case FR_TYPE_INT16:
2631 one.vb_int16 = 1;
2632 break;
2633
2634 case FR_TYPE_INT32:
2635 one.vb_int32 = 1;
2636 break;
2637
2638 case FR_TYPE_INT64:
2639 one.vb_int64 = 1;
2640 break;
2641
2642 case FR_TYPE_FLOAT32:
2643 one.vb_float32 = 1;
2644 break;
2645
2646 case FR_TYPE_FLOAT64:
2647 one.vb_float64 = 1;
2648 break;
2649
2650 default:
2651 fr_assert(0);
2652 return -1;
2653 }
2654
2655 rcode = fr_value_calc_binary_op(ctx, dst, src->type, src, T_ADD, &one);
2656 return handle_result(dst->type, op, rcode);
2657
2658 } else if (op == T_COMPLEMENT) {
2659 if (dst != src) {
2660 fr_value_box_init(dst, src->type, src->enumv, false);
2661 fr_value_box_safety_copy(dst, src);
2662 }
2663
2664#undef COMP
2665#define COMP(_type, _field) case FR_TYPE_ ## _type: dst->vb_ ##_field = (_field ## _t) ~src->vb_ ##_field; break
2666 switch (src->type) {
2667 COMP(UINT8, uint8);
2668 COMP(UINT16, uint16);
2669 COMP(UINT32, uint32);
2670 COMP(UINT64, uint64);
2671 COMP(SIZE, size);
2672
2673 COMP(INT8, int8);
2674 COMP(INT16, int16);
2675 COMP(INT32, int32);
2676 COMP(INT64, int64);
2677
2678 default:
2679 goto invalid;
2680 }
2681
2682 return 0;
2683
2684 } else if (op == T_SUB) {
2685 fr_type_t type = src->type;
2686
2687 if ((dst != src) && !fr_type_is_signed(src->type)) {
2688 type = upcast_unsigned[src->type];
2689
2690 if (type == FR_TYPE_NULL) {
2691 type = src->type; /* hope for the best */
2692 }
2693 }
2694
2695 fr_value_box_init(&one, type, NULL, src->tainted); /* init to zero */
2696 rcode = fr_value_calc_binary_op(ctx, dst, type, &one, T_SUB, src);
2697
2698 return handle_result(dst->type, op, rcode);
2699
2700 } else if (op == T_NOT) {
2701 bool value = fr_value_box_is_truthy(src);
2702
2703 fr_value_box_clear(dst);
2704 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2705 dst->vb_bool = !value;
2706
2707 return 0;
2708
2709 } else {
2710 invalid:
2711 return handle_result(src->type, op, ERR_INVALID);
2712 }
2713
2714}
2715
2716/*
2717 * Empty lists are empty:
2718 *
2719 * {}
2720 * {{}}
2721 * {''}
2722 * {{},''}
2723 *
2724 * etc.
2725 */
2726static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
2727{
2729 switch (item->type) {
2730 default:
2731 return false;
2732
2733 case FR_TYPE_GROUP:
2734 if (!fr_value_calc_list_empty(&item->vb_group)) return false;
2735 break;
2736
2737 case FR_TYPE_STRING:
2738 case FR_TYPE_OCTETS:
2739 if (item->vb_length != 0) return false;
2740 break;
2741 }
2742 }
2743
2744 return true;
2745}
2746
2747
2748/*
2749 * Loop over input lists, calling fr_value_calc_binary_op()
2750 *
2751 * This implementation is arguably wrong... it should be checking individual entries in list1 against individual entries in list2.
2752 * Instead, it checks if ANY entry in list1 matches ANY entry in list2.
2753 */
2754int 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)
2755{
2756 int rcode;
2757 bool invert = false;
2758 bool a_empty, b_empty;
2759
2760 if (!fr_comparison_op[op]) {
2761 fr_strerror_printf("Invalid operator '%s' passed to list comparison", fr_tokens[op]);
2762 return -1;
2763 }
2764
2765 /*
2766 * v3 hack. != really means !( ... == ... )
2767 */
2768 if (op == T_OP_NE) {
2769 invert = true;
2770 op = T_OP_CMP_EQ;
2771 }
2772
2773 /*
2774 * It's annoying when the debug prints out cmp({},{}) and says "not equal".
2775 *
2776 * What's happening behind the scenes is that one side is an empty value-box group, such as when
2777 * an xlat expansion fails. And the other side is an empty string. If we believe that strings
2778 * are actually sets of characters, then {}=='', and we're all OK
2779 */
2780 a_empty = fr_value_box_list_empty(list1) || fr_value_calc_list_empty(list1);
2781 b_empty = fr_value_box_list_empty(list2) || fr_value_calc_list_empty(list2);
2782
2783 /*
2784 * Both lists are empty, they should be equal when checked for equality.
2785 */
2786 if (a_empty && b_empty) {
2787 switch (op) {
2788 case T_OP_CMP_EQ:
2789 case T_OP_LE:
2790 case T_OP_GE:
2791 invert = !invert;
2792 break;
2793
2794 default:
2795 break;
2796 }
2797
2798 goto done;
2799 }
2800
2801 /*
2802 * Emulate v3. :(
2803 */
2804 fr_value_box_list_foreach(list1, a) {
2805 fr_value_box_list_foreach(list2, b) {
2806 rcode = fr_value_calc_binary_op(ctx, dst, FR_TYPE_BOOL, a, op, b);
2807 if (rcode < 0) return rcode;
2808
2809 /*
2810 * No match: keep looking for a match.
2811 */
2812 fr_assert(dst->type == FR_TYPE_BOOL);
2813 if (!dst->vb_bool) continue;
2814
2815 /*
2816 * Found a match, we're done.
2817 */
2818 dst->vb_bool = !invert;
2819 return 0;
2820 }
2821 }
2822
2823 /*
2824 * No match,
2825 */
2826done:
2827 fr_value_box_clear(dst);
2828 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2829 dst->vb_bool = invert;
2830 return 0;
2831}
static uint8_t overflow[100]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define RCSID(id)
Definition build.h:603
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:422
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
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:776
static const fr_type_t upcast_cmp[FR_TYPE_MAX+1][FR_TYPE_MAX+1]
Updates type (a,b) -> c.
Definition calc.c:427
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:1318
static int get_ipv6_prefix(uint8_t const *in)
Definition calc.c:1588
static const fr_binary_op_t calc_type[FR_TYPE_MAX+1]
Map output type to its associated function.
Definition calc.c:1970
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:1521
static int invalid_type(fr_type_t type)
Definition calc.c:699
#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:66
#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:1695
#define COERCE_A(_type, _enumv)
Definition calc.c:48
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:1369
static const fr_type_t upcast_unsigned[FR_TYPE_MAX+1]
Definition calc.c:690
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:1794
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:904
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:1673
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:1611
static int cast_ipv6_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1453
static int handle_result(fr_type_t type, fr_token_t op, int rcode)
Definition calc.c:706
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:1881
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:728
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:1090
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:2754
#define ERR_INVALID
Definition calc.c:38
#define swap(_a, _b)
Definition calc.c:33
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:1685
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:819
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:1965
static int cast_ipv4_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1253
static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
Definition calc.c:2726
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:1745
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:2372
#define is_ipv6(_x)
Definition calc.c:1671
#define COERCE_B(_type, _enumv)
Definition calc.c:49
static const fr_token_t assignment2op[T_TOKEN_LAST]
Definition calc.c:2508
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:2527
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:2013
#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:2588
#define T(_x)
Definition calc.c:2506
#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:819
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:950
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition dbuff.h:598
Test enumeration values.
Definition dict_test.h:92
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
Definition lst.c:121
#define fr_sub(_out, _a, _b)
Subtracts two integers.
Definition math.h:201
#define fr_add(_out, _a, _b)
Adds two integers.
Definition math.h:190
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
Definition math.h:179
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:37
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:146
const bool fr_comparison_op[T_TOKEN_LAST]
Definition token.c:264
@ T_AND
Definition token.h:53
@ T_INVALID
Definition token.h:37
@ T_SUB
Definition token.h:50
@ T_RSHIFT
Definition token.h:60
@ T_NOT
Definition token.h:55
@ T_XOR
Definition token.h:56
@ T_DIV
Definition token.h:52
@ T_MOD
Definition token.h:58
@ T_OP_EQ
Definition token.h:81
@ T_COMPLEMENT
Definition token.h:57
@ T_ADD
Definition token.h:49
@ T_OP_SET
Definition token.h:82
@ T_OP_NE
Definition token.h:95
@ T_LSHIFT
Definition token.h:61
@ T_OP_REG_EQ
Definition token.h:100
@ T_OP_CMP_EQ_TYPE
Definition token.h:105
@ T_OP_CMP_EQ
Definition token.h:104
@ T_OP_INCRM
Definition token.h:111
@ T_MUL
Definition token.h:51
@ T_OP_LE
Definition token.h:98
@ T_OP_CMP_NE_TYPE
Definition token.h:106
@ T_OP_GE
Definition token.h:96
@ T_OP_GT
Definition token.h:97
@ T_OP_LT
Definition token.h:99
@ T_OP_REG_NE
Definition token.h:101
@ T_OR
Definition token.h:54
enum fr_token fr_token_t
#define T_TOKEN_LAST
Definition token.h:127
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:1065
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const_push(_msg)
Definition strerror.h:227
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define fr_type_is_structural(_x)
Definition types.h:392
#define fr_type_is_integer_except_bool(_x)
Definition types.h:380
#define fr_type_is_numeric(_x)
Definition types.h:382
#define fr_type_is_signed(_x)
Definition types.h:383
#define fr_type_is_leaf(_x)
Definition types.h:393
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:454
#define fr_type_is_integer(_x)
Definition types.h:381
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:4015
ssize_t fr_value_box_list_concat_as_octets(fr_value_box_safety_t *safety, 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:6632
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:4465
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:1017
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:7627
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:5278
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:4591
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4400
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:4702
void fr_value_box_safety_set(fr_value_box_t *box, fr_value_box_safety_t const *safety)
Replace the safety of a box.
Definition value.c:7566
ssize_t fr_value_box_list_concat_as_string(fr_value_box_safety_t *safety, 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:6515
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
Definition value.c:7555
void fr_value_box_safety_copy(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
Definition value.c:7497
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4448
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:4953
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:5040
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:5194
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
Definition value.h:262
static fr_sbuff_err_t char size_t fr_sbuff_t * in
Definition value.h:1061
fr_value_box_safe_for_t safe_for
A unique value to indicate if that value box is safe for consumption by a particular module for a par...
Definition value.h:187
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:640
static fr_sbuff_err_t char ** out
Definition value.h:1061
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1388
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:634
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:253
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:178
The safety of a value.
Definition value.h:186