818b45e033b03ee3a04e672f1c057afe5d57442b
[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
14 /*
15  *      Internal function to cut down on duplicated code.
16  *
17  *      Returns NULL on don't proxy, realm otherwise.
18  */
19 static REALM *check_for_realm(REQUEST *request)
20 {
21         const char *name;
22         char *realmname;
23         VALUE_PAIR *vp;
24         REALM *realm;
25
26         /*
27          *      If the request has a proxy entry, then it's a proxy
28          *      reply, and we're walking through the module list again.
29          *
30          *      In that case, don't bother trying to proxy the request
31          *      again.
32          *
33          *      Also, if there's no User-Name attribute, we can't
34          *      proxy it, either.
35          */
36         if ((request->proxy != NULL) ||
37             (request->username == NULL)) {
38                 return NULL;
39         }
40
41         name = (char *)request->username->strvalue;
42         realmname = strrchr(name, '@');
43         if (realmname != NULL)
44           realmname++;
45         
46         realm = realm_find(realmname);
47         if (realm == NULL)
48           return NULL;
49
50         DEBUG2("  rlm_realm: Proxying request from user %s to realm %s",
51                name, realm->realm);
52
53         /*
54          *      If we've been told to strip the realm off, then do so.
55          */
56         if (realm->striprealm) {
57                 /*
58                  *      Create the Stripped-User-Name attribute, if it
59                  *      doesn't exist.
60                  *
61                  *      This code is copied from rlm_preprocess.
62                  */
63                 vp = pairfind(request->packet->vps, PW_STRIPPED_USER_NAME);
64                 if (!vp) {
65                         vp = paircreate(PW_STRIPPED_USER_NAME, PW_TYPE_STRING);
66                         if (!vp) {
67                                 radlog(L_ERR|L_CONS, "no memory");
68                                 exit(1);
69                         }
70                         strcpy(vp->strvalue, name);
71                         vp->length = strlen((char *)vp->strvalue);
72                         pairadd(&request->packet->vps, vp);
73                         request->username = vp;
74                 }
75                 
76                 /*
77                  *      Let's strip the Stripped-User-Name attribute.
78                  */
79                 realmname = strrchr((char *)vp->strvalue, '@');
80                 if (realmname != NULL) {
81                         *realmname = '\0';
82                         vp->length = strlen((char *)vp->strvalue);
83                 }
84         }
85
86         /*
87          *      Don't add a 'Realm' attribute, proxy.c does
88          *      that for us.
89          */
90
91         /*
92          *      Perhaps accounting proxying was turned off.
93          */
94         if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
95             (realm->acct_port == 0)) {
96                 /* log a warning that the packet isn't getting proxied ??? */
97                 return NULL;
98         }
99
100         /*
101          *      Perhaps authentication proxying was turned off.
102          */
103         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
104             (realm->auth_port == 0)) {
105                 /* log a warning that the packet isn't getting proxied ??? */
106                 return NULL;
107         }
108
109
110         return realm;
111 }
112
113 /*
114  *      Maybe add a "Proxy-To-Realm" attribute to the request.
115  *
116  *      If it's a LOCAL realm, then don't bother.
117  */
118 static void add_proxy_to_realm(VALUE_PAIR **vps, REALM *realm)
119 {
120         VALUE_PAIR *vp;
121
122         /*
123          *      If it's the LOCAL realm, we do NOT proxy it, but
124          *      we DO strip the User-Name, if told to do so.
125          */
126         if (strcmp(realm->server, "LOCAL") == 0) {
127                 return;
128         }
129
130         /*
131          *      Tell the server to proxy this request to another
132          *      realm.
133          */
134         vp = pairmake("Proxy-To-Realm", realm->realm, T_OP_EQ);
135         if (!vp) {
136                 radlog(L_ERR|L_CONS, "no memory");
137                 exit(1);
138         }
139         
140         /*
141          *  Add it, even if it's already present.
142          */
143         pairadd(vps, vp);
144 }
145
146 /*
147  *  Examine a request for a username with an @suffix, and if it
148  *  corresponds to something in the realms file, set that realm as
149  *  Proxy-To.
150  *
151  *  This should very nearly duplicate the old proxy_send() code
152  */
153 static int realm_authorize(void *instance, REQUEST *request,
154                            VALUE_PAIR **check_pairs, VALUE_PAIR **reply_pairs)
155 {
156         REALM *realm;
157
158         instance = instance;
159         reply_pairs = reply_pairs; /* -Wunused */
160         
161         /*
162          *      Check if we've got to proxy the request.
163          *      If not, return without adding a Proxy-To-Realm
164          *      attribute.
165          */
166         realm = check_for_realm(request);
167         if (!realm) {
168                 return RLM_MODULE_OK;
169         }
170
171         /*
172          *      Maybe add a Proxy-To-Realm attribute to the request.
173          */
174         add_proxy_to_realm(check_pairs, realm);
175
176         return RLM_MODULE_OK; /* try the next module */
177 }
178
179 /*
180  * This does the exact same thing as the realm_authorize, it's just called
181  * differently.
182  */
183 static int realm_preacct(void *instance, REQUEST *request)
184 {
185         const char *name = (char *)request->username->strvalue;
186         REALM *realm;
187
188         instance = instance; /* -Wunused */
189         
190         if (!name)
191           return RLM_MODULE_OK;
192         
193
194         /*
195          *      Check if we've got to proxy the request.
196          *      If not, return without adding a Proxy-To-Realm
197          *      attribute.
198          */
199         realm = check_for_realm(request);
200         if (!realm) {
201                 return RLM_MODULE_OK;
202         }
203
204
205         /*
206          *      Maybe add a Proxy-To-Realm attribute to the request.
207          */
208         add_proxy_to_realm(&request->config_items, realm);
209
210         return RLM_MODULE_OK; /* try the next module */
211 }
212
213 /* globally exported name */
214 module_t rlm_realm = {
215   "Realm",
216   0,                            /* type: reserved */
217   NULL,                         /* initialization */
218   NULL,                         /* instantiation */
219   realm_authorize,              /* authorization */
220   NULL,                         /* authentication */
221   realm_preacct,                /* preaccounting */
222   NULL,                         /* accounting */
223   NULL,                         /* detach */
224   NULL,                         /* destroy */
225 };