The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
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: 95debffebadce30125b06ec89c85c82b701fdfff $
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: 95debffebadce30125b06ec89c85c82b701fdfff $")
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, *p;
906 size_t i, 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 if (op == T_MUL) {
922
924
925 } else {
926 COERCE_B(FR_TYPE_OCTETS, dst->enumv);
927 }
928
929 len = a->vb_length + b->vb_length;
930
931 switch (op) {
932 case T_ADD: /* dst = a . b */
933 buf = talloc_array(ctx, uint8_t, len);
934 if (!buf) {
935 oom:
936 fr_strerror_const("Out of memory");
937 return -1;
938 }
939
940 memcpy(buf, a->vb_octets, a->vb_length);
941 memcpy(buf + a->vb_length, b->vb_octets, b->vb_length);
942
943 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
946 break;
947
948 case T_SUB:
949 /*
950 * The inverse of add!
951 */
952 if (a->vb_length < b->vb_length) {
953 fr_strerror_const("Suffix to remove is longer than input string.");
954 return -1;
955 }
956
957 if (memcmp(a->vb_octets + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
958 fr_strerror_const("Suffix to remove is not a suffix of the input string.");
959 return -1;
960 }
961
962 len = a->vb_length - b->vb_length;
963 buf = talloc_array(ctx, uint8_t, len);
964 if (!buf) goto oom;
965
966 memcpy(buf, a->vb_strvalue, len);
967
968 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
970 break;
971
972 case T_AND:
973 if (a->vb_length != b->vb_length) {
974 length_error:
975 fr_strerror_const("Cannot perform operation on strings of different length");
976 return -1;
977 }
978
979 buf = talloc_array(ctx, uint8_t, a->vb_length);
980 if (!buf) goto oom;
981
982 for (len = 0; len < a->vb_length; len++) {
983 buf[len] = a->vb_octets[len] & b->vb_octets[len];
984 }
985
986 set_result:
987 fr_value_box_memdup_shallow(dst, dst->enumv, buf, a->vb_length, false);
990 break;
991
992 case T_OR:
993 if (a->vb_length != b->vb_length) goto length_error;
994
995 buf = talloc_array(ctx, uint8_t, a->vb_length);
996 if (!buf) goto oom;
997
998 for (len = 0; len < a->vb_length; len++) {
999 buf[len] = a->vb_octets[len] | b->vb_octets[len];
1000 }
1001 goto set_result;
1002
1003 case T_XOR:
1004 if (a->vb_length != b->vb_length) goto length_error;
1005
1006 buf = talloc_array(ctx, uint8_t, a->vb_length);
1007 if (!buf) goto oom;
1008
1009 for (len = 0; len < a->vb_length; len++) {
1010 buf[len] = a->vb_octets[len] ^ b->vb_octets[len];
1011 }
1012
1013 goto set_result;
1014
1015 case T_RSHIFT:
1016 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1017
1018 len = a->vb_length - b->vb_uint32;
1019 buf = talloc_array(ctx, uint8_t, len);
1020 if (!buf) goto oom;
1021
1022 memcpy(buf, a->vb_octets, len);
1023
1024 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1026 break;
1027
1028 case T_LSHIFT:
1029 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1030
1031 len = a->vb_length - b->vb_uint32;
1032
1033 buf = talloc_array(ctx, uint8_t, len);
1034 if (!buf) goto oom;
1035
1036 memcpy(buf, a->vb_octets + b->vb_uint32, len);
1037
1038 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1040 break;
1041
1042 case T_MUL:
1043 /*
1044 * 0 * 0 = 0
1045 */
1046 if (!b->vb_uint64 || !a->vb_length) {
1047 fr_value_box_memdup(ctx, dst, dst->enumv, (const uint8_t *) "", 0, false);
1049 break;
1050 }
1051
1052 if (b->vb_uint64 > 256) return ERR_OVERFLOW;
1053 if (a->vb_length > 16) return ERR_OVERFLOW;
1054
1055 len = a->vb_length * b->vb_uint64;
1056
1057 buf = talloc_array(ctx, uint8_t, len);
1058 if (!buf) goto oom;
1059
1060 for (i = 0, p = buf; i < b->vb_uint64; i++, p += a->vb_length) {
1061 memcpy(p, a->vb_octets, a->vb_length);
1062 }
1063
1064 fr_value_box_memdup_shallow(dst, dst->enumv, buf, len, false);
1066 break;
1067
1068 default:
1069 return ERR_INVALID; /* invalid operator */
1070 }
1071
1072 if (a == &one) fr_value_box_clear_value(&one);
1073 if (b == &two) fr_value_box_clear_value(&two);
1074
1075 return 0;
1076}
1077
1078static 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)
1079{
1080 char *buf, *p;
1081 size_t i, len;
1082 fr_value_box_t one = {};
1083 fr_value_box_t two = {};
1084
1085 fr_assert(dst->type == FR_TYPE_STRING);
1086
1087 COERCE_A(FR_TYPE_STRING, dst->enumv);
1088
1089 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1090 /*
1091 * Don't touch the RHS.
1092 */
1093 fr_assert(b->type == FR_TYPE_UINT32);
1094
1095 } else if (op == T_MUL) {
1097
1098 COERCE_B(FR_TYPE_UINT64, NULL);
1099
1100 } else {
1101 COERCE_B(FR_TYPE_STRING, dst->enumv);
1102 }
1103
1104 len = a->vb_length + b->vb_length;
1105
1106 switch (op) {
1107 case T_ADD:
1108 buf = talloc_array(ctx, char, len + 1);
1109 if (!buf) {
1110 oom:
1111 fr_strerror_const("Out of memory");
1112 return -1;
1113 }
1114
1115 len = a->vb_length + b->vb_length;
1116 memcpy(buf, a->vb_strvalue, a->vb_length);
1117 memcpy(buf + a->vb_length, b->vb_strvalue, b->vb_length);
1118 buf[len] = '\0';
1119
1120 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1123 break;
1124
1125 case T_XOR: /* is prepend for strings */
1126 buf = talloc_array(ctx, char, len + 1);
1127 if (!buf) goto oom;
1128
1129 len = a->vb_length + b->vb_length;
1130 memcpy(buf, b->vb_strvalue, b->vb_length);
1131 memcpy(buf + b->vb_length, a->vb_strvalue, a->vb_length);
1132 buf[len] = '\0';
1133
1134 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1137 break;
1138
1139 case T_SUB:
1140 /*
1141 * The inverse of add!
1142 */
1143 if (a->vb_length < b->vb_length) {
1144 fr_strerror_const("Suffix to remove is longer than input string");
1145 return -1;
1146 }
1147
1148 if (memcmp(a->vb_strvalue + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
1149 fr_strerror_const("Right side of substract is not a suffix of the input string");
1150 return -1;
1151 }
1152
1153 len = a->vb_length - b->vb_length;
1154 buf = talloc_array(ctx, char, len + 1);
1155 if (!buf) goto oom;
1156
1157 memcpy(buf, a->vb_strvalue, len);
1158 buf[len] = '\0';
1159
1160 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1162 break;
1163
1164 case T_RSHIFT:
1165 if (b->vb_uint32 > a->vb_length) return ERR_UNDERFLOW;
1166
1167 len = a->vb_length - b->vb_uint32;
1168 buf = talloc_array(ctx, char, len + 1);
1169 if (!buf) goto oom;
1170
1171 memcpy(buf, a->vb_strvalue, len);
1172 buf[len] = '\0';
1173
1174 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1176 break;
1177
1178 case T_LSHIFT:
1179 if (b->vb_uint32 > a->vb_length) return ERR_OVERFLOW;
1180
1181 len = a->vb_length - b->vb_uint32;
1182
1183 buf = talloc_array(ctx, char, len + 1);
1184 if (!buf) goto oom;
1185
1186 memcpy(buf, a->vb_strvalue + b->vb_uint32, len);
1187 buf[len] = '\0';
1188
1189 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1191 break;
1192
1193 case T_MUL:
1194 /*
1195 * 0 * 0 = 0
1196 */
1197 if (!b->vb_uint64 || !a->vb_length) {
1198 fr_value_box_strdup(ctx, dst, dst->enumv, "", false);
1200 break;
1201 }
1202
1203 if (b->vb_uint64 > 256) return ERR_OVERFLOW;
1204 if (a->vb_length > 16) return ERR_OVERFLOW;
1205
1206 len = a->vb_length * b->vb_uint64;
1207
1208 buf = talloc_array(ctx, char, len + 1);
1209 if (!buf) goto oom;
1210
1211 for (i = 0, p = buf; i < b->vb_uint64; i++, p += a->vb_length) {
1212 memcpy(p, a->vb_strvalue, a->vb_length);
1213 }
1214 *p = '\0';
1215
1216 fr_value_box_bstrndup_shallow(dst, dst->enumv, buf, len, false);
1218 break;
1219
1220 default:
1221 return ERR_INVALID; /* invalid operator */
1222 }
1223
1224 if (a == &one) fr_value_box_clear_value(&one);
1225 if (b == &two) fr_value_box_clear_value(&two);
1226
1227 return 0;
1228}
1229
1231{
1232 switch (in->type) {
1233 default:
1234 fr_strerror_printf("Cannot operate on ipaddr and %s",
1235 fr_type_to_str(in->type));
1236 return -1;
1237
1239 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_addr;
1240
1241 fr_value_box_init(out, FR_TYPE_IPV4_ADDR, NULL, in->tainted);
1242 out->vb_ip = in->vb_ip;
1243 break;
1244
1246 if (in->vb_ip.af == AF_INET6) goto cast_ipv6_prefix;
1247
1248 fr_value_box_init(out, FR_TYPE_IPV4_PREFIX, NULL, in->tainted);
1249 out->vb_ip = in->vb_ip;
1250 break;
1251
1253 case FR_TYPE_IPV4_ADDR:
1254 if (unlikely(fr_value_box_copy(NULL, out, in) < 0)) return -1;
1255 break;
1256
1257 case FR_TYPE_IPV6_ADDR:
1259 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_ADDR, NULL, in) < 0) return -1;
1260 break;
1261
1263 cast_ipv6_prefix:
1264 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV4_PREFIX, NULL, in) < 0) return -1;
1265 break;
1266
1267 /*
1268 * All of these get mashed to 32-bits. The cast
1269 * operation will check bounds (both negative and
1270 * positive) on the run-time values.
1271 */
1272 case FR_TYPE_BOOL:
1273
1274 case FR_TYPE_UINT8:
1275 case FR_TYPE_UINT16:
1276 case FR_TYPE_UINT32:
1277 case FR_TYPE_UINT64:
1278
1279 case FR_TYPE_SIZE:
1280
1281 case FR_TYPE_INT8:
1282 case FR_TYPE_INT16:
1283 case FR_TYPE_INT32:
1284 case FR_TYPE_INT64:
1285
1286 case FR_TYPE_FLOAT32:
1287 case FR_TYPE_FLOAT64:
1288 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT32, NULL, in) < 0) return -1;
1289 break;
1290 }
1291
1292 return 0;
1293}
1294
1295static 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)
1296{
1297 fr_value_box_t one, two;
1298 fr_value_box_t *a, *b;
1299
1300 fr_assert((dst->type == FR_TYPE_IPV4_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1301
1302 if (cast_ipv4_addr(&one, in1) < 0) return -1;
1303 a = &one;
1304
1305 if (cast_ipv4_addr(&two, in2) < 0) return -1;
1306 b = &two;
1307
1308 switch (op) {
1309 case T_ADD:
1310 case T_OR:
1311 /*
1312 * For simplicity, make sure that the prefix is first.
1313 */
1314 if (b->type == FR_TYPE_IPV4_PREFIX) swap(a,b);
1315
1316 /*
1317 * We can only add something to a prefix, and
1318 * that something has to be a number. The cast
1319 * operation already ensured that the number is
1320 * uint32, and is at least vaguely within the
1321 * allowed range.
1322 */
1323 if (a->type != FR_TYPE_IPV4_PREFIX) return ERR_INVALID;
1324
1325 if (b->type != FR_TYPE_UINT32) return ERR_INVALID;
1326
1327 /*
1328 * Trying to add a number outside of the given prefix. That's not allowed.
1329 */
1330 if (b->vb_uint32 >= (((uint32_t) 1) << (32 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1331
1332 dst->vb_ip.af = AF_INET;
1333 dst->vb_ipv4addr = htonl(ntohl(a->vb_ipv4addr) | b->vb_uint32);
1334 dst->vb_ip.prefix = 32;
1337 break;
1338
1339 default:
1340 return ERR_INVALID;
1341 }
1342
1343 return 0;
1344}
1345
1346static 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)
1347{
1348 int prefix;
1349 fr_value_box_t one, two, tmp;
1350
1351 fr_assert((dst->type == FR_TYPE_IPV4_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1352
1353 switch (op) {
1354 case T_AND:
1355 if (fr_type_is_integer(a->type)) {
1356 if (fr_value_box_cast(NULL, &one, FR_TYPE_UINT32, NULL, a) < 0) return -1;
1357
1358 a = &one;
1359 swap(a, b);
1360
1361 } else if (fr_type_is_integer(b->type)) {
1362 if (fr_value_box_cast(NULL, &two, FR_TYPE_UINT32, NULL, b) < 0) return -1;
1363 b = &two;
1364
1365 } else {
1366 fr_strerror_const("Invalid input types for ipv4prefix");
1367 return -1;
1368 }
1369
1370 switch (a->type) {
1371 case FR_TYPE_IPV6_ADDR:
1372 if (fr_value_box_cast(NULL, &tmp, FR_TYPE_IPV4_ADDR, NULL, a) < 0) return -1;
1373 a = &tmp;
1374 break;
1375
1376 case FR_TYPE_IPV4_ADDR:
1378 break;
1379
1380 default:
1381 fr_strerror_printf("Invalid input data type '%s' for logical 'and'",
1382 fr_type_to_str(a->type));
1383
1384 return -1;
1385 }
1386
1387 if (b->vb_uint32 == 0) { /* set everything to zero */
1388 dst->vb_ipv4addr = 0;
1389 prefix = 0;
1390
1391 } else if ((~b->vb_uint32) == 0) { /* all 1's */
1392 dst->vb_ipv4addr = a->vb_ipv4addr;
1393 prefix = 32;
1394
1395 } else {
1396 uint32_t mask;
1397
1398 mask = ~b->vb_uint32; /* 0xff00 -> 0x00ff */
1399 mask++; /* 0x00ff -> 0x0100 */
1400 if ((mask & b->vb_uint32) != mask) {
1401 fr_strerror_printf("Invalid network mask '0x%08x'", b->vb_uint32);
1402 return -1;
1403 }
1404
1405 mask = 0xfffffffe;
1406 prefix = 31;
1407
1408 while (prefix > 0) {
1409 if (mask == b->vb_uint32) break;
1410
1411 prefix--;
1412 /* coverity[overflow_const] */
1413 mask <<= 1;
1414 }
1415 fr_assert(prefix > 0);
1416
1417 dst->vb_ipv4addr = htonl(ntohl(a->vb_ipv4addr) & b->vb_uint32);
1418 }
1419
1420 dst->vb_ip.af = AF_INET;
1421 dst->vb_ip.prefix = prefix;
1422 break;
1423
1424 default:
1425 return ERR_INVALID;
1426 }
1427
1428 return 0;
1429}
1430
1432{
1433 switch (in->type) {
1434 default:
1435 fr_strerror_printf("Cannot operate on ipv6addr and %s",
1436 fr_type_to_str(in->type));
1437 return -1;
1438
1440 if (in->vb_ip.af == AF_INET) goto cast_ipv4_addr;
1441
1442 fr_assert(in->vb_ip.af == AF_INET6);
1443 fr_value_box_init(out, FR_TYPE_IPV6_ADDR, NULL, in->tainted);
1444 out->vb_ip = in->vb_ip;
1445 break;
1446
1448 if (in->vb_ip.af == AF_INET) goto cast_ipv4_prefix;
1449
1450 fr_assert(in->vb_ip.af == AF_INET6);
1451 fr_value_box_init(out, FR_TYPE_IPV6_PREFIX, NULL, in->tainted);
1452 out->vb_ip = in->vb_ip;
1453 break;
1454
1455
1457 case FR_TYPE_IPV6_ADDR:
1458 if (unlikely(fr_value_box_copy(NULL, out, in) < 0)) return -1;
1459 break;
1460
1461 case FR_TYPE_IPV4_ADDR:
1463 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_ADDR, NULL, in) < 0) return -1;
1464 break;
1465
1467 cast_ipv4_prefix:
1468 if (fr_value_box_cast(NULL, out, FR_TYPE_IPV6_PREFIX, NULL, in) < 0) return -1;
1469 break;
1470
1471 /*
1472 * All of these get mashed to 64-bits. The cast
1473 * operation will check bounds (both negative and
1474 * positive) on the run-time values.
1475 */
1476 case FR_TYPE_BOOL:
1477
1478 case FR_TYPE_UINT8:
1479 case FR_TYPE_UINT16:
1480 case FR_TYPE_UINT32:
1481 case FR_TYPE_UINT64:
1482
1483 case FR_TYPE_SIZE:
1484
1485 case FR_TYPE_INT8:
1486 case FR_TYPE_INT16:
1487 case FR_TYPE_INT32:
1488 case FR_TYPE_INT64:
1489
1490 case FR_TYPE_FLOAT32:
1491 case FR_TYPE_FLOAT64:
1492 if (fr_value_box_cast(NULL, out, FR_TYPE_UINT64, NULL, in) < 0) return -1;
1493 break;
1494 }
1495
1496 return 0;
1497}
1498
1499static 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)
1500{
1501 fr_value_box_t one, two;
1502 fr_value_box_t *a, *b;
1503 int i;
1504 uint64_t mask;
1505
1506 fr_assert((dst->type == FR_TYPE_IPV6_ADDR) || (dst->type == FR_TYPE_COMBO_IP_ADDR));
1507
1508 if (cast_ipv6_addr(&one, in1) < 0) return -1;
1509 a = &one;
1510
1511 if (cast_ipv6_addr(&two, in2) < 0) return -1;
1512 b = &two;
1513
1514 switch (op) {
1515 case T_ADD:
1516 case T_OR:
1517 /*
1518 * For simplicity, make sure that the prefix is first.
1519 */
1520 if (b->type == FR_TYPE_IPV6_PREFIX) swap(a, b);
1521
1522 /*
1523 * We can only add something to a prefix, and
1524 * that something has to be a number. The cast
1525 * operation already ensured that the number is
1526 * uint64, and is at least vaguely within the
1527 * allowed range.
1528 */
1529 if (a->type != FR_TYPE_IPV6_PREFIX) return ERR_INVALID;
1530
1531 if (b->type != FR_TYPE_UINT64) return ERR_INVALID;
1532
1533 /*
1534 * If we're adding a UINT64, the prefix can't be shorter than 64.
1535 */
1536 if (a->vb_ip.prefix <= 64) return ERR_OVERFLOW;
1537
1538 /*
1539 * Trying to add a number outside of the given prefix. That's not allowed.
1540 */
1541 if (b->vb_uint64 >= (((uint64_t) 1) << (128 - a->vb_ip.prefix))) return ERR_OVERFLOW;
1542
1543 /*
1544 * Add in the relevant low bits.
1545 */
1546 memcpy(&dst->vb_ipv6addr, a->vb_ipv6addr, sizeof(dst->vb_ipv6addr));
1547 mask = b->vb_uint64;
1548 for (i = 15; i >= ((a->vb_ip.prefix + 7) >> 3); i--) {
1549 dst->vb_ipv6addr[i] |= mask & 0xff;
1550 mask >>= 8;
1551 }
1552
1553 dst->vb_ip.af = AF_INET6;
1554 dst->vb_ip.prefix = 128;
1555 dst->vb_ip.scope_id = a->vb_ip.scope_id;
1557 break;
1558
1559 default:
1560 return ERR_INVALID;
1561 }
1562
1563 return 0;
1564}
1565
1566static int get_ipv6_prefix(uint8_t const *in)
1567{
1568 int i, j, prefix;
1569
1570 prefix = 128;
1571 for (i = 15; i >= 0; i--) {
1572 if (!in[i]) {
1573 prefix -= 8;
1574 continue;
1575 }
1576
1577 for (j = 0; j < 8; j++) {
1578 if ((in[i] & (1 << j)) == 0) {
1579 prefix--;
1580 continue;
1581 }
1582 return prefix;
1583 }
1584 }
1585
1586 return prefix;
1587}
1588
1589static 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)
1590{
1591 int i, prefix = 128;
1592 uint8_t const *pa, *pb;
1593 uint8_t *pdst;
1594
1595 fr_assert((dst->type == FR_TYPE_IPV6_PREFIX) || (dst->type == FR_TYPE_COMBO_IP_PREFIX));
1596
1597 if (a->type == FR_TYPE_OCTETS) {
1598 if (a->vb_length != (128 / 8)) {
1599 fr_strerror_printf("Invalid length %zu for octets network mask", a->vb_length);
1600 return -1;
1601 }
1602 pa = a->vb_octets;
1603 prefix = get_ipv6_prefix(pa);
1604
1605 } else if (a->type == FR_TYPE_IPV6_ADDR) {
1606 pa = (const uint8_t *) &a->vb_ipv6addr;
1607
1608 } else {
1609 return ERR_INVALID;
1610 }
1611
1612 if (b->type == FR_TYPE_OCTETS) {
1613 if (b->vb_length != (128 / 8)) {
1614 fr_strerror_printf("Invalid length %zu for octets network mask", b->vb_length);
1615 return -1;
1616 }
1617 pb = b->vb_octets;
1618 prefix = get_ipv6_prefix(pb);
1619
1620 } else if (b->type == FR_TYPE_IPV6_ADDR) {
1621 pb = (const uint8_t *) &b->vb_ip.addr.v6;
1622
1623 } else {
1624 return ERR_INVALID;
1625 }
1626
1627 switch (op) {
1628 case T_AND:
1629 fr_value_box_init(dst, FR_TYPE_IPV6_PREFIX, NULL, false);
1630 pdst = (uint8_t *) &dst->vb_ip.addr.v6;
1631
1632 for (i = 0; i < 16; i++) {
1633 pdst[i] = pa[i] & pb[i];
1634 }
1635
1636 dst->vb_ip.af = AF_INET6;
1637 dst->vb_ip.prefix = prefix;
1640 break;
1641
1642 default:
1643 return ERR_INVALID;
1644 }
1645
1646 return 0;
1647}
1648
1649#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)))
1650
1651static 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)
1652{
1653 /*
1654 * IPv6 is better than IPv4!
1655 */
1656 if (is_ipv6(in1) || is_ipv6(in2)) {
1657 return calc_ipv6_addr(ctx, dst, in1, op, in2);
1658 }
1659
1660 return calc_ipv4_addr(ctx, dst, in1, op, in2);
1661}
1662
1663static 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)
1664{
1665 if (is_ipv6(in1) || is_ipv6(in2)) {
1666 return calc_ipv6_prefix(ctx, dst, in1, op, in2);
1667 }
1668
1669 return calc_ipv4_prefix(ctx, dst, in1, op, in2);
1670}
1671
1672
1673static 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)
1674{
1675 fr_value_box_t one, two;
1676 fr_value_box_t const *a = in1;
1677 fr_value_box_t const *b = in2;
1678
1679 fr_assert(dst->type == FR_TYPE_FLOAT32);
1680
1681 /*
1682 * Intermediate calculations are done using increased precision.
1683 */
1686
1687 switch (op) {
1688 case T_ADD:
1689 dst->vb_float32 = a->vb_float64 + b->vb_float64;
1690 break;
1691
1692 case T_SUB:
1693 dst->vb_float32 = a->vb_float64 - b->vb_float64;
1694 break;
1695
1696 case T_MUL:
1697 dst->vb_float32 = a->vb_float64 * b->vb_float64;
1698 break;
1699
1700 case T_DIV:
1701 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1702
1703 dst->vb_float32 = a->vb_float64 / b->vb_float64;
1704 break;
1705
1706 case T_MOD:
1707 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1708
1709 dst->vb_float32 = fmod(a->vb_float64, b->vb_float64);
1710 break;
1711
1712 default:
1713 return ERR_INVALID;
1714 }
1715
1718
1719 return 0;
1720
1721}
1722
1723static 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)
1724{
1725 fr_value_box_t one, two;
1726 fr_value_box_t const *a = in1;
1727 fr_value_box_t const *b = in2;
1728
1729 fr_assert(dst->type == FR_TYPE_FLOAT64);
1730
1733
1734 switch (op) {
1735 case T_ADD:
1736 dst->vb_float64 = a->vb_float64 + b->vb_float64;
1737 break;
1738
1739 case T_SUB:
1740 dst->vb_float64 = a->vb_float64 - b->vb_float64;
1741 break;
1742
1743 case T_MUL:
1744 dst->vb_float64 = a->vb_float64 * b->vb_float64;
1745 break;
1746
1747 case T_DIV:
1748 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1749
1750 dst->vb_float64 = a->vb_float64 / b->vb_float64;
1751 break;
1752
1753 case T_MOD:
1754 if (fpclassify(b->vb_float64) == FP_ZERO) return ERR_ZERO;
1755
1756 dst->vb_float64 = fmod(a->vb_float64, b->vb_float64);
1757 break;
1758
1759 default:
1760 return ERR_INVALID;
1761 }
1762
1765
1766 return 0;
1767}
1768
1769/*
1770 * Do all intermediate operations on 64-bit numbers.
1771 */
1772static 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)
1773{
1774 fr_value_box_t one, two, result;
1775 fr_value_box_t const *a = in1;
1776 fr_value_box_t const *b = in2;
1777
1778 fr_value_box_init(&result, FR_TYPE_UINT64, NULL, a->tainted | b->tainted);
1779
1780 COERCE_A(FR_TYPE_UINT64, NULL);
1781
1782 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1783 /*
1784 * Don't touch the RHS.
1785 */
1786 fr_assert(b->type == FR_TYPE_UINT32);
1787
1788 } else {
1789 COERCE_B(FR_TYPE_UINT64, dst->enumv);
1790 }
1791
1792 switch (op) {
1793 case T_ADD:
1794 if (!fr_add(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1795 break;
1796
1797 case T_SUB:
1798 if (!fr_sub(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_UNDERFLOW;
1799 break;
1800
1801 case T_MUL:
1802 if (!fr_multiply(&result.vb_uint64, a->vb_uint64, b->vb_uint64)) return ERR_OVERFLOW;
1803 break;
1804
1805 case T_DIV:
1806 if (b->vb_uint64 == 0) return ERR_ZERO;
1807
1808 result.vb_uint64 = a->vb_uint64 / b->vb_uint64;
1809 break;
1810
1811 case T_MOD:
1812 if (b->vb_uint64 == 0) return ERR_ZERO;
1813
1814 result.vb_uint64 = a->vb_uint64 % b->vb_uint64;
1815 break;
1816
1817 case T_AND:
1818 result.vb_uint64 = a->vb_uint64 & b->vb_uint64;
1819 break;
1820
1821 case T_OR:
1822 result.vb_uint64 = a->vb_uint64 | b->vb_uint64;
1823 break;
1824
1825 case T_XOR:
1826 result.vb_uint64 = a->vb_uint64 ^ b->vb_uint64;
1827 break;
1828
1829 case T_RSHIFT:
1830 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_UNDERFLOW;
1831
1832 result.vb_uint64 = a->vb_uint64 >> b->vb_uint32;
1833 break;
1834
1835 case T_LSHIFT:
1836 if (b->vb_uint32 >= (8 * sizeof(a->vb_uint64))) return ERR_OVERFLOW;
1837
1838 result.vb_uint64 = a->vb_uint64 << b->vb_uint32;
1839 break;
1840
1841 default:
1842 return ERR_INVALID;
1843 }
1844
1845 /*
1846 * Once we're done, cast the result to the final data type.
1847 */
1848 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1849
1852
1853 return 0;
1854}
1855
1856/*
1857 * Same as above, except uint64 -> int64. These functions should be kept in sync!
1858 */
1859static 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)
1860{
1861 fr_value_box_t one, two, result;
1862 fr_value_box_t const *a = in1;
1863 fr_value_box_t const *b = in2;
1864
1865 fr_value_box_init(&result, FR_TYPE_INT64, NULL, a->tainted | b->tainted);
1866
1867 COERCE_A(FR_TYPE_INT64, NULL);
1868
1869 if ((op == T_RSHIFT) || (op == T_LSHIFT)) {
1870 /*
1871 * Don't touch the RHS.
1872 */
1873 fr_assert(b->type == FR_TYPE_UINT32);
1874
1875 } else {
1876 COERCE_B(FR_TYPE_INT64, dst->enumv);
1877 }
1878
1879 switch (op) {
1880 case T_ADD:
1881 if (!fr_add(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1882 break;
1883
1884 case T_SUB:
1885 if (!fr_sub(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_UNDERFLOW;
1886 break;
1887
1888 case T_MUL:
1889 if (!fr_multiply(&result.vb_int64, a->vb_int64, b->vb_int64)) return ERR_OVERFLOW;
1890 break;
1891
1892 case T_DIV:
1893 if (b->vb_int64 == 0) return ERR_ZERO;
1894
1895 result.vb_int64 = a->vb_int64 / b->vb_int64;
1896 break;
1897
1898 case T_MOD:
1899 if (b->vb_int64 == 0) return ERR_ZERO;
1900
1901 result.vb_int64 = a->vb_int64 % b->vb_int64;
1902 break;
1903
1904 case T_AND:
1905 result.vb_int64 = a->vb_int64 & b->vb_int64;
1906 break;
1907
1908 case T_OR:
1909 result.vb_int64 = a->vb_int64 | b->vb_int64;
1910 break;
1911
1912 case T_XOR:
1913 result.vb_int64 = a->vb_int64 ^ b->vb_int64;
1914 break;
1915
1916 case T_RSHIFT:
1917 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_UNDERFLOW;
1918
1919 result.vb_int64 = a->vb_int64 >> b->vb_uint32;
1920 break;
1921
1922 case T_LSHIFT:
1923 if (b->vb_uint32 >= (8 * sizeof(a->vb_int64))) return ERR_OVERFLOW;
1924
1925 result.vb_int64 = a->vb_int64 << b->vb_uint32;
1926 break;
1927
1928 default:
1929 return ERR_INVALID;
1930 }
1931
1932 /*
1933 * Once we're done, cast the result to the final data type.
1934 */
1935 if (fr_value_box_cast(ctx, dst, dst->type, dst->enumv, &result) < 0) return -1;
1936
1939
1940 return 0;
1941}
1942
1943typedef 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);
1944
1945/** Map output type to its associated function
1946 *
1947 */
1981
1982/** Calculate DST = A OP B
1983 *
1984 * The result is written to DST only *after* it has been calculated.
1985 * So it's safe to pass DST as either A or B. DST should already exist.
1986 *
1987 * This function should arguably not take comparison operators, but
1988 * whatever. The "promote types" code is the same for all of the
1989 * binary operations, so we might as well just have one function.
1990 */
1991int 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)
1992{
1993 int rcode = -1;
1994 fr_value_box_t one, two;
1996 fr_binary_op_t func;
1997
1998 if ((hint != FR_TYPE_NULL) && !fr_type_is_leaf(hint)) return invalid_type(hint);
1999
2000 /*
2001 * Casting to structural types should be a parse error,
2002 * and not a run-time calculation error.
2003 */
2004 if (!fr_type_is_leaf(a->type)) return invalid_type(a->type);
2005 if (!fr_type_is_leaf(b->type)) return invalid_type(b->type);
2006
2009
2010 /*
2011 * === and !== also check types. If the types are
2012 * different, it's a failure. Otherwise they revert to == and !=.
2013 */
2014 switch (op) {
2015 case T_OP_CMP_EQ_TYPE:
2016 if (a->type != b->type) {
2017 mismatch_type:
2018 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
2019 dst->vb_bool = false;
2020 return 0;
2021 }
2022 op = T_OP_CMP_EQ;
2023 break;
2024
2025 case T_OP_CMP_NE_TYPE:
2026 if (a->type != b->type) goto mismatch_type;
2027
2028 op = T_OP_NE;
2029 break;
2030
2031 case T_OP_REG_EQ:
2032 case T_OP_REG_NE:
2033 if (b->type != FR_TYPE_STRING) {
2034 fr_strerror_const("Invalid type for regular expression");
2035 return -1;
2036 }
2037
2038 rcode = fr_regex_cmp_op(op, a, b);
2039 if (rcode < 0) return rcode;
2040
2041 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); /* @todo - enum */
2042 dst->vb_bool = (rcode != 0);
2043 return 0;
2044
2045 default:
2046 break;
2047 }
2048
2051
2052 /*
2053 * We don't know what the output type should be. Try to
2054 * guess based on a variety of factors.
2055 */
2056 if (hint == FR_TYPE_NULL) do {
2057 /*
2058 * All kinds of special cases :(
2059 *
2060 * date1 - date2 --> time_delta
2061 *
2062 * time_delta * FOO --> float64, because time_delta is _printed_ as a floating point
2063 * number. And this is the least surprising thing to do.
2064 */
2065 if ((op == T_SUB) && (a->type == b->type) && (a->type == FR_TYPE_DATE)) {
2066 hint = FR_TYPE_TIME_DELTA;
2067 break;
2068 }
2069
2070 if (op == T_MUL) {
2071 if (a->type == FR_TYPE_TIME_DELTA) {
2072 hint = upcast_op[FR_TYPE_FLOAT64][b->type];
2073 if (hint == FR_TYPE_NULL) hint = upcast_op[b->type][FR_TYPE_FLOAT64];
2074
2075 } else if (b->type == FR_TYPE_TIME_DELTA) {
2076 hint = upcast_op[a->type][FR_TYPE_FLOAT64];
2077 if (hint == FR_TYPE_NULL) hint = upcast_op[FR_TYPE_FLOAT64][a->type];
2078 }
2079
2080 if ((a->type == FR_TYPE_STRING) &&
2081 (fr_type_is_integer_except_bool(b->type))) {
2082 hint = FR_TYPE_STRING;
2083 }
2084
2085 if ((a->type == FR_TYPE_OCTETS) &&
2086 (fr_type_is_integer_except_bool(b->type))) {
2087 hint = FR_TYPE_OCTETS;
2088 }
2089
2090 if (hint != FR_TYPE_NULL) break;
2091 }
2092
2093 /*
2094 * date % time_delta --> time_delta
2095 */
2096 if ((op == T_MOD) && (a->type == FR_TYPE_DATE)) {
2097 hint = FR_TYPE_TIME_DELTA;
2098 break;
2099 }
2100
2101 switch (op) {
2102 case T_OP_CMP_EQ:
2103 case T_OP_NE:
2104 case T_OP_GE:
2105 case T_OP_GT:
2106 case T_OP_LE:
2107 case T_OP_LT:
2108 /*
2109 * Comparison operators always return
2110 * "bool".
2111 */
2112 hint = FR_TYPE_BOOL;
2113 break;
2114
2115 case T_AND:
2116 /*
2117 * Get mask from IP + number
2118 */
2119 if ((a->type == FR_TYPE_IPV4_ADDR) || (b->type == FR_TYPE_IPV4_ADDR)) {
2120 hint = FR_TYPE_IPV4_PREFIX;
2121 break;
2122 }
2123
2124 if ((a->type == FR_TYPE_IPV6_ADDR) || (b->type == FR_TYPE_IPV6_ADDR)) {
2125 hint = FR_TYPE_IPV6_PREFIX;
2126 break;
2127 }
2129
2130 case T_OR:
2131 case T_ADD:
2132 case T_SUB:
2133 case T_MUL:
2134 case T_DIV:
2135 case T_MOD:
2136 case T_XOR:
2137 /*
2138 * Try to "up-cast" the types. This is
2139 * so that we can take (for example)
2140 * uint8 + uint16, and have the output as
2141 * uint16.
2142 *
2143 * There must be only one entry per [a,b]
2144 * pairing. That way we're sure that [a,b]==[b,a]
2145 */
2146 hint = upcast_op[a->type][b->type];
2147 if (hint == FR_TYPE_NULL) {
2148 hint = upcast_op[b->type][a->type];
2149 } else if (a->type != b->type) {
2150 fr_assert(upcast_op[b->type][a->type] == FR_TYPE_NULL);
2151 }
2152
2153 /*
2154 * No idea what to do. :(
2155 */
2156 if (hint == FR_TYPE_NULL) {
2157 fr_strerror_printf("Invalid operation on data types - '%s' %s '%s'",
2158 fr_type_to_str(a->type), fr_tokens[op], fr_type_to_str(b->type));
2159 goto done;
2160 }
2161
2162 break;
2163
2164 /*
2165 * The RHS MUST be a numerical type. We don't need to do any upcasting here.
2166 *
2167 * @todo - the output type could be larger than the input type, if the shift is
2168 * more than the input type can handle. e.g. uint8 << 4 could result in uint16
2169 */
2170 case T_LSHIFT:
2171 if (!fr_type_is_integer(a->type)) {
2172 return handle_result(a->type, T_LSHIFT, ERR_INVALID);
2173 }
2174
2175 if (fr_type_is_signed(a->type)) {
2176 hint = FR_TYPE_INT64;
2177 break;
2178 }
2179 hint = FR_TYPE_UINT64;
2180 break;
2181
2182 case T_RSHIFT:
2183 hint = a->type;
2184 break;
2185
2186 default:
2187 return handle_result(a->type, op, ERR_INVALID);
2188 }
2189 } while (0);
2190
2191 /*
2192 * Now that we've figured out the correct types, perform the operation.
2193 */
2194 switch (op) {
2195 case T_OP_CMP_EQ:
2196 case T_OP_NE:
2197 case T_OP_GE:
2198 case T_OP_GT:
2199 case T_OP_LE:
2200 case T_OP_LT:
2201 if (hint != FR_TYPE_BOOL) {
2202 fr_strerror_printf("Invalid destination type '%s' for comparison operator",
2203 fr_type_to_str(hint));
2204 goto done;
2205 }
2206
2207 /*
2208 * Convert the types to ones which are comparable.
2209 */
2210 if (a->type != b->type) {
2211 fr_dict_attr_t const *enumv = NULL;
2212
2213 /*
2214 * If we're doing comparisons and one of them has an enum, and the other is an
2215 * enum name, then use the enum name to convert the string to the other type.
2216 *
2217 * We can then do type-specific comparisons.
2218 */
2219 if ((a->type == FR_TYPE_STRING) && b->enumv) {
2220 enumv = b->enumv;
2221 hint = b->type;
2222
2223 } else if ((b->type == FR_TYPE_STRING) && a->enumv) {
2224 enumv = a->enumv;
2225 hint = a->type;
2226
2227 } else {
2228 /*
2229 * Try to "up-cast" the types. This is so that we can take (for example)
2230 * uint8 < uint16, and have it make sense.
2231 *
2232 * There must be only one entry per [a,b] pairing. That way we're sure
2233 * that [a,b]==[b,a]
2234 */
2235 hint = upcast_cmp[a->type][b->type];
2236 if (hint == FR_TYPE_NULL) {
2237 hint = upcast_cmp[b->type][a->type];
2238 } else {
2239 fr_assert(upcast_cmp[b->type][a->type] == FR_TYPE_NULL);
2240 }
2241
2242 /*
2243 * time_deltas have a scale in the enumv, but default to "seconds" if
2244 * there's no scale. As a result, if we compare time_delta(ms) to integer,
2245 * then the integer is interpreted as seconds, and the scale is wrong.
2246 *
2247 * The solution is to use the appropriate scale.
2248 */
2249 if (hint == a->type) enumv = a->enumv;
2250 if (hint == b->type) enumv = b->enumv;
2251
2252 if (hint == FR_TYPE_NULL) {
2253 fr_strerror_printf("Cannot compare incompatible types (%s)... %s (%s)...",
2254 fr_type_to_str(a->type),
2255 fr_tokens[op],
2256 fr_type_to_str(b->type));
2257 goto done;
2258 }
2259 }
2260
2261 /*
2262 * Cast them to the appropriate type, which may be different from either of the
2263 * inputs.
2264 */
2265 if (a->type != hint) {
2266 if (fr_value_box_cast(NULL, &one, hint, enumv, a) < 0) goto done;
2267 a = &one;
2269 }
2270
2271 if (b->type != hint) {
2272 if (fr_value_box_cast(NULL, &two, hint, enumv, b) < 0) goto done;
2273 b = &two;
2275 }
2276 }
2277
2278 rcode = fr_value_box_cmp_op(op, a, b);
2279 if (rcode < 0) goto done;
2280
2281 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false);
2282 dst->vb_bool = (rcode > 0);
2283 break;
2284
2285 /*
2286 * For shifts, the RHS value MUST be an integer. There's no reason to have it as
2287 * anything other than an 8-bit field.
2288 */
2289 case T_LSHIFT:
2290 case T_RSHIFT:
2291 if (b->type != FR_TYPE_UINT32) {
2292 if (fr_value_box_cast(ctx, &two, FR_TYPE_UINT32, NULL, b) < 0) {
2293 fr_strerror_printf("Cannot parse shift value as integer - %s",
2294 fr_strerror());
2295 goto done;
2296 }
2297 b = &two;
2298 }
2300
2301 case T_ADD:
2302 case T_SUB:
2303 case T_MUL:
2304 case T_DIV:
2305 case T_MOD:
2306 case T_AND:
2307 case T_OR:
2308 case T_XOR:
2309 fr_assert(hint != FR_TYPE_NULL);
2310
2311 func = calc_type[hint];
2312 if (!func) {
2313 fr_strerror_printf("Cannot perform any operations for destination type %s",
2314 fr_type_to_str(hint));
2315 rcode = -1;
2316 break;
2317 }
2318
2319 /*
2320 * It's OK to use one of the inputs as the
2321 * output. In order to ensure that nothing bad
2322 * happens, we use an intermediate value-box.
2323 */
2324 fr_value_box_init(&out, hint, NULL, false);
2325
2326 rcode = func(ctx, &out, a, op, b); /* not calc_type[hint], to shut up clang */
2327 if (rcode < 0) goto done;
2328
2329 fr_value_box_copy_shallow(NULL, dst, &out);
2330 dst->tainted = a->tainted | b->tainted;
2331 break;
2332
2333 default:
2334 rcode = ERR_INVALID;
2335 break;
2336 }
2337
2338done:
2341
2342 return handle_result(hint, op, rcode);
2343}
2344
2345/** Calculate DST = OP { A, B, C, ... }
2346 *
2347 * The result is written to DST only *after* it has been calculated.
2348 * So it's safe to pass DST as one of the inputs. DST should already
2349 * exist.
2350 */
2352{
2353 fr_value_box_t out, *vb;
2354 fr_binary_op_t calc;
2355
2356 if (group->type != FR_TYPE_GROUP) {
2357 fr_strerror_const("Invalid type passed to multivalue calculation");
2358 return -1;
2359 }
2360
2363 fr_strerror_printf("Invalid operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2364 return -1;
2365 }
2366
2367 if (type == FR_TYPE_STRING) {
2368 fr_sbuff_t *sbuff;
2369
2370 if (op != T_ADD) goto invalid_type;
2371
2372 FR_SBUFF_TALLOC_THREAD_LOCAL(&sbuff, 1024, (1 << 16));
2373
2374 if (fr_value_box_list_concat_as_string(dst, sbuff, UNCONST(fr_value_box_list_t *, &group->vb_group),
2375 NULL, 0, NULL, FR_VALUE_BOX_LIST_NONE, FR_VALUE_BOX_SAFE_FOR_ANY, false) < 0) return -1;
2376
2377 if (fr_value_box_bstrndup(ctx, dst, NULL, fr_sbuff_start(sbuff), fr_sbuff_used(sbuff), false) < 0) return -1;
2378 return 0;
2379 }
2380
2381 if (type == FR_TYPE_OCTETS) {
2382 fr_dbuff_t *dbuff;
2383
2384 if (op != T_ADD) goto invalid_type;
2385
2386 FR_DBUFF_TALLOC_THREAD_LOCAL(&dbuff, 1024, (1 << 16));
2387
2388 if (fr_value_box_list_concat_as_octets(dst, dbuff, UNCONST(fr_value_box_list_t *, &group->vb_group), NULL, 0, FR_VALUE_BOX_LIST_NONE, false) < 0) return -1;
2389
2390 if (fr_value_box_memdup(ctx, dst, NULL, fr_dbuff_start(dbuff), fr_dbuff_used(dbuff), false) < 0) return -1;
2391
2392 return 0;
2393 }
2394
2395 /*
2396 * Can't add or multiply booleans.
2397 */
2398 if ((type == FR_TYPE_BOOL) && !((op == T_AND) || (op == T_OR) || (op == T_XOR))) goto unsupported;
2399
2400 switch (op) {
2401 case T_ADD:
2402 case T_MUL:
2403 case T_AND:
2404 case T_OR:
2405 case T_XOR:
2406 break;
2407
2408 default:
2409 goto invalid_type;
2410 }
2411
2412 /*
2413 * Strings and octets are different.
2414 */
2415 if (!fr_type_is_numeric(type)) {
2416 unsupported:
2417 fr_strerror_printf("Not yet supported operation %s for data type %s", fr_tokens[op], fr_type_to_str(type));
2418 return -1;
2419 }
2420
2421 switch (type) {
2422 case FR_TYPE_UINT8:
2423 case FR_TYPE_UINT16:
2424 case FR_TYPE_UINT32:
2425 case FR_TYPE_UINT64:
2426 calc = calc_uint64;
2427 break;
2428
2429 case FR_TYPE_INT8:
2430 case FR_TYPE_INT16:
2431 case FR_TYPE_INT32:
2432 case FR_TYPE_INT64:
2433 calc = calc_int64;
2434 break;
2435
2436 case FR_TYPE_TIME_DELTA:
2437 if ((op != T_ADD) && (op != T_SUB)) goto invalid_type;
2438 calc = calc_time_delta;
2439 break;
2440
2441 case FR_TYPE_FLOAT32:
2442 calc = calc_float32;
2443 break;
2444
2445 case FR_TYPE_FLOAT64:
2446 calc = calc_float64;
2447 break;
2448
2449 default:
2450 goto unsupported;
2451 }
2452
2453 vb = fr_value_box_list_head(&group->vb_group);
2454 if (!vb) {
2455 fr_strerror_printf("Empty input is invalid");
2456 return -1;
2457 }
2458
2459 if (fr_value_box_cast(ctx, &out, type, NULL, vb) < 0) return -1;
2460
2461 while ((vb = fr_value_box_list_next(&group->vb_group, vb)) != NULL) {
2462 int rcode;
2463 fr_value_box_t box;
2464
2465 if (vb->type == type) {
2466 rcode = calc(ctx, &out, &out, op, vb);
2467 if (rcode < 0) return rcode;
2468
2469 } else {
2470 if (fr_value_box_cast(ctx, &box, type, NULL, vb) < 0) return -1;
2471
2472 rcode = calc(ctx, &out, &out, op, &box);
2473 if (rcode < 0) return rcode;
2474 }
2475 }
2476
2477 return fr_value_box_copy(ctx, dst, &out);
2478}
2479
2480
2481#define T(_x) [T_OP_ ## _x ## _EQ] = T_ ## _x
2482
2484 T(ADD),
2485 T(SUB),
2486 T(MUL),
2487 T(DIV),
2488 T(AND),
2489 T(OR),
2490 T(XOR),
2491 T(RSHIFT),
2492 T(LSHIFT),
2493};
2494
2495/** Calculate DST OP SRC
2496 *
2497 * e.g. "foo += bar".
2498 *
2499 * This is done by doing some sanity checks, and then just calling
2500 * the "binary operation" function.
2501 */
2503{
2504 int rcode;
2505
2506 if (!fr_type_is_leaf(dst->type)) return invalid_type(dst->type);
2507 if (!fr_type_is_leaf(src->type)) return invalid_type(src->type);
2508
2509 if (dst->immutable) {
2510 fr_strerror_printf("Cannot modify immutable value");
2511 return -1;
2512 }
2513
2514 /*
2515 * These operators are included here for testing and completeness. But see comments in
2516 * fr_edit_list_apply_pair_assignment() for what the caller should be doing.
2517 */
2518 if ((op == T_OP_EQ) || (op == T_OP_SET)) {
2519 /*
2520 * Allow for unintentional mistakes.
2521 */
2522 if (src == dst) return 0;
2523
2525 return fr_value_box_cast(ctx, dst, dst->type, dst->enumv, src); /* cast, as the RHS might not (yet) be the same! */
2526 }
2527
2528 if (assignment2op[op] == T_INVALID) {
2529 return handle_result(dst->type, op, ERR_INVALID);
2530 }
2531 op = assignment2op[op];
2532
2533 /*
2534 * Just call the binary op function. It already ensures that (a) the inputs are "const", and (b)
2535 * the output is over-written only at the final step.
2536 */
2537 if (src->type != FR_TYPE_GROUP) {
2538 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, src);
2539
2540 } else {
2541 fr_value_box_t *vb = NULL;
2542
2543 /*
2544 * If the RHS is a group, then we loop over the group recursively, doing the operation.
2545 */
2546 rcode = 0; /* in case group is empty */
2547
2548 while ((vb = fr_value_box_list_next(&src->vb_group, vb)) != NULL) {
2549 rcode = fr_value_calc_binary_op(ctx, dst, dst->type, dst, op, vb);
2550 if (rcode < 0) break;
2551 }
2552 }
2553
2554 if (rcode < 0) return handle_result(dst->type, op, rcode);
2555
2556 return 0;
2557}
2558
2559/** Calculate unary operations
2560 *
2561 * e.g. "foo++", or "-foo".
2562 */
2563int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
2564{
2565 int rcode = -1;
2566 fr_value_box_t one;
2567
2568 if (!fr_type_is_numeric(src->type)) return invalid_type(src->type);
2569
2570 if (dst->immutable) {
2571 fr_strerror_printf("Cannot modify immutable value");
2572 return -1;
2573 }
2574
2575 if (op == T_OP_INCRM) {
2576 /*
2577 * Add 1 or subtract 1 means RHS is always 1.
2578 */
2579 fr_value_box_init(&one, src->type, NULL, false);
2580 switch (src->type) {
2581 case FR_TYPE_UINT8:
2582 one.vb_uint8 = 1;
2583 break;
2584
2585 case FR_TYPE_UINT16:
2586 one.vb_uint16 = 1;
2587 break;
2588
2589 case FR_TYPE_UINT32:
2590 one.vb_uint32 = 1;
2591 break;
2592
2593 case FR_TYPE_UINT64:
2594 one.vb_uint64 = 1;
2595 break;
2596
2597 case FR_TYPE_SIZE:
2598 one.vb_size = 1;
2599 break;
2600
2601 case FR_TYPE_INT8:
2602 one.vb_int8 = 1;
2603 break;
2604
2605 case FR_TYPE_INT16:
2606 one.vb_int16 = 1;
2607 break;
2608
2609 case FR_TYPE_INT32:
2610 one.vb_int32 = 1;
2611 break;
2612
2613 case FR_TYPE_INT64:
2614 one.vb_int64 = 1;
2615 break;
2616
2617 case FR_TYPE_FLOAT32:
2618 one.vb_float32 = 1;
2619 break;
2620
2621 case FR_TYPE_FLOAT64:
2622 one.vb_float64 = 1;
2623 break;
2624
2625 default:
2626 fr_assert(0);
2627 return -1;
2628 }
2629
2630 rcode = fr_value_calc_binary_op(ctx, dst, src->type, src, T_ADD, &one);
2631 return handle_result(dst->type, op, rcode);
2632
2633 } else if (op == T_COMPLEMENT) {
2634 if (dst != src) {
2635 fr_value_box_init(dst, src->type, src->enumv, false);
2636 fr_value_box_safety_copy(dst, src);
2637 }
2638
2639#undef COMP
2640#define COMP(_type, _field) case FR_TYPE_ ## _type: dst->vb_ ##_field = (_field ## _t) ~src->vb_ ##_field; break
2641 switch (src->type) {
2642 COMP(UINT8, uint8);
2643 COMP(UINT16, uint16);
2644 COMP(UINT32, uint32);
2645 COMP(UINT64, uint64);
2646 COMP(SIZE, size);
2647
2648 COMP(INT8, int8);
2649 COMP(INT16, int16);
2650 COMP(INT32, int32);
2651 COMP(INT64, int64);
2652
2653 default:
2654 goto invalid;
2655 }
2656
2657 return 0;
2658
2659 } else if (op == T_SUB) {
2660 fr_type_t type = src->type;
2661
2662 if ((dst != src) && !fr_type_is_signed(src->type)) {
2663 type = upcast_unsigned[src->type];
2664
2665 if (type == FR_TYPE_NULL) {
2666 type = src->type; /* hope for the best */
2667 }
2668 }
2669
2670 fr_value_box_init(&one, type, NULL, src->tainted); /* init to zero */
2671 rcode = fr_value_calc_binary_op(ctx, dst, type, &one, T_SUB, src);
2672
2673 return handle_result(dst->type, op, rcode);
2674
2675 } else if (op == T_NOT) {
2676 bool value = fr_value_box_is_truthy(src);
2677
2678 fr_value_box_clear(dst);
2679 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2680 dst->vb_bool = !value;
2681
2682 return 0;
2683
2684 } else {
2685 invalid:
2686 return handle_result(src->type, op, ERR_INVALID);
2687 }
2688
2689}
2690
2691/*
2692 * Empty lists are empty:
2693 *
2694 * {}
2695 * {{}}
2696 * {''}
2697 * {{},''}
2698 *
2699 * etc.
2700 */
2701static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
2702{
2704 switch (item->type) {
2705 default:
2706 return false;
2707
2708 case FR_TYPE_GROUP:
2709 if (!fr_value_calc_list_empty(&item->vb_group)) return false;
2710 break;
2711
2712 case FR_TYPE_STRING:
2713 case FR_TYPE_OCTETS:
2714 if (item->vb_length != 0) return false;
2715 break;
2716 }
2717 }
2718
2719 return true;
2720}
2721
2722
2723/*
2724 * Loop over input lists, calling fr_value_calc_binary_op()
2725 *
2726 * This implementation is arguably wrong... it should be checking individual entries in list1 against individual entries in list2.
2727 * Instead, it checks if ANY entry in list1 matches ANY entry in list2.
2728 */
2729int 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)
2730{
2731 int rcode;
2732 bool invert = false;
2733 bool a_empty, b_empty;
2734
2735 if (!fr_comparison_op[op]) {
2736 fr_strerror_printf("Invalid operator '%s' passed to list comparison", fr_tokens[op]);
2737 return -1;
2738 }
2739
2740 /*
2741 * v3 hack. != really means !( ... == ... )
2742 */
2743 if (op == T_OP_NE) {
2744 invert = true;
2745 op = T_OP_CMP_EQ;
2746 }
2747
2748 /*
2749 * It's annoying when the debug prints out cmp({},{}) and says "not equal".
2750 *
2751 * What's happening behind the scenes is that one side is an empty value-box group, such as when
2752 * an xlat expansion fails. And the other side is an empty string. If we believe that strings
2753 * are actually sets of characters, then {}=='', and we're all OK
2754 */
2755 a_empty = fr_value_box_list_empty(list1) || fr_value_calc_list_empty(list1);
2756 b_empty = fr_value_box_list_empty(list2) || fr_value_calc_list_empty(list2);
2757
2758 /*
2759 * Both lists are empty, they should be equal when checked for equality.
2760 */
2761 if (a_empty && b_empty) {
2762 switch (op) {
2763 case T_OP_CMP_EQ:
2764 case T_OP_LE:
2765 case T_OP_GE:
2766 invert = !invert;
2767 break;
2768
2769 default:
2770 break;
2771 }
2772
2773 goto done;
2774 }
2775
2776 /*
2777 * Emulate v3. :(
2778 */
2779 fr_value_box_list_foreach(list1, a) {
2780 fr_value_box_list_foreach(list2, b) {
2781 rcode = fr_value_calc_binary_op(ctx, dst, FR_TYPE_BOOL, a, op, b);
2782 if (rcode < 0) return rcode;
2783
2784 /*
2785 * No match: keep looking for a match.
2786 */
2787 fr_assert(dst->type == FR_TYPE_BOOL);
2788 if (!dst->vb_bool) continue;
2789
2790 /*
2791 * Found a match, we're done.
2792 */
2793 dst->vb_bool = !invert;
2794 return 0;
2795 }
2796 }
2797
2798 /*
2799 * No match,
2800 */
2801done:
2802 fr_value_box_clear(dst);
2803 fr_value_box_init(dst, FR_TYPE_BOOL, NULL, false); // @todo - add enum!
2804 dst->vb_bool = invert;
2805 return 0;
2806}
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:186
#define RCSID(id)
Definition build.h:560
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define unlikely(_x)
Definition build.h:455
#define UNUSED
Definition build.h:384
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:1295
static int get_ipv6_prefix(uint8_t const *in)
Definition calc.c:1566
static const fr_binary_op_t calc_type[FR_TYPE_MAX+1]
Map output type to its associated function.
Definition calc.c:1948
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:1499
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:1673
#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:1346
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:1772
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:1651
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:1589
static int cast_ipv6_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1431
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:1859
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:1078
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:2729
#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:1663
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:1943
static int cast_ipv4_addr(fr_value_box_t *out, fr_value_box_t const *in)
Definition calc.c:1230
static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
Definition calc.c:2701
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:1723
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:2351
#define is_ipv6(_x)
Definition calc.c:1649
#define COERCE_B(_type, _enumv)
Definition calc.c:48
static const fr_token_t assignment2op[T_TOKEN_LAST]
Definition calc.c:2483
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:2502
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:1991
#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:2563
#define T(_x)
Definition calc.c:2481
#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:775
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
Definition dbuff.h:906
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
Definition dbuff.h:564
static fr_slen_t in
Definition dict.h:882
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:198
#define fr_add(_out, _a, _b)
Adds two integers.
Definition math.h:187
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
Definition math.h:176
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:266
enum fr_token fr_token_t
@ 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
#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:1028
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:558
#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_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
ssize_t fr_value_box_list_concat_as_string(fr_value_box_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:6414
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:3968
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:4416
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:1006
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:7421
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:5187
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:4540
ssize_t fr_value_box_list_concat_as_octets(fr_value_box_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:6530
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:4353
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:4643
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
Definition value.c:7383
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:7361
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
Definition value.c:4399
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:4862
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:4949
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:5103
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
Definition value.h:233
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
Definition value.h:616
#define VALUE_BOX_VERIFY(_x)
Definition value.h:1370
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
Definition value.h:610
#define fr_value_box_list_foreach(_list_head, _iter)
Definition value.h:224
static size_t char ** out
Definition value.h:1030
#define FR_VALUE_BOX_SAFE_FOR_ANY
Definition value.h:173