X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fvaluepair.c;h=96d76c30476927a19e5c665bd43005ed8b8036e8;hb=06abdefb5b1f70a21af63dc369aaf6116565ec9b;hp=f6d620099979080623fc935807960d25037b088e;hpb=73e197cdd04d0a69da8d173aa3be7b295baa113b;p=freeradius.git diff --git a/src/main/valuepair.c b/src/main/valuepair.c index f6d6200..96d76c3 100644 --- a/src/main/valuepair.c +++ b/src/main/valuepair.c @@ -18,21 +18,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * Copyright 2000 The FreeRADIUS server project + * Copyright 2000,2006 The FreeRADIUS server project * Copyright 2000 Alan DeKok */ -static const char rcsid[] = "$Id$"; +#include +RCSID("$Id$") -#include - -#include -#include -#include - -#ifdef HAVE_NETINET_IN_H -# include -#endif +#include +#include #ifdef HAVE_REGEX_H # include @@ -51,47 +45,150 @@ static const char rcsid[] = "$Id$"; #endif #endif -#include - struct cmp { - int attribute; - int otherattr; + unsigned int attribute; + unsigned int otherattr; void *instance; /* module instance */ RAD_COMPARE_FUNC compare; struct cmp *next; }; static struct cmp *cmp; - -/* - * Compare 2 attributes. May call the attribute compare function. - */ -static int compare_pair(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, - VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs) +int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp) { int ret = -2; - struct cmp *c; /* * Check for =* and !* and return appropriately */ if( check->operator == T_OP_CMP_TRUE ) - return 0; /* always return 0/EQUAL */ + return 0; if( check->operator == T_OP_CMP_FALSE ) - return 1; /* always return 1/NOT EQUAL */ + return 1; + +#ifdef HAVE_REGEX_H + if (check->operator == T_OP_REG_EQ) { + int i, compare; + regex_t reg; + char name[1024]; + char value[1024]; + regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; + + snprintf(name, sizeof(name), "%%{%s}", check->name); + radius_xlat(value, sizeof(value), name, request, NULL); + + /* + * Include substring matches. + */ + compare = regcomp(®, check->vp_strvalue, REG_EXTENDED); + if (compare != 0) { + char buffer[256]; + regerror(compare, ®, buffer, sizeof(buffer)); + + RDEBUG("Invalid regular expression %s: %s", + check->vp_strvalue, buffer); + return -1; + } + compare = regexec(®, value, REQUEST_MAX_REGEX + 1, + rxmatch, 0); + regfree(®); + + /* + * Add %{0}, %{1}, etc. + */ + for (i = 0; i <= REQUEST_MAX_REGEX; i++) { + char *p; + char buffer[sizeof(check->vp_strvalue)]; + + /* + * Didn't match: delete old + * match, if it existed. + */ + if ((compare != 0) || + (rxmatch[i].rm_so == -1)) { + p = request_data_get(request, request, + REQUEST_DATA_REGEX | i); + if (p) { + free(p); + continue; + } + + /* + * No previous match + * to delete, stop. + */ + break; + } + + /* + * Copy substring into buffer. + */ + memcpy(buffer, value + rxmatch[i].rm_so, + rxmatch[i].rm_eo - rxmatch[i].rm_so); + buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; + + /* + * Copy substring, and add it to + * the request. + * + * Note that we don't check + * for out of memory, which is + * the only error we can get... + */ + p = strdup(buffer); + request_data_add(request, request, + REQUEST_DATA_REGEX | i, + p, free); + } + if (compare == 0) return 0; + return -1; + } + + if (check->operator == T_OP_REG_NE) { + int compare; + regex_t reg; + char name[1024]; + char value[1024]; + regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; + + snprintf(name, sizeof(name), "%%{%s}", check->name); + radius_xlat(value, sizeof(value), name, request, NULL); + + /* + * Include substring matches. + */ + compare = regcomp(®, (char *)check->vp_strvalue, + REG_EXTENDED); + if (compare != 0) { + char buffer[256]; + regerror(compare, ®, buffer, sizeof(buffer)); + + RDEBUG("Invalid regular expression %s: %s", + check->vp_strvalue, buffer); + return -1; + } + compare = regexec(®, value, REQUEST_MAX_REGEX + 1, + rxmatch, 0); + regfree(®); + + if (compare != 0) return 0; + return -1; + + } +#endif /* - * See if there is a special compare function. - * - * FIXME: use new RB-Tree code. + * Tagged attributes are equal if and only if both the + * tag AND value match. */ - for (c = cmp; c; c = c->next) - if (c->attribute == check->attribute) - return (c->compare)(c->instance, req, request, check, - check_pairs, reply_pairs); - - if (!request) return -1; /* doesn't exist, don't compare it */ + if (check->flags.has_tag) { + ret = ((int) vp->flags.tag) - ((int) check->flags.tag); + if (ret != 0) return ret; + } + /* + * Not a regular expression, compare the types. + */ switch(check->type) { #ifdef ASCEND_BINARY /* @@ -101,42 +198,41 @@ static int compare_pair(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, case PW_TYPE_ABINARY: #endif case PW_TYPE_OCTETS: - if (request->length != check->length) { + if (vp->length != check->length) { ret = 1; /* NOT equal */ break; } - ret = memcmp(request->vp_strvalue, check->vp_strvalue, - request->length); + ret = memcmp(vp->vp_strvalue, check->vp_strvalue, + vp->length); break; case PW_TYPE_STRING: - if (check->flags.caseless) { - ret = strcasecmp((char *)request->vp_strvalue, - (char *)check->vp_strvalue); - } else { - ret = strcmp((char *)request->vp_strvalue, - (char *)check->vp_strvalue); - } + ret = strcmp((char *)vp->vp_strvalue, + (char *)check->vp_strvalue); break; + case PW_TYPE_BYTE: + case PW_TYPE_SHORT: case PW_TYPE_INTEGER: + ret = vp->vp_integer - check->vp_integer; + break; case PW_TYPE_DATE: - ret = request->lvalue - check->lvalue; + ret = vp->vp_date - check->vp_date; break; case PW_TYPE_IPADDR: - ret = ntohl(request->vp_ipaddr) - ntohl(check->vp_ipaddr); + ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr); break; case PW_TYPE_IPV6ADDR: - ret = memcmp(&request->vp_ipv6addr, &check->vp_ipv6addr, - sizeof(request->vp_ipv6addr)); + ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, + sizeof(vp->vp_ipv6addr)); break; - + case PW_TYPE_IPV6PREFIX: - ret = memcmp(&request->vp_ipv6prefix, &check->vp_ipv6prefix, - sizeof(request->vp_ipv6prefix)); + ret = memcmp(&vp->vp_ipv6prefix, &check->vp_ipv6prefix, + sizeof(vp->vp_ipv6prefix)); break; - + case PW_TYPE_IFID: - ret = memcmp(&request->vp_ifid, &check->vp_ifid, - sizeof(request->vp_ifid)); + ret = memcmp(&vp->vp_ifid, &check->vp_ifid, + sizeof(vp->vp_ifid)); break; default: @@ -148,9 +244,61 @@ static int compare_pair(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, /* + * Compare 2 attributes. May call the attribute compare function. + */ +int radius_callback_compare(REQUEST *req, VALUE_PAIR *request, + VALUE_PAIR *check, VALUE_PAIR *check_pairs, + VALUE_PAIR **reply_pairs) +{ + struct cmp *c; + + /* + * Check for =* and !* and return appropriately + */ + if( check->operator == T_OP_CMP_TRUE ) + return 0; /* always return 0/EQUAL */ + if( check->operator == T_OP_CMP_FALSE ) + return 1; /* always return 1/NOT EQUAL */ + + /* + * See if there is a special compare function. + * + * FIXME: use new RB-Tree code. + */ + for (c = cmp; c; c = c->next) + if ((c->attribute == check->attribute) && + (check->vendor == 0)) { + return (c->compare)(c->instance, req, request, check, + check_pairs, reply_pairs); + } + + if (!request) return -1; /* doesn't exist, don't compare it */ + + return radius_compare_vps(req, check, request); +} + + +/* + * Find a comparison function for two attributes. + */ +int radius_find_compare(unsigned int attribute) +{ + struct cmp *c; + + for (c = cmp; c; c = c->next) { + if (c->attribute == attribute) { + return TRUE; + } + } + + return FALSE; +} + + +/* * See what attribute we want to compare with. */ -static int otherattr(int attr) +static int otherattr(unsigned int attr) { struct cmp *c; @@ -175,7 +323,7 @@ static int otherattr(int attr) * For example, PW_GROUP in a check item needs to be compared * with PW_USER_NAME in the incoming request. */ -int paircompare_register(int attr, int compare_attr, RAD_COMPARE_FUNC fun, void *instance) +int paircompare_register(unsigned int attr, int compare_attr, RAD_COMPARE_FUNC fun, void *instance) { struct cmp *c; @@ -183,8 +331,6 @@ int paircompare_register(int attr, int compare_attr, RAD_COMPARE_FUNC fun, void c = rad_malloc(sizeof(struct cmp)); - if (compare_attr < 0) - compare_attr = attr; c->compare = fun; c->attribute = attr; c->otherattr = compare_attr; @@ -198,7 +344,7 @@ int paircompare_register(int attr, int compare_attr, RAD_COMPARE_FUNC fun, void /* * Unregister a function. */ -void paircompare_unregister(int attr, RAD_COMPARE_FUNC fun) +void paircompare_unregister(unsigned int attr, RAD_COMPARE_FUNC fun) { struct cmp *c, *last; @@ -233,9 +379,6 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR int result = 0; int compare; int other; -#ifdef HAVE_REGEX_H - regex_t reg; -#endif for (check_item = check; check_item != NULL; check_item = check_item->next) { /* @@ -272,7 +415,12 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR * This hack makes CHAP-Password work.. */ case PW_USER_PASSWORD: - if (pairfind(request, PW_USER_PASSWORD) == NULL) { + if (check_item->operator == T_OP_CMP_EQ) { + DEBUG("WARNING: Found User-Password == \"...\"."); + DEBUG("WARNING: Are you sure you don't mean Cleartext-Password?"); + DEBUG("WARNING: See \"man rlm_pap\" for more information."); + } + if (pairfind(request, PW_USER_PASSWORD, 0) == NULL) { continue; } break; @@ -285,9 +433,11 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR auth_item = request; try_again: - for (; auth_item != NULL; auth_item = auth_item->next) { - if (auth_item->attribute == other || other == 0) - break; + if (other >= 0) { + for (; auth_item != NULL; auth_item = auth_item->next) { + if (auth_item->attribute == (unsigned int) other || other == 0) + break; + } } /* @@ -299,7 +449,7 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR * to not find it, then we succeeded. */ if (check_item->operator == T_OP_CMP_FALSE) - return 0; + continue; else return -1; } @@ -334,7 +484,8 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR /* * OK it is present now compare them. */ - compare = compare_pair(req, auth_item, check_item, check, reply); + compare = radius_callback_compare(req, auth_item, check_item, + check, reply); switch (check_item->operator) { case T_OP_EQ: @@ -370,104 +521,17 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR #ifdef HAVE_REGEX_H case T_OP_REG_EQ: - { - int i; - regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; - - if ((auth_item->type == PW_TYPE_IPADDR) && - (auth_item->vp_strvalue[0] == '\0')) { - inet_ntop(AF_INET, &(auth_item->lvalue), - auth_item->vp_strvalue, - sizeof(auth_item->vp_strvalue)); - } - - /* - * Include substring matches. - */ - regcomp(®, (char *)check_item->vp_strvalue, - REG_EXTENDED); - compare = regexec(®, - (char *)auth_item->vp_strvalue, - REQUEST_MAX_REGEX + 1, - rxmatch, 0); - regfree(®); - - /* - * Add %{0}, %{1}, etc. - */ - for (i = 0; i <= REQUEST_MAX_REGEX; i++) { - char *p; - char buffer[sizeof(check_item->vp_strvalue)]; - - /* - * Didn't match: delete old - * match, if it existed. - */ - if ((compare != 0) || - (rxmatch[i].rm_so == -1)) { - p = request_data_get(req, req, - REQUEST_DATA_REGEX | i); - if (p) { - free(p); - continue; - } - - /* - * No previous match - * to delete, stop. - */ - break; - } - - /* - * Copy substring into buffer. - */ - memcpy(buffer, - auth_item->vp_strvalue + rxmatch[i].rm_so, - rxmatch[i].rm_eo - rxmatch[i].rm_so); - buffer[rxmatch[i].rm_eo - rxmatch[i].rm_so] = '\0'; - - /* - * Copy substring, and add it to - * the request. - * - * Note that we don't check - * for out of memory, which is - * the only error we can get... - */ - p = strdup(buffer); - request_data_add(req, - req, - REQUEST_DATA_REGEX | i, - p, free); - } - } - if (compare != 0) result = -1; - break; - case T_OP_REG_NE: - if ((auth_item->type == PW_TYPE_IPADDR) && - (auth_item->vp_strvalue[0] == '\0')) { - inet_ntop(AF_INET, &(auth_item->lvalue), - auth_item->vp_strvalue, - sizeof(auth_item->vp_strvalue)); - } - - regcomp(®, (char *)check_item->vp_strvalue, REG_EXTENDED|REG_NOSUB); - compare = regexec(®, (char *)auth_item->vp_strvalue, - 0, NULL, 0); - regfree(®); - if (compare == 0) result = -1; + result = compare; break; #endif - } /* switch over the operator of the check item */ /* * This attribute didn't match, but maybe there's * another of the same attribute, which DOES match. */ - if (result != 0) { + if ((result != 0) && (other >= 0)) { auth_item = auth_item->next; result = 0; goto try_again; @@ -475,20 +539,10 @@ int paircompare(REQUEST *req, VALUE_PAIR *request, VALUE_PAIR *check, VALUE_PAIR } /* for every entry in the check item list */ - return 0; /* it matched */ + return result; } /* - * Compare two attributes simply. Calls compare_pair. - */ - -int simplepaircmp(REQUEST *req, VALUE_PAIR *first, VALUE_PAIR *second) -{ - return compare_pair( req, first, second, NULL, NULL ); -} - - -/* * Move pairs, replacing/over-writing them, and doing xlat. */ /* @@ -519,6 +573,7 @@ void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from) * Don't move 'fallthrough' over. */ if (i->attribute == PW_FALL_THROUGH) { + tailfrom = i; continue; } @@ -541,7 +596,7 @@ void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from) pairparsevalue(i, buffer); } - found = pairfind(*to, i->attribute); + found = pairfind(*to, i->attribute, i->vendor); switch (i->operator) { /* @@ -553,7 +608,7 @@ void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from) if (!i->vp_strvalue[0] || (strcmp((char *)found->vp_strvalue, (char *)i->vp_strvalue) == 0)){ - pairdelete(to, found->attribute); + pairdelete(to, found->attribute, found->vendor); /* * 'tailto' may have been @@ -591,6 +646,7 @@ void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from) vp = found->next; memcpy(found, i, sizeof(*found)); found->next = vp; + tailfrom = i; continue; } break; @@ -631,3 +687,72 @@ void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from) } } /* loop over the 'from' list */ } + +/* + * Create a pair, and add it to a particular list of VPs + * + * Note that this function ALWAYS returns. If we're OOM, then + * it causes the server to exit! + */ +VALUE_PAIR *radius_paircreate(REQUEST *request, VALUE_PAIR **vps, + unsigned int attribute, unsigned int vendor, int type) +{ + VALUE_PAIR *vp; + + request = request; /* -Wunused */ + + vp = paircreate(attribute, vendor, type); + if (!vp) { + radlog(L_ERR, "No memory!"); + rad_assert("No memory" == NULL); + _exit(1); + } + + if (vps) pairadd(vps, vp); + + return vp; +} + +/* + * Create a pair, and add it to a particular list of VPs + * + * Note that this function ALWAYS returns. If we're OOM, then + * it causes the server to exit! + */ +VALUE_PAIR *radius_pairmake(REQUEST *request, VALUE_PAIR **vps, + const char *attribute, const char *value, + int operator) +{ + VALUE_PAIR *vp; + + request = request; /* -Wunused */ + + vp = pairmake(attribute, value, operator); + if (!vp) return NULL; + + if (vps) pairadd(vps, vp); + + return vp; +} + +void debug_pair(VALUE_PAIR *vp) +{ + if (!vp || !debug_flag || !fr_log_fp) return; + + fputc('\t', fr_log_fp); + vp_print(fr_log_fp, vp); + fputc('\n', fr_log_fp); +} + +void debug_pair_list(VALUE_PAIR *vp) +{ + if (!vp || !debug_flag || !fr_log_fp) return; + + while (vp) { + fputc('\t', fr_log_fp); + vp_print(fr_log_fp, vp); + fputc('\n', fr_log_fp); + vp = vp->next; + } + fflush(fr_log_fp); +}