⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlm_radutmp2.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * rlm_radutmp.c * * Version:	$Id$ * *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2001,2002,2003,2004,2006  The FreeRADIUS server project */#include	<freeradius-devel/ident.h>RCSID("$Id$")#include	<freeradius-devel/radiusd.h>#include	<freeradius-devel/radutmp.h>#include	<freeradius-devel/modules.h>#include	<freeradius-devel/rad_assert.h>#include	<fcntl.h>#include        <limits.h>#include "config.h"#define LOCK_LEN sizeof(struct radutmp)static const char porttypes[] = "ASITX";/* *	Used for caching radutmp lookups in the accounting *	component. The session (checksimul) component doesn't use it, *	but probably should, though we're not sure how... * *	The intent here is to keep this structure as small as *	possible, so that it doesn't take up too much memory. */typedef struct nas_port {	uint32_t		nas_address;	unsigned int		nas_port;	off_t			offset;	struct nas_port		*next; /* for the free list */} NAS_PORT;/* *	Per-file information. * *	Hmm... having multiple filenames managed by one instance *	of the module makes it difficult for the module to do *	simultaneous-use checking, without more code edits. */typedef struct radutmp_cache_t {	const char	*filename; /* for future reference */	time_t		last_used; /* for future reference */	rbtree_t	*nas_ports;	NAS_PORT	*free_offsets;	off_t		max_offset;	int		cached_file;	int		permission;#ifdef HAVE_PTHREAD_H	pthread_mutex_t	mutex;#endif} radutmp_cache_t;/* *	We cache the users, too, so that we only have to read radutmp *	once. */typedef struct radutmp_simul_t {	char		login[sizeof(((struct radutmp *) NULL)->login) + 1];	int		simul_count;} radutmp_simul_t;/* *	Data we store per module. */typedef struct rlm_radutmp_t {	char		*filename;	char		*username;	int		case_sensitive;	int		check_nas;	int		permission;	int		callerid_ok;	rbtree_t	*user_tree; /* for simultaneous-use */	/*	 *	As the filenames can be dynamically translated,	 *	we want to keep track of them in a separate data	 *	structure, so that we can have per-file caches.	 */	radutmp_cache_t cache;} rlm_radutmp_t;#ifndef HAVE_PTHREAD_H/* *	This is easier than ifdef's throughout the code. */#define pthread_mutex_init(_x, _y)#define pthread_mutex_destroy(_x)#define pthread_mutex_lock(_x)#define pthread_mutex_unlock(_x)#endifstatic const CONF_PARSER module_config[] = {	{ "filename", PW_TYPE_STRING_PTR,	  offsetof(rlm_radutmp_t,filename), NULL,  RADUTMP },	{ "username", PW_TYPE_STRING_PTR,	  offsetof(rlm_radutmp_t,username), NULL,  "%{User-Name}"},	{ "case_sensitive", PW_TYPE_BOOLEAN,	  offsetof(rlm_radutmp_t,case_sensitive), NULL,  "yes"},	{ "check_with_nas", PW_TYPE_BOOLEAN,	  offsetof(rlm_radutmp_t,check_nas), NULL,  "yes"},	{ "perm",     PW_TYPE_INTEGER,	  offsetof(rlm_radutmp_t,permission), NULL,  "0644" },	{ "callerid", PW_TYPE_BOOLEAN,	  offsetof(rlm_radutmp_t,callerid_ok), NULL, "no" },	{ NULL, -1, 0, NULL, NULL }		/* end the list */};/* *	NAS PORT cmp */static int nas_port_cmp(const void *a, const void *b){	const NAS_PORT *one = a;	const NAS_PORT *two = b;	if (one->nas_address < two->nas_address) return -1;	if (one->nas_address > two->nas_address) return +1;	if (one->nas_port < two->nas_port) return -1;	if (one->nas_port > two->nas_port) return +1;	return 0;}/* *	Compare two user names. */static int user_cmp(const void *a, const void *b){	const radutmp_simul_t *one = a;	const radutmp_simul_t *two = b;	return strcmp(one->login, two->login);}/* *	Compare two user names, case insensitive. */static int user_case_cmp(const void *a, const void *b){	const radutmp_simul_t *one = a;	const radutmp_simul_t *two = b;	return strcasecmp(one->login, two->login);}/* *	Detach. */static int radutmp_detach(void *instance){	NAS_PORT	*this, *next;	rlm_radutmp_t *inst = instance;	rbtree_free(inst->cache.nas_ports);	for (this = inst->cache.free_offsets;	     this != NULL;	     this = next) {		next = this->next;		free(this);	}	if (inst->cache.filename) free(inst->cache.filename);	pthread_mutex_destroy(&(inst->cache.mutex));	rbtree_free(inst->user_tree);	free(inst);	return 0;}/* *	Instantiate. */static int radutmp_instantiate(CONF_SECTION *conf, void **instance){	rlm_radutmp_t *inst;	inst = rad_malloc(sizeof(*inst));	if (!inst) {		return -1;	}	memset(inst, 0, sizeof(*inst));	if (cf_section_parse(conf, inst, module_config)) {		radutmp_detach(inst);		return -1;	}	inst->cache.nas_ports = rbtree_create(nas_port_cmp, free, 0);	if (!inst->cache.nas_ports) {		radlog(L_ERR, "rlm_radutmp: Failed to create nas tree");		radutmp_detach(inst);		return -1;	}	pthread_mutex_init(&(inst->cache.mutex), NULL);	inst->cache.permission = inst->permission;	if (inst->case_sensitive) {		inst->user_tree = rbtree_create(user_cmp, free, 0);	} else {		inst->user_tree = rbtree_create(user_case_cmp, free, 0);	}	if (!inst->user_tree) {		radlog(L_ERR, "rlm_radutmp: Failed to create user tree");		radutmp_detach(inst);		return -1;	}	*instance = inst;	return 0;}/* *	Reset the cached entries. */static int cache_reset(rlm_radutmp_t *inst, radutmp_cache_t *cache){	NAS_PORT *this, *next;	/*	 *	Cache is already reset, do nothing.	 */	if ((rbtree_num_elements(cache->nas_ports) == 0) &&	    (cache->free_offsets == NULL)) {		DEBUG2("  rlm_radutmp: Not resetting the cache");		return 1;	}	DEBUG2("  rlm_radutmp: Resetting the cache");	pthread_mutex_lock(&cache->mutex);	rbtree_free(inst->user_tree);	rbtree_free(cache->nas_ports);	for (this = cache->free_offsets;	     this != NULL;	     this = next) {		next = this->next;		free(this);	}	cache->free_offsets = NULL;	/*	 *	Re-create the caches.	 */	cache->nas_ports = rbtree_create(nas_port_cmp, free, 0);	if (!cache->nas_ports) {		pthread_mutex_unlock(&cache->mutex);		radlog(L_ERR, "rlm_radutmp: No memory");		return 0;	}	cache->max_offset = 0;	cache->cached_file = 1;	if (inst->case_sensitive) {		inst->user_tree = rbtree_create(user_cmp, free, 0);	} else {		inst->user_tree = rbtree_create(user_case_cmp, free, 0);	}	if (!inst->user_tree) {		pthread_mutex_unlock(&cache->mutex);		radlog(L_ERR, "rlm_radutmp: No memory");		return 0;	}	pthread_mutex_unlock(&cache->mutex);	return 1;}/* *	Compare two offsets in a tree. */static int offset_cmp(const void *a, const void *b){	const NAS_PORT *one = a;	const NAS_PORT *two = b;	if (one->offset < two->offset) return -1;	if (one->offset > two->offset) return +1;	return 0;}/* *	Data structure to use when walking the trees, for zap. */typedef struct offset_walk_t {	rlm_radutmp_t	*inst;	radutmp_cache_t	*cache;	rbtree_t	*offset_tree;	uint32_t	nas_address;	int		fd;	time_t		now;} offset_walk_t;/* *	Walk over the cache, finding entries with the matching NAS IP address. */static int nas_port_walk(void *context, void *data){	offset_walk_t	*walk = context;	NAS_PORT	*nas_port = data;	/*	 *	Doesn't match, keep going.	 */	if (walk->nas_address != nas_port->nas_address) return 0;	/*	 *	Insert it into the offset tree, for later deletion.	 */	if (rbtree_insert(walk->offset_tree, nas_port) != 1) {		DEBUG2("  rlm_radumtp: Insertion failed in nas port walk.");		return 1;	}	return 0;}/* *	Walk through the offset tree, operating on the cache */static int offset_walk(void *context, void *data){	offset_walk_t	*walk = context;	NAS_PORT	*nas_port = data;	struct radutmp	utmp;	radutmp_simul_t *user, myUser;	/*	 *	Seek to the entry, and possibly re-write it.	 */	if (lseek(walk->fd, nas_port->offset, SEEK_SET) < 0) {		rad_assert(0 == 1);	}	if (read(walk->fd, &utmp, sizeof(utmp)) != sizeof(utmp)) {		rad_assert(0 == 1);	}	/*	 *	If the entry in the file is NEWER than the reboot	 *	packet, don't re-write it, and don't delete it.	 */	if (utmp.time > walk->now) {		return 0;	}	utmp.type = P_IDLE;	utmp.time = walk->now;	if (lseek(walk->fd, -(off_t)sizeof(utmp), SEEK_CUR) < 0) {		radlog(L_ERR, "rlm_radutmp: offset_walk: failed in lseek: %s",		       strerror(errno));		return 1;	}	write(walk->fd, &utmp, sizeof(utmp));	strlcpy(myUser.login, utmp.login, sizeof(myUser.login));	user = rbtree_finddata(walk->inst->user_tree, &myUser);	rad_assert(user != NULL);	rad_assert(user->simul_count > 0);	user->simul_count--;	if (user->simul_count == 0) {		rbtree_deletebydata(walk->inst->user_tree, user);	}	if (rbtree_deletebydata(walk->cache->nas_ports, nas_port) == 0) {		radlog(L_ERR, "rlm_radutmp: Failed to delete entry from cache");		return 1;	}	/*	 *	Insert the entry into the free list.	 */	nas_port->next = walk->cache->free_offsets;	walk->cache->free_offsets = nas_port;	return 0;}/* *	Zap all users on a NAS from the radutmp file. */static int radutmp_zap(rlm_radutmp_t *inst,		       radutmp_cache_t *cache,		       uint32_t nas_address,		       time_t now){	int		rcode;	rbtree_t	*offset_tree;	offset_walk_t	walk;	rad_assert(now != 0);	/*	 *	If there's nothing in the file, do nothing,	 *	but truncate the file, just to be safe.	 */	if (rbtree_num_elements(cache->nas_ports) == 0) {		truncate(cache->filename, (off_t) 0);		DEBUG2("  rlm_radutmp: No entries in file.  Quenching zap.");		return 1;	}	/*	 *	Create the offset tree, as we want to delete utmp	 *	entries starting from the start of the file, and we	 *	can't delete nodes from an rbtree while we're walking	 *	it.	 */	offset_tree = rbtree_create(offset_cmp, NULL, 0);	if (!offset_tree) {		radlog(L_ERR, "rlm_radutmp: Out of memory");		return 0;	}	pthread_mutex_lock(&cache->mutex);	/*	 *	Walk through the cache, finding entries for this NAS,	 *	and add those entries to the offset tree.	 */	memset(&walk, 0, sizeof(walk));	walk.inst = inst;	walk.offset_tree = offset_tree;	walk.nas_address = nas_address;	rcode = rbtree_walk(cache->nas_ports, PreOrder, nas_port_walk, &walk);	if (rcode != 0) {		pthread_mutex_unlock(&cache->mutex);		rbtree_free(offset_tree);		radlog(L_ERR, "rlm_radutmp: Failed walking the cache.");		return 0;	}	/*	 *	If both trees have the same number of elements, then	 *	don't do anything special, as UDP packets may be	 *	received out of order, by several seconds.  The	 *	"offset_walk" routine MAY NOT delete the entries, if	 *	it sees that the entries in the file are newer than	 *	the reboot packet.	 */	/*	 *	If there's nothing to do, don't do anything.	 */	if (rbtree_num_elements(offset_tree) == 0) {		DEBUG2("  rlm_radutmp: NAS IP %08x has no users recorded in file %s.",		       htonl(nas_address), cache->filename);		pthread_mutex_unlock(&cache->mutex);		rbtree_free(offset_tree);		return 1;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -