*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2001 The FreeRADIUS server project
- * Copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
+ * Copyright 2002,2006 The FreeRADIUS server project
+ * Copyright 2002 Kostas Kalevras <kkalev@noc.ntua.gr>
*/
-#include "config.h"
-#include "autoconf.h"
-#include "libradius.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "config.h"
-#if HAVE_REGEX_H
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
+
+#ifdef HAVE_REGEX_H
# include <regex.h>
#endif
-#include "radiusd.h"
-#include "modules.h"
-#include "conffile.h"
-
#define RLM_REGEX_INPACKET 0
#define RLM_REGEX_INCONFIG 1
#define RLM_REGEX_INREPLY 2
-
-static const char rcsid[] = "$Id$";
+#define RLM_REGEX_INPROXY 3
+#define RLM_REGEX_INPROXYREPLY 4
typedef struct rlm_attr_rewrite_t {
char *attribute; /* The attribute to search for */
- int attr_num; /* The attribute number */
+ DICT_ATTR *da; /* The attribute definition */
char *search; /* The pattern to search for */
- char *searchin_str; /* The VALUE_PAIR list to search in. Can be either packet,reply or config */
+ int search_len; /* The length of the search pattern */
+ char *searchin_str; /* The VALUE_PAIR list to search in. Can be either packet,reply,proxy,proxy_reply or control (plus it's alias 'config') */
char searchin; /* The same as above just coded as a number for speed */
char *replace; /* The replacement */
+ int replace_len; /* The length of the replacement string */
+ int append; /* Switch to control append mode (1,0) */
int nocase; /* Ignore case */
int new_attr; /* Boolean. Do we create a new attribute or not? */
int num_matches; /* Maximum number of matches */
- char *name; /* The module name */
+ const char *name; /* The module name */
} rlm_attr_rewrite_t;
-
-static CONF_PARSER module_config[] = {
+static const CONF_PARSER module_config[] = {
{ "attribute", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,attribute), NULL, NULL },
{ "searchfor", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,search), NULL, NULL },
{ "searchin", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,searchin_str), NULL, "packet" },
{ "replacewith", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,replace), NULL, NULL },
+ { "append", PW_TYPE_BOOLEAN, offsetof(rlm_attr_rewrite_t,append),NULL, "no" },
{ "ignore_case", PW_TYPE_BOOLEAN, offsetof(rlm_attr_rewrite_t,nocase), NULL, "yes" },
{ "new_attribute", PW_TYPE_BOOLEAN, offsetof(rlm_attr_rewrite_t,new_attr), NULL, "no" },
{ "max_matches", PW_TYPE_INTEGER, offsetof(rlm_attr_rewrite_t,num_matches), NULL, "10" },
{ NULL, -1, 0, NULL, NULL }
};
-
static int attr_rewrite_instantiate(CONF_SECTION *conf, void **instance)
{
rlm_attr_rewrite_t *data;
DICT_ATTR *dattr;
- char *instance_name = NULL;
-
+
/*
* Set up a storage area for instance data
*/
data = rad_malloc(sizeof(*data));
+ if (!data) {
+ return -1;
+ }
+ memset(data, 0, sizeof(*data));
/*
* If the configuration parameters can't be parsed, then
}
/*
- * Discover the attribute number of the key.
+ * Discover the attribute number of the key.
*/
if (data->attribute == NULL) {
radlog(L_ERR, "rlm_attr_rewrite: 'attribute' must be set.");
radlog(L_ERR, "rlm_attr_rewrite: search/replace strings must be set.");
return -1;
}
+ data->search_len = strlen(data->search);
+ data->replace_len = strlen(data->replace);
+
+ if (data->replace_len == 0 && data->new_attr){
+ radlog(L_ERR, "rlm_attr_rewrite: replace string must not be zero length in order to create new attribute.");
+ return -1;
+ }
if (data->num_matches < 1 || data->num_matches > MAX_STRING_LEN) {
radlog(L_ERR, "rlm_attr_rewrite: Illegal range for match number.");
data->searchin = RLM_REGEX_INPACKET;
else if (strcmp(data->searchin_str, "config") == 0)
data->searchin = RLM_REGEX_INCONFIG;
+ else if (strcmp(data->searchin_str, "control") == 0)
+ data->searchin = RLM_REGEX_INCONFIG;
else if (strcmp(data->searchin_str, "reply") == 0)
data->searchin = RLM_REGEX_INREPLY;
+#ifdef WITH_PROXY
+ else if (strcmp(data->searchin_str, "proxy") == 0)
+ data->searchin = RLM_REGEX_INPROXY;
+ else if (strcmp(data->searchin_str, "proxy_reply") == 0)
+ data->searchin = RLM_REGEX_INPROXYREPLY;
+#endif
else {
radlog(L_ERR, "rlm_attr_rewrite: Illegal searchin directive given. Assuming packet.");
data->searchin = RLM_REGEX_INPACKET;
}
- free((char *)data->searchin_str);
}
dattr = dict_attrbyname(data->attribute);
if (dattr == NULL) {
data->attribute);
return -1;
}
- data->attr_num = dattr->attr;
+ data->da = dattr;
/* Add the module instance name */
- data->name = NULL;
- instance_name = cf_section_name2(conf);
- if (instance_name != NULL)
- data->name = strdup(instance_name);
-
-
+ data->name = cf_section_name2(conf); /* may be NULL */
+
*instance = data;
-
+
return 0;
}
rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
int ret = RLM_MODULE_NOOP;
VALUE_PAIR *attr_vp = NULL;
+ VALUE_PAIR *tmp = NULL;
regex_t preg;
- regmatch_t pmatch;
+ regmatch_t pmatch[9];
int cflags = 0;
int err = 0;
+ char done_xlat = 0;
unsigned int len = 0;
char err_msg[MAX_STRING_LEN];
unsigned int i = 0;
+ unsigned int j = 0;
unsigned int counter = 0;
char new_str[MAX_STRING_LEN];
char *ptr, *ptr2;
char search_STR[MAX_STRING_LEN];
char replace_STR[MAX_STRING_LEN];
- int replace_len = 0;
- if ((attr_vp = pairfind(request->config_items, PW_REWRITE_RULE)) != NULL){
- if (data->name == NULL || strcmp(data->name,attr_vp->strvalue))
+ if ((attr_vp = pairfind(request->config_items, PW_REWRITE_RULE, 0)) != NULL){
+ if (data->name == NULL || strcmp(data->name,attr_vp->vp_strvalue))
return RLM_MODULE_NOOP;
}
- if (!data->new_attr){
+ if (data->new_attr){
+ /* new_attribute = yes */
+ if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) {
+ DEBUG2("%s: xlat on replace string failed.", data->name);
+ return ret;
+ }
+ attr_vp = pairmake(data->attribute,replace_STR,0);
+ if (attr_vp == NULL){
+ DEBUG2("%s: Could not add new attribute %s with value '%s'", data->name,
+ data->attribute,replace_STR);
+ return ret;
+ }
+ switch(data->searchin){
+ case RLM_REGEX_INPACKET:
+ pairadd(&request->packet->vps,attr_vp);
+ break;
+ case RLM_REGEX_INCONFIG:
+ pairadd(&request->config_items,attr_vp);
+ break;
+ case RLM_REGEX_INREPLY:
+ pairadd(&request->reply->vps,attr_vp);
+ break;
+#ifdef WITH_PROXY
+ case RLM_REGEX_INPROXY:
+ if (!request->proxy) {
+ pairbasicfree(attr_vp);
+ return RLM_MODULE_NOOP;
+ }
+ pairadd(&request->proxy->vps, attr_vp);
+ break;
+ case RLM_REGEX_INPROXYREPLY:
+ if (!request->proxy_reply) {
+ pairbasicfree(attr_vp);
+ return RLM_MODULE_NOOP;
+ }
+ pairadd(&request->proxy_reply->vps, attr_vp);
+ break;
+#endif
+ default:
+ radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
+ data->searchin = RLM_REGEX_INPACKET;
+ pairadd(&request->packet->vps,attr_vp);
+ break;
+ }
+ DEBUG2("%s: Added attribute %s with value '%s'", data->name,data->attribute,replace_STR);
+ ret = RLM_MODULE_OK;
+ } else {
+ int replace_len = 0;
+
+ /* new_attribute = no */
switch (data->searchin) {
case RLM_REGEX_INPACKET:
- if (data->attr_num == PW_USER_NAME)
+ if (!data->da->vendor && (data->da->attr == PW_USER_NAME))
attr_vp = request->username;
- else if (data->attr_num == PW_PASSWORD)
+ else if (!data->da->vendor && (data->da->attr == PW_USER_PASSWORD))
attr_vp = request->password;
else
- attr_vp = pairfind(request->packet->vps, data->attr_num);
+ tmp = request->packet->vps;
break;
case RLM_REGEX_INCONFIG:
- attr_vp = pairfind(request->config_items, data->attr_num);
+ tmp = request->config_items;
break;
case RLM_REGEX_INREPLY:
- attr_vp = pairfind(request->reply->vps, data->attr_num);
+ tmp = request->reply->vps;
break;
+#ifdef WITH_PROXY
+ case RLM_REGEX_INPROXYREPLY:
+ if (!request->proxy_reply)
+ return RLM_MODULE_NOOP;
+ tmp = request->proxy_reply->vps;
+ break;
+ case RLM_REGEX_INPROXY:
+ if (!request->proxy)
+ return RLM_MODULE_NOOP;
+ tmp = request->proxy->vps;
+ break;
+#endif
default:
- radlog(L_ERR, "rlm_attr_rewrite: Illegal value for searchin. Changing to packet.");
+ radlog(L_ERR, "%s: Illegal value for searchin. Changing to packet.", data->name);
data->searchin = RLM_REGEX_INPACKET;
- attr_vp = pairfind(request->packet->vps, data->attr_num);
+ attr_vp = pairfind(request->packet->vps, data->da->attr, data->da->vendor);
break;
}
+do_again:
+ if (tmp != NULL)
+ attr_vp = pairfind(tmp, data->da->attr, data->da->vendor);
if (attr_vp == NULL) {
- DEBUG2("rlm_attr_rewrite: Could not find value pair for attribute %s",data->attribute);
+ DEBUG2("%s: Could not find value pair for attribute %s", data->name,data->attribute);
return ret;
}
- if (attr_vp->strvalue == NULL || attr_vp->length == 0){
- DEBUG2("rlm_attr_rewrite: Attribute %s string value NULL or of zero length",data->attribute);
+ if (attr_vp->vp_strvalue == NULL || attr_vp->length == 0){
+ DEBUG2("%s: Attribute %s string value NULL or of zero length", data->name,data->attribute);
return ret;
}
cflags |= REG_EXTENDED;
if (data->nocase)
cflags |= REG_ICASE;
- if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL)) {
- DEBUG2("rlm_attr_rewrite: xlat on search string failed.");
+ if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL) && data->search_len != 0) {
+ DEBUG2("%s: xlat on search string failed.", data->name);
return ret;
}
- }
- if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) {
- DEBUG2("rlm_attr_rewrite: xlat on replace string failed.");
- return ret;
- }
- replace_len = strlen(replace_STR);
- if (!data->new_attr){
if ((err = regcomp(&preg,search_STR,cflags))) {
regerror(err, &preg, err_msg, MAX_STRING_LEN);
- DEBUG2("rlm_attr_rewrite: regcomp() returned error: %s",err_msg);
+ DEBUG2("%s: regcomp() returned error: %s", data->name,err_msg);
return ret;
}
+
+ if ((attr_vp->type == PW_TYPE_IPADDR) &&
+ (attr_vp->vp_strvalue[0] == '\0')) {
+ inet_ntop(AF_INET, &(attr_vp->vp_ipaddr),
+ attr_vp->vp_strvalue,
+ sizeof(attr_vp->vp_strvalue));
+ }
+
ptr = new_str;
- ptr2 = attr_vp->strvalue;
+ ptr2 = attr_vp->vp_strvalue;
counter = 0;
- for ( /**/ ;i < data->num_matches; i++) {
- err = regexec(&preg, ptr2, 1, &pmatch, 0);
+ for ( i = 0 ;i < (unsigned)data->num_matches; i++) {
+ err = regexec(&preg, ptr2, REQUEST_MAX_REGEX, pmatch, 0);
if (err == REG_NOMATCH) {
if (i == 0) {
- DEBUG2("rlm_attr_rewrite: No match found for attribute %s with value '%s'",
- data->attribute, attr_vp->strvalue);
+ DEBUG2("%s: Does not match: %s = %s", data->name,
+ data->attribute, attr_vp->vp_strvalue);
regfree(&preg);
- return RLM_MODULE_OK;
+ goto to_do_again;
} else
break;
}
if (err != 0) {
regfree(&preg);
- radlog(L_ERR, "rlm_attr_rewrite: match failure for attribute %s with value '%s'",
- data->attribute, attr_vp->strvalue);
+ radlog(L_ERR, "%s: match failure for attribute %s with value '%s'", data->name,
+ data->attribute, attr_vp->vp_strvalue);
return ret;
}
- if (pmatch.rm_so == -1)
+ if (pmatch[0].rm_so == -1)
break;
- len = pmatch.rm_so;
+ len = pmatch[0].rm_so;
+ if (data->append) {
+ len = len + (pmatch[0].rm_eo - pmatch[0].rm_so);
+ }
counter += len;
if (counter >= MAX_STRING_LEN) {
regfree(&preg);
- DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value '%s'",
- data->attribute, attr_vp->strvalue);
+ DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
+ data->attribute, attr_vp->vp_strvalue);
return ret;
}
- strncpy(ptr, ptr2,len);
+ memcpy(ptr, ptr2,len);
ptr += len;
- ptr2 += pmatch.rm_eo;
+ *ptr = '\0';
+ ptr2 += pmatch[0].rm_eo;
+
+ if (i == 0){
+ /*
+ * We only run on the first match, sorry
+ */
+ for(j = 0; j <= REQUEST_MAX_REGEX; j++){
+ char *p;
+ char buffer[sizeof(attr_vp->vp_strvalue)];
+
+ /*
+ * Stolen from src/main/valuepair.c, paircompare()
+ */
+
+ /*
+ * Delete old matches if the corresponding match does not
+ * exist in the current regex
+ */
+ if (pmatch[j].rm_so == -1){
+ p = request_data_get(request,request,REQUEST_DATA_REGEX | j);
+ if (p){
+ free(p);
+ continue;
+ }
+ break;
+ }
+ memcpy(buffer,
+ attr_vp->vp_strvalue + pmatch[j].rm_so,
+ pmatch[j].rm_eo - pmatch[j].rm_so);
+ buffer[pmatch[j].rm_eo - pmatch[j].rm_so] = '\0';
+ p = strdup(buffer);
+ request_data_add(request,request,REQUEST_DATA_REGEX | j,p,free);
+ }
+ }
+
+ if (!done_xlat){
+ if (data->replace_len != 0 &&
+ radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL) == 0) {
+ DEBUG2("%s: xlat on replace string failed.", data->name);
+ return ret;
+ }
+ replace_len = (data->replace_len != 0) ? strlen(replace_STR) : 0;
+ done_xlat = 1;
+ }
counter += replace_len;
if (counter >= MAX_STRING_LEN) {
regfree(&preg);
- DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value '%s'",
- data->attribute, attr_vp->strvalue);
+ DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
+ data->attribute, attr_vp->vp_strvalue);
return ret;
}
- strncpy(ptr, replace_STR, replace_len);
- ptr += replace_len;
+ if (replace_len){
+ memcpy(ptr, replace_STR, replace_len);
+ ptr += replace_len;
+ *ptr = '\0';
+ }
}
regfree(&preg);
len = strlen(ptr2) + 1; /* We add the ending NULL */
counter += len;
if (counter >= MAX_STRING_LEN){
- DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value '%s'",
- data->attribute, attr_vp->strvalue);
+ DEBUG2("%s: Replacement out of limits for attribute %s with value '%s'", data->name,
+ data->attribute, attr_vp->vp_strvalue);
return ret;
}
- strncpy(ptr, ptr2, len);
+ memcpy(ptr, ptr2, len);
+ ptr[len] = '\0';
- DEBUG2("rlm_attr_rewrite: Changed value for attribute %s from '%s' to '%s'",
- data->attribute, attr_vp->strvalue, new_str);
- attr_vp->length = strlen(new_str);
- strncpy(attr_vp->strvalue, new_str, (attr_vp->length + 1));
+ DEBUG2("%s: Changed value for attribute %s from '%s' to '%s'", data->name,
+ data->attribute, attr_vp->vp_strvalue, new_str);
+ if (pairparsevalue(attr_vp, new_str) == NULL) {
+ DEBUG2("%s: Could not write value '%s' into attribute %s: %s", data->name, new_str, data->attribute, fr_strerror());
+ return ret;
+ }
+to_do_again:
ret = RLM_MODULE_OK;
- }
- else{
- attr_vp = pairmake(data->attribute,replace_STR,0);
- switch(data->searchin){
- case RLM_REGEX_INPACKET:
- pairadd(&request->packet->vps,attr_vp);
- break;
- case RLM_REGEX_INCONFIG:
- pairadd(&request->config_items,attr_vp);
- break;
- case RLM_REGEX_INREPLY:
- pairadd(&request->reply->vps,attr_vp);
- break;
- default:
- radlog(L_ERR, "rlm_attr_rewrite: Illegal value for searchin. Changing to packet.");
- data->searchin = RLM_REGEX_INPACKET;
- pairadd(&request->packet->vps,attr_vp);
- break;
+
+ if (tmp != NULL){
+ tmp = attr_vp->next;
+ if (tmp != NULL)
+ goto do_again;
}
- DEBUG2("rlm_attr_rewrite: Added attribute %s with value '%s'",data->attribute,attr_vp->strvalue);
- ret = RLM_MODULE_OK;
}
-
return ret;
}
-
static int attr_rewrite_accounting(void *instance, REQUEST *request)
{
return do_attr_rewrite(instance, request);
{
return do_attr_rewrite(instance, request);
}
+
static int attr_rewrite_authenticate(void *instance, REQUEST *request)
{
return do_attr_rewrite(instance, request);
}
+
static int attr_rewrite_preacct(void *instance, REQUEST *request)
{
return do_attr_rewrite(instance, request);
}
-static int attr_rewrite_ismul(void *instance, REQUEST *request)
+
+static int attr_rewrite_checksimul(void *instance, REQUEST *request)
{
return do_attr_rewrite(instance, request);
}
-static int attr_rewrite_detach(void *instance)
+#ifdef WITH_PROXY
+static int attr_rewrite_preproxy(void *instance, REQUEST *request)
{
- rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
+ return do_attr_rewrite(instance, request);
+}
+
+static int attr_rewrite_postproxy(void *instance, REQUEST *request)
+{
+ return do_attr_rewrite(instance, request);
+}
+#endif
- free(data->attribute);
- free(data->search);
- free(data->replace);
- if (data->name)
- free(data->name);
+static int attr_rewrite_postauth(void *instance, REQUEST *request)
+{
+ return do_attr_rewrite(instance, request);
+}
+static int attr_rewrite_detach(void *instance)
+{
free(instance);
return 0;
}
* is single-threaded.
*/
module_t rlm_attr_rewrite = {
- "attr_rewrite",
+ RLM_MODULE_INIT,
+ "attr_rewrite",
RLM_TYPE_THREAD_UNSAFE, /* type */
- NULL, /* initialization */
attr_rewrite_instantiate, /* instantiation */
+ attr_rewrite_detach, /* detach */
{
attr_rewrite_authenticate, /* authentication */
attr_rewrite_authorize, /* authorization */
attr_rewrite_preacct, /* preaccounting */
attr_rewrite_accounting, /* accounting */
- attr_rewrite_ismul /* checksimul */
+ attr_rewrite_checksimul, /* checksimul */
+#ifdef WITH_PROXY
+ attr_rewrite_preproxy, /* pre-proxy */
+ attr_rewrite_postproxy, /* post-proxy */
+#else
+ NULL, NULL,
+#endif
+ attr_rewrite_postauth /* post-auth */
},
- attr_rewrite_detach, /* detach */
- NULL, /* destroy */
};