2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 if the
4 * License as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 * @file rlm_sometimes.c
19 * @brief Switches between retuning different return codes.
21 * @copyright 2012 The FreeRADIUS server project
23 #include <freeradius-devel/ident.h>
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
30 * The instance data for rlm_sometimes is the list of fake values we are
33 typedef struct rlm_sometimes_t {
43 * A mapping of configuration file names to internal variables.
45 * Note that the string is dynamically allocated, so it MUST
46 * be freed. When the configuration file parse re-reads the string,
47 * it free's the old one, and strdup's the new one, placing the pointer
48 * to the strdup'd string into 'config.string'. This gets around
51 static const CONF_PARSER module_config[] = {
52 { "rcode", PW_TYPE_STRING_PTR, offsetof(rlm_sometimes_t,rcode_str),
55 { "key", PW_TYPE_STRING_PTR, offsetof(rlm_sometimes_t,key),
58 { "start", PW_TYPE_INTEGER, offsetof(rlm_sometimes_t,start),
61 { "end", PW_TYPE_INTEGER, offsetof(rlm_sometimes_t,end),
64 { NULL, -1, 0, NULL, NULL } /* end the list */
67 static int str2rcode(const char *s)
69 if(!strcasecmp(s, "reject"))
70 return RLM_MODULE_REJECT;
71 else if(!strcasecmp(s, "fail"))
72 return RLM_MODULE_FAIL;
73 else if(!strcasecmp(s, "ok"))
75 else if(!strcasecmp(s, "handled"))
76 return RLM_MODULE_HANDLED;
77 else if(!strcasecmp(s, "invalid"))
78 return RLM_MODULE_INVALID;
79 else if(!strcasecmp(s, "userlock"))
80 return RLM_MODULE_USERLOCK;
81 else if(!strcasecmp(s, "notfound"))
82 return RLM_MODULE_NOTFOUND;
83 else if(!strcasecmp(s, "noop"))
84 return RLM_MODULE_NOOP;
85 else if(!strcasecmp(s, "updated"))
86 return RLM_MODULE_UPDATED;
89 "rlm_sometimes: Unknown module rcode '%s'.\n", s);
94 static int sometimes_instantiate(CONF_SECTION *conf, void **instance)
96 rlm_sometimes_t *inst;
99 * Set up a storage area for instance data
101 *instance = inst = talloc_zero(conf, rlm_sometimes_t);
102 if (!inst) return -1;
105 * If the configuration parameters can't be parsed, then
108 if (cf_section_parse(conf, inst, module_config) < 0) {
113 * Convert the rcode string to an int, and get rid of it
115 inst->rcode = str2rcode(inst->rcode_str);
116 if (inst->rcode == -1) {
120 inst->da = dict_attrbyname(inst->key);
122 radlog(L_ERR, "rlm_sometimes; Unknown attributes %s", inst->key);
132 * A lie! It always returns!
134 static rlm_rcode_t sometimes_return(void *instance, RADIUS_PACKET *packet,
135 RADIUS_PACKET *reply)
139 rlm_sometimes_t *inst = instance;
143 * Set it to NOOP and the module will always do nothing
145 if (inst->rcode == RLM_MODULE_NOOP) return inst->rcode;
148 * Hash based on the given key. Usually User-Name.
150 vp = pairfind(packet->vps, inst->da->attr, inst->da->vendor, TAG_ANY);
151 if (!vp) return RLM_MODULE_NOOP;
153 hash = fr_hash(&vp->data, vp->length);
154 hash &= 0xff; /* ensure it's 0..255 */
158 * Ranges are INCLUSIVE.
159 * [start,end] returns "rcode"
160 * Everything else returns "noop"
162 if (value < inst->start) return RLM_MODULE_NOOP;
163 if (value > inst->end) return RLM_MODULE_NOOP;
166 * If we're returning "handled", then set the packet
167 * code in the reply, so that the server responds.
169 if ((inst->rcode == RLM_MODULE_HANDLED) && reply) {
170 switch (packet->code) {
171 case PW_AUTHENTICATION_REQUEST:
172 reply->code = PW_AUTHENTICATION_ACK;
175 case PW_ACCOUNTING_REQUEST:
176 reply->code = PW_ACCOUNTING_RESPONSE;
180 reply->code = PW_COA_ACK;
183 case PW_DISCONNECT_REQUEST:
184 reply->code = PW_DISCONNECT_ACK;
195 static rlm_rcode_t sometimes_packet(void *instance, REQUEST *request)
197 return sometimes_return(instance, request->packet, request->reply);
200 static rlm_rcode_t sometimes_reply(void *instance, REQUEST *request)
202 return sometimes_return(instance, request->reply, NULL);
205 static rlm_rcode_t sometimes_pre_proxy(void *instance, REQUEST *request)
207 if (!request->proxy) return RLM_MODULE_NOOP;
209 return sometimes_return(instance, request->proxy, request->proxy_reply);
212 static rlm_rcode_t sometimes_post_proxy(void *instance, REQUEST *request)
214 if (!request->proxy_reply) return RLM_MODULE_NOOP;
216 return sometimes_return(instance, request->proxy_reply, NULL);
219 module_t rlm_sometimes = {
222 RLM_TYPE_CHECK_CONFIG_SAFE | RLM_TYPE_HUP_SAFE, /* type */
223 sometimes_instantiate, /* instantiation */
226 sometimes_packet, /* authentication */
227 sometimes_packet, /* authorization */
228 sometimes_packet, /* preaccounting */
229 sometimes_packet, /* accounting */
231 sometimes_pre_proxy, /* pre-proxy */
232 sometimes_post_proxy, /* post-proxy */
233 sometimes_reply /* post-auth */
236 sometimes_packet, /* recv-coa */
237 sometimes_reply /* send-coa */