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 2000 The FreeRADIUS server project
21 * FIXME add copyrights
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
38 #include "libradius.h"
42 static const char rcsid[] = "$Id$";
44 #define REALM_FORMAT_PREFIX 0
45 #define REALM_FORMAT_SUFFIX 1
47 typedef struct realm_config_t {
53 static CONF_PARSER module_config[] = {
54 { "format", PW_TYPE_STRING_PTR,
55 offsetof(realm_config_t,formatstring), NULL, "suffix" },
56 { "delimiter", PW_TYPE_STRING_PTR,
57 offsetof(realm_config_t,delim), NULL, "@" },
58 { NULL, -1, 0, NULL, NULL } /* end the list */
62 * Internal function to cut down on duplicated code.
64 * Returns NULL on don't proxy, realm otherwise.
66 static REALM *check_for_realm(void *instance, REQUEST *request)
69 char namebuf[MAX_STRING_LEN];
71 char *realmname = NULL;
76 struct realm_config_t *inst = instance;
79 * If the request has a proxy entry, then it's a proxy
80 * reply, and we're walking through the module list again.
82 * In that case, don't bother trying to proxy the request
85 * Also, if there's no User-Name attribute, we can't
88 if ((request->proxy != NULL) ||
89 (request->username == NULL)) {
90 DEBUG2(" rlm_realm: Proxy reply, or no user name. Ignoring.");
95 * Check for 'Realm' attribute. If it exists, then we've proxied
96 * it already ( via another rlm_realm instance ) and should return.
99 if ( (vp = pairfind(request->packet->vps, PW_REALM)) != NULL ) {
100 DEBUG2(" rlm_realm: Request already proxied. Ignoring.");
105 * We will be modifing this later, so we want our own copy
108 strNcpy(namebuf, (char *)request->username->strvalue, sizeof(namebuf));
114 case REALM_FORMAT_SUFFIX:
116 /* DEBUG2(" rlm_realm: Checking for suffix after \"%c\"", inst->delim[0]); */
117 realmname = strrchr(username, inst->delim[0]);
124 case REALM_FORMAT_PREFIX:
126 /* DEBUG2(" rlm_realm: Checking for prefix before \"%c\"", inst->delim[0]); */
128 ptr = strchr(username, inst->delim[0]);
132 realmname = username;
142 DEBUG2(" rlm_realm: Looking up realm %s for User-Name = \"%s\"",
143 (realmname == NULL) ? "NULL" : realmname,
144 request->username->strvalue);
149 realm = realm_find(realmname, (request->packet->code == PW_ACCOUNTING_REQUEST));
151 DEBUG2(" rlm_realm: No such realm %s",
152 (realmname == NULL) ? "NULL" : realmname);
155 DEBUG2(" rlm_realm: Found realm %s", realm->realm);
158 * If we've been told to strip the realm off, then do so.
160 if (realm->striprealm) {
162 * Create the Stripped-User-Name attribute, if it
166 if (request->username->attribute != PW_STRIPPED_USER_NAME) {
167 vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
169 radlog(L_ERR|L_CONS, "no memory");
172 pairadd(&request->packet->vps, vp);
173 DEBUG2(" rlm_realm: Adding Stripped-User-Name = \"%s\"", username);
175 vp = request->username;
176 DEBUG2(" rlm_realm: Setting Stripped-User-Name = \"%s\"", username);
179 strcpy(vp->strvalue, username);
180 vp->length = strlen((char *)vp->strvalue);
181 request->username = vp;
184 DEBUG2(" rlm_realm: Proxying request from user %s to realm %s",
185 username, realm->realm);
188 * Figure out what to do with the request.
191 switch (request->packet->code) {
193 DEBUG2("rlm_realm: Unknown packet code %d\n",
194 request->packet->code);
195 return NULL; /* don't do anything */
198 * Perhaps accounting proxying was turned off.
200 case PW_ACCOUNTING_REQUEST:
201 if (realm->acct_ipaddr == htonl(INADDR_NONE)) {
202 DEBUG2("rlm_realm: Accounting realm is LOCAL.");
206 if (realm->acct_port == 0) {
207 DEBUG2("rlm_realm: acct_port is not set. proxy cancelled");
213 * Perhaps authentication proxying was turned off.
215 case PW_AUTHENTICATION_REQUEST:
216 if (realm->ipaddr == htonl(INADDR_NONE)) {
217 DEBUG2("rlm_realm: Authentication realm is LOCAL.");
221 if (realm->auth_port == 0) {
222 DEBUG2("rlm_realm: auth_port is not set. proxy cancelled");
229 * Add the realm name to the request.
231 pairadd(&request->packet->vps, pairmake("Realm", realm->realm,
233 DEBUG2(" rlm_realm: Adding Realm = \"%s\"", realm->realm);
236 * Local realm, don't proxy it.
246 * Add a "Proxy-To-Realm" attribute to the request.
248 static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm)
253 * Tell the server to proxy this request to another
256 vp = pairmake("Proxy-To-Realm", realm->realm, T_OP_EQ);
258 radlog(L_ERR|L_CONS, "no memory");
263 * Add it, even if it's already present.
269 * Perform the realm module instantiation. Configuration info is
270 * stored in *instance for later use.
273 static int realm_instantiate(CONF_SECTION *conf, void **instance)
275 struct realm_config_t *inst;
277 /* setup a storage area for instance data */
278 inst = rad_malloc(sizeof(struct realm_config_t));
280 if(cf_section_parse(conf, inst, module_config) < 0) {
285 if(strcasecmp(inst->formatstring, "suffix") == 0) {
286 inst->format = REALM_FORMAT_SUFFIX;
287 } else if(strcasecmp(inst->formatstring, "prefix") == 0) {
288 inst->format = REALM_FORMAT_PREFIX;
290 radlog(L_ERR, "Bad value \"%s\" for realm format value", inst->formatstring);
294 free(inst->formatstring);
295 if(strlen(inst->delim) != 1) {
296 radlog(L_ERR, "Bad value \"%s\" for realm delimiter value", inst->delim);
311 * Examine a request for a username with an realm, and if it
312 * corresponds to something in the realms file, set that realm as
315 * This should very nearly duplicate the old proxy_send() code
317 static int realm_authorize(void *instance, REQUEST *request)
322 * Check if we've got to proxy the request.
323 * If not, return without adding a Proxy-To-Realm
326 realm = check_for_realm(instance, request);
328 return RLM_MODULE_NOOP;
332 * Maybe add a Proxy-To-Realm attribute to the request.
334 DEBUG2("rlm_realm: Preparing to proxy authentication request to realm %s\n",
336 add_proxy_to_realm(&request->config_items, realm);
338 return RLM_MODULE_UPDATED; /* try the next module */
342 * This does the exact same thing as the realm_authorize, it's just called
345 static int realm_preacct(void *instance, REQUEST *request)
347 const char *name = (char *)request->username->strvalue;
351 return RLM_MODULE_OK;
355 * Check if we've got to proxy the request.
356 * If not, return without adding a Proxy-To-Realm
359 realm = check_for_realm(instance, request);
361 return RLM_MODULE_NOOP;
366 * Maybe add a Proxy-To-Realm attribute to the request.
368 DEBUG2("rlm_realm: Preparing to proxy accounting request to realm %s\n",
370 add_proxy_to_realm(&request->config_items, realm);
372 return RLM_MODULE_OK; /* try the next module */
375 static int realm_detach(void *instance)
377 struct realm_config_t *inst = instance;
383 /* globally exported name */
384 module_t rlm_realm = {
386 0, /* type: reserved */
387 NULL, /* initialization */
388 realm_instantiate, /* instantiation */
390 NULL, /* authentication */
391 realm_authorize, /* authorization */
392 realm_preacct, /* preaccounting */
393 NULL, /* accounting */
394 NULL /* checksimul */
396 realm_detach, /* detach */