The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
paircmp.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program 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
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; 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: d133e58a1390dc449109aa2a2c2c13cdbb3f25b4 $
19  *
20  * @brief Valuepair functions that are radiusd-specific and as such do not
21  * belong in the library.
22  * @file src/lib/server/paircmp.c
23  *
24  * @ingroup AVP
25  *
26  * @copyright 2000,2006 The FreeRADIUS server project
27  * @copyright 2000 Alan DeKok (aland@freeradius.org)
28  */
29 
30 RCSID("$Id: d133e58a1390dc449109aa2a2c2c13cdbb3f25b4 $")
31 
32 #include <freeradius-devel/server/paircmp.h>
33 #include <freeradius-devel/server/regex.h>
34 #include <freeradius-devel/server/request.h>
35 #include <freeradius-devel/unlang/xlat.h>
36 #include <freeradius-devel/util/debug.h>
37 #include <ctype.h>
38 
39 /** Compares check and vp by value.
40  *
41  * Does not call any per-attribute comparison function, but does honour
42  * check.operator. Basically does "vp.value check.op check.value".
43  *
44  * @param[in] request Current request.
45  * @param[in] check rvalue, and operator.
46  * @param[in] vp lvalue.
47  * @return
48  * - 0 if check and vp are equal
49  * - -1 if vp value is less than check value.
50  * - 1 is vp value is more than check value.
51  * - -2 on error.
52  */
53 #ifdef HAVE_REGEX
54 int paircmp_pairs(request_t *request, fr_pair_t const *check, fr_pair_t *vp)
55 #else
57 #endif
58 {
59  int ret = 0;
60 
61  /*
62  * Check for =* and !* and return appropriately
63  */
64  if (check->op == T_OP_CMP_TRUE) return 0;
65  if (check->op == T_OP_CMP_FALSE) return 1;
66 
67  if (!vp) {
68  REDEBUG("Non-Unary operations require two operands");
69  return -2;
70  }
71 
72 #ifdef HAVE_REGEX
73  if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) {
74  ssize_t slen;
75  regex_t *preg = NULL;
76  uint32_t subcaptures;
77  fr_regmatch_t *regmatch;
78 
79  char *expr = NULL, *value = NULL;
80  char const *expr_p, *value_p;
81 
82  if (check->vp_type == FR_TYPE_STRING) {
83  expr_p = check->vp_strvalue;
84  } else {
85  fr_value_box_aprint(request, &expr, &check->data, NULL);
86  expr_p = expr;
87  }
88 
89  if (vp->vp_type == FR_TYPE_STRING) {
90  value_p = vp->vp_strvalue;
91  } else {
92  fr_value_box_aprint(request, &value, &vp->data, NULL);
93  value_p = value;
94  }
95 
96  if (!expr_p || !value_p) {
97  REDEBUG("Error stringifying operand for regular expression");
98 
99  regex_error:
100  talloc_free(preg);
101  talloc_free(expr);
103  return -2;
104  }
105 
106  /*
107  * Include substring matches.
108  */
109  slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1,
110  NULL, true, true);
111  if (slen <= 0) {
112  REMARKER(expr_p, -slen, "%s", fr_strerror());
113 
114  goto regex_error;
115  }
116 
117  subcaptures = regex_subcapture_count(preg);
118  if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1; /* +1 for %{0} (whole match) capture group */
119  MEM(regmatch = regex_match_data_alloc(NULL, subcaptures));
120 
121  /*
122  * Evaluate the expression
123  */
124  slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, regmatch);
125  if (slen < 0) {
126  RPERROR("Invalid regex");
127 
128  goto regex_error;
129  }
130 
131  if (check->op == T_OP_REG_EQ) {
132  /*
133  * Add in %{0}. %{1}, etc.
134  */
135  regex_sub_to_request(request, &preg, &regmatch);
136  ret = (slen == 1) ? 0 : -1;
137  } else {
138  ret = (slen != 1) ? 0 : -1;
139  }
140 
141  talloc_free(regmatch);
142  talloc_free(preg);
143  talloc_free(expr);
145 
146  goto finish;
147  }
148 #endif
149 
150  /*
151  * Attributes must be of the same type.
152  *
153  * FIXME: deal with type mismatch properly if one side contain
154  * OCTETS or STRING by converting the other side to
155  * a string
156  *
157  */
158  if (vp->vp_type != check->vp_type) return -1;
159 
160  /*
161  * Not a regular expression, compare the types.
162  */
163  switch (check->vp_type) {
164  case FR_TYPE_OCTETS:
165  if (vp->vp_length != check->vp_length) {
166  ret = 1; /* NOT equal */
167  break;
168  }
169  ret = memcmp(vp->vp_strvalue, check->vp_strvalue, vp->vp_length);
170  break;
171 
172  case FR_TYPE_STRING:
173  ret = strcmp(vp->vp_strvalue, check->vp_strvalue);
174  break;
175 
176  case FR_TYPE_UINT8:
177  ret = vp->vp_uint8 - check->vp_uint8;
178  break;
179 
180  case FR_TYPE_UINT16:
181  ret = vp->vp_uint16 - check->vp_uint16;
182  break;
183 
184  case FR_TYPE_UINT32:
185  ret = vp->vp_uint32 - check->vp_uint32;
186  break;
187 
188  case FR_TYPE_UINT64:
189  /*
190  * Don't want integer overflow!
191  */
192  if (vp->vp_uint64 < check->vp_uint64) {
193  ret = -1;
194  } else if (vp->vp_uint64 > check->vp_uint64) {
195  ret = +1;
196  } else {
197  ret = 0;
198  }
199  break;
200 
201  case FR_TYPE_INT32:
202  ret = CMP(vp->vp_int32, check->vp_int32);
203  break;
204 
205  case FR_TYPE_DATE:
206  ret = fr_unix_time_cmp(vp->vp_date, check->vp_date);
207  break;
208 
209  case FR_TYPE_IPV4_ADDR:
210  ret = ntohl(vp->vp_ipv4addr) - ntohl(check->vp_ipv4addr);
211  break;
212 
213  case FR_TYPE_IPV6_ADDR:
214  ret = memcmp(vp->vp_ip.addr.v6.s6_addr, check->vp_ip.addr.v6.s6_addr,
215  sizeof(vp->vp_ip.addr.v6.s6_addr));
216  break;
217 
218  case FR_TYPE_IPV4_PREFIX:
219  case FR_TYPE_IPV6_PREFIX:
220  ret = fr_pair_cmp_op(check->op, vp, check);
221  if (ret == -1) return -2; // error
222  if (check->op == T_OP_LT || check->op == T_OP_LE)
223  ret = (ret == 1) ? -1 : 1;
224  else if (check->op == T_OP_GT || check->op == T_OP_GE)
225  ret = (ret == 1) ? 1 : -1;
226  else if (check->op == T_OP_CMP_EQ)
227  ret = (ret == 1) ? 0 : -1;
228  break;
229 
230  case FR_TYPE_IFID:
231  ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid));
232  break;
233 
234  default:
235  break;
236  }
237 
238 finish:
239  if (ret > 0) return 1;
240  if (ret < 0) return -1;
241  return 0;
242 }
#define RCSID(id)
Definition: build.h:444
#define CMP(_a, _b)
Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want an ordering.
Definition: build.h:110
#define UNUSED
Definition: build.h:313
Test enumeration values.
Definition: dict_test.h:92
#define RPERROR(fmt,...)
Definition: log.h:302
#define REMARKER(_str, _marker_idx, _marker,...)
Output string with error marker, showing where format error occurred.
Definition: log.h:498
talloc_free(reap)
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
Definition: merged_model.c:86
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
Definition: merged_model.c:89
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_UINT16
16 Bit unsigned integer.
Definition: merged_model.c:98
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
Definition: merged_model.c:111
@ FR_TYPE_UINT8
8 Bit unsigned integer.
Definition: merged_model.c:97
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_INT32
32 Bit signed integer.
Definition: merged_model.c:105
@ FR_TYPE_UINT64
64 Bit unsigned integer.
Definition: merged_model.c:100
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
Definition: merged_model.c:88
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
Definition: merged_model.c:87
@ FR_TYPE_IFID
Interface ID.
Definition: merged_model.c:90
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
int paircmp_pairs(UNUSED request_t *request, fr_pair_t const *check, fr_pair_t *vp)
Compares check and vp by value.
Definition: paircmp.c:56
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define check(_handle, _len_p)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
static int8_t fr_unix_time_cmp(fr_unix_time_t a, fr_unix_time_t b)
Compare two fr_unix_time_t values.
Definition: time.h:942
@ T_OP_CMP_TRUE
Definition: token.h:104
@ T_OP_CMP_FALSE
Definition: token.h:105
@ T_OP_REG_EQ
Definition: token.h:102
@ T_OP_CMP_EQ
Definition: token.h:106
@ T_OP_LE
Definition: token.h:100
@ T_OP_GE
Definition: token.h:98
@ T_OP_GT
Definition: token.h:99
@ T_OP_LT
Definition: token.h:101
@ T_OP_REG_NE
Definition: token.h:103
#define fr_pair_cmp_op(_op, _a, _b)
Compare two attributes using and operator.
Definition: pair.h:665
char const * fr_strerror(void)
Get the last library error.
Definition: strerror.c:554
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print