6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2001 The FreeRADIUS server project
21 * Copyright 2001 Kostas Kalevras <kkalev@noc.ntua.gr>
26 #include "libradius.h"
40 #define RLM_REGEX_INPACKET 0
41 #define RLM_REGEX_INCONFIG 1
42 #define RLM_REGEX_INREPLY 2
44 static const char rcsid[] = "$Id$";
46 typedef struct rlm_attr_rewrite_t {
47 char *attribute; /* The attribute to search for */
48 int attr_num; /* The attribute number */
49 char *search; /* The pattern to search for */
50 char *searchin_str; /* The VALUE_PAIR list to search in. Can be either packet,reply or config */
51 char searchin; /* The same as above just coded as a number for speed */
52 char *replace; /* The replacement */
53 int nocase; /* Ignore case */
54 int num_matches; /* Maximum number of matches */
58 static CONF_PARSER module_config[] = {
59 { "attribute", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,attribute), NULL, NULL },
60 { "searchfor", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,search), NULL, NULL },
61 { "searchin", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,searchin_str), NULL, "packet" },
62 { "replacewith", PW_TYPE_STRING_PTR, offsetof(rlm_attr_rewrite_t,replace), NULL, NULL },
63 { "ignore_case", PW_TYPE_BOOLEAN, offsetof(rlm_attr_rewrite_t,nocase), NULL, "1" },
64 { "max_matches", PW_TYPE_INTEGER, offsetof(rlm_attr_rewrite_t,num_matches), NULL, "10" },
65 { NULL, -1, 0, NULL, NULL }
69 static int attr_rewrite_instantiate(CONF_SECTION *conf, void **instance)
71 rlm_attr_rewrite_t *data;
75 * Set up a storage area for instance data
77 data = rad_malloc(sizeof(*data));
80 * If the configuration parameters can't be parsed, then
83 if (cf_section_parse(conf, data, module_config) < 0) {
89 * Discover the attribute number of the key.
91 if (data->attribute == NULL) {
92 radlog(L_ERR, "rlm_attr_rewrite: 'attribute' must be set.");
95 if (data->search == NULL || data->replace == NULL) {
96 radlog(L_ERR, "rlm_attr_rewrite: search/replace strings must be set.");
100 if (data->num_matches < 1 || data->num_matches > MAX_STRING_LEN) {
101 radlog(L_ERR, "rlm_attr_rewrite: Illegal range for match number.");
104 if (data->searchin_str == NULL) {
105 radlog(L_ERR, "rlm_attr_rewrite: Illegal searchin directive given. Assuming packet.");
106 data->searchin = RLM_REGEX_INPACKET;
109 if (strcmp(data->searchin_str, "packet") == 0)
110 data->searchin = RLM_REGEX_INPACKET;
111 else if (strcmp(data->searchin_str, "config") == 0)
112 data->searchin = RLM_REGEX_INCONFIG;
113 else if (strcmp(data->searchin_str, "reply") == 0)
114 data->searchin = RLM_REGEX_INREPLY;
116 radlog(L_ERR, "rlm_attr_rewrite: Illegal searchin directive given. Assuming packet.");
117 data->searchin = RLM_REGEX_INPACKET;
119 free((char *)data->searchin_str);
121 dattr = dict_attrbyname(data->attribute);
123 radlog(L_ERR, "rlm_attr_rewrite: No such attribute %s",
127 data->attr_num = dattr->attr;
134 static int do_attr_rewrite(void *instance, REQUEST *request)
136 rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
137 int ret = RLM_MODULE_NOOP;
138 VALUE_PAIR *attr_vp = NULL;
143 unsigned int len = 0;
144 char err_msg[MAX_STRING_LEN];
146 unsigned int counter = 0;
147 char new_str[MAX_STRING_LEN];
149 char search_STR[MAX_STRING_LEN];
150 char replace_STR[MAX_STRING_LEN];
153 switch (data->searchin) {
154 case RLM_REGEX_INPACKET:
155 if (data->attr_num == PW_USER_NAME)
156 attr_vp = request->username;
157 else if (data->attr_num == PW_PASSWORD)
158 attr_vp = request->password;
160 attr_vp = pairfind(request->packet->vps, data->attr_num);
162 case RLM_REGEX_INCONFIG:
163 attr_vp = pairfind(request->config_items, data->attr_num);
165 case RLM_REGEX_INREPLY:
166 attr_vp = pairfind(request->reply->vps, data->attr_num);
169 radlog(L_ERR, "rlm_attr_rewrite: Illegal value for searchin. Changing to packet.");
170 data->searchin = RLM_REGEX_INPACKET;
171 attr_vp = pairfind(request->packet->vps, data->attr_num);
174 if (attr_vp == NULL) {
175 DEBUG2("rlm_attr_rewrite: Could not find value pair for attribute %s",data->attribute);
178 if (attr_vp->strvalue == NULL || attr_vp->length == 0){
179 DEBUG2("rlm_attr_rewrite: Attribute %s string value NULL or of zero length",data->attribute);
182 cflags |= REG_EXTENDED;
186 if (!radius_xlat(search_STR, sizeof(search_STR), data->search, request, NULL)) {
187 DEBUG2("rlm_attr_rewrite: xlat on search string failed.");
190 if (!radius_xlat(replace_STR, sizeof(replace_STR), data->replace, request, NULL)) {
191 DEBUG2("rlm_attr_rewrite: xlat on replace string failed.");
194 replace_len = strlen(replace_STR);
196 if ((err = regcomp(&preg,search_STR,cflags))) {
197 regerror(err, &preg, err_msg, MAX_STRING_LEN);
198 DEBUG2("rlm_attr_rewrite: regcomp() returned error: %s",err_msg);
202 ptr2 = attr_vp->strvalue;
205 for ( /**/ ;i < data->num_matches; i++) {
206 err = regexec(&preg, ptr2, 1, &pmatch, 0);
207 if (err == REG_NOMATCH) {
209 DEBUG2("rlm_attr_rewrite: No match found for attribute %s with value %s",
210 data->attribute, attr_vp->strvalue);
212 return RLM_MODULE_OK;
218 radlog(L_ERR, "rlm_attr_rewrite: match failure for attribute %s with value %s",
219 data->attribute, attr_vp->strvalue);
222 if (pmatch.rm_so == -1)
226 if (counter >= MAX_STRING_LEN) {
228 DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value %s",
229 data->attribute, attr_vp->strvalue);
233 strncpy(ptr, ptr2,len);
235 ptr2 += pmatch.rm_eo;
237 counter += replace_len;
238 if (counter >= MAX_STRING_LEN) {
240 DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value %s",
241 data->attribute, attr_vp->strvalue);
244 strncpy(ptr, replace_STR, replace_len);
248 len = strlen(ptr2) + 1; /* We add the ending NULL */
250 if (counter >= MAX_STRING_LEN){
251 DEBUG2("rlm_attr_rewrite: Replacement out of limits for attribute %s with value %s",
252 data->attribute, attr_vp->strvalue);
255 strncpy(ptr, ptr2, len);
257 DEBUG2("rlm_attr_rewrite: Changed value for attribute %s from %s to %s",
258 data->attribute, attr_vp->strvalue, new_str);
259 attr_vp->length = strlen(new_str);
260 strncpy(attr_vp->strvalue, new_str, (attr_vp->length + 1));
268 static int attr_rewrite_accounting(void *instance, REQUEST *request)
270 return do_attr_rewrite(instance, request);
273 static int attr_rewrite_authorize(void *instance, REQUEST *request)
275 return do_attr_rewrite(instance, request);
277 static int attr_rewrite_authenticate(void *instance, REQUEST *request)
279 return do_attr_rewrite(instance, request);
281 static int attr_rewrite_preacct(void *instance, REQUEST *request)
283 return do_attr_rewrite(instance, request);
285 static int attr_rewrite_ismul(void *instance, REQUEST *request)
287 return do_attr_rewrite(instance, request);
290 static int attr_rewrite_detach(void *instance)
292 rlm_attr_rewrite_t *data = (rlm_attr_rewrite_t *) instance;
294 free(data->attribute);
303 * The module name should be the only globally exported symbol.
304 * That is, everything else should be 'static'.
306 * If the module needs to temporarily modify it's instantiation
307 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
308 * The server will then take care of ensuring that the module
309 * is single-threaded.
311 module_t rlm_attr_rewrite = {
313 RLM_TYPE_THREAD_UNSAFE, /* type */
314 NULL, /* initialization */
315 attr_rewrite_instantiate, /* instantiation */
317 attr_rewrite_authenticate, /* authentication */
318 attr_rewrite_authorize, /* authorization */
319 attr_rewrite_preacct, /* preaccounting */
320 attr_rewrite_accounting, /* accounting */
321 attr_rewrite_ismul /* checksimul */
323 attr_rewrite_detach, /* detach */