📄 rlm_attr_filter.c
字号:
/* * rlm_attr_filter.c - Filter A/V Pairs received back from proxy reqs * before sending reply to the NAS/Server that sent * it to us. * * Version: $Id: rlm_attr_filter.c,v 1.19.2.1 2005/08/11 21:06:38 aland Exp $ * * This program is is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2 if the * License as published by the Free Software Foundation. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Copyright (C) 2001 The FreeRADIUS server project * Copyright (C) 2001 Chris Parker <cparker@starnetusa.net> */#include "autoconf.h"#include "libradius.h"#include <sys/stat.h>#include <stdlib.h>#include <string.h>#include <netdb.h>#include <ctype.h>#include <fcntl.h>#include <limits.h>#ifdef HAVE_REGEX_H# include <regex.h>#endif#include "radiusd.h"#include "modules.h"static const char rcsid[] = "$Id: rlm_attr_filter.c,v 1.19.2.1 2005/08/11 21:06:38 aland Exp $";struct attr_filter_instance { /* autz */ char *attrsfile; PAIR_LIST *attrs;};static int check_pair(VALUE_PAIR *check_item, VALUE_PAIR *reply_item, int comp, int *pa, int *fa) {#ifdef HAVE_REGEX_H regex_t reg;#endif switch(check_item->operator) { case T_OP_SET: /* nothing to do for set */ break; case T_OP_EQ: default: radlog(L_ERR, "Invalid operator for item %s: " "reverting to '=='", check_item->name); case T_OP_CMP_TRUE: /* comp always == 0 */ case T_OP_CMP_FALSE: /* comp always == 1 */ case T_OP_CMP_EQ: if (comp == 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_NE: if (comp != 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_LT: if (comp < 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_GT: if (comp > 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_LE: if (comp <= 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_GE: if (comp >= 0) { ++*(pa); } else { ++*(fa); } break;#ifdef HAVE_REGEX_H case T_OP_REG_EQ: regcomp(®, (char *)check_item->strvalue, REG_EXTENDED); comp = regexec(®, (char *)reply_item->strvalue, 0, NULL, 0); regfree(®); if (comp == 0) { ++*(pa); } else { ++*(fa); } break; case T_OP_REG_NE: regcomp(®, (char *)check_item->strvalue, REG_EXTENDED); comp = regexec(®, (char *)reply_item->strvalue, 0, NULL, 0); regfree(®); if (comp != 0) { ++*(pa); } else { ++*(fa); } break;#endif } return 0;}/* * Copy the specified attribute to the specified list */static int mypairappend(VALUE_PAIR *item, VALUE_PAIR **to){ VALUE_PAIR *tmp; tmp = paircreate(item->attribute, item->type); if (!tmp) { radlog(L_ERR|L_CONS, "no memory"); return -1; } /* * Copy EVERYTHING. */ memcpy(tmp, item, sizeof(*tmp)); tmp->next = NULL; pairadd(to, tmp); return 0;}/* * See if a VALUE_PAIR list contains Fall-Through = Yes */static int fallthrough(VALUE_PAIR *vp){ VALUE_PAIR *tmp; tmp = pairfind(vp, PW_FALL_THROUGH); return tmp ? tmp->lvalue : 0;}static CONF_PARSER module_config[] = { { "attrsfile", PW_TYPE_STRING_PTR, offsetof(struct attr_filter_instance,attrsfile), NULL, "${raddbdir}/attrs" }, { NULL, -1, 0, NULL, NULL }};static int getattrsfile(const char *filename, PAIR_LIST **pair_list){ int rcode; PAIR_LIST *attrs = NULL; PAIR_LIST *entry; VALUE_PAIR *vp; rcode = pairlist_read(filename, &attrs, 1); if (rcode < 0) { return -1; } /* * Walk through the 'attrs' file list. */ entry = attrs; while (entry) { entry->check = entry->reply; entry->reply = NULL; for (vp = entry->check; vp != NULL; vp = vp->next) { /* * If it's NOT a vendor attribute, * and it's NOT a wire protocol * and we ignore Fall-Through, * then bitch about it, giving a good warning message. */ if (!(vp->attribute & ~0xffff) && (vp->attribute > 0xff) && (vp->attribute > 1000)) { log_debug("[%s]:%d WARNING! Check item \"%s\"\n" "\tfound in filter list for realm \"%s\".\n", filename, entry->lineno, vp->name, entry->name); } } entry = entry->next; } *pair_list = attrs; return 0;}/* * (Re-)read the "attrs" file into memory. */static int attr_filter_instantiate(CONF_SECTION *conf, void **instance){ struct attr_filter_instance *inst; int rcode; inst = rad_malloc(sizeof *inst); if (!inst) { return -1; } memset(inst, 0, sizeof(*inst)); if (cf_section_parse(conf, inst, module_config) < 0) { free(inst); return -1; } rcode = getattrsfile(inst->attrsfile, &inst->attrs); if (rcode != 0) { radlog(L_ERR|L_CONS, "Errors reading %s", inst->attrsfile); free(inst->attrsfile); free(inst); return -1; } radlog(L_ERR|L_CONS, " rlm_attr_filter: Authorize method will be"\ " deprecated."); *instance = inst; return 0;}static int attr_filter_authorize(void *instance, REQUEST *request){ struct attr_filter_instance *inst = instance; VALUE_PAIR *request_pairs; VALUE_PAIR **reply_items; VALUE_PAIR *reply_item; VALUE_PAIR *reply_tmp = NULL; VALUE_PAIR *check_item; PAIR_LIST *pl; int found = 0; int compare; int pass, fail; VALUE_PAIR *realmpair; REALM *realm; char *realmname; /* * It's not a proxy reply, so return NOOP */ if( request->proxy == NULL ) { return( RLM_MODULE_NOOP ); } request_pairs = request->packet->vps; reply_items = &request->reply->vps; /* * Get the realm. Can't use request->config_items as * that gets freed by rad_authenticate.... use the one * set in the original request vps */ realmpair = pairfind(request_pairs, PW_REALM); if(!realmpair) { /* Can't find a realm, so no filtering of attributes * or should we use a DEFAULT entry? * For now, just return NOTFOUND. (maybe NOOP?) */ return RLM_MODULE_NOTFOUND; } realmname = (char *) realmpair->strvalue; realm = realm_find(realmname, FALSE); /* * Find the attr_filter profile entry for the realm. */ for(pl = inst->attrs; pl; pl = pl->next) { /* * If the current entry is NOT a default, * AND the realm does NOT match the current entry, * then skip to the next entry. */ if ( (strcmp(pl->name, "DEFAULT") != 0) && (strcmp(realmname, pl->name) != 0) ) { continue; } DEBUG2(" attr_filter: Matched entry %s at line %d", pl->name, pl->lineno); found = 1; check_item = pl->check; while( check_item != NULL ) { /* * If it is a SET operator, add the attribute to * the reply list without checking reply_items. * */ if( check_item->operator == T_OP_SET ) { if (mypairappend(check_item, &reply_tmp) < 0) { return RLM_MODULE_FAIL; } } check_item = check_item->next; } /* * Iterate through the reply items, comparing each reply item * to every rule, then moving it to the reply_tmp list * only if it matches all rules for that attribute. * IE, Idle-Timeout is moved only if it matches all rules that * describe an Idle-Timeout. */ for(reply_item = *reply_items; reply_item != NULL; reply_item = reply_item->next ) { /* reset the pass,fail vars for each reply item */ pass = fail = 0; /* reset the check_item pointer to beginning of the list */ check_item = pl->check; while( check_item != NULL ) { if(reply_item->attribute == check_item->attribute) { compare = simplepaircmp(request, reply_item, check_item); check_pair(check_item, reply_item, compare, &pass, &fail); } check_item = check_item->next; } /* only move attribute if it passed all rules */ if (fail == 0 && pass > 0) { if (mypairappend( reply_item, &reply_tmp) < 0) { return RLM_MODULE_FAIL; } } } /* If we shouldn't fall through, break */ if(!fallthrough(pl->check)) break; } pairfree(&request->reply->vps); request->reply->vps = reply_tmp; /* * See if we succeeded. If we didn't find the realm, * then exit from the module. */ if (!found) return RLM_MODULE_OK; /* * Remove server internal parameters. */ pairdelete(reply_items, PW_FALL_THROUGH); return RLM_MODULE_UPDATED;}static int attr_filter_accounting(void *instance, REQUEST *request){ struct attr_filter_instance *inst = instance; VALUE_PAIR *request_pairs; VALUE_PAIR *send_item;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -