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

📄 rlm_radutmp2.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
			fd = open(cache->filename, O_RDWR | O_CREAT,				  inst->permission);		}	} else {		/* exists, but may be empty */		struct stat buf;		/*		 *	If the file is empty, reset the cache.		 */		if ((stat(cache->filename, &buf) == 0) &&		    (buf.st_size == 0) &&		    (!cache_reset(inst, cache))) {			return RLM_MODULE_FAIL;		}		DEBUG2("  rlm_radutmp: File %s was truncated.  Resetting cache.",		       cache->filename);	}	/*	 *	Error from creation, or error other than ENOENT: die.	 */	if (fd < 0) {		radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",		       cache->filename, strerror(errno));		return RLM_MODULE_FAIL;	}	/*	 *	OK.  Now that we've prepared everything we want to do,	 *	let's see if we've cached the entry.	 */	myPort.nas_address = utmp.nas_address;	myPort.nas_port = utmp.nas_port;	pthread_mutex_lock(&cache->mutex);	node = rbtree_find(cache->nas_ports, &myPort);	pthread_mutex_unlock(&cache->mutex);	if (node) {		nas_port = rbtree_node2data(cache->nas_ports, node);#if 0		/*		 *	stat the file, and get excited if it's been		 *	truncated.		 *		 *	i.e wipe out the cache, and re-read the file.		 */		/*		 *	Now find the new entry.		 */		pthread_mutex_lock(&cache->mutex);		node = rbtree_find(cache->nas_ports, &myPort);		pthread_mutex_unlock(&cache->mutex);#endif	}	if (!node) {		radutmp_simul_t *user;		/*		 *	Not found in the cache, and we're trying to		 *	delete an existing record: ignore it.		 */		if (status == PW_STATUS_STOP) {			DEBUG2("  rlm_radumtp: Logout entry for NAS %s port %u with no Login: ignoring it.",			       nas, utmp.nas_port);			return RLM_MODULE_NOOP;		}		pthread_mutex_lock(&cache->mutex);		/*		 *	It's a START or ALIVE.  Try to find a free		 *	offset where we can store the new entry, or		 *	create one, if one doesn't already exist.		 */		if (!cache->free_offsets) {			cache->free_offsets = rad_malloc(sizeof(NAS_PORT));			memset(cache->free_offsets, 0,			       sizeof(*(cache->free_offsets)));			cache->free_offsets->offset = cache->max_offset;			cache->max_offset += sizeof(u);		}		/*		 *	Grab the offset, and put it into the various		 *	caches.		 */		nas_port = cache->free_offsets;		cache->free_offsets = nas_port->next;		nas_port->nas_address = nas_address;		nas_port->nas_port = utmp.nas_port;		if (!rbtree_insert(cache->nas_ports, nas_port)) {			rad_assert(0 == 1);		}		/*		 *	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);		}		pthread_mutex_unlock(&cache->mutex);	}	/*	 *	Entry was found, or newly created in the cache.	 *	Seek to the place in the file.	 */	lseek(fd, nas_port->offset, SEEK_SET);	/*	 *	Lock the utmp file, prefer lockf() over flock().	 */	rad_lockfd(fd, LOCK_LEN);	/*	 *	If it WAS found in the cache, double-check it against	 *	what is in the file.	 */	if (node) {		/*		 *	If we didn't read anything, then this entry		 *	doesn't exist.		 *		 *	Similarly, if the entry in the file doesn't		 *	match what we recall, then nuke the cache		 *	entry.		 */		read_size = read(fd, &u, sizeof(u));		if ((read_size < 0) ||		    ((read_size > 0) && (read_size  != sizeof(u)))) {			/*			 *	Bad read, or bad record.			 */			radlog(L_ERR, "rlm_radutmp: Badly formed file %s",			       cache->filename);			close(fd);			return RLM_MODULE_FAIL;		}		rad_assert(read_size != 0);		/*		 *	We've read a record, go poke at it.		 */		if (read_size > 0) {			/*			 *	If these aren't true, then			 *			 *	a) we have cached a "logout" entry,			 *	   which we don't do.			 *			 *	b) we have cached the wrong NAS address			 *			 *	c) we have cached the wrong NAS port.			 */			rad_assert(u.type == P_LOGIN);			rad_assert(u.nas_address == utmp.nas_address);			rad_assert(u.nas_port == utmp.nas_port);			/*			 *	An update for the same session.			 */			if (strncmp(utmp.session_id, u.session_id,				    sizeof(u.session_id)) == 0) {				/*				 *	It's a duplicate start, so we				 *	don't bother writing it.				 */				if (status == PW_STATUS_START) {					DEBUG2("  rlm_radutmp: Login entry for NAS %s port %u duplicate, ignoring it.",					       nas, u.nas_port);					close(fd);					return RLM_MODULE_OK;				/*				 *	ALIVE for this session, keep the				 *	original login time.				 */				} else if (status == PW_STATUS_ALIVE) {					utmp.time = u.time;				/*				 *	Stop: delete it from our cache.				 */				} else if (status == PW_STATUS_STOP) {					radutmp_simul_t *user, myUser;					pthread_mutex_lock(&cache->mutex);					rbtree_deletebydata(cache->nas_ports,							    nas_port);					strlcpy(myUser.login,						u.login, sizeof(myUser.login));					user = rbtree_finddata(inst->user_tree,							       &myUser);					rad_assert(user != NULL);					rad_assert(user->simul_count > 0);					user->simul_count--;					if (user->simul_count == 0) {						rbtree_deletebydata(inst->user_tree, user);					}					pthread_mutex_unlock(&cache->mutex); 				} else {					/*					 *	We don't know how to					 *	handle this.					 */					rad_assert(0 == 1);				}			} else { /* session ID doesn't match */				/*				 *	STOP for the right NAS & port,				 *	but the Acct-Session-Id is				 *	different.  This means that				 *	we missed the original "stop",				 *	and a new "start".				 */				if (status == PW_STATUS_STOP) {					radlog(L_ERR, "rlm_radutmp: Logout entry for NAS %s port %u has old Acct-Session-ID, ignoring it.",					       nas, u.nas_port);					close(fd);					return RLM_MODULE_OK;				}			} /* checked session ID's */		}  /* else we haven't read anything from the file. */	} /* else the entry wasn't cached, but could have been inserted */	/*	 *	Hmm... we may have received a start or alive packet	 *	AFTER a stop or nas-down, in that case, we want to	 *	discard the new packet.  However, the original code	 *	could over-write an idle record with a new login	 *	record for another NAS && port, so we won't worry	 *	about this case too much.	 */	/*	 *	Seek to where the entry is, and write it blindly.	 */	lseek(fd, nas_port->offset, SEEK_SET); /* FIXME: err */	if (status != PW_STATUS_STOP) {		utmp.type = P_LOGIN;		rad_assert(nas_port != NULL); /* it WAS cached */	} else {		/* FIXME: maybe assert that the entry was deleted... */		memcpy(&utmp, &u, sizeof(utmp));		utmp.type = P_IDLE;	}	write(fd, &utmp, sizeof(utmp)); /* FIXME: err */	close(fd);	/* and implicitly release the locks */	return RLM_MODULE_OK;}/* *	See if a user is already logged in. Sets request->simul_count *	to the current session count for this user and sets *	request->simul_mpp to 2 if it looks like a multilink attempt *	based on the requested IP address, otherwise leaves *	request->simul_mpp alone. * *	Check twice. If on the first pass the user exceeds his *	max. number of logins, do a second pass and validate all *	logins by querying the terminal server (using eg. SNMP). */static int radutmp_checksimul(void *instance, REQUEST *request){	struct radutmp	u;	int		fd;	VALUE_PAIR	*vp;	uint32_t	ipno = 0;	char		*call_num = NULL;	int		rcode;	rlm_radutmp_t	*inst = instance;	char		login[256];	char		filename[1024];	radutmp_cache_t *cache;	radutmp_simul_t *user, myUser;	/*	 *	Get the 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;	}	*login = '\0';	radius_xlat(login, sizeof(login), inst->username, request, NULL);	if (!*login) {		return RLM_MODULE_NOOP;	}	/*	 *	WTF?  This is probably wrong... we probably want to	 *	be able to check users across multiple session accounting	 *	methods.	 */	request->simul_count = 0;	strlcpy(myUser.login, login, sizeof(myUser.login));	pthread_mutex_lock(&inst->cache.mutex);	user = rbtree_finddata(inst->user_tree, &myUser);	if (user) request->simul_count = user->simul_count;	user = NULL;		/* someone else may delete it */	pthread_mutex_unlock(&inst->cache.mutex);	/*	 *	The number of users logged in is OK,	 *	OR, we've been told to not check the NAS.	 */	if ((request->simul_count < request->simul_max) ||	    !inst->check_nas) {		return RLM_MODULE_OK;	}	/*	 *	The user is logged in at least N times, and	 *	we're told to check the NAS.  In that case,	 *	we've got to read the file, and check each	 *	NAS port by hand.	 */	if ((fd = open(cache->filename, O_RDWR)) < 0) {		/*		 *	If the file doesn't exist, then no users		 *	are logged in.		 */		if (errno == ENOENT) {			request->simul_count = 0;			return RLM_MODULE_OK;		}		/*		 *	Error accessing the file.		 */		radlog(L_ERR, "rlm_radumtp: Error accessing file %s: %s",		       cache->filename, strerror(errno));		return RLM_MODULE_FAIL;	}	/*	 *	Setup some stuff, like for MPP detection.	 */	if ((vp = pairfind(request->packet->vps, PW_FRAMED_IP_ADDRESS)) != NULL)		ipno = vp->vp_ipaddr;	if ((vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) != NULL)		call_num = vp->vp_strvalue;	/*	 *	lock the file while reading/writing.	 */	rad_lockfd(fd, LOCK_LEN);	/*	 *	FIXME: If we get a 'Start' for a user/nas/port which is	 *	listed, but for which we did NOT get a 'Stop', then	 *	it's not a duplicate session.  This happens with	 *	static IP's like DSL.	 */	request->simul_count = 0;	while (read(fd, &u, sizeof(u)) == sizeof(u)) {		if (((strncmp(login, u.login, RUT_NAMESIZE) == 0) ||		     (!inst->case_sensitive &&		      (strncasecmp(login, u.login, RUT_NAMESIZE) == 0))) &&		    (u.type == P_LOGIN)) {			char session_id[sizeof(u.session_id) + 1];			char utmp_login[sizeof(u.login) + 1];			strlcpy(session_id, u.session_id, sizeof(session_id));			/*			 *	The login name MAY fill the whole field,			 *	and thus won't be zero-filled.			 *			 *	Note that we take the user name from			 *	the utmp file, as that's the canonical			 *	form.  The 'login' variable may contain			 *	a string which is an upper/lowercase			 *	version of u.login.  When we call the			 *	routine to check the terminal server,			 *	the NAS may be case sensitive.			 *			 *	e.g. We ask if "bob" is using a port,			 *	and the NAS says "no", because "BOB"			 *	is using the port.			 */			strlcpy(utmp_login, u.login, sizeof(u.login));			/*			 *	rad_check_ts may take seconds			 *	to return, and we don't want			 *	to block everyone else while			 *	that's happening.  */			rad_unlockfd(fd, LOCK_LEN);			rcode = rad_check_ts(u.nas_address, u.nas_port,					     utmp_login, session_id);			rad_lockfd(fd, LOCK_LEN);			if (rcode == 0) {				/*				 *	Stale record - zap it.				 *				 *	Hmm... this ends up calling				 *	the accounting section				 *	recursively...				 */				session_zap(request, u.nas_address,					    u.nas_port, login, session_id,					    u.framed_address, u.proto,0);			}			else if (rcode == 1) {				/*				 *	User is still logged in.				 */				++request->simul_count;				/*				 *	Does it look like a MPP attempt?				 */				if (strchr("SCPA", u.proto) &&				    ipno && u.framed_address == ipno)					request->simul_mpp = 2;				else if (strchr("SCPA", u.proto) && call_num &&					!strncmp(u.caller_id,call_num,16))					request->simul_mpp = 2;			}			else {				/*				 *	Failed to check the terminal				 *	server for duplicate logins:				 *	Return an error.				 */				close(fd);				radlog(L_ERR, "rlm_radutmp: Failed to check the terminal server for user '%s'.", utmp_login);				return RLM_MODULE_FAIL;			}		}	}	close(fd);		/* and implicitly release the locks */	return RLM_MODULE_OK;}/* globally exported name */module_t rlm_radutmp = {  "radutmp",  0,       			/* type: reserved */  NULL,                 	/* initialization */  radutmp_instantiate,          /* instantiation */  {	  NULL,                 /* authentication */	  NULL,                 /* authorization */	  NULL,                 /* preaccounting */	  radutmp_accounting,   /* accounting */	  radutmp_checksimul,	/* checksimul */	  NULL,			/* pre-proxy */	  NULL,			/* post-proxy */	  NULL			/* post-auth */  },  radutmp_detach,               /* detach */  NULL,         	        /* destroy */};

⌨️ 快捷键说明

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