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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000 The FreeRADIUS server project
21 * FIXME add copyrights
24 #include <freeradius-devel/autoconf.h>
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
38 #include <freeradius-devel/radiusd.h>
39 #include <freeradius-devel/modules.h>
41 static const char rcsid[] = "$Id$";
43 #define REALM_FORMAT_PREFIX 0
44 #define REALM_FORMAT_SUFFIX 1
46 typedef struct realm_config_t {
54 static CONF_PARSER module_config[] = {
55 { "format", PW_TYPE_STRING_PTR,
56 offsetof(realm_config_t,formatstring), NULL, "suffix" },
57 { "delimiter", PW_TYPE_STRING_PTR,
58 offsetof(realm_config_t,delim), NULL, "@" },
59 { "ignore_default", PW_TYPE_BOOLEAN,
60 offsetof(realm_config_t,ignore_default), NULL, "no" },
61 { "ignore_null", PW_TYPE_BOOLEAN,
62 offsetof(realm_config_t,ignore_null), NULL, "no" },
63 { NULL, -1, 0, NULL, NULL } /* end the list */
67 * Internal function to cut down on duplicated code.
69 * Returns -1 on failure, 0 on no failure. returnrealm
70 * is NULL on don't proxy, realm otherwise.
72 static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
74 char namebuf[MAX_STRING_LEN];
76 char *realmname = NULL;
81 struct realm_config_t *inst = instance;
83 /* initiate returnrealm */
86 if (request->packet->src_ipaddr.af != AF_INET) {
87 DEBUG2("rlm_realm: IPv6 is not supported!");
92 * If the request has a proxy entry, then it's a proxy
93 * reply, and we're walking through the module list again.
95 * In that case, don't bother trying to proxy the request
98 * Also, if there's no User-Name attribute, we can't
101 if ((request->proxy != NULL) ||
102 (request->username == NULL)) {
103 DEBUG2(" rlm_realm: Proxy reply, or no User-Name. Ignoring.");
108 * Check for 'Realm' attribute. If it exists, then we've proxied
109 * it already ( via another rlm_realm instance ) and should return.
112 if ( (vp = pairfind(request->packet->vps, PW_REALM)) != NULL ) {
113 DEBUG2(" rlm_realm: Request already proxied. Ignoring.");
118 * We will be modifing this later, so we want our own copy
121 strNcpy(namebuf, (char *)request->username->vp_strvalue, sizeof(namebuf));
127 case REALM_FORMAT_SUFFIX:
129 /* DEBUG2(" rlm_realm: Checking for suffix after \"%c\"", inst->delim[0]); */
130 realmname = strrchr(username, inst->delim[0]);
137 case REALM_FORMAT_PREFIX:
139 /* DEBUG2(" rlm_realm: Checking for prefix before \"%c\"", inst->delim[0]); */
141 ptr = strchr(username, inst->delim[0]);
145 realmname = username;
156 * Print out excruciatingly descriptive debugging messages
157 * for the people who find it too difficult to think about
161 DEBUG2(" rlm_realm: Looking up realm \"%s\" for User-Name = \"%s\"",
162 realmname, request->username->vp_strvalue);
164 if( inst->ignore_null ) {
165 DEBUG2(" rlm_realm: No '%c' in User-Name = \"%s\", skipping NULL due to config.",
166 inst->delim[0], request->username->vp_strvalue);
169 DEBUG2(" rlm_realm: No '%c' in User-Name = \"%s\", looking up realm NULL",
170 inst->delim[0], request->username->vp_strvalue);
174 * Allow DEFAULT realms unless told not to.
176 realm = realm_find(realmname, (request->packet->code == PW_ACCOUNTING_REQUEST));
178 DEBUG2(" rlm_realm: No such realm \"%s\"",
179 (realmname == NULL) ? "NULL" : realmname);
182 if( inst->ignore_default &&
183 (strcmp(realm->realm, "DEFAULT")) == 0) {
184 DEBUG2(" rlm_realm: Found DEFAULT, but skipping due to config.");
189 DEBUG2(" rlm_realm: Found realm \"%s\"", realm->realm);
192 * If we've been told to strip the realm off, then do so.
194 if (realm->striprealm) {
196 * Create the Stripped-User-Name attribute, if it
200 if (request->username->attribute != PW_STRIPPED_USER_NAME) {
201 vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
203 radlog(L_ERR|L_CONS, "no memory");
206 pairadd(&request->packet->vps, vp);
207 DEBUG2(" rlm_realm: Adding Stripped-User-Name = \"%s\"", username);
209 vp = request->username;
210 DEBUG2(" rlm_realm: Setting Stripped-User-Name = \"%s\"", username);
213 strcpy(vp->vp_strvalue, username);
214 vp->length = strlen((char *)vp->vp_strvalue);
215 request->username = vp;
218 DEBUG2(" rlm_realm: Proxying request from user %s to realm %s",
219 username, realm->realm);
222 * Add the realm name to the request.
224 pairadd(&request->packet->vps, pairmake("Realm", realm->realm,
226 DEBUG2(" rlm_realm: Adding Realm = \"%s\"", realm->realm);
229 * Figure out what to do with the request.
231 switch (request->packet->code) {
233 DEBUG2(" rlm_realm: Unknown packet code %d\n",
234 request->packet->code);
235 return 0; /* don't do anything */
238 * Perhaps accounting proxying was turned off.
240 case PW_ACCOUNTING_REQUEST:
241 if (realm->acct_ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE)) {
242 DEBUG2(" rlm_realm: Accounting realm is LOCAL.");
246 if (realm->acct_port == 0) {
247 DEBUG2(" rlm_realm: acct_port is not set. Proxy cancelled.");
253 * Perhaps authentication proxying was turned off.
255 case PW_AUTHENTICATION_REQUEST:
256 if (realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE)) {
257 DEBUG2(" rlm_realm: Authentication realm is LOCAL.");
261 if (realm->auth_port == 0) {
262 DEBUG2(" rlm_realm: auth_port is not set. Proxy cancelled.");
269 * If this request has arrived from another freeradius server
270 * that has already proxied the request, we don't need to do
273 for (vp = request->packet->vps; vp; vp = vp->next) {
274 if (vp->attribute == PW_FREERADIUS_PROXIED_TO) {
275 if (request->packet->code == PW_AUTHENTICATION_REQUEST &&
276 vp->lvalue == realm->ipaddr.ipaddr.ip4addr.s_addr) {
277 DEBUG2(" rlm_realm: Request not proxied due to Freeradius-Proxied-To");
280 if (request->packet->code == PW_ACCOUNTING_REQUEST &&
281 vp->lvalue == realm->acct_ipaddr.ipaddr.ip4addr.s_addr) {
282 DEBUG2(" rlm_realm: Request not proxied due to Freeradius-Proxied-To");
289 * We got this far, which means we have a realm, set returnrealm
291 *returnrealm = realm;
296 * Add a "Proxy-To-Realm" attribute to the request.
298 static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm)
303 * Tell the server to proxy this request to another
306 vp = pairmake("Proxy-To-Realm", realm->realm, T_OP_EQ);
308 radlog(L_ERR|L_CONS, "no memory");
313 * Add it, even if it's already present.
319 * Perform the realm module instantiation. Configuration info is
320 * stored in *instance for later use.
323 static int realm_instantiate(CONF_SECTION *conf, void **instance)
325 struct realm_config_t *inst;
327 /* setup a storage area for instance data */
328 inst = rad_malloc(sizeof(*inst));
332 memset(inst, 0, sizeof(*inst));
334 if(cf_section_parse(conf, inst, module_config) < 0) {
339 if(strcasecmp(inst->formatstring, "suffix") == 0) {
340 inst->format = REALM_FORMAT_SUFFIX;
341 } else if(strcasecmp(inst->formatstring, "prefix") == 0) {
342 inst->format = REALM_FORMAT_PREFIX;
344 radlog(L_ERR, "Bad value \"%s\" for realm format value", inst->formatstring);
348 free(inst->formatstring);
349 if(strlen(inst->delim) != 1) {
350 radlog(L_ERR, "Bad value \"%s\" for realm delimiter value", inst->delim);
365 * Examine a request for a username with an realm, and if it
366 * corresponds to something in the realms file, set that realm as
369 * This should very nearly duplicate the old proxy_send() code
371 static int realm_authorize(void *instance, REQUEST *request)
376 * Check if we've got to proxy the request.
377 * If not, return without adding a Proxy-To-Realm
380 if (check_for_realm(instance, request, &realm) < 0) {
381 return RLM_MODULE_FAIL;
384 return RLM_MODULE_NOOP;
388 * Maybe add a Proxy-To-Realm attribute to the request.
390 DEBUG2(" rlm_realm: Preparing to proxy authentication request to realm \"%s\"\n",
392 add_proxy_to_realm(&request->config_items, realm);
394 return RLM_MODULE_UPDATED; /* try the next module */
398 * This does the exact same thing as the realm_authorize, it's just called
401 static int realm_preacct(void *instance, REQUEST *request)
403 const char *name = (char *)request->username->vp_strvalue;
407 return RLM_MODULE_OK;
411 * Check if we've got to proxy the request.
412 * If not, return without adding a Proxy-To-Realm
415 if (check_for_realm(instance, request, &realm) < 0) {
416 return RLM_MODULE_FAIL;
419 return RLM_MODULE_NOOP;
424 * Maybe add a Proxy-To-Realm attribute to the request.
426 DEBUG2(" rlm_realm: Preparing to proxy accounting request to realm \"%s\"\n",
428 add_proxy_to_realm(&request->config_items, realm);
430 return RLM_MODULE_UPDATED; /* try the next module */
433 static int realm_detach(void *instance)
435 struct realm_config_t *inst = instance;
441 /* globally exported name */
442 module_t rlm_realm = {
445 0, /* type: reserved */
446 realm_instantiate, /* instantiation */
447 realm_detach, /* detach */
449 NULL, /* authentication */
450 realm_authorize, /* authorization */
451 realm_preacct, /* preaccounting */
452 NULL, /* accounting */
453 NULL, /* checksimul */
454 NULL, /* pre-proxy */
455 NULL, /* post-proxy */