📄 rlm_fastusers.c
字号:
/* * rlm_fastusers.c authorization: Find a user in the hashed "users" file. * accounting: Do nothing. Auth module only. * * Version: $Id: rlm_fastusers.c,v 1.33 2004/05/15 15:09:44 mgriego Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000 The FreeRADIUS server project * Copyright 2000 Jeff Carneal <jeff@apex.net> */#include "autoconf.h"#include "libradius.h"#include <sys/socket.h>#include <sys/time.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <pwd.h>#include <grp.h>#include <ctype.h>#include <fcntl.h>#include <limits.h>#include "radiusd.h"#include "modules.h"struct fastuser_instance { char *compat_mode; int hash_reload; /* hash table */ int hashsize; PAIR_LIST **hashtable; PAIR_LIST *defaults; PAIR_LIST *acctusers; int stats; char *usersfile; char *acctusersfile; time_t next_reload; time_t lastusersload; time_t lastacctusersload;};/* Function declarations */static int fallthrough(VALUE_PAIR *vp);static int fastuser_buildhash(struct fastuser_instance *inst);static int fastuser_getfile(struct fastuser_instance *inst, const char *filename, PAIR_LIST **default_list, PAIR_LIST **pair_list, int isacctfile);static int fastuser_hash(const char *s, int hashtablesize);static int fastuser_store(PAIR_LIST **hashtable, PAIR_LIST *entry, int idx);static PAIR_LIST *fastuser_find(REQUEST *request, PAIR_LIST *user, const char *username);static void fastuser_tablestats(PAIR_LIST **hashtable, int size);static int fastuser_passcheck(REQUEST *request, PAIR_LIST *user, const char *name);static CONF_PARSER module_config[] = { { "usersfile", PW_TYPE_STRING_PTR, offsetof(struct fastuser_instance,usersfile), NULL, "${raddbdir}/users_fast" }, { "acctusersfile", PW_TYPE_STRING_PTR, offsetof(struct fastuser_instance,acctusersfile), NULL, "${raddbdir}/acct_users" }, { "hashsize", PW_TYPE_INTEGER, offsetof(struct fastuser_instance,hashsize), NULL, "100000" }, { "stats", PW_TYPE_BOOLEAN, offsetof(struct fastuser_instance,stats), NULL, "no" }, { "compat", PW_TYPE_STRING_PTR, offsetof(struct fastuser_instance,compat_mode), NULL, "cistron" }, { "hash_reload", PW_TYPE_INTEGER, offsetof(struct fastuser_instance,hash_reload), NULL, "600" }, { NULL, -1, 0, NULL, NULL }};/* * See if a VALUE_PAIR list contains Fall-Through = Yes */static int fallthrough(VALUE_PAIR *vp){ VALUE_PAIR *tmp; tmp = pairfind(vp, PW_FALL_THROUGH); return tmp ? tmp->lvalue : 0;}/* * returncheck - Check for Auth-Type = Reject and return appropriate * module return code if it is found. */static int rad_check_return(VALUE_PAIR *list){ VALUE_PAIR *authtype; /* * We check for Auth-Type = Reject here */ authtype = pairfind(list, PW_AUTHTYPE); if((authtype) && authtype->lvalue == PW_AUTHTYPE_REJECT) { DEBUG2("rad_check_return: Auth-Type is Reject"); return RLM_MODULE_REJECT; } return RLM_MODULE_UPDATED;}static int fastuser_buildhash(struct fastuser_instance *inst) { int memsize=0; int rcode, hashindex; PAIR_LIST **newhash=NULL, **oldhash=NULL; PAIR_LIST *newdefaults=NULL, *newacctusers, *cur=NULL; PAIR_LIST *olddefaults=NULL, *oldacctusers=NULL; struct stat statbuf; int reloadusers = 1; int reloadacctusers = 1; /* * Allocate space for hash table here */ memsize = sizeof(PAIR_LIST *) * inst->hashsize; newhash = (PAIR_LIST **) rad_malloc(memsize); memset((PAIR_LIST *)newhash, 0, memsize); /* Check acct_users last modification time */ if ((stat(inst->acctusersfile, &statbuf) != -1) && (statbuf.st_mtime <= inst->lastacctusersload)) { DEBUG2("rlm_fastusers: File %s was unchanged. Not reloading.", inst->acctusersfile); reloadacctusers = 0; rcode = 0; } else /* Read acct_users */ rcode = fastuser_getfile(inst, inst->acctusersfile, NULL, &newacctusers, 1); if (rcode != 0) { radlog(L_ERR|L_CONS, "rlm_fastusers: Errors reading %s", inst->usersfile); return -1; } /* Check users last modification time */ if ((stat(inst->usersfile, &statbuf) != -1) && (statbuf.st_mtime <= inst->lastusersload)) { DEBUG2("rlm_fastusers: File %s was unchanged. Not reloading.", inst->usersfile); reloadusers = 0; rcode = 0; /* This was allocated earlier but will remain unused */ free(newhash); } else /* Read users */ rcode = fastuser_getfile(inst, inst->usersfile, &newdefaults, newhash, 0); if (rcode != 0) { radlog(L_ERR|L_CONS, "rlm_fastusers: Errors reading %s", inst->usersfile); return -1; } if (reloadusers) { /* * We need to do this now so that users auths * aren't blocked while we free the old table * below */ inst->lastusersload = time(NULL); oldhash = inst->hashtable; inst->hashtable = newhash; olddefaults = inst->defaults; inst->defaults = newdefaults; /* * When we get here, we assume the hash built properly. * So we begin to tear down the old one */ if (oldhash) { for(hashindex=0; hashindex<inst->hashsize; hashindex++) { if(oldhash[hashindex]) { cur = oldhash[hashindex]; pairlist_free(&cur); } } free(oldhash); } pairlist_free(&olddefaults); } if (reloadacctusers) { inst->lastacctusersload = time(NULL); oldacctusers = inst->acctusers; inst->acctusers = newacctusers; pairlist_free(&oldacctusers); } if(inst->stats) fastuser_tablestats(inst->hashtable, inst->hashsize); return 0;}static int fastuser_getfile(struct fastuser_instance *inst, const char *filename, PAIR_LIST **default_list, PAIR_LIST **pair_list, int isacctfile) { int rcode; PAIR_LIST *users = NULL; PAIR_LIST *entry=NULL, *next=NULL, *cur=NULL, *defaults=NULL, *lastdefault=NULL; int compat_mode = FALSE; VALUE_PAIR *vp=NULL; int hashindex = 0; int numdefaults = 0, numusers=0; radlog(L_INFO, " fastusers: Reading %s", filename); rcode = pairlist_read(filename, &users, 1); if (rcode < 0) { return -1; } if (strcmp(inst->compat_mode, "cistron") == 0) { compat_mode = TRUE; } entry = users; while (entry) { if (compat_mode) { DEBUG("[%s]:%d Cistron compatibility checks for entry %s ...", filename, entry->lineno, entry->name); } /* * Look for improper use of '=' in the * check items. They should be using * '==' for on-the-wire RADIUS attributes, * and probably ':=' for server * configuration items. */ for (vp = entry->check; vp != NULL; vp = vp->next) { /* * Ignore attributes which are set * properly. */ if (vp->operator != T_OP_EQ) continue; /* * If it's a vendor attribute, * or it's a wire protocol, * ensure it has '=='. */ if (((vp->attribute & ~0xffff) != 0) || (vp->attribute < 0x100)) { if (!compat_mode) { DEBUG("[%s]:%d WARNING! Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for user %s", filename, entry->lineno, vp->name, vp->name, entry->name); } else { DEBUG("\tChanging '%s =' to '%s =='", vp->name, vp->name); } vp->operator = T_OP_CMP_EQ; continue; } /* * Cistron Compatibility mode. * * Re-write selected attributes * to be '+=', instead of '='. * * All others get set to '==' */ if (compat_mode) { /* * Non-wire attributes become += * * On the write attributes * become == */ if ((vp->attribute >= 0x100) && (vp->attribute <= 0xffff) && (vp->attribute != PW_HINT) && (vp->attribute != PW_HUNTGROUP_NAME)) { DEBUG("\tChanging '%s =' to '%s +='", vp->name, vp->name); vp->operator = T_OP_ADD; } else { DEBUG("\tChanging '%s =' to '%s =='", vp->name, vp->name); vp->operator = T_OP_CMP_EQ; } } } /* end of loop over check items */ /* * Look for server configuration items * in the reply list. * * It's a common enough mistake, that it's * worth doing. */ for (vp = entry->reply; vp != NULL; vp = vp->next) { /* * If it's NOT a vendor attribute, * and it's NOT a wire protocol * and we ignore Fall-Through, * then bitch about it, giving a * good warning message. */ if (!(vp->attribute & ~0xffff) && (vp->attribute > 0xff) && (vp->attribute > 1000)) { log_debug("[%s]:%d WARNING! Check item \"%s\"\n" "\tfound in reply item list for user \"%s\".\n" "\tThis attribute MUST go on the first line" " with the other check items", filename, entry->lineno, vp->name, entry->name); } } /* * Ok, we've done all the same BS as * rlm_users, so here we tear apart the * linked list, and store our users in * the hashtable we've built instead */ /* Save what was next */ next = entry->next; if(!isacctfile) { /* Save the DEFAULT entry specially */ if(strcmp(entry->name, "DEFAULT")==0) { /* Save this as the last default we've seen */ lastdefault = entry; numdefaults++; /* put it at the end of the list */ if(defaults) { for(cur=defaults; cur->next; cur=cur->next); cur->next = entry; entry->next = NULL; } else { defaults = entry; defaults->next = NULL; } } else { numusers++; /* Hash the username */ hashindex = fastuser_hash(entry->name, inst->hashsize); /* Store the last default before this entry */ entry->lastdefault = lastdefault; /* Store user in the hash */ fastuser_store(pair_list, entry, hashindex); } } /* Restore entry to next pair_list */ entry = next; } /* while(entry) loop */ if(!isacctfile && (default_list)) { *default_list = defaults; radlog(L_INFO, "rlm_fastusers: Loaded %d users and %d defaults", numusers, numdefaults); } else { *pair_list = users; } return 0;}/* Hashes the username sent to it and returns index into hashtable */int fastuser_hash(const char *s, int hashtablesize) { unsigned int hash = 0; while (*s != '\0') { hash = hash * 7907 + (unsigned char)*s++; } return (hash % hashtablesize);}/* Stores the username sent into the hashtable */static int fastuser_store(PAIR_LIST **hashtable, PAIR_LIST *new, int idx) { PAIR_LIST *cur; cur = hashtable[idx]; /* store new record at end of list */ if(cur) { while (cur->next != NULL) cur=cur->next; cur->next = new; new->next = NULL; } else { new->next = hashtable[idx]; hashtable[idx] = new; } return 1;}/* * Looks up user in hashtable. If user can't be found, returns 0. * Otherwise returns a pointer to the structure for the user */static PAIR_LIST *fastuser_find(REQUEST *request, PAIR_LIST *user, const char *username){ PAIR_LIST *cur=user;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -