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>
42 * For POSIX Regular expressions.
43 * (0) Means no extended regular expressions.
44 * REG_EXTENDED means use extended regular expressions.
47 #define REG_EXTENDED (0)
56 void *instance; /* module instance */
57 RAD_COMPARE_FUNC compare;
60 static struct cmp *cmp;
64 * Compare 2 attributes. May call the attribute compare function.
66 static int paircompare(VALUE_PAIR *request, VALUE_PAIR *check,
67 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
76 if (request->attribute != check->attribute)
81 * See if there is a special compare function.
83 for (c = cmp; c; c = c->next)
84 if (c->attribute == check->attribute)
85 return (c->compare)(c->instance, request, check,
86 check_pairs, reply_pairs);
91 * Ascend binary attributes can be treated
92 * as opaque objects, I guess...
97 if (request->length != check->length) {
98 ret = 1; /* NOT equal */
101 ret = memcmp(request->strvalue, check->strvalue,
105 ret = strcmp((char *)request->strvalue,
106 (char *)check->strvalue);
108 case PW_TYPE_INTEGER:
110 ret = request->lvalue - check->lvalue;
113 ret = ntohl(request->lvalue) - ntohl(check->lvalue);
124 * See what attribute we want to compare with.
126 static int otherattr(int attr)
130 for (c = cmp; c; c = c->next) {
131 if (c->attribute == attr)
139 * Register a function as compare function.
140 * compare_attr is the attribute in the request we want to
141 * compare with. Normally this is the same as "attr".
142 * You can set this to:
144 * -1 the same as "attr"
145 * 0 always call compare function, not tied to request attribute
146 * >0 Attribute to compare with.
148 * For example, PW_GROUP in a check item needs to be compared
149 * with PW_USER_NAME in the incoming request.
151 int paircompare_register(int attr, int compare_attr, RAD_COMPARE_FUNC fun, void *instance)
155 paircompare_unregister(attr, fun);
157 c = rad_malloc(sizeof(struct cmp));
159 if (compare_attr < 0)
163 c->otherattr = compare_attr;
164 c->instance = instance;
172 * Unregister a function.
174 void paircompare_unregister(int attr, RAD_COMPARE_FUNC fun)
176 struct cmp *c, *last;
179 for (c = cmp; c; c = c->next) {
180 if (c->attribute == attr && c->compare == fun)
185 if (c == NULL) return;
188 last->next = c->next;
196 * Compare two pair lists except for the password information.
197 * For every element in "check" at least one matching copy must
198 * be present in "reply".
202 int paircmp(VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR **reply)
204 VALUE_PAIR *check_item = check;
205 VALUE_PAIR *auth_item;
213 while (result == 0 && check_item != NULL) {
215 * If the user is setting a configuration value,
216 * then don't bother comparing it to any attributes
217 * sent to us by the user. It ALWAYS matches.
219 if ((check_item->operator == T_OP_SET) ||
220 (check_item->operator == T_OP_ADD)) {
221 check_item = check_item->next;
225 switch (check_item->attribute) {
227 * Attributes we skip during comparison.
228 * These are "server" check items.
230 case PW_CRYPT_PASSWORD:
231 check_item = check_item->next;
236 * IF the password attribute exists, THEN
237 * we can do comparisons against it. If not,
238 * then the request did NOT contain a Password
239 * attribute, so we CANNOT do comparisons
242 * This hack makes CHAP-Password work..
245 if (pairfind(request, PW_PASSWORD) == NULL) {
246 check_item = check_item->next;
253 * See if this item is present in the request.
255 other = otherattr(check_item->attribute);
257 for (; auth_item != NULL; auth_item = auth_item->next) {
258 if (auth_item->attribute == other || other == 0)
262 if (auth_item == NULL) {
268 * OK it is present now compare them.
270 compare = paircompare(auth_item, check_item, check, reply);
272 switch (check_item->operator) {
275 radlog(L_ERR, "Invalid operator for item %s: "
276 "reverting to '=='", check_item->name);
279 if (compare != 0) return -1;
283 if (compare == 0) return -1;
287 if (compare >= 0) return -1;
291 if (compare <= 0) return -1;
295 if (compare > 0) return -1;
299 if (compare < 0) return -1;
304 regcomp(®, (char *)check_item->strvalue, REG_EXTENDED);
305 compare = regexec(®, (char *)auth_item->strvalue,
308 if (compare != 0) return -1;
312 regcomp(®, (char *)check_item->strvalue, REG_EXTENDED);
313 compare = regexec(®, (char *)auth_item->strvalue,
316 if (compare == 0) return -1;
323 check_item = check_item->next;
330 * Compare two attributes simply. Calls paircompare.
333 int simplepaircmp(VALUE_PAIR *first, VALUE_PAIR *second)
335 return paircompare( first, second, NULL, NULL );
340 * Compare a Connect-Info and a Connect-Rate
342 static int connectcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
343 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
348 check_pairs = check_pairs; /* shut the compiler up */
349 reply_pairs = reply_pairs;
351 rate = atoi((char *)request->strvalue);
352 return rate - check->lvalue;
357 * Compare a portno with a range.
359 static int portcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
360 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
362 char buf[MAX_STRING_LEN];
365 int port = request->lvalue;
368 check_pairs = check_pairs; /* shut the compiler up */
369 reply_pairs = reply_pairs;
371 if ((strchr((char *)check->strvalue, ',') == NULL) &&
372 (strchr((char *)check->strvalue, '-') == NULL)) {
373 return (request->lvalue - check->lvalue);
377 strcpy(buf, (char *)check->strvalue);
378 s = strtok(buf, ",");
381 if ((p = strchr(s, '-')) != NULL)
387 if (lo <= port && port <= hi) {
390 s = strtok(NULL, ",");
397 * Compare prefix/suffix.
400 * - if PW_STRIP_USER_NAME is present in check_pairs,
401 * strip the username of prefix/suffix.
402 * - if PW_STRIP_USER_NAME is not present in check_pairs,
403 * add a PW_STRIPPED_USER_NAME to the request.
405 static int presufcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
406 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
409 char *name = (char *)request->strvalue;
410 char rest[MAX_STRING_LEN];
415 reply_pairs = reply_pairs; /* shut the compiler up */
418 printf("Comparing %s and %s, check->attr is %d\n",
419 name, check->strvalue, check->attribute);
422 len = strlen((char *)check->strvalue);
423 switch (check->attribute) {
425 ret = strncmp(name, (char *)check->strvalue, len);
426 if (ret == 0 && rest)
427 strcpy(rest, name + len);
430 namelen = strlen(name);
433 ret = strcmp(name + namelen - len,
434 (char *)check->strvalue);
435 if (ret == 0 && rest) {
436 strncpy(rest, name, namelen - len);
437 rest[namelen - len] = 0;
444 if (pairfind(check_pairs, PW_STRIP_USER_NAME)) {
446 * I don't think we want to update the User-Name
447 * attribute in place... - atd
449 strcpy((char *)request->strvalue, rest);
450 request->length = strlen(rest);
452 if ((vp = pairfind(check_pairs, PW_STRIPPED_USER_NAME)) != NULL){
453 strcpy((char *)vp->strvalue, rest);
454 vp->length = strlen(rest);
455 } else if ((vp = paircreate(PW_STRIPPED_USER_NAME,
456 PW_TYPE_STRING)) != NULL) {
457 strcpy((char *)vp->strvalue, rest);
458 vp->length = strlen(rest);
459 pairadd(&request, vp);
460 } /* else no memory! Die, die!: FIXME!! */
468 * Compare the current time to a range.
469 * Hmm... it would save work, and probably be better,
470 * if we were passed the REQUEST data structure, so we
471 * could use it's 'timestamp' element. That way, we could
472 * do the comparison against when the packet came in, not now,
473 * and have one less system call to do.
475 static int timecmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
476 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
479 request = request; /* shut the compiler up */
480 check_pairs = check_pairs;
481 reply_pairs = reply_pairs;
483 if (timestr_match((char *)check->strvalue, time(NULL)) >= 0) {
490 * Matches if there is NO SUCH ATTRIBUTE as the one named
491 * in check->strvalue. If there IS such an attribute, it
494 * This is ugly, and definitely non-optimal. We should be
495 * doing the lookup only ONCE, and storing the result
496 * in check->lvalue...
498 static int attrcmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
499 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
506 check_pairs = check_pairs; /* shut the compiler up */
507 reply_pairs = reply_pairs;
509 if (check->lvalue == 0) {
510 dict = dict_attrbyname((char *)check->strvalue);
516 attr = check->lvalue;
520 * If there's no such attribute, then return MATCH,
523 pair = pairfind(request, attr);
532 * Compare the expiration date.
534 static int expirecmp(void *instance, VALUE_PAIR *request, VALUE_PAIR *check,
535 VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
540 request = request; /* shut the compiler up */
541 check_pairs = check_pairs;
542 reply_pairs = reply_pairs;
545 * FIXME! This should be request->timestamp!
549 if (now <= check->lvalue) {
557 * Register server-builtin special attributes.
559 void pair_builtincompare_init(void)
561 paircompare_register(PW_NAS_PORT_ID, -1, portcmp, NULL);
562 paircompare_register(PW_PREFIX, PW_USER_NAME, presufcmp, NULL);
563 paircompare_register(PW_SUFFIX, PW_USER_NAME, presufcmp, NULL);
564 paircompare_register(PW_CONNECT_RATE, PW_CONNECT_INFO, connectcmp, NULL);
565 paircompare_register(PW_CURRENT_TIME, 0, timecmp, NULL);
566 paircompare_register(PW_NO_SUCH_ATTRIBUTE, 0, attrcmp, NULL);
567 paircompare_register(PW_EXPIRATION, 0, expirecmp, NULL);