2 * rlm_files.c authorization: Find a user in the "users" file.
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 2002 The FreeRADIUS server project
21 * Copyright 2000 Jeff Carneal <jeff@apex.net>
24 static const char rcsid[] = "$Id$";
26 #include <freeradius-devel/autoconf.h>
37 #include <freeradius-devel/radiusd.h>
38 #include <freeradius-devel/modules.h>
40 struct file_instance {
45 lrad_hash_table_t *users;
49 lrad_hash_table_t *acctusers;
52 char *preproxy_usersfile;
53 lrad_hash_table_t *preproxy_users;
57 lrad_hash_table_t *auth_users;
60 char *postproxy_usersfile;
61 lrad_hash_table_t *postproxy_users;
63 /* post-authenticate */
64 char *postauth_usersfile;
65 lrad_hash_table_t *postauth_users;
70 * See if a VALUE_PAIR list contains Fall-Through = Yes
72 static int fallthrough(VALUE_PAIR *vp)
75 tmp = pairfind(vp, PW_FALL_THROUGH);
77 return tmp ? tmp->lvalue : 0;
80 static const CONF_PARSER module_config[] = {
81 { "usersfile", PW_TYPE_FILENAME,
82 offsetof(struct file_instance,usersfile), NULL, NULL },
83 { "acctusersfile", PW_TYPE_FILENAME,
84 offsetof(struct file_instance,acctusersfile), NULL, NULL },
85 { "preproxy_usersfile", PW_TYPE_FILENAME,
86 offsetof(struct file_instance,preproxy_usersfile), NULL, NULL },
87 { "auth_usersfile", PW_TYPE_FILENAME,
88 offsetof(struct file_instance,auth_usersfile), NULL, NULL },
89 { "postproxy_usersfile", PW_TYPE_FILENAME,
90 offsetof(struct file_instance,postproxy_usersfile), NULL, NULL },
91 { "postauth_usersfile", PW_TYPE_FILENAME,
92 offsetof(struct file_instance,postauth_usersfile), NULL, NULL },
93 { "compat", PW_TYPE_STRING_PTR,
94 offsetof(struct file_instance,compat_mode), NULL, "cistron" },
95 { NULL, -1, 0, NULL, NULL }
99 static void my_pairlist_free(void *data)
101 PAIR_LIST *pl = data;
107 static int getusersfile(const char *filename, lrad_hash_table_t **pht,
108 char *compat_mode_str)
111 PAIR_LIST *users = NULL;
112 PAIR_LIST *entry, *next;
113 lrad_hash_table_t *ht, *tailht;
121 rcode = pairlist_read(filename, &users, 1);
127 * Walk through the 'users' file list, if we're debugging,
128 * or if we're in compat_mode.
131 (strcmp(compat_mode_str, "cistron") == 0)) {
133 int compat_mode = FALSE;
135 if (strcmp(compat_mode_str, "cistron") == 0) {
142 DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...",
143 filename, entry->lineno,
148 * Look for improper use of '=' in the
149 * check items. They should be using
150 * '==' for on-the-wire RADIUS attributes,
151 * and probably ':=' for server
152 * configuration items.
154 for (vp = entry->check; vp != NULL; vp = vp->next) {
156 * Ignore attributes which are set
159 if (vp->operator != T_OP_EQ) {
164 * If it's a vendor attribute,
165 * or it's a wire protocol,
166 * ensure it has '=='.
168 if (((vp->attribute & ~0xffff) != 0) ||
169 (vp->attribute < 0x100)) {
171 DEBUG("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s",
172 filename, entry->lineno,
176 DEBUG("\tChanging '%s =' to '%s =='",
179 vp->operator = T_OP_CMP_EQ;
184 * Cistron Compatibility mode.
186 * Re-write selected attributes
187 * to be '+=', instead of '='.
189 * All others get set to '=='
193 * Non-wire attributes become +=
195 * On the write attributes
198 if ((vp->attribute >= 0x100) &&
199 (vp->attribute <= 0xffff) &&
200 (vp->attribute != PW_HINT) &&
201 (vp->attribute != PW_HUNTGROUP_NAME)) {
202 DEBUG("\tChanging '%s =' to '%s +='",
204 vp->operator = T_OP_ADD;
206 DEBUG("\tChanging '%s =' to '%s =='",
208 vp->operator = T_OP_CMP_EQ;
212 } /* end of loop over check items */
216 * Look for server configuration items
219 * It's a common enough mistake, that it's
222 for (vp = entry->reply; vp != NULL; vp = vp->next) {
224 * If it's NOT a vendor attribute,
225 * and it's NOT a wire protocol
226 * and we ignore Fall-Through,
227 * then bitch about it, giving a
228 * good warning message.
230 if (!(vp->attribute & ~0xffff) &&
231 (vp->attribute > 0xff) &&
232 (vp->attribute > 1000)) {
233 log_debug("[%s]:%d WARNING! Check item \"%s\"\n"
234 "\tfound in reply item list for user \"%s\".\n"
235 "\tThis attribute MUST go on the first line"
236 " with the other check items",
237 filename, entry->lineno, vp->name,
247 ht = lrad_hash_table_create(my_pairlist_free);
249 pairlist_free(&users);
253 tailht = lrad_hash_table_create(NULL);
255 lrad_hash_table_free(ht);
256 pairlist_free(&users);
261 * Now that we've read it in, put the entries into a hash
264 for (entry = users; entry != NULL; entry = next) {
270 entry->order = order++;
272 hash = lrad_hash_string(entry->name);
275 * Insert it into the hash table, and remember
276 * the tail of the linked list.
278 tail = lrad_hash_table_finddata(tailht, hash);
281 * Insert it into the head & tail.
283 if (!lrad_hash_table_insert(ht, hash, entry) ||
284 !lrad_hash_table_insert(tailht, hash, entry)) {
285 pairlist_free(&next);
286 lrad_hash_table_free(ht);
287 lrad_hash_table_free(tailht);
292 if (!lrad_hash_table_replace(tailht, hash, entry)) {
293 pairlist_free(&next);
294 lrad_hash_table_free(ht);
295 lrad_hash_table_free(tailht);
301 lrad_hash_table_free(tailht);
310 static int file_detach(void *instance)
312 struct file_instance *inst = instance;
313 lrad_hash_table_free(inst->users);
314 lrad_hash_table_free(inst->acctusers);
315 lrad_hash_table_free(inst->preproxy_users);
316 lrad_hash_table_free(inst->auth_users);
317 lrad_hash_table_free(inst->postproxy_users);
318 lrad_hash_table_free(inst->postauth_users);
319 free(inst->usersfile);
320 free(inst->acctusersfile);
321 free(inst->preproxy_usersfile);
322 free(inst->auth_usersfile);
323 free(inst->postproxy_usersfile);
324 free(inst->postauth_usersfile);
325 free(inst->compat_mode);
333 * (Re-)read the "users" file into memory.
335 static int file_instantiate(CONF_SECTION *conf, void **instance)
337 struct file_instance *inst;
340 inst = rad_malloc(sizeof *inst);
344 memset(inst, 0, sizeof(*inst));
346 if (cf_section_parse(conf, inst, module_config) < 0) {
351 rcode = getusersfile(inst->usersfile, &inst->users, inst->compat_mode);
353 radlog(L_ERR|L_CONS, "Errors reading %s", inst->usersfile);
358 rcode = getusersfile(inst->acctusersfile, &inst->acctusers, inst->compat_mode);
360 radlog(L_ERR|L_CONS, "Errors reading %s", inst->acctusersfile);
366 * Get the pre-proxy stuff
368 rcode = getusersfile(inst->preproxy_usersfile, &inst->preproxy_users, inst->compat_mode);
370 radlog(L_ERR|L_CONS, "Errors reading %s", inst->preproxy_usersfile);
375 rcode = getusersfile(inst->auth_usersfile, &inst->auth_users, inst->compat_mode);
377 radlog(L_ERR|L_CONS, "Errors reading %s", inst->auth_usersfile);
382 rcode = getusersfile(inst->postproxy_usersfile, &inst->postproxy_users, inst->compat_mode);
384 radlog(L_ERR|L_CONS, "Errors reading %s", inst->postproxy_usersfile);
389 rcode = getusersfile(inst->postauth_usersfile, &inst->postauth_users, inst->compat_mode);
391 radlog(L_ERR|L_CONS, "Errors reading %s", inst->postauth_usersfile);
401 * Common code called by everything below.
403 static int file_common(struct file_instance *inst, REQUEST *request,
404 const char *filename, lrad_hash_table_t *ht,
405 VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs)
407 VALUE_PAIR *namepair;
409 VALUE_PAIR **config_pairs;
410 VALUE_PAIR *check_tmp;
411 VALUE_PAIR *reply_tmp;
412 const PAIR_LIST *user_pl, *default_pl;
415 inst = inst; /* -Wunused fix later? */
417 namepair = request->username;
418 name = namepair ? (char *) namepair->vp_strvalue : "NONE";
419 config_pairs = &request->config_items;
421 if (!ht) return RLM_MODULE_NOOP;
423 user_pl = lrad_hash_table_finddata(ht, lrad_hash_string(name));
424 default_pl = lrad_hash_table_finddata(ht, lrad_hash_string("DEFAULT"));
427 * Find the entry for the user.
429 while (user_pl || default_pl) {
434 user_pl = user_pl->next;
436 } else if (!user_pl) {
438 default_pl = default_pl->next;
441 if (user_pl->order < default_pl->order) {
443 user_pl = user_pl->next;
446 default_pl = default_pl->next;
450 if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) {
451 DEBUG2(" %s: Matched entry %s at line %d",
452 filename, pl->name, pl->lineno);
454 check_tmp = paircopy(pl->check);
455 reply_tmp = paircopy(pl->reply);
456 pairxlatmove(request, reply_pairs, &reply_tmp);
457 pairmove(config_pairs, &check_tmp);
458 pairfree(&reply_tmp);
459 pairfree(&check_tmp); /* should be NULL */
464 if (!fallthrough(pl->reply))
470 * Remove server internal parameters.
472 pairdelete(reply_pairs, PW_FALL_THROUGH);
475 * See if we succeeded.
478 return RLM_MODULE_NOOP; /* on to the next module */
480 return RLM_MODULE_OK;
486 * Find the named user in the database. Create the
487 * set of attribute-value pairs to check and reply with
488 * for this user from the database. The main code only
489 * needs to check the password, the rest is done here.
491 static int file_authorize(void *instance, REQUEST *request)
493 struct file_instance *inst = instance;
495 return file_common(inst, request, "users", inst->users,
496 request->packet->vps, &request->reply->vps);
501 * Pre-Accounting - read the acct_users file for check_items and
502 * config_items. Reply items are Not Recommended(TM) in acct_users,
503 * except for Fallthrough, which should work
505 static int file_preacct(void *instance, REQUEST *request)
507 struct file_instance *inst = instance;
509 return file_common(inst, request, "acct_users", inst->acctusers,
510 request->packet->vps, &request->reply->vps);
513 static int file_preproxy(void *instance, REQUEST *request)
515 struct file_instance *inst = instance;
517 return file_common(inst, request, "preproxy_users",
518 inst->preproxy_users,
519 request->packet->vps, &request->proxy->vps);
522 static int file_postproxy(void *instance, REQUEST *request)
524 struct file_instance *inst = instance;
526 return file_common(inst, request, "postproxy_users",
527 inst->postproxy_users,
528 request->proxy_reply->vps, &request->reply->vps);
531 static int file_authenticate(void *instance, REQUEST *request)
533 struct file_instance *inst = instance;
535 return file_common(inst, request, "auth_users",
537 request->packet->vps, &request->reply->vps);
540 static int file_postauth(void *instance, REQUEST *request)
542 struct file_instance *inst = instance;
544 return file_common(inst, request, "postauth_users",
545 inst->postauth_users,
546 request->packet->vps, &request->reply->vps);
550 /* globally exported name */
551 module_t rlm_files = {
554 0, /* type: reserved */
555 file_instantiate, /* instantiation */
556 file_detach, /* detach */
558 file_authenticate, /* authentication */
559 file_authorize, /* authorization */
560 file_preacct, /* preaccounting */
561 NULL, /* accounting */
562 NULL, /* checksimul */
563 file_preproxy, /* pre-proxy */
564 file_postproxy, /* post-proxy */
565 file_postauth /* post-auth */