2 * valuepair.c Valuepair functions that are radiusd-specific
3 * and as such do not belong in the library.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Copyright 2000 The FreeRADIUS server project
22 * Copyright 2000 Alan DeKok <aland@ox.org>
25 static const char rcsid[] = "$Id$";
28 #include "libradius.h"
35 # include <netinet/in.h>
47 void *instance; /* module instance */
48 RAD_COMPARE_FUNC compare;
51 static struct cmp *cmp;
55 * Compare 2 attributes. May call the attribute compare function.
57 static int paircompare(VALUE_PAIR *request, VALUE_PAIR *check,
58 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
67 if (request->attribute != check->attribute)
72 * See if there is a special compare function.
74 for (c = cmp; c; c = c->next)
75 if (c->attribute == check->attribute)
76 return (c->compare)(c->instance, request, check,
77 check_pairs, reply_pairs);
82 * Ascend binary attributes can be treated
83 * as opaque objects, I guess...
88 if (request->length != check->length) {
89 ret = 1; /* NOT equal */
92 ret = memcmp(request->strvalue, check->strvalue,
96 ret = strcmp((char *)request->strvalue,
97 (char *)check->strvalue);
101 ret = request->lvalue - check->lvalue;
104 ret = ntohl(request->lvalue) - ntohl(check->lvalue);
115 * See what attribute we want to compare with.
117 static int otherattr(int attr)
121 for (c = cmp; c; c = c->next) {
122 if (c->attribute == attr)
130 * Register a function as compare function.
131 * compare_attr is the attribute in the request we want to
132 * compare with. Normally this is the same as "attr".
133 * You can set this to:
135 * -1 the same as "attr"
136 * 0 always call compare function, not tied to request attribute
137 * >0 Attribute to compare with.
139 * For example, PW_GROUP in a check item needs to be compared
140 * with PW_USER_NAME in the incoming request.
142 int paircompare_register(int attr, int compare_attr, RAD_COMPARE_FUNC fun, void *instance)
146 paircompare_unregister(attr, fun);
148 c = rad_malloc(sizeof(struct cmp));
150 if (compare_attr < 0)
154 c->otherattr = compare_attr;
155 c->instance = instance;
163 * Unregister a function.
165 void paircompare_unregister(int attr, RAD_COMPARE_FUNC fun)
167 struct cmp *c, *last;
170 for (c = cmp; c; c = c->next) {
171 if (c->attribute == attr && c->compare == fun)
176 if (c == NULL) return;
179 last->next = c->next;
187 * Compare two pair lists except for the password information.
188 * For every element in "check" at least one matching copy must
189 * be present in "reply".
193 int paircmp(VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR **reply)
195 VALUE_PAIR *check_item = check;
196 VALUE_PAIR *auth_item;
204 while (result == 0 && check_item != NULL) {
206 * If the user is setting a configuration value,
207 * then don't bother comparing it to any attributes
208 * sent to us by the user. It ALWAYS matches.
210 if ((check_item->operator == T_OP_SET) ||
211 (check_item->operator == T_OP_ADD)) {
212 check_item = check_item->next;
216 switch (check_item->attribute) {
218 * Attributes we skip during comparison.
219 * These are "server" check items.
221 case PW_CRYPT_PASSWORD:
222 check_item = check_item->next;
226 * See if this item is present in the request.
228 other = otherattr(check_item->attribute);
230 for (; auth_item != NULL; auth_item = auth_item->next) {
231 if (auth_item->attribute == other || other == 0)
235 if (auth_item == NULL) {
241 * OK it is present now compare them.
243 compare = paircompare(auth_item, check_item, check, reply);
245 switch (check_item->operator) {
248 radlog(L_ERR, "Invalid operator for item %s: "
249 "reverting to '=='", check_item->name);
252 if (compare != 0) return -1;
256 if (compare == 0) return -1;
260 if (compare >= 0) return -1;
264 if (compare <= 0) return -1;
268 if (compare > 0) return -1;
272 if (compare < 0) return -1;
277 regcomp(®, (char *)check_item->strvalue, 0);
278 compare = regexec(®, (char *)auth_item->strvalue,
281 if (compare != 0) return -1;
285 regcomp(®, (char *)check_item->strvalue, 0);
286 compare = regexec(®, (char *)auth_item->strvalue,
289 if (compare == 0) return -1;
296 check_item = check_item->next;
303 * Compare two attributes simply. Calls paircompare.
306 int simplepaircmp(VALUE_PAIR *first, VALUE_PAIR *second)
308 return paircompare( first, second, NULL, NULL );
313 * Compare a Connect-Info and a Connect-Rate
315 static int connectcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
316 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
321 check_pairs = check_pairs; /* shut the compiler up */
322 reply_pairs = reply_pairs;
324 rate = atoi((char *)request->strvalue);
325 return rate - check->lvalue;
330 * Compare a portno with a range.
332 static int portcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
333 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
335 char buf[MAX_STRING_LEN];
338 int port = request->lvalue;
341 check_pairs = check_pairs; /* shut the compiler up */
342 reply_pairs = reply_pairs;
344 if ((strchr((char *)check->strvalue, ',') == NULL) &&
345 (strchr((char *)check->strvalue, '-') == NULL)) {
346 return (request->lvalue - check->lvalue);
350 strcpy(buf, (char *)check->strvalue);
351 s = strtok(buf, ",");
354 if ((p = strchr(s, '-')) != NULL)
360 if (lo <= port && port <= hi) {
363 s = strtok(NULL, ",");
370 * Compare prefix/suffix.
373 * - if PW_STRIP_USER_NAME is present in check_pairs,
374 * strip the username of prefix/suffix.
375 * - if PW_STRIP_USER_NAME is not present in check_pairs,
376 * add a PW_STRIPPED_USER_NAME to the request.
378 static int presufcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
379 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
382 char *name = (char *)request->strvalue;
383 char rest[MAX_STRING_LEN];
388 reply_pairs = reply_pairs; /* shut the compiler up */
391 printf("Comparing %s and %s, check->attr is %d\n",
392 name, check->strvalue, check->attribute);
395 len = strlen((char *)check->strvalue);
396 switch (check->attribute) {
398 ret = strncmp(name, (char *)check->strvalue, len);
399 if (ret == 0 && rest)
400 strcpy(rest, name + len);
403 namelen = strlen(name);
406 ret = strcmp(name + namelen - len,
407 (char *)check->strvalue);
408 if (ret == 0 && rest) {
409 strncpy(rest, name, namelen - len);
410 rest[namelen - len] = 0;
417 if (pairfind(check_pairs, PW_STRIP_USER_NAME)) {
419 * I don't think we want to update the User-Name
420 * attribute in place... - atd
422 strcpy((char *)request->strvalue, rest);
423 request->length = strlen(rest);
425 if ((vp = pairfind(check_pairs, PW_STRIPPED_USER_NAME)) != NULL){
426 strcpy((char *)vp->strvalue, rest);
427 vp->length = strlen(rest);
428 } else if ((vp = paircreate(PW_STRIPPED_USER_NAME,
429 PW_TYPE_STRING)) != NULL) {
430 strcpy((char *)vp->strvalue, rest);
431 vp->length = strlen(rest);
432 pairadd(&request, vp);
433 } /* else no memory! Die, die!: FIXME!! */
441 * Compare the current time to a range.
442 * Hmm... it would save work, and probably be better,
443 * if we were passed the REQUEST data structure, so we
444 * could use it's 'timestamp' element. That way, we could
445 * do the comparison against when the packet came in, not now,
446 * and have one less system call to do.
448 static int timecmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
449 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
452 request = request; /* shut the compiler up */
453 check_pairs = check_pairs;
454 reply_pairs = reply_pairs;
456 if (timestr_match((char *)check->strvalue, time(NULL)) >= 0) {
463 * Matches if there is NO SUCH ATTRIBUTE as the one named
464 * in check->strvalue. If there IS such an attribute, it
467 * This is ugly, and definitely non-optimal. We should be
468 * doing the lookup only ONCE, and storing the result
469 * in check->lvalue...
471 static int attrcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
472 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
479 check_pairs = check_pairs; /* shut the compiler up */
480 reply_pairs = reply_pairs;
482 if (check->lvalue == 0) {
483 dict = dict_attrbyname((char *)check->strvalue);
489 attr = check->lvalue;
493 * If there's no such attribute, then return MATCH,
496 pair = pairfind(request, attr);
505 * Register server-builtin special attributes.
507 void pair_builtincompare_init(void)
509 paircompare_register(PW_NAS_PORT_ID, -1, portcmp, NULL);
510 paircompare_register(PW_PREFIX, PW_USER_NAME, presufcmp, NULL);
511 paircompare_register(PW_SUFFIX, PW_USER_NAME, presufcmp, NULL);
512 paircompare_register(PW_CONNECT_RATE, PW_CONNECT_INFO, connectcmp, NULL);
513 paircompare_register(PW_CURRENT_TIME, 0, timecmp, NULL);
514 paircompare_register(PW_NO_SUCH_ATTRIBUTE, 0, attrcmp, NULL);