* 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 <aland@ox.org>
*/
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-#include <freeradius-devel/autoconf.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
#ifdef HAVE_REGEX_H
# include <regex.h>
#endif
#endif
-#include <freeradius-devel/radiusd.h>
-
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
/*
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:
/*
+ * 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;
* 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;
c = rad_malloc(sizeof(struct cmp));
- if (compare_attr < 0)
- compare_attr = attr;
c->compare = fun;
c->attribute = attr;
c->otherattr = compare_attr;
/*
* 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;
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) {
/*
*
* This hack makes CHAP-Password work..
*/
- case PW_PASSWORD:
- if (pairfind(request, PW_PASSWORD) == NULL) {
+ case PW_USER_PASSWORD:
+ 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;
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;
+ }
}
/*
* to not find it, then we succeeded.
*/
if (check_item->operator == T_OP_CMP_FALSE)
- return 0;
+ continue;
else
return -1;
}
/*
* 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:
#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;
} /* 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.
*/
/*
* Don't move 'fallthrough' over.
*/
if (i->attribute == PW_FALL_THROUGH) {
+ tailfrom = i;
continue;
}
pairparsevalue(i, buffer);
}
- found = pairfind(*to, i->attribute);
+ found = pairfind(*to, i->attribute, i->vendor);
switch (i->operator) {
/*
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
vp = found->next;
memcpy(found, i, sizeof(*found));
found->next = vp;
+ tailfrom = i;
continue;
}
break;
}
} /* 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);
+}