summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_expr/paircmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/rlm_expr/paircmp.c')
-rw-r--r--src/modules/rlm_expr/paircmp.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/modules/rlm_expr/paircmp.c b/src/modules/rlm_expr/paircmp.c
new file mode 100644
index 0000000..cc69cc1
--- /dev/null
+++ b/src/modules/rlm_expr/paircmp.c
@@ -0,0 +1,231 @@
+/*
+ * paircmp.c Valuepair functions for various attributes
+ *
+ * Version: $Id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * 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,2006 The FreeRADIUS server project
+ * Copyright 2000 Alan DeKok <aland@ox.org>
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
+#include "rlm_expr.h"
+
+/*
+ * Compare prefix/suffix.
+ *
+ * If they compare:
+ * - if PW_STRIP_USER_NAME is present in check_pairs,
+ * strip the username of prefix/suffix.
+ * - if PW_STRIP_USER_NAME is not present in check_pairs,
+ * add a PW_STRIPPED_USER_NAME to the request.
+ */
+static int presufcmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ VALUE_PAIR *vp;
+ char const *name;
+ char rest[MAX_STRING_LEN];
+ int len, namelen;
+ int ret = -1;
+
+ if (!request->username) {
+ return -1;
+ }
+
+ VERIFY_VP(request->username);
+ VERIFY_VP(check);
+ rad_assert(request->username->da->type == PW_TYPE_STRING);
+
+ name = request->username->vp_strvalue;
+
+#if 0 /* DEBUG */
+ printf("Comparing %s and %s, check->attr is %d\n", name, check->vp_strvalue, check->attribute);
+#endif
+
+ len = strlen(check->vp_strvalue);
+ if (check->da->vendor == 0) switch (check->da->attr) {
+ case PW_PREFIX:
+ ret = strncmp(name, check->vp_strvalue, len);
+ if (ret == 0)
+ strlcpy(rest, name + len, sizeof(rest));
+ break;
+ case PW_SUFFIX:
+ namelen = strlen(name);
+ if (namelen < len)
+ break;
+ ret = strcmp(name + namelen - len,
+ check->vp_strvalue);
+ if (ret == 0) {
+ strlcpy(rest, name, namelen - len + 1);
+ }
+ break;
+ }
+ if (ret != 0) {
+ return ret;
+ }
+
+ /*
+ * If Strip-User-Name == No, then don't do any more.
+ */
+ vp = fr_pair_find_by_num(check_pairs, PW_STRIP_USER_NAME, 0, TAG_ANY);
+ if (vp && !vp->vp_integer) return ret;
+
+ /*
+ * See where to put the stripped user name.
+ */
+ vp = fr_pair_find_by_num(check_pairs, PW_STRIPPED_USER_NAME, 0, TAG_ANY);
+ if (!vp) {
+ vp = radius_pair_create(request->packet, &request->packet->vps, PW_STRIPPED_USER_NAME, 0);
+ if (!vp) return ret;
+ request->username = vp;
+ }
+
+ fr_pair_value_strcpy(vp, rest);
+
+ return ret;
+}
+
+
+/*
+ * Compare the request packet type.
+ */
+static int packetcmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if (request->packet->code == check->vp_integer) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Compare the response packet type.
+ */
+static int responsecmp(UNUSED void *instance,
+ REQUEST *request,
+ UNUSED VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if (request->reply->code == check->vp_integer) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Generic comparisons, via xlat.
+ */
+static int genericcmp(UNUSED void *instance,
+ REQUEST *request,
+ VALUE_PAIR *req,
+ VALUE_PAIR *check,
+ UNUSED VALUE_PAIR *check_pairs,
+ UNUSED VALUE_PAIR **reply_pairs)
+{
+ if ((check->op != T_OP_REG_EQ) &&
+ (check->op != T_OP_REG_NE)) {
+ int rcode;
+ char name[1024];
+ char value[1024];
+ VALUE_PAIR *vp;
+
+ snprintf(name, sizeof(name), "%%{%s}", check->da->name);
+
+ if (radius_xlat(value, sizeof(value), request, name, NULL, NULL) < 0) {
+ return 0;
+ }
+ vp = fr_pair_make(req, NULL, check->da->name, value, check->op);
+
+ /*
+ * Paircmp returns 0 for failed comparison,
+ * 1 for succeeded.
+ */
+ rcode = fr_pair_cmp(check, vp);
+
+ /*
+ * We're being called from radius_callback_compare,
+ * which wants 0 for success, and 1 for fail (sigh)
+ *
+ * We should really fix the API so that it is
+ * consistent. i.e. the comparison callbacks should
+ * return ONLY the resut of comparing A to B.
+ * The radius_callback_cmp function should then
+ * take care of using the operator to see if the
+ * condition (A OP B) is true or not.
+ *
+ * This would also allow "<", etc. to work in the
+ * callback functions...
+ *
+ * See rlm_ldap, ...groupcmp() for something that
+ * returns 0 for matched, and 1 for didn't match.
+ */
+ rcode = !rcode;
+ fr_pair_list_free(&vp);
+
+ return rcode;
+ }
+
+ /*
+ * Will do the xlat for us
+ */
+ return radius_compare_vps(request, check, req);
+}
+
+static int generic_attrs[] = {
+ PW_CLIENT_IP_ADDRESS,
+ PW_PACKET_SRC_IP_ADDRESS,
+ PW_PACKET_DST_IP_ADDRESS,
+ PW_PACKET_SRC_PORT,
+ PW_PACKET_DST_PORT,
+ PW_REQUEST_PROCESSING_STAGE,
+ PW_PACKET_SRC_IPV6_ADDRESS,
+ PW_PACKET_DST_IPV6_ADDRESS,
+ PW_VIRTUAL_SERVER,
+ 0
+};
+
+/*
+ * Register server-builtin special attributes.
+ */
+void pair_builtincompare_add(void *instance)
+{
+ int i;
+
+ paircompare_register(dict_attrbyvalue(PW_PREFIX, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, presufcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_SUFFIX, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, presufcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_PACKET_TYPE, 0), NULL, true, packetcmp, instance);
+ paircompare_register(dict_attrbyvalue(PW_RESPONSE_PACKET_TYPE, 0), NULL, true, responsecmp, instance);
+
+ for (i = 0; generic_attrs[i] != 0; i++) {
+ paircompare_register(dict_attrbyvalue(generic_attrs[i], 0), NULL, true, genericcmp, instance);
+ }
+}