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

📄 rlm_radutmp.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_radutmp.c * * Version:	$Id: rlm_radutmp.c,v 1.24 2004/02/26 19:04:34 aland 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 * FIXME add copyrights */#include	"autoconf.h"#include	<sys/types.h>#include	<stdio.h>#include	<string.h>#include	<stdlib.h>#include	<unistd.h>#include	<fcntl.h>#include	<time.h>#include	<errno.h>#include        <limits.h>#include "config.h"#include	"radiusd.h"#include	"radutmp.h"#include	"modules.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. */typedef struct nas_port {	uint32_t		nasaddr;	unsigned int	port;	off_t			offset;	struct nas_port 	*next;} NAS_PORT;typedef struct rlm_radutmp_t {	NAS_PORT	*nas_port_list;	char		*filename;	char		*username;	int		case_sensitive;	int		check_nas;	int		permission;	int		callerid_ok;} rlm_radutmp_t;static 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 */};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)) {		free(inst);		return -1;	}	inst->nas_port_list = NULL;	*instance = inst;	return 0;}/* *	Detach. */static int radutmp_detach(void *instance){	NAS_PORT *p, *next;	rlm_radutmp_t *inst = instance;	for (p = inst->nas_port_list ; p ; p=next) {		next = p->next;		free(p);	}	if (inst->filename) free(inst->filename);	if (inst->username) free(inst->username);	free(inst);	return 0;}/* *	Zap all users on a NAS from the radutmp file. */static int radutmp_zap(rlm_radutmp_t *inst,		       const char *filename,		       uint32_t nasaddr,		       time_t t){	struct radutmp	u;	int		fd;	if (t == 0) time(&t);	fd = open(filename, O_RDWR);	if (fd < 0) {		radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s",		       filename, strerror(errno));		return RLM_MODULE_FAIL;	}	/*	 *	Lock the utmp file, prefer lockf() over flock().	 */	rad_lockfd(fd, LOCK_LEN);	/*	 *	Find the entry for this NAS / portno combination.	 */	while (read(fd, &u, sizeof(u)) == sizeof(u)) {	  if ((nasaddr != 0 && nasaddr != u.nas_address) ||	      u.type != P_LOGIN)	    continue;	  /*	   *	Match. Zap it.	   */	  if (lseek(fd, -(off_t)sizeof(u), SEEK_CUR) < 0) {	    radlog(L_ERR, "rlm_radutmp: radutmp_zap: negative lseek!");	    lseek(fd, (off_t)0, SEEK_SET);	  }	  u.type = P_IDLE;	  u.time = t;	  write(fd, &u, sizeof(u));	}	close(fd);	/* and implicitely release the locks */	return 0;}/* *	Lookup a NAS_PORT in the nas_port_list */static NAS_PORT *nas_port_find(NAS_PORT *nas_port_list, uint32_t nasaddr, unsigned int port){	NAS_PORT	*cl;	for(cl = nas_port_list; cl; cl = cl->next)		if (nasaddr == cl->nasaddr &&			port == cl->port)			break;	return cl;}/* *	Store logins in the RADIUS utmp file. */static int radutmp_accounting(void *instance, REQUEST *request){	struct radutmp	ut, u;	VALUE_PAIR	*vp;	int		status = -1;	uint32_t	nas_address = 0;	uint32_t	framed_address = 0;	int		protocol = -1;	time_t		t;	int		fd;	int		just_an_update = 0;	int		port_seen = 0;	int		nas_port_type = 0;	int		off;	rlm_radutmp_t	*inst = instance;	char		buffer[256];	char		filename[1024];	char		ip_name[32]; /* 255.255.255.255 */	const char	*nas;	NAS_PORT	*cache;	int		r;	/*	 *	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->lvalue;	/*	 *	Look for weird reboot packets.	 *	 *	ComOS (up to and including 3.5.1b20) does not send	 *	standard PW_STATUS_ACCOUNTING_XXX 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->lvalue == 0)			check1 = 1;		if ((vp = pairfind(request->packet->vps, PW_ACCT_SESSION_ID))		     != NULL && vp->length == 8 &&		     memcmp(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);	time(&t);	memset(&ut, 0, sizeof(ut));	ut.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->lvalue;				ut.framed_address = vp->lvalue;				break;			case PW_FRAMED_PROTOCOL:				protocol = vp->lvalue;				break;			case PW_NAS_IP_ADDRESS:				nas_address = vp->lvalue;				ut.nas_address = vp->lvalue;				break;			case PW_NAS_PORT:				ut.nas_port = vp->lvalue;				port_seen = 1;				break;			case PW_ACCT_DELAY_TIME:				ut.delay = vp->lvalue;				break;			case PW_ACCT_SESSION_ID:				/*				 *	If length > 8, only store the				 *	last 8 bytes.				 */				off = vp->length - sizeof(ut.session_id);				/*				 * 	Ascend is br0ken - it adds a \0				 * 	to the end of any string.				 * 	Compensate.				 */				if (vp->length > 0 &&				    vp->strvalue[vp->length - 1] == 0)					off--;				if (off < 0) off = 0;				memcpy(ut.session_id, vp->strvalue + off,					sizeof(ut.session_id));				break;			case PW_NAS_PORT_TYPE:				if (vp->lvalue <= 4)					ut.porttype = porttypes[vp->lvalue];				nas_port_type = vp->lvalue;				break;			case PW_CALLING_STATION_ID:				if(inst->callerid_ok)					strNcpy(ut.caller_id,						(char *)vp->strvalue,						sizeof(ut.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;		ut.nas_address = nas_address;		nas = client_name(nas_address);	/* MUST be a valid client */	} else {		/* might be a client, might not be. */		RADCLIENT *cl;		/*		 *	Hack like 'client_name()', but with sane		 *	fall-back.		 */		cl = client_find(nas_address);		if (cl) {			if (cl->shortname[0]) {				nas = cl->shortname;			} else {				nas = cl->longname;			}		} 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)		ut.proto = 'P';	else if (protocol == PW_SLIP)		ut.proto = 'S';	else		ut.proto = 'T';	ut.time = t - ut.delay;	/*	 *	Get the utmp filename, via xlat.	 */	radius_xlat(filename, sizeof(filename), inst->filename, request, NULL);	/*	 *	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);		radutmp_zap(inst, filename, nas_address, ut.time);		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);		radutmp_zap(inst, filename, nas_address, ut.time);

⌨️ 快捷键说明

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