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

📄 rlm_radutmp2.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 *	Open the file, to re-write only a few of the entries.	 */	walk.fd = open(cache->filename, O_RDWR);	if (walk.fd < 0) {		pthread_mutex_unlock(&cache->mutex);		rbtree_free(offset_tree);		radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",		       cache->filename, strerror(errno));		return 0;	}	/*	 *	Lock the utmp file, prefer lockf() over flock().	 *	 *	FIXME: maybe we want to lock per-record?	 */	rad_lockfd(walk.fd, LOCK_LEN);	/*	 *	Walk through the offset tree, from start to finish,	 *	deleting entries from the NAS tree, adding them to	 *	the "free offset" cache, and lseek'ing to that offset	 *	in the file, and clearing out the data.	 */	walk.cache = cache;	walk.now = now;	rcode = rbtree_walk(offset_tree, InOrder, offset_walk, &walk);	rbtree_free(offset_tree);	if (rcode != 0) {		radlog(L_ERR, "rlm_radutmp: Failed walking the offsets.");		return 0;	}	close(walk.fd);	/* and implicitly release the locks */	/*	 *	Just to clean up the file.  If it's empty,	 *	nuke everything.	 */	if (rbtree_num_elements(cache->nas_ports) == 0) {		NAS_PORT	*this, *next; /* too many copies of code */		for (this = inst->cache.free_offsets;		     this != NULL;		     this = next) {			next = this->next;			free(this);		}		truncate(cache->filename, 0);		rad_assert(rbtree_num_elements(inst->user_tree) == 0);	}	pthread_mutex_unlock(&cache->mutex);	return 1;}/* *	Read a file, to cache all of its entries. */static int cache_file(rlm_radutmp_t *inst, radutmp_cache_t *cache){	int		fd;	int		read_size;	struct		stat buf;	struct		radutmp utmp;	NAS_PORT	**tail;	rad_assert(cache->max_offset == 0);	rad_assert(cache->free_offsets == NULL);	/*	 *	Doesn't exist, we're fine.	 */	if (stat(cache->filename, &buf) < 0) {		if (errno == ENOENT) {			cache->cached_file = 1;			return 0;		}		radlog(L_ERR, "rlm_radutmp: Cannot stat %s: %s",		       cache->filename, strerror(errno));		return 1;	}	/*	 *	Nothing's there, we're OK.	 */	if (buf.st_size == 0) {		cache->cached_file = 1;		return 0;	}	/*	 *	Don't let others much around with our data.	 */	pthread_mutex_lock(&cache->mutex);	/*	 *	Read the file and cache it's entries.	 */	fd = open(cache->filename, O_RDONLY, cache->permission);	if (fd < 0) {		pthread_mutex_unlock(&cache->mutex);		radlog(L_ERR, "rlm_radutmp: Error opening %s: %s",		       cache->filename, strerror(errno));		return 1;	}	/*	 *	Insert free entries into the tail, so that entries	 *	get used from the start.	 */	tail = &(cache->free_offsets);	/*	 *	Don't lock the file, as we're only reading it.	 */	do {		read_size = read(fd, &utmp, sizeof(utmp));		/*		 *	Read one record.		 */		if (read_size == sizeof(utmp)) {			radutmp_simul_t *user, myUser;			NAS_PORT *nas_port = rad_malloc(sizeof(*nas_port));			memset(nas_port, 0, sizeof(nas_port));			nas_port->offset = cache->max_offset;			cache->max_offset += sizeof(utmp);			/*			 *	Idle.  Add it to the list of free			 *	offsets.			 */			if (utmp.type == P_IDLE) {				*tail = nas_port;				tail = &(nas_port->next);				continue;			}			/*			 *	It's a login record,			 */			nas_port->nas_address = utmp.nas_address;			nas_port->nas_port = utmp.nas_port;			if (!rbtree_insert(cache->nas_ports, nas_port)) {				rad_assert(0 == 1);			}			/*			 *	Adds a trailing \0, so myUser.login has			 *	an extra char allocated..			 */			strlcpy(myUser.login, utmp.login, sizeof(myUser.login));			user = rbtree_finddata(inst->user_tree, &myUser);			if (user) {				user->simul_count++;			} else {				/*				 *	Allocate new entry, and add it				 *	to the tree.				 */				user = rad_malloc(sizeof(user));				strlcpy(user->login, utmp.login,					sizeof(user->login));				user->simul_count = 1;				if (!rbtree_insert(inst->user_tree, user)) {					rad_assert(0 == 1);				}			}			continue;		}		/*		 *	We've read a partial record.  WTF?		 */		if (read_size != 0) {			pthread_mutex_unlock(&cache->mutex);			close(fd);			radlog(L_ERR, "rlm_radutmp: Badly formed file %s",			       cache->filename);			return 1;		}		/*		 *	Read nothing, stop.		 */	} while (read_size != 0);	pthread_mutex_unlock(&cache->mutex);	close(fd);		/* and release the lock. */	cache->cached_file = 1;	return 0;}/* *	Store logins in the RADIUS utmp file. */static int radutmp_accounting(void *instance, REQUEST *request){	rlm_radutmp_t	*inst = instance;	struct radutmp	utmp, u;	VALUE_PAIR	*vp;	int		status = -1;	uint32_t	nas_address = 0;	uint32_t	framed_address = 0;	int		protocol = -1;	int		fd;	int		port_seen = 0;	char		buffer[256];	char		filename[1024];	char		ip_name[32]; /* 255.255.255.255 */	const char	*nas;	NAS_PORT	*nas_port, myPort;	radutmp_cache_t *cache;	int		read_size;	rbnode_t	*node;	/*	 *	Which type is this.	 */	if ((vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE)) == NULL) {		radlog(L_ERR, "rlm_radutmp: No Accounting-Status-Type record.");		return RLM_MODULE_NOOP;	}	status = vp->vp_integer;	/*	 *	Look for weird reboot packets.	 *	 *	ComOS (up to and including 3.5.1b20) does not send	 *	standard PW_STATUS_ACCOUNTING_* messages.	 *	 *	Check for:  o no Acct-Session-Time, or time of 0	 *		    o Acct-Session-Id of "00000000".	 *	 *	We could also check for NAS-Port, that attribute	 *	should NOT be present (but we don't right now).	 */	if ((status != PW_STATUS_ACCOUNTING_ON) &&	    (status != PW_STATUS_ACCOUNTING_OFF)) do {		int check1 = 0;		int check2 = 0;		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_TIME))		     == NULL || vp->vp_date == 0)			check1 = 1;		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID))		     != NULL && vp->length == 8 &&		     memcmp(vp->vp_strvalue, "00000000", 8) == 0)			check2 = 1;		if (check1 == 0 || check2 == 0) {#if 0 /* Cisco sometimes sends START records without username. */			radlog(L_ERR, "rlm_radutmp: no username in record");			return RLM_MODULE_FAIL;#else			break;#endif		}		radlog(L_INFO, "rlm_radutmp: converting reboot records.");		if (status == PW_STATUS_STOP)			status = PW_STATUS_ACCOUNTING_OFF;		if (status == PW_STATUS_START)			status = PW_STATUS_ACCOUNTING_ON;	} while(0);	memset(&utmp, 0, sizeof(utmp));	utmp.porttype = 'A';	/*	 *	First, find the interesting attributes.	 */	for (vp = request->packet->vps; vp; vp = vp->next) {		switch (vp->attribute) {			case PW_LOGIN_IP_HOST:			case PW_FRAMED_IP_ADDRESS:				framed_address = vp->vp_ipaddr;				utmp.framed_address = vp->vp_ipaddr;				break;			case PW_FRAMED_PROTOCOL:				protocol = vp->vp_integer;				break;			case PW_NAS_IP_ADDRESS:				nas_address = vp->vp_ipaddr;				utmp.nas_address = vp->vp_ipaddr;				break;			case PW_NAS_PORT:				utmp.nas_port = vp->vp_integer;				port_seen = 1;				break;			case PW_ACCT_DELAY_TIME:				utmp.delay = vp->vp_integer;				break;			case PW_ACCT_SESSION_ID:				/*				 *	If it's too big, only use the				 *	last bit.				 */				if (vp->length > sizeof(utmp.session_id)) {					int length = vp->length - sizeof(utmp.session_id);					/*					 * 	Ascend is br0ken - it					 * 	adds a \0 to the end					 * 	of any string.					 * 	Compensate.					 */					if (vp->vp_strvalue[vp->length - 1] == 0) {						length--;					}					memcpy(utmp.session_id,					      vp->vp_strvalue + length,					      sizeof(utmp.session_id));				} else {					memset(utmp.session_id, 0,					       sizeof(utmp.session_id));					memcpy(utmp.session_id,					       vp->vp_strvalue,					       vp->length);				}				break;			case PW_NAS_PORT_TYPE:				if (vp->vp_integer <= 4)					utmp.porttype = porttypes[vp->vp_integer];				break;			case PW_CALLING_STATION_ID:				if(inst->callerid_ok)					strlcpy(utmp.caller_id,						(char *)vp->vp_strvalue,						sizeof(utmp.caller_id));				break;		}	}	/*	 *	If we didn't find out the NAS address, use the	 *	originator's IP address.	 */	if (nas_address == 0) {		nas_address = request->packet->src_ipaddr;		utmp.nas_address = nas_address;		nas = request->client->shortname;	} else if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr == nas_address) {		/* might be a client, might not be. */		nas = request->client->shortname;	} else {		/*		 *	The NAS isn't a client, it's behind		 *	a proxy server.  In that case, just		 *	get the IP address.		 */		nas = ip_ntoa(ip_name, nas_address);	}	/*	 *	Set the protocol field.	 */	if (protocol == PW_PPP)		utmp.proto = 'P';	else if (protocol == PW_SLIP)		utmp.proto = 'S';	else		utmp.proto = 'T';	utmp.time = request->timestamp - utmp.delay;	/*	 *	Get the utmp filename, via xlat.	 */	radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);	/*	 *	Future: look up filename in filename tree, to get	 *	radutmp_cache_t pointer	 */	cache = &inst->cache;	/*	 *	For now, double-check the filename, to be sure it isn't	 *	changing.	 */	if (!cache->filename) {		cache->filename = strdup(filename);		rad_assert(cache->filename != NULL);	} else if (strcmp(cache->filename, filename) != 0) {		radlog(L_ERR, "rlm_radutmp: We do not support dynamically named files.");		return RLM_MODULE_FAIL;	}	/*	 *	If the lookup failed, create a new one, and add it	 *	to the filename tree, and cache the file, as below.	 */	/*	 *	For aging, in the future.	 */	cache->last_used = request->timestamp;	/*	 *	If we haven't already read the file, then read the	 *	entire file, in order to cache its entries.	 */	if (!cache->cached_file) {		cache_file(inst, cache);	}	/*	 *	See if this was a reboot.	 *	 *	Hmm... we may not want to zap all of the users when	 *	the NAS comes up, because of issues with receiving	 *	UDP packets out of order.	 */	if (status == PW_STATUS_ACCOUNTING_ON && nas_address) {		radlog(L_INFO, "rlm_radutmp: NAS %s restarted (Accounting-On packet seen)",		       nas);		if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {			rad_assert(0 == 1);		}		return RLM_MODULE_OK;	}	if (status == PW_STATUS_ACCOUNTING_OFF && nas_address) {		radlog(L_INFO, "rlm_radutmp: NAS %s rebooted (Accounting-Off packet seen)",		       nas);		if (!radutmp_zap(inst, cache, nas_address, utmp.time)) {			rad_assert(0 == 1);		}		return RLM_MODULE_OK;	}	/*	 *	If we don't know this type of entry, then pretend we	 *	succeeded.	 */	if (status != PW_STATUS_START &&	    status != PW_STATUS_STOP &&	    status != PW_STATUS_ALIVE) {		radlog(L_ERR, "rlm_radutmp: NAS %s port %u unknown packet type %d, ignoring it.",		       nas, utmp.nas_port, status);		return RLM_MODULE_NOOP;	}	/*	 *	Perhaps we don't want to store this record into	 *	radutmp. We skip records:	 *	 *	- without a NAS-Port (telnet / tcp access)	 *	- with the username "!root" (console admin login)	 */	if (!port_seen) {		DEBUG2("  rlm_radutmp: No NAS-Port in the packet.  Cannot do anything.");		DEBUG2("  rlm_radumtp: WARNING: checkrad will probably not work!");		return RLM_MODULE_NOOP;	}	/*	 *	Translate the User-Name attribute, or whatever else	 *	they told us to use.	 */	*buffer = '\0';	radius_xlat(buffer, sizeof(buffer), inst->username, request, NULL);	/*	 *	Don't log certain things...	 */	if (strcmp(buffer, "!root") == 0) {		DEBUG2("  rlm_radutmp: Not recording administrative user");		return RLM_MODULE_NOOP;	}	strlcpy(utmp.login, buffer, RUT_NAMESIZE);	/*	 *	First, try to open the file.  If it doesn't exist,	 *	nuke the existing caches, and try to create it.	 *	 *	FIXME: Create any intermediate directories, as	 *	appropriate.  See rlm_detail.	 */	fd = open(cache->filename, O_RDWR, inst->permission);	if (fd < 0) {		if (errno == ENOENT) {			DEBUG2("  rlm_radutmp: File %s doesn't exist, creating it.", cache->filename);			if (!cache_reset(inst, cache)) return RLM_MODULE_FAIL;			/*			 *	Try to create the file.			 */

⌨️ 快捷键说明

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