All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_realm.c
Go to the documentation of this file.
1 /*
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 as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: c07b3ce2becf0d5cee942ca9271ea02c1f37ae95 $
19  * @file rlm_realm.c
20  * @brief Parses NAIs and assigns requests to realms.
21  *
22  * @copyright 2000-2013 The FreeRADIUS server project
23  */
24 RCSID("$Id: c07b3ce2becf0d5cee942ca9271ea02c1f37ae95 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 
29 #include "trustrouter.h"
30 
31 #define REALM_FORMAT_PREFIX 0
32 #define REALM_FORMAT_SUFFIX 1
33 
34 typedef struct rlm_realm_t {
35  int format;
36  char const *format_string;
37  char const *delim;
40 
41 #ifdef HAVE_TRUST_ROUTER_TR_DH_H
42  char const *default_community;
43  char const *rp_realm;
44  char const *trust_router;
45  uint32_t tr_port;
46 #endif
47 } rlm_realm_t;
48 
50  { FR_CONF_OFFSET("format", PW_TYPE_STRING, rlm_realm_t, format_string), .dflt = "suffix" },
51  { FR_CONF_OFFSET("delimiter", PW_TYPE_STRING, rlm_realm_t, delim), .dflt = "@" },
52  { FR_CONF_OFFSET("ignore_default", PW_TYPE_BOOLEAN, rlm_realm_t, ignore_default), .dflt = "no" },
53  { FR_CONF_OFFSET("ignore_null", PW_TYPE_BOOLEAN, rlm_realm_t, ignore_null), .dflt = "no" },
54 
55 #ifdef HAVE_TRUST_ROUTER_TR_DH_H
56  { FR_CONF_OFFSET("default_community", PW_TYPE_STRING, rlm_realm_t, default_community), .dflt = "none" },
57  { FR_CONF_OFFSET("rp_realm", PW_TYPE_STRING, rlm_realm_t, rp_realm), .dflt = "none" },
58  { FR_CONF_OFFSET("trust_router", PW_TYPE_STRING, rlm_realm_t, trust_router), .dflt = "none" },
59  { FR_CONF_OFFSET("tr_port", PW_TYPE_INTEGER, rlm_realm_t, tr_port), .dflt = "0" },
60 #endif
62 };
63 
64 /*
65  * Internal function to cut down on duplicated code.
66  *
67  * Returns -1 on failure, 0 on no failure. returnrealm
68  * is NULL on don't proxy, realm otherwise.
69  */
70 static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
71 {
72  char *namebuf;
73  char *username;
74  char const *realmname = NULL;
75  char *ptr;
76  VALUE_PAIR *vp;
77  REALM *realm;
78 
79  struct rlm_realm_t *inst = instance;
80 
81  /* initiate returnrealm */
82  *returnrealm = NULL;
83 
84  /*
85  * If the request has a proxy entry, then it's a proxy
86  * reply, and we're walking through the module list again.
87  *
88  * In that case, don't bother trying to proxy the request
89  * again.
90  *
91  * Also, if there's no User-Name attribute, we can't
92  * proxy it, either.
93  */
94  if ((!request->username)
95 #ifdef WITH_PROXY
96  || (request->proxy != NULL)
97 #endif
98  ) {
99 
100  RDEBUG2("Proxy reply, or no User-Name. Ignoring");
101  return RLM_MODULE_NOOP;
102  }
103 
104  /*
105  * Check for 'Realm' attribute. If it exists, then we've proxied
106  * it already ( via another rlm_realm instance ) and should return.
107  */
108 
109  if (fr_pair_find_by_num(request->packet->vps, 0, PW_REALM, TAG_ANY) != NULL) {
110  RDEBUG2("Request already has destination realm set. Ignoring");
111  return RLM_MODULE_NOOP;
112  }
113 
114  /*
115  * We will be modifing this later, so we want our own copy
116  * of it.
117  */
118  namebuf = talloc_typed_strdup(request, request->username->vp_strvalue);
119  username = namebuf;
120 
121  switch (inst->format) {
122  case REALM_FORMAT_SUFFIX:
123  RDEBUG2("Checking for suffix after \"%c\"", inst->delim[0]);
124  ptr = strrchr(username, inst->delim[0]);
125  if (ptr) {
126  *ptr = '\0';
127  realmname = ptr + 1;
128  }
129  break;
130 
131  case REALM_FORMAT_PREFIX:
132  RDEBUG2("Checking for prefix before \"%c\"", inst->delim[0]);
133  ptr = strchr(username, inst->delim[0]);
134  if (ptr) {
135  *ptr = '\0';
136  ptr++;
137  realmname = username;
138  username = ptr;
139  }
140  break;
141 
142  default:
143  realmname = NULL;
144  break;
145  }
146 
147  /*
148  * Print out excruciatingly descriptive debugging messages
149  * for the people who find it too difficult to think about
150  * what's going on.
151  */
152  if (realmname) {
153  RDEBUG2("Looking up realm \"%s\" for User-Name = \"%s\"",
154  realmname, request->username->vp_strvalue);
155  } else {
156  if (inst->ignore_null) {
157  RDEBUG2("No '%c' in User-Name = \"%s\", skipping NULL due to config.",
158  inst->delim[0], request->username->vp_strvalue);
159  talloc_free(namebuf);
160  return RLM_MODULE_NOOP;
161  }
162  RDEBUG2("No '%c' in User-Name = \"%s\", looking up realm NULL",
163  inst->delim[0], request->username->vp_strvalue);
164  }
165 
166  /*
167  * Allow DEFAULT realms unless told not to.
168  */
169  realm = realm_find(realmname);
170 
171 #ifdef HAVE_TRUST_ROUTER_TR_DH_H
172  /*
173  * Try querying for the dynamic realm.
174  */
175  if (!realm && inst->trust_router)
176  realm = tr_query_realm(request, realmname, inst->default_community, inst->rp_realm, inst->trust_router, inst->tr_port);
177 #endif
178 
179  if (!realm) {
180  RDEBUG2("No such realm \"%s\"", (!realmname) ? "NULL" : realmname);
181  talloc_free(namebuf);
182  return RLM_MODULE_NOOP;
183  }
184  if (inst->ignore_default && (strcmp(realm->name, "DEFAULT")) == 0) {
185  RDEBUG2("Found DEFAULT, but skipping due to config");
186  talloc_free(namebuf);
187  return RLM_MODULE_NOOP;
188  }
189 
190  RDEBUG2("Found realm \"%s\"", realm->name);
191 
192  /*
193  * If we've been told to strip the realm off, then do so.
194  */
195  if (realm->strip_realm) {
196  /*
197  * Create the Stripped-User-Name attribute, if it
198  * doesn't exist.
199  *
200  */
201  if (request->username->da->attr != PW_STRIPPED_USER_NAME) {
202  vp = radius_pair_create(request->packet, &request->packet->vps,
203  PW_STRIPPED_USER_NAME, 0);
204  RDEBUG2("Adding Stripped-User-Name = \"%s\"", username);
205  } else {
206  vp = request->username;
207  RDEBUG2("Setting Stripped-User-Name = \"%s\"", username);
208  }
209 
210  fr_pair_value_strcpy(vp, username);
211  request->username = vp;
212  }
213 
214  /*
215  * Add the realm name to the request.
216  * If the realm is a regex, the use the realm as entered
217  * by the user. Otherwise, use the configured realm name,
218  * as realm name comparison is case insensitive. We want
219  * to use the configured name, rather than what the user
220  * entered.
221  */
222  if (realm->name[0] != '~') realmname = realm->name;
223  pair_make_request("Realm", realmname, T_OP_EQ);
224  RDEBUG2("Adding Realm = \"%s\"", realmname);
225 
226  talloc_free(namebuf);
227  username = NULL;
228 
229  /*
230  * Figure out what to do with the request.
231  */
232  switch (request->packet->code) {
233  default:
234  RDEBUG2("Unknown packet code %d\n",
235  request->packet->code);
236  return RLM_MODULE_NOOP;
237 
238  /*
239  * Perhaps accounting proxying was turned off.
240  */
242  if (!realm->acct_pool) {
243  RDEBUG2("Accounting realm is LOCAL");
244  return RLM_MODULE_OK;
245  }
246  break;
247 
248  /*
249  * Perhaps authentication proxying was turned off.
250  */
252  if (!realm->auth_pool) {
253  RDEBUG2("Authentication realm is LOCAL");
254  return RLM_MODULE_OK;
255  }
256  break;
257  }
258 
259 #ifdef WITH_PROXY
260  RDEBUG2("Proxying request from user %s to realm %s",
261  request->username->vp_strvalue, realm->name);
262 
263  /*
264  * Skip additional checks if it's not an accounting
265  * request.
266  */
267  if (request->packet->code != PW_CODE_ACCOUNTING_REQUEST) {
268  *returnrealm = realm;
269  return RLM_MODULE_UPDATED;
270  }
271 
272  /*
273  * FIXME: Each server should have a unique server key,
274  * and put it in the accounting packet. Every server
275  * should know about the keys, and NOT proxy requests to
276  * a server with key X if the packet already contains key
277  * X.
278  */
279 
280  /*
281  * If this request has arrived from another freeradius server
282  * that has already proxied the request, we don't need to do
283  * it again.
284  */
285  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_FREERADIUS_PROXIED_TO, TAG_ANY);
286  if (vp && (request->packet->src_ipaddr.af == AF_INET)) {
287  int i;
288  fr_ipaddr_t my_ipaddr;
289 
290  my_ipaddr.af = AF_INET;
291  my_ipaddr.prefix = 32;
292  my_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
293 
294  /*
295  * Loop over the home accounting servers for this
296  * realm. If one of them has the same IP as the
297  * FreeRADIUS-Proxied-To attribute, then the
298  * packet has already been sent there. Don't
299  * send it there again.
300  */
301  for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
302  if (fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr, &my_ipaddr) == 0) {
303  RDEBUG2("Suppressing proxy due to FreeRADIUS-Proxied-To");
304  return RLM_MODULE_OK;
305  }
306  }
307 
308  /*
309  * See detail_recv() in src/main/listen.c for the
310  * additional checks.
311  */
312 #ifdef WITH_DETAIL
313  } else if ((request->listener->type == RAD_LISTEN_DETAIL) &&
314  !fr_is_inaddr_any(&request->packet->src_ipaddr)) {
315  int i;
316 
317  /*
318  * Loop over the home accounting servers for this
319  * realm. If one of them has the same IP as the
320  * FreeRADIUS-Proxied-To attribute, then the
321  * packet has already been sent there. Don't
322  * send it there again.
323  */
324  for (i = 0; i < realm->acct_pool->num_home_servers; i++) {
325  if ((fr_ipaddr_cmp(&realm->acct_pool->servers[i]->ipaddr,
326  &request->packet->src_ipaddr) == 0) &&
327  (realm->acct_pool->servers[i]->port == request->packet->src_port)) {
328  RDEBUG2("Suppressing proxy because packet was already sent to a server in that realm");
329  return RLM_MODULE_OK;
330  }
331  }
332 #endif /* WITH_DETAIL */
333  }
334 #endif /* WITH_PROXY */
335 
336  /*
337  * We got this far, which means we have a realm, set returnrealm
338  */
339  *returnrealm = realm;
340 
341  return RLM_MODULE_UPDATED;
342 }
343 
344 /*
345  * Perform the realm module instantiation. Configuration info is
346  * stored in *instance for later use.
347  */
348 
349 static int mod_instantiate(CONF_SECTION *conf, void *instance)
350 {
351  struct rlm_realm_t *inst = instance;
352 
353  if (strcasecmp(inst->format_string, "suffix") == 0) {
354  inst->format = REALM_FORMAT_SUFFIX;
355 
356  } else if (strcasecmp(inst->format_string, "prefix") == 0) {
357  inst->format = REALM_FORMAT_PREFIX;
358 
359  } else {
360  cf_log_err_cs(conf, "Invalid value \"%s\" for format",
361  inst->format_string);
362  return -1;
363  }
364 
365  if (strcmp(inst->delim, "\\\\") == 0) {
366  /* it's OK */
367  } else if (strlen(inst->delim) != 1) {
368  cf_log_err_cs(conf, "Invalid value \"%s\" for delimiter",
369  inst->delim);
370  return -1;
371  }
372 
373 #ifdef HAVE_TRUST_ROUTER_TR_DH_H
374  /* initialize the trust router integration code */
375  if (strcmp(inst->trust_router, "none") != 0) {
376  if (!tr_init()) return -1;
377  } else {
378  rad_const_free(inst->trust_router);
379  }
380 #endif
381 
382  return 0;
383 }
384 
385 
386 /*
387  * Examine a request for a username with an realm, and if it
388  * corresponds to something in the realms file, set that realm as
389  * Proxy-To.
390  *
391  * This should very nearly duplicate the old proxy_send() code
392  */
393 static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
394 {
395  rlm_rcode_t rcode;
396  REALM *realm;
397 
398  /*
399  * Check if we've got to proxy the request.
400  * If not, return without adding a Proxy-To-Realm
401  * attribute.
402  */
403  rcode = check_for_realm(instance, request, &realm);
404  if (rcode != RLM_MODULE_UPDATED) return rcode;
405  if (!realm) return RLM_MODULE_NOOP;
406 
407  /*
408  * Maybe add a Proxy-To-Realm attribute to the request.
409  */
410  RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n",
411  realm->name);
412  pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
413 
414  return RLM_MODULE_UPDATED; /* try the next module */
415 }
416 
417 /*
418  * This does the exact same thing as the mod_authorize, it's just called
419  * differently.
420  */
421 static rlm_rcode_t CC_HINT(nonnull) mod_preacct(void *instance, REQUEST *request)
422 {
423  int rcode;
424  REALM *realm;
425 
426  if (!request->username) {
427  return RLM_MODULE_NOOP;
428  }
429 
430  /*
431  * Check if we've got to proxy the request.
432  * If not, return without adding a Proxy-To-Realm
433  * attribute.
434  */
435  rcode = check_for_realm(instance, request, &realm);
436  if (rcode != RLM_MODULE_UPDATED) return rcode;
437  if (!realm) return RLM_MODULE_NOOP;
438 
439  /*
440  * Maybe add a Proxy-To-Realm attribute to the request.
441  */
442  RDEBUG2("Preparing to proxy accounting request to realm \"%s\"\n",
443  realm->name);
444  pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
445 
446  return RLM_MODULE_UPDATED; /* try the next module */
447 }
448 
449 #ifdef WITH_COA
450 /*
451  * CoA realms via Operator-Name. Because the realm isn't in a
452  * User-Name, concepts like "prefix" and "suffix' don't matter.
453  */
454 static rlm_rcode_t mod_realm_recv_coa(UNUSED void *instance, REQUEST *request)
455 {
456  VALUE_PAIR *vp;
457  REALM *realm;
458 
459  if (fr_pair_find_by_num(request->packet->vps, 0, PW_REALM, TAG_ANY) != NULL) {
460  RDEBUG2("Request already has destination realm set. Ignoring");
461  return RLM_MODULE_NOOP;
462  }
463 
464  vp = fr_pair_find_by_num(request->packet->vps, 0, PW_OPERATOR_NAME, TAG_ANY);
465  if (!vp) return RLM_MODULE_NOOP;
466 
467  /*
468  * Catch the case of broken dictionaries.
469  */
470  if (vp->da->type != PW_TYPE_STRING) return RLM_MODULE_NOOP;
471 
472  /*
473  * The string is too short.
474  */
475  if (vp->vp_length == 1) return RLM_MODULE_NOOP;
476 
477  /*
478  * '1' means "the rest of the string is a realm"
479  */
480  if (vp->vp_strvalue[0] != '1') return RLM_MODULE_NOOP;
481 
482  realm = realm_find(vp->vp_strvalue + 1);
483  if (!realm) return RLM_MODULE_NOTFOUND;
484 
485  if (!realm->coa_pool) {
486  RDEBUG2("CoA realm is LOCAL");
487  return RLM_MODULE_OK;
488  }
489 
490  /*
491  * Maybe add a Proxy-To-Realm attribute to the request.
492  */
493  RDEBUG2("Preparing to proxy authentication request to realm \"%s\"\n",
494  realm->name);
495  pair_make_config("Proxy-To-Realm", realm->name, T_OP_EQ);
496 
497  return RLM_MODULE_UPDATED; /* try the next module */
498 }
499 #endif
500 
501 /* globally exported name */
502 extern module_t rlm_realm;
503 module_t rlm_realm = {
505  .name = "realm",
506  .type = RLM_TYPE_HUP_SAFE,
507  .inst_size = sizeof(struct rlm_realm_t),
508  .config = module_config,
509  .instantiate = mod_instantiate,
510  .methods = {
512  [MOD_PREACCT] = mod_preacct,
513 #ifdef WITH_COA
515 #endif
516  },
517 };
518 
home_server_t * servers[1]
Definition: realms.h:174
bool ignore_null
Definition: rlm_realm.c:39
static int check_for_realm(void *instance, REQUEST *request, REALM **returnrealm)
Definition: rlm_realm.c:70
REALM * tr_query_realm(REQUEST *request, char const *realm, char const *community, char const *rprealm, char const *trustrouter, unsigned int port)
RAD_LISTEN_TYPE type
Definition: listen.h:76
The module is OK, continue.
Definition: radiusd.h:91
Metadata exported by the module.
Definition: modules.h:134
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
int fr_is_inaddr_any(fr_ipaddr_t *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition: packet.c:91
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
static rlm_rcode_t mod_authorize(void *instance, REQUEST *request)
Handle authorization requests using Couchbase document data.
VALUE_PAIR * username
Cached username VALUE_PAIR from request RADIUS_PACKET.
Definition: radiusd.h:222
module_t rlm_realm
Definition: rlm_realm.c:503
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
Headers for trust router code.
#define pair_make_request(_a, _b, _c)
Definition: radiusd.h:545
char const * format_string
Definition: rlm_realm.c:36
int format
Definition: rlm_realm.c:35
home_pool_t * auth_pool
Definition: realms.h:183
Definition: realms.h:178
rad_listen_t * listener
The listener that received the request.
Definition: radiusd.h:218
#define inst
Definition: token.h:46
#define RLM_TYPE_HUP_SAFE
Will be restarted on HUP.
Definition: modules.h:79
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
int af
Address family.
Definition: inet.h:42
RFC2865 - Access-Request.
Definition: radius.h:92
bool strip_realm
Definition: realms.h:181
void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
Copy data into an "string" data type.
Definition: pair.c:2013
home_pool_t * coa_pool
Definition: realms.h:186
#define pair_make_config(_a, _b, _c)
Definition: radiusd.h:547
RFC2866 - Accounting-Request.
Definition: radius.h:95
#define REALM_FORMAT_SUFFIX
Definition: rlm_realm.c:32
unsigned int attr
Attribute number.
Definition: dict.h:79
union fr_ipaddr_t::@1 ipaddr
unsigned int code
Packet code (type).
Definition: libradius.h:155
bool ignore_default
Definition: rlm_realm.c:38
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void rad_const_free(void const *ptr)
Definition: util.c:424
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
bool tr_init(void)
A truth value.
Definition: radius.h:56
static rlm_rcode_t mod_realm_recv_coa(UNUSED void *instance, REQUEST *request)
Definition: rlm_realm.c:454
32 Bit unsigned integer.
Definition: radius.h:34
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
static rs_t * conf
Definition: radsniff.c:46
int strcasecmp(char *s1, char *s2)
Definition: missing.c:73
int num_home_servers
Definition: realms.h:173
Module succeeded without doing anything.
Definition: radiusd.h:96
static rlm_rcode_t CC_HINT(nonnull)
Definition: rlm_realm.c:393
#define RDEBUG2(fmt,...)
Definition: log.h:244
REALM * realm_find(char const *name)
Definition: realms.c:2235
uint64_t magic
Used to validate module struct.
Definition: modules.h:135
#define TAG_ANY
Definition: pair.h:191
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
char const * name
Definition: realms.h:179
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Definition: rlm_realm.c:349
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define REALM_FORMAT_PREFIX
Definition: rlm_realm.c:31
static CONF_PARSER module_config[]
Definition: rlm_realm.c:49
2 methods index for preacct section.
Definition: modules.h:43
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
8 methods index for recvcoa section.
Definition: modules.h:50
IPv4/6 prefix.
Definition: inet.h:41
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
String of printable characters.
Definition: radius.h:33
home_pool_t * acct_pool
Definition: realms.h:184
PW_TYPE type
Value type.
Definition: dict.h:80
1 methods index for authorize section.
Definition: modules.h:42
User not found.
Definition: radiusd.h:95
struct rlm_realm_t rlm_realm_t
#define RCSID(id)
Definition: build.h:135
OK (pairs modified).
Definition: radiusd.h:97
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
uint16_t port
Definition: realms.h:79
int fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition: inet.c:1026
char const * delim
Definition: rlm_realm.c:37
fr_ipaddr_t ipaddr
IP address of home server.
Definition: realms.h:78