minor re-formatting.
[freeradius.git] / src / modules / rlm_realm / rlm_realm.c
1 #include "autoconf.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "libradius.h"
8 #include "radiusd.h"
9 #include "modules.h"
10
11 static const char rcsid[] = "$Id$";
12
13 #define  REALM_FORMAT_PREFIX   0
14 #define  REALM_FORMAT_SUFFIX   1
15
16 typedef struct realm_config_t {
17         int        format;
18         char       *formatstring;
19         char       *delim;
20 } realm_config_t;
21
22 static realm_config_t config;
23
24 static CONF_PARSER module_config[] = {
25   { "format", PW_TYPE_STRING_PTR, &config.formatstring, "suffix" },
26   { "delimiter", PW_TYPE_STRING_PTR, &config.delim, "@" },
27   { NULL, -1, NULL, NULL }    /* end the list */
28 };
29
30 /*
31  *      Internal function to cut down on duplicated code.
32  *
33  *      Returns NULL on don't proxy, realm otherwise.
34  */
35 static REALM *check_for_realm(void *instance, REQUEST *request)
36 {
37         char namebuf[MAX_STRING_LEN];
38         char *username;
39         char *realmname = (char *)NULL;
40         char *ptr;
41         VALUE_PAIR *vp;
42         REALM *realm;
43
44         struct realm_config_t *inst = instance;
45
46         namebuf[0] = '\0';
47         username = namebuf;
48
49         /*
50          *      If the request has a proxy entry, then it's a proxy
51          *      reply, and we're walking through the module list again.
52          *
53          *      In that case, don't bother trying to proxy the request
54          *      again.
55          *
56          *      Also, if there's no User-Name attribute, we can't
57          *      proxy it, either.
58          */
59         if ((request->proxy != NULL) ||
60             (request->username == NULL)) {
61                 return NULL;
62         }
63
64         strncpy(namebuf, request->username->strvalue, MAX_STRING_LEN-1);
65
66         switch(inst->format)
67         {
68
69         case REALM_FORMAT_SUFFIX:
70           
71           /* DEBUG2("  rlm_realm: Checking for suffix after \"%c\"", inst->delim[0]); */
72
73                 realmname = strchr(username, inst->delim[0]);           
74                 if (realmname) {
75                         *realmname = '\0';
76                         realmname++;
77                 }
78                 break;
79                 
80         case REALM_FORMAT_PREFIX:
81                 
82                 /* DEBUG2("  rlm_realm: Checking for prefix before \"%c\"", inst->delim[0]); */
83                 
84                 ptr = strchr(username, inst->delim[0]);
85                 if (ptr) {
86                         *ptr = '\0';
87                      ptr++;
88                      realmname = username;
89                      username = ptr;    
90                 }
91                 break;
92                
93         default:
94                 realmname = NULL;
95                 break;
96         }
97
98         /*
99          *      Allow NULL realms.
100          */
101         realm = realm_find(realmname);
102         if (!realm) {
103                 return NULL;
104         }
105         
106         /* make sure it's proxyable realm */
107         if (realm->notrealm) {
108                 return NULL;
109         }
110
111         DEBUG2("  rlm_realm: Proxying request from user %s to realm %s",
112                username, realm->realm);
113
114         /*
115          *      If we've been told to strip the realm off, then do so.
116          */
117         if (realm->striprealm) {
118                 /*
119                  *      Create the Stripped-User-Name attribute, if it
120                  *      doesn't exist.
121                  *
122                  */
123                 vp = pairfind(request->packet->vps, PW_STRIPPED_USER_NAME);
124                 if (!vp) {
125                         vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
126                         if (!vp) {
127                                 radlog(L_ERR|L_CONS, "no memory");
128                                 exit(1);
129                         }
130                         strcpy(vp->strvalue, username);
131                         vp->length = strlen((char *)vp->strvalue);
132                         pairadd(&request->packet->vps, vp);
133                         request->username = vp;
134                 }
135         }
136
137         /*
138          *      Don't add a 'Realm' attribute, proxy.c does
139          *      that for us.
140          */
141
142         /*
143          *      Perhaps accounting proxying was turned off.
144          */
145         if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
146             (realm->acct_port == 0)) {
147                 /* log a warning that the packet isn't getting proxied ??? */
148                 DEBUG2("rlm_realm:  acct_port is not set.  proxy cancelled");
149                 return NULL;
150         }
151
152         /*
153          *      Perhaps authentication proxying was turned off.
154          */
155         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
156             (realm->auth_port == 0)) {
157                 /* log a warning that the packet isn't getting proxied ??? */
158                 DEBUG2("rlm_realm:  auth_port is not set.  proxy cancelled");
159                 return NULL;
160         }
161
162
163         return realm;
164 }
165
166 /*
167  *      Maybe add a "Proxy-To-Realm" attribute to the request.
168  *
169  *      If it's a LOCAL realm, then don't bother.
170  */
171 static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm)
172 {
173         VALUE_PAIR *vp;
174
175         /*
176          *      If it's the LOCAL realm, we do NOT proxy it, but
177          *      we DO strip the User-Name, if told to do so.
178          */
179         if (strcmp(realm->server, "LOCAL") == 0) {
180                 return;
181         }
182
183         /*
184          *      Tell the server to proxy this request to another
185          *      realm.
186          */
187         vp = pairmake("Proxy-To-Realm", realm->realm, T_OP_EQ);
188         if (!vp) {
189                 radlog(L_ERR|L_CONS, "no memory");
190                 exit(1);
191         }
192         
193         /*
194          *  Add it, even if it's already present.
195          */
196         pairadd(vps, vp);
197 }
198
199 /*
200  *  Perform the realm module instantiation.  Configuration info is
201  *  stored in *instance for later use.
202  */
203
204 static int realm_instantiate(CONF_SECTION *conf, void **instance)
205 {
206         struct realm_config_t *inst;
207
208         /* setup a storage area for instance data */
209         inst = malloc(sizeof(struct realm_config_t));
210         if(!inst) {
211                radlog(L_ERR|L_CONS, "Out of memory\n");
212                return -1;
213         }
214
215         if(cf_section_parse(conf, module_config) < 0) {
216                free(inst);
217                return -1;
218         }
219
220         /* copy the configuration info into the instance data */
221
222         if(strcasecmp(config.formatstring, "suffix") == 0) {
223              inst->format = REALM_FORMAT_SUFFIX;
224         } else if(strcasecmp(config.formatstring, "prefix") == 0) {
225              inst->format = REALM_FORMAT_PREFIX;
226         } else {
227              radlog(L_ERR, "Bad value \"%s\" for realm format value", config.formatstring);
228              free(inst);
229              return -1;
230         }
231         if(strlen(config.delim) != 1) {
232              radlog(L_ERR, "Bad value \"%s\" for realm delimiter value", config.delim);
233              free(inst);
234              return -1;
235         }
236         inst->delim = config.delim;
237
238         /* set these to NULL to prevent other instances from reusing the data */
239
240         config.formatstring = NULL;
241         config.delim = NULL;
242
243         *instance = inst;
244         return 0;
245
246 }
247
248
249
250  
251
252 /*
253  *  Examine a request for a username with an realm, and if it
254  *  corresponds to something in the realms file, set that realm as
255  *  Proxy-To.
256  *
257  *  This should very nearly duplicate the old proxy_send() code
258  */
259 static int realm_authorize(void *instance, REQUEST *request)
260 {
261         REALM *realm;
262
263         /*
264          *      Check if we've got to proxy the request.
265          *      If not, return without adding a Proxy-To-Realm
266          *      attribute.
267          */
268         realm = check_for_realm(instance, request);
269         if (!realm) {
270                 return RLM_MODULE_OK;
271         }
272
273         /*
274          *      Maybe add a Proxy-To-Realm attribute to the request.
275          */
276         add_proxy_to_realm(&request->config_items, realm);
277
278         return RLM_MODULE_UPDATED; /* try the next module */
279 }
280
281 /*
282  * This does the exact same thing as the realm_authorize, it's just called
283  * differently.
284  */
285 static int realm_preacct(void *instance, REQUEST *request)
286 {
287         const char *name = (char *)request->username->strvalue;
288         REALM *realm;
289
290         if (!name)
291           return RLM_MODULE_OK;
292         
293
294         /*
295          *      Check if we've got to proxy the request.
296          *      If not, return without adding a Proxy-To-Realm
297          *      attribute.
298          */
299         realm = check_for_realm(instance, request);
300         if (!realm) {
301                 return RLM_MODULE_OK;
302         }
303
304
305         /*
306          *      Maybe add a Proxy-To-Realm attribute to the request.
307          */
308         add_proxy_to_realm(&request->config_items, realm);
309
310         return RLM_MODULE_OK; /* try the next module */
311 }
312
313 /* globally exported name */
314 module_t rlm_realm = {
315   "realm",
316   0,                            /* type: reserved */
317   NULL,                         /* initialization */
318   realm_instantiate,            /* instantiation */
319   realm_authorize,              /* authorization */
320   NULL,                         /* authentication */
321   realm_preacct,                /* preaccounting */
322   NULL,                         /* accounting */
323   NULL,                         /* checksimul */
324   NULL,                         /* detach */
325   NULL,                         /* destroy */
326 };