5ec426916638bf88b8c877f373cafbbd2e440dbb
[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/autoconf.h>
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <freeradius-devel/radiusd.h>
34
35
36 /*
37  *      Compare a Connect-Info and a Connect-Rate
38  */
39 static int connectcmp(void *instance,
40                       REQUEST *req UNUSED,
41                       VALUE_PAIR *request,
42                       VALUE_PAIR *check,
43                       VALUE_PAIR *check_pairs,
44                       VALUE_PAIR **reply_pairs)
45 {
46         int rate;
47
48         instance = instance;
49         check_pairs = check_pairs; /* shut the compiler up */
50         reply_pairs = reply_pairs;
51
52         rate = atoi((char *)request->vp_strvalue);
53         return rate - check->lvalue;
54 }
55
56
57 /*
58  *      Compare a portno with a range.
59  */
60 static int portcmp(void *instance,
61                    REQUEST *req UNUSED, VALUE_PAIR *request, VALUE_PAIR *check,
62         VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
63 {
64         char buf[MAX_STRING_LEN];
65         char *s, *p;
66         uint32_t lo, hi;
67         uint32_t port = request->lvalue;
68
69         instance = instance;
70         check_pairs = check_pairs; /* shut the compiler up */
71         reply_pairs = reply_pairs;
72
73         if ((strchr((char *)check->vp_strvalue, ',') == NULL) &&
74                         (strchr((char *)check->vp_strvalue, '-') == NULL)) {
75                 return (request->lvalue - check->lvalue);
76         }
77
78         /* Same size */
79         strcpy(buf, (char *)check->vp_strvalue);
80         s = strtok(buf, ",");
81
82         while (s != NULL) {
83                 if ((p = strchr(s, '-')) != NULL)
84                         p++;
85                 else
86                         p = s;
87                 lo = strtoul(s, NULL, 10);
88                 hi = strtoul(p, NULL, 10);
89                 if (lo <= port && port <= hi) {
90                         return 0;
91                 }
92                 s = strtok(NULL, ",");
93         }
94
95         return -1;
96 }
97
98 /*
99  *      Compare prefix/suffix.
100  *
101  *      If they compare:
102  *      - if PW_STRIP_USER_NAME is present in check_pairs,
103  *        strip the username of prefix/suffix.
104  *      - if PW_STRIP_USER_NAME is not present in check_pairs,
105  *        add a PW_STRIPPED_USER_NAME to the request.
106  */
107 static int presufcmp(void *instance,
108                      REQUEST *req UNUSED,
109                      VALUE_PAIR *request, VALUE_PAIR *check,
110         VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
111 {
112         VALUE_PAIR *vp;
113         char *name = (char *)request->vp_strvalue;
114         char rest[MAX_STRING_LEN];
115         int len, namelen;
116         int ret = -1;
117
118         instance = instance;
119         reply_pairs = reply_pairs; /* shut the compiler up */
120
121 #if 0 /* DEBUG */
122         printf("Comparing %s and %s, check->attr is %d\n",
123                 name, check->vp_strvalue, check->attribute);
124 #endif
125
126         len = strlen((char *)check->vp_strvalue);
127         switch (check->attribute) {
128                 case PW_PREFIX:
129                         ret = strncmp(name, (char *)check->vp_strvalue, len);
130                         if (ret == 0 && rest)
131                                 strcpy(rest, name + len);
132                         break;
133                 case PW_SUFFIX:
134                         namelen = strlen(name);
135                         if (namelen < len)
136                                 break;
137                         ret = strcmp(name + namelen - len,
138                                         (char *)check->vp_strvalue);
139                         if (ret == 0 && rest) {
140                                 strNcpy(rest, name, namelen - len + 1);
141                         }
142                         break;
143         }
144         if (ret != 0)
145                 return ret;
146
147         /*
148          *      If Strip-User-Name == No, then don't do any more.
149          */
150         vp = pairfind(check_pairs, PW_STRIP_USER_NAME);
151         if (vp && !vp->lvalue) return ret;
152
153         /*
154          *      See where to put the stripped user name.
155          */
156         vp = pairfind(check_pairs, PW_STRIPPED_USER_NAME);
157         if (!vp) {
158                 vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
159                 if (!vp) return ret; /* no memory, do anything? */
160
161                 pairadd(&request, vp);
162         }
163
164         strcpy((char *)vp->vp_strvalue, rest);
165         vp->length = strlen(rest);
166
167         return ret;
168 }
169
170
171 /*
172  *      Matches if there is NO SUCH ATTRIBUTE as the one named
173  *      in check->vp_strvalue.  If there IS such an attribute, it
174  *      doesn't match.
175  *
176  *      This is ugly, and definitely non-optimal.  We should be
177  *      doing the lookup only ONCE, and storing the result
178  *      in check->lvalue...
179  */
180 static int attrcmp(void *instance,
181                    REQUEST *req UNUSED,
182                    VALUE_PAIR *request, VALUE_PAIR *check,
183                    VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
184 {
185         VALUE_PAIR *pair;
186         DICT_ATTR  *dict;
187         int attr;
188
189         instance = instance;
190         check_pairs = check_pairs; /* shut the compiler up */
191         reply_pairs = reply_pairs;
192
193         if (check->lvalue == 0) {
194                 dict = dict_attrbyname((char *)check->vp_strvalue);
195                 if (dict == NULL) {
196                         return -1;
197                 }
198                 attr = dict->attr;
199         } else {
200                 attr = check->lvalue;
201         }
202
203         /*
204          *      If there's no such attribute, then return MATCH,
205          *      else FAILURE.
206          */
207         pair = pairfind(request, attr);
208         if (pair == NULL) {
209                 return 0;
210         }
211
212         return -1;
213 }
214
215 /*
216  *      Compare the request packet type.
217  */
218 static int packetcmp(void *instance UNUSED, REQUEST *req,
219                      VALUE_PAIR *request UNUSED,
220                      VALUE_PAIR *check,
221                      VALUE_PAIR *check_pairs UNUSED,
222                      VALUE_PAIR **reply_pairs UNUSED)
223 {
224         if (req->packet->code == check->lvalue) {
225                 return 0;
226         }
227
228         return 1;
229 }
230
231 /*
232  *      Compare the response packet type.
233  */
234 static int responsecmp(void *instance UNUSED,
235                        REQUEST *req,
236                        VALUE_PAIR *request UNUSED,
237                        VALUE_PAIR *check,
238                        VALUE_PAIR *check_pairs UNUSED,
239                        VALUE_PAIR **reply_pairs UNUSED)
240 {
241         if (req->reply->code == check->lvalue) {
242                 return 0;
243         }
244
245         return 1;
246 }
247
248 /*
249  *      Register server-builtin special attributes.
250  */
251 void pair_builtincompare_init(void)
252 {
253         paircompare_register(PW_NAS_PORT, -1, 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_NO_SUCH_ATTRIBUTE, 0, attrcmp, NULL);
258         paircompare_register(PW_PACKET_TYPE, 0, packetcmp, NULL);
259         paircompare_register(PW_RESPONSE_PACKET_TYPE, 0, responsecmp, NULL);
260 }
261
262 void pair_builtincompare_detach(void)
263 {
264         paircompare_unregister(PW_NAS_PORT, portcmp);
265         paircompare_unregister(PW_PREFIX, presufcmp);
266         paircompare_unregister(PW_SUFFIX, presufcmp);
267         paircompare_unregister(PW_CONNECT_RATE, connectcmp);
268         paircompare_unregister(PW_NO_SUCH_ATTRIBUTE, attrcmp);
269         paircompare_unregister(PW_PACKET_TYPE, packetcmp);
270         paircompare_unregister(PW_RESPONSE_PACKET_TYPE, responsecmp);
271 }