Delete trailing whitespace.
[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
29 /*
30  *      Compare a Connect-Info and a Connect-Rate
31  */
32 static int connectcmp(void *instance,
33                       REQUEST *req UNUSED,
34                       VALUE_PAIR *request,
35                       VALUE_PAIR *check,
36                       VALUE_PAIR *check_pairs,
37                       VALUE_PAIR **reply_pairs)
38 {
39         int rate;
40
41         instance = instance;
42         check_pairs = check_pairs; /* shut the compiler up */
43         reply_pairs = reply_pairs;
44
45         rate = atoi((char *)request->vp_strvalue);
46         return rate - check->vp_integer;
47 }
48
49
50 /*
51  *      Compare a portno with a range.
52  */
53 static int portcmp(void *instance,
54                    REQUEST *req UNUSED, VALUE_PAIR *request, VALUE_PAIR *check,
55         VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
56 {
57         char buf[MAX_STRING_LEN];
58         char *s, *p;
59         uint32_t lo, hi;
60         uint32_t port = request->vp_integer;
61
62         instance = instance;
63         check_pairs = check_pairs; /* shut the compiler up */
64         reply_pairs = reply_pairs;
65
66         if ((strchr((char *)check->vp_strvalue, ',') == NULL) &&
67                         (strchr((char *)check->vp_strvalue, '-') == NULL)) {
68                 return (request->vp_integer - check->vp_integer);
69         }
70
71         /* Same size */
72         strcpy(buf, (char *)check->vp_strvalue);
73         s = strtok(buf, ",");
74
75         while (s != NULL) {
76                 if ((p = strchr(s, '-')) != NULL)
77                         p++;
78                 else
79                         p = s;
80                 lo = strtoul(s, NULL, 10);
81                 hi = strtoul(p, NULL, 10);
82                 if (lo <= port && port <= hi) {
83                         return 0;
84                 }
85                 s = strtok(NULL, ",");
86         }
87
88         return -1;
89 }
90
91 /*
92  *      Compare prefix/suffix.
93  *
94  *      If they compare:
95  *      - if PW_STRIP_USER_NAME is present in check_pairs,
96  *        strip the username of prefix/suffix.
97  *      - if PW_STRIP_USER_NAME is not present in check_pairs,
98  *        add a PW_STRIPPED_USER_NAME to the request.
99  */
100 static int presufcmp(void *instance,
101                      REQUEST *req,
102                      VALUE_PAIR *request, VALUE_PAIR *check,
103         VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
104 {
105         VALUE_PAIR *vp;
106         char *name = (char *)request->vp_strvalue;
107         char rest[MAX_STRING_LEN];
108         int len, namelen;
109         int ret = -1;
110
111         instance = instance;
112         reply_pairs = reply_pairs; /* shut the compiler up */
113
114 #if 0 /* DEBUG */
115         printf("Comparing %s and %s, check->attr is %d\n",
116                 name, check->vp_strvalue, check->attribute);
117 #endif
118
119         len = strlen((char *)check->vp_strvalue);
120         switch (check->attribute) {
121                 case PW_PREFIX:
122                         ret = strncmp(name, (char *)check->vp_strvalue, len);
123                         if (ret == 0 && rest)
124                                 strcpy(rest, name + len);
125                         break;
126                 case PW_SUFFIX:
127                         namelen = strlen(name);
128                         if (namelen < len)
129                                 break;
130                         ret = strcmp(name + namelen - len,
131                                         (char *)check->vp_strvalue);
132                         if (ret == 0 && rest) {
133                                 strlcpy(rest, name, namelen - len + 1);
134                         }
135                         break;
136         }
137         if (ret != 0)
138                 return ret;
139
140         /*
141          *      If Strip-User-Name == No, then don't do any more.
142          */
143         vp = pairfind(check_pairs, PW_STRIP_USER_NAME);
144         if (vp && !vp->vp_integer) return ret;
145
146         /*
147          *      See where to put the stripped user name.
148          */
149         vp = pairfind(check_pairs, PW_STRIPPED_USER_NAME);
150         if (!vp) {
151                 /*
152                  *      If "request" is NULL, then the memory will be
153                  *      lost!
154                  */
155                 vp = radius_paircreate(req, &request,
156                                        PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
157         }
158
159         strlcpy((char *)vp->vp_strvalue, rest, sizeof(vp->vp_strvalue));
160         vp->length = strlen(vp->vp_strvalue);
161
162         return ret;
163 }
164
165
166 /*
167  *      Compare the request packet type.
168  */
169 static int packetcmp(void *instance UNUSED, REQUEST *req,
170                      VALUE_PAIR *request UNUSED,
171                      VALUE_PAIR *check,
172                      VALUE_PAIR *check_pairs UNUSED,
173                      VALUE_PAIR **reply_pairs UNUSED)
174 {
175         if (req->packet->code == check->vp_integer) {
176                 return 0;
177         }
178
179         return 1;
180 }
181
182 /*
183  *      Compare the response packet type.
184  */
185 static int responsecmp(void *instance UNUSED,
186                        REQUEST *req,
187                        VALUE_PAIR *request UNUSED,
188                        VALUE_PAIR *check,
189                        VALUE_PAIR *check_pairs UNUSED,
190                        VALUE_PAIR **reply_pairs UNUSED)
191 {
192         if (req->reply->code == check->vp_integer) {
193                 return 0;
194         }
195
196         return 1;
197 }
198
199 /*
200  *      Generic comparisons, via xlat.
201  */
202 static int genericcmp(void *instance UNUSED,
203                       REQUEST *req,
204                       VALUE_PAIR *request UNUSED,
205                       VALUE_PAIR *check,
206                       VALUE_PAIR *check_pairs UNUSED,
207                       VALUE_PAIR **reply_pairs UNUSED)
208 {
209         if ((check->operator != T_OP_REG_EQ) &&
210             (check->operator != T_OP_REG_EQ)) {
211                 int rcode;
212                 char name[1024];
213                 char value[1024];
214                 VALUE_PAIR *vp;
215
216                 snprintf(name, sizeof(name), "%%{%s}", check->name);
217
218                 rcode = radius_xlat(value, sizeof(value), name, req, NULL);
219                 vp = pairmake(check->name, value, T_OP_EQ);
220
221                 rcode = radius_compare_vps(req, check, vp);
222                 pairfree(&vp);
223
224                 return rcode;
225         }
226
227         /*
228          *      Will do the xlat for us
229          */
230         return radius_compare_vps(req, check, NULL);
231 }
232
233 static int generic_attrs[] = {
234         PW_CLIENT_IP_ADDRESS,
235         PW_PACKET_SRC_IP_ADDRESS,
236         PW_PACKET_DST_IP_ADDRESS,
237         PW_PACKET_SRC_PORT,
238         PW_PACKET_DST_PORT,
239         PW_REQUEST_PROCESSING_STAGE,
240         PW_PACKET_SRC_IPV6_ADDRESS,
241         PW_PACKET_DST_IPV6_ADDRESS,
242         PW_SERVER_IDENTITY,
243         0
244 };
245
246 /*
247  *      Register server-builtin special attributes.
248  */
249 void pair_builtincompare_init(void)
250 {
251         int i;
252
253         paircompare_register(PW_NAS_PORT, PW_NAS_PORT, portcmp, NULL);
254         paircompare_register(PW_PREFIX, PW_USER_NAME, presufcmp, NULL);
255         paircompare_register(PW_SUFFIX, PW_USER_NAME, presufcmp, NULL);
256         paircompare_register(PW_CONNECT_RATE, PW_CONNECT_INFO, connectcmp, NULL);
257         paircompare_register(PW_PACKET_TYPE, 0, packetcmp, NULL);
258         paircompare_register(PW_RESPONSE_PACKET_TYPE, 0, responsecmp, NULL);
259
260         for (i = 0; generic_attrs[i] != 0; i++) {
261                 paircompare_register(generic_attrs[i], -1, genericcmp, NULL);
262         }
263 }
264
265 void pair_builtincompare_detach(void)
266 {
267         int i;
268
269         paircompare_unregister(PW_NAS_PORT, portcmp);
270         paircompare_unregister(PW_PREFIX, presufcmp);
271         paircompare_unregister(PW_SUFFIX, presufcmp);
272         paircompare_unregister(PW_CONNECT_RATE, connectcmp);
273         paircompare_unregister(PW_PACKET_TYPE, packetcmp);
274         paircompare_unregister(PW_RESPONSE_PACKET_TYPE, responsecmp);
275
276         for (i = 0; generic_attrs[i] != 0; i++) {
277                 paircompare_unregister(generic_attrs[i], genericcmp);
278         }
279
280 }