Automatic search and replace for pairfind.
[freeradius.git] / src / modules / rlm_expr / paircmp.c
1 /*
2  * paircmp.c    Valuepair functions for various attributes
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Alan DeKok <aland@ox.org>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include "rlm_expr.h"
29
30 /*
31  *      Compare a Connect-Info and a Connect-Rate
32  */
33 static int connectcmp(void *instance,
34                       REQUEST *req UNUSED,
35                       VALUE_PAIR *request,
36                       VALUE_PAIR *check,
37                       VALUE_PAIR *check_pairs,
38                       VALUE_PAIR **reply_pairs)
39 {
40         int rate;
41
42         instance = instance;
43         check_pairs = check_pairs; /* shut the compiler up */
44         reply_pairs = reply_pairs;
45
46         rate = atoi((char *)request->vp_strvalue);
47         return rate - check->vp_integer;
48 }
49
50
51 /*
52  *      Compare a portno with a range.
53  */
54 static int portcmp(void *instance,
55                    REQUEST *req UNUSED, VALUE_PAIR *request, VALUE_PAIR *check,
56         VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
57 {
58         char buf[MAX_STRING_LEN];
59         char *s, *p, *next;
60         uint32_t lo, hi;
61         uint32_t port;
62
63         instance = instance;
64         check_pairs = check_pairs; /* shut the compiler up */
65         reply_pairs = reply_pairs;
66
67         if (!request) return -1;
68
69         port = request->vp_integer;
70
71         if ((strchr((char *)check->vp_strvalue, ',') == NULL) &&
72                         (strchr((char *)check->vp_strvalue, '-') == NULL)) {
73                 return (request->vp_integer - check->vp_integer);
74         }
75
76         /* Same size */
77         strcpy(buf, check->vp_strvalue);
78
79         s = buf;
80         while (1) {
81                 next = strchr(s, ',');
82                 if (next) *next = '\0';
83
84                 if ((p = strchr(s, '-')) != NULL)
85                         p++;
86                 else
87                         p = s;
88                 lo = strtoul(s, NULL, 10);
89                 hi = strtoul(p, NULL, 10);
90                 if (lo <= port && port <= hi) {
91                         return 0;
92                 }
93
94                 if (!next) break;
95                 s = next + 1;
96         }
97
98         return -1;
99 }
100
101 /*
102  *      Compare prefix/suffix.
103  *
104  *      If they compare:
105  *      - if PW_STRIP_USER_NAME is present in check_pairs,
106  *        strip the username of prefix/suffix.
107  *      - if PW_STRIP_USER_NAME is not present in check_pairs,
108  *        add a PW_STRIPPED_USER_NAME to the request.
109  */
110 static int presufcmp(UNUSED void *instance,
111                      REQUEST *req,
112                      VALUE_PAIR *request, VALUE_PAIR *check,
113                      VALUE_PAIR *check_pairs, UNUSED VALUE_PAIR **reply_pairs)
114 {
115         VALUE_PAIR *vp;
116         char *name;
117         char rest[MAX_STRING_LEN];
118         int len, namelen;
119         int ret = -1;
120
121         if (!request) return -1;
122
123         name = request->vp_strvalue;
124
125 #if 0 /* DEBUG */
126         printf("Comparing %s and %s, check->attr is %d\n",
127                 name, check->vp_strvalue, check->attribute);
128 #endif
129
130         len = strlen((char *)check->vp_strvalue);
131         switch (check->attribute) {
132                 case PW_PREFIX:
133                         ret = strncmp(name, check->vp_strvalue, len);
134                         if (ret == 0)
135                                 strlcpy(rest, name + len, sizeof(rest));
136                         break;
137                 case PW_SUFFIX:
138                         namelen = strlen(name);
139                         if (namelen < len)
140                                 break;
141                         ret = strcmp(name + namelen - len,
142                                         (char *)check->vp_strvalue);
143                         if (ret == 0) {
144                                 strlcpy(rest, name, namelen - len + 1);
145                         }
146                         break;
147         }
148         if (ret != 0)
149                 return ret;
150
151         /*
152          *      If Strip-User-Name == No, then don't do any more.
153          */
154         vp = pairfind(check_pairs, PW_STRIP_USER_NAME, 0);
155         if (vp && !vp->vp_integer) return ret;
156
157         /*
158          *      See where to put the stripped user name.
159          */
160         vp = pairfind(check_pairs, PW_STRIPPED_USER_NAME, 0);
161         if (!vp) {
162                 /*
163                  *      If "request" is NULL, then the memory will be
164                  *      lost!
165                  */
166                 vp = radius_paircreate(req, &request,
167                                        PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
168                 if (!vp) return ret;
169                 req->username = vp;
170         }
171
172         strlcpy((char *)vp->vp_strvalue, rest, sizeof(vp->vp_strvalue));
173         vp->length = strlen(vp->vp_strvalue);
174
175         return ret;
176 }
177
178
179 /*
180  *      Compare the request packet type.
181  */
182 static int packetcmp(void *instance UNUSED, REQUEST *req,
183                      VALUE_PAIR *request UNUSED,
184                      VALUE_PAIR *check,
185                      VALUE_PAIR *check_pairs UNUSED,
186                      VALUE_PAIR **reply_pairs UNUSED)
187 {
188         if (req->packet->code == check->vp_integer) {
189                 return 0;
190         }
191
192         return 1;
193 }
194
195 /*
196  *      Compare the response packet type.
197  */
198 static int responsecmp(void *instance UNUSED,
199                        REQUEST *req,
200                        VALUE_PAIR *request UNUSED,
201                        VALUE_PAIR *check,
202                        VALUE_PAIR *check_pairs UNUSED,
203                        VALUE_PAIR **reply_pairs UNUSED)
204 {
205         if (req->reply->code == check->vp_integer) {
206                 return 0;
207         }
208
209         return 1;
210 }
211
212 /*
213  *      Generic comparisons, via xlat.
214  */
215 static int genericcmp(void *instance UNUSED,
216                       REQUEST *req,
217                       VALUE_PAIR *request UNUSED,
218                       VALUE_PAIR *check,
219                       VALUE_PAIR *check_pairs UNUSED,
220                       VALUE_PAIR **reply_pairs UNUSED)
221 {
222         if ((check->operator != T_OP_REG_EQ) &&
223             (check->operator != T_OP_REG_EQ)) {
224                 int rcode;
225                 char name[1024];
226                 char value[1024];
227                 VALUE_PAIR *vp;
228
229                 snprintf(name, sizeof(name), "%%{%s}", check->name);
230
231                 radius_xlat(value, sizeof(value), name, req, NULL);
232                 vp = pairmake(check->name, value, check->operator);
233
234                 /*
235                  *      Paircmp returns 0 for failed comparison,
236                  *      1 for succeeded.
237                  */
238                 rcode = paircmp(check, vp);
239
240                 /*
241                  *      We're being called from radius_callback_compare,
242                  *      which wants 0 for success, and 1 for fail (sigh)
243                  *
244                  *      We should really fix the API so that it is
245                  *      consistent.  i.e. the comparison callbacks should
246                  *      return ONLY the resut of comparing A to B.
247                  *      The radius_callback_cmp function should then
248                  *      take care of using the operator to see if the
249                  *      condition (A OP B) is true or not.
250                  *
251                  *      This would also allow "<", etc. to work in the
252                  *      callback functions...
253                  *
254                  *      See rlm_ldap, ...groupcmp() for something that
255                  *      returns 0 for matched, and 1 for didn't match.
256                  */
257                 rcode = !rcode;
258                 pairfree(&vp);
259
260                 return rcode;
261         }
262
263         /*
264          *      Will do the xlat for us
265          */
266         return radius_compare_vps(req, check, NULL);
267 }
268
269 static int generic_attrs[] = {
270         PW_CLIENT_IP_ADDRESS,
271         PW_PACKET_SRC_IP_ADDRESS,
272         PW_PACKET_DST_IP_ADDRESS,
273         PW_PACKET_SRC_PORT,
274         PW_PACKET_DST_PORT,
275         PW_REQUEST_PROCESSING_STAGE,
276         PW_PACKET_SRC_IPV6_ADDRESS,
277         PW_PACKET_DST_IPV6_ADDRESS,
278         PW_VIRTUAL_SERVER,
279         0
280 };
281
282 /*
283  *      Register server-builtin special attributes.
284  */
285 void pair_builtincompare_init(void)
286 {
287         int i;
288
289         paircompare_register(PW_NAS_PORT, PW_NAS_PORT, portcmp, NULL);
290         paircompare_register(PW_PREFIX, PW_USER_NAME, presufcmp, NULL);
291         paircompare_register(PW_SUFFIX, PW_USER_NAME, presufcmp, NULL);
292         paircompare_register(PW_CONNECT_RATE, PW_CONNECT_INFO, connectcmp, NULL);
293         paircompare_register(PW_PACKET_TYPE, 0, packetcmp, NULL);
294         paircompare_register(PW_RESPONSE_PACKET_TYPE, 0, responsecmp, NULL);
295
296         for (i = 0; generic_attrs[i] != 0; i++) {
297                 paircompare_register(generic_attrs[i], -1, genericcmp, NULL);
298         }
299 }
300
301 void pair_builtincompare_detach(void)
302 {
303         int i;
304
305         paircompare_unregister(PW_NAS_PORT, portcmp);
306         paircompare_unregister(PW_PREFIX, presufcmp);
307         paircompare_unregister(PW_SUFFIX, presufcmp);
308         paircompare_unregister(PW_CONNECT_RATE, connectcmp);
309         paircompare_unregister(PW_PACKET_TYPE, packetcmp);
310         paircompare_unregister(PW_RESPONSE_PACKET_TYPE, responsecmp);
311
312         for (i = 0; generic_attrs[i] != 0; i++) {
313                 paircompare_unregister(generic_attrs[i], genericcmp);
314         }
315
316 }