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

📄 acct.c

📁 国际标准协议的
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *	RADIUS Accounting
 *	Remote Authentication Dial In User Service
 */

static char sccsid[] =
"@(#)acct.c	1.6  Copyright 2004 Livingston Enterprises Inc";

#include	<sys/types.h>
#include	<sys/socket.h>
#include	<sys/time.h>
#include	<sys/file.h>
#include 	<sys/stat.h>
#include	<netinet/in.h>


#include	<stdio.h>
#include	<errno.h>
#include	<strings.h>
#include	<netdb.h>
#include	<pwd.h>
#include	<time.h>
#include	<ctype.h>
#include	<unistd.h>
#include	<signal.h>
#include	<limits.h>
#include	<errno.h>
#include	<sys/wait.h>
#include	<fcntl.h>	
	

#include	"radius.h"
#include	"account.h"

extern char		recv_buffer[4096];
extern char		send_buffer[4096];
extern char		*progname;
extern int		debug_flag;
extern char		*radacct_dir;
extern char		*radius_dir;
extern UINT4		expiration_seconds;
extern UINT4		warning_seconds;
extern int		errno;
extern REALM_STRUCT	*first_realm;
extern CLIENT_STRUCT	*first_client;

UINT4			calctime();

rad_accounting(authreq, activefd)
AUTH_REQ	*authreq;
int		activefd;
{
	FILE		*outfd;
	char		*ip_hostname();
	char		clientname[128];
	char		buffer[512];
	VALUE_PAIR	*pair;
	long		curtime;
	VALUE_PAIR	*namepair;
	char		msg[128];
	int		realm_user();
	int		parse_user();
	int		realm_find();
	u_short		realm_status;			
	char		name_str[32];
	char		realm_suffix[64];	
	char		addr_str[32];
	UINT4		status_type;

	/* Check the Acct Status */
	status_type = check_acct_status(authreq->request);

	/* Get the username from the request */
	namepair = authreq->request;
	while(namepair != (VALUE_PAIR *)NULL) {
   		if(namepair->attribute == PW_USER_NAME) {
          		break;
              	} 
                namepair = namepair->next;
        }
	if((namepair==(VALUE_PAIR *)NULL) || (strlen(namepair->strvalue)<=0)) {
                sprintf(msg, "Acct: from %s - No User Name\n", ip_hostname(authreq->ipaddr));
                msg[127] = '\0';
                log_err(msg);

		if(status_type==PW_ACCT_START)
		{
                pairfree(authreq->request);
                memset(authreq, 0, sizeof(AUTH_REQ));
                free(authreq);
                }

                return;
        }

	memset(name_str,'\0',sizeof(name_str));
	memset(realm_suffix,'\0',sizeof(realm_suffix));
	/* Parse the user_name_string and find the radius server */
  	if(realm_status=realm_user(namepair->strvalue)){
 		if(parse_user(namepair->strvalue, name_str,realm_suffix) != 0) {
                	sprintf(msg, "Acct: from %s - Invalid User: %s\n", ip_hostname(authreq->ipaddr), namepair->strvalue);
                        msg[127] = '\0';
                        log_err(msg);

			if(status_type==PW_ACCT_START)
			{
	                pairfree(authreq->request);
	                memset(authreq, 0, sizeof(AUTH_REQ));
	                free(authreq);
	                }

			return;
             	}
     	}else{
        	memcpy(name_str,namepair->strvalue,sizeof(namepair->strvalue));
        }

	/* Verify the realm and the radius host(remote/local) */
        if(realm_find(authreq, realm_suffix) != 0) {
           	sprintf(msg, "Acct: from %s - Invalid Realm: %s\n", ip_hostname(authreq->ipaddr), realm_suffix);
                msg[127] = '\0';
                log_err(msg);

		if(status_type==PW_ACCT_START)
		{
                pairfree(authreq->request);
                memset(authreq, 0, sizeof(AUTH_REQ));
                free(authreq);
                }
                return;
      	}

	/* Forward accounting request to remote server */
	if(authreq->proxy_state) 
	{
		printf("\n转发计帐请求开始");
		forward_acct_request(authreq, activefd);
		printf("\n转发计帐请求结束");
	}
	

	/* Just for test */
	/*------
	sprintf(msg,"Acct: check acct status - %d\n",status_type);
	msg[127]='\0';
	log_err(msg);
	------*/
	
	switch(status_type) {
	case PW_ACCT_START:
		modify_online(authreq->request);
		break;
	case PW_ACCT_STOP:
		log_to_result(authreq);

		if(authreq->proxy_state==0) 
		{
			send_acct(authreq->request);
		}
		break;
	default:
		break;
	}	

	/*
	 * Create a directory for this client.
	 */
	ipaddr2str(clientname,authreq->ipaddr);
	sprintf(buffer, "%s/%s", radacct_dir, clientname);
	mkdir(buffer, 0755);

	/*
	 * Write Detail file.
	 */
	sprintf(buffer, "%s/%s/detail", radacct_dir, clientname);
	if((outfd = fopen(buffer, "a")) == (FILE *)NULL) 
	{
		sprintf(buffer,"Acct: Couldn't open file %s/%s/detail\n",radacct_dir, clientname);
		log_err(buffer);
		/* don't respond if we can't save record */
	} else {

		/* Post a timestamp */
		curtime = time(0);
		fputs(ctime(&curtime), outfd);

		/* Write each attribute/value to the log file */
		pair = authreq->request;

		while(pair != (VALUE_PAIR *)NULL) {
			fputs("\t", outfd);
			fprint_attr_val(outfd, pair);
			fputs("\n", outfd);
		pair = pair->next;
		}
		fputs("\n", outfd);
		fclose(outfd);
		/* let NAS know it is OK to delete from buffer */
		send_acct_reply(authreq, (VALUE_PAIR *)NULL, (char *)NULL,activefd);
	}

	if(status_type==PW_ACCT_START)
	{
        pairfree(authreq->request);
        memset(authreq, 0, sizeof(AUTH_REQ));
        free(authreq);
        }

	return;
}

/*************************************************************************
 *
 *	Function: send_acct_reply
 *
 *	Purpose: Reply to the request with an ACKNOWLEDGE.  Also attach
 *		 reply attribute value pairs and any user message provided.
 *
 *************************************************************************/

send_acct_reply(authreq, reply, msg, activefd)
AUTH_REQ	*authreq;
VALUE_PAIR	*reply;
char		*msg;
int		activefd;
{
	AUTH_HDR		*auth;
	u_short			total_length;
	struct	sockaddr_in	saremote;
	struct	sockaddr_in	*sin;
	u_char			*ptr;
	int			len;
	UINT4			lvalue;
	u_char			digest[16];
	int			secretlen;
	char			*ip_hostname();

	auth = (AUTH_HDR *)send_buffer;

	/* Build standard header */
	auth->code = PW_ACCOUNTING_RESPONSE;
	auth->id = authreq->id;
	memcpy(auth->vector, authreq->vector, AUTH_VECTOR_LEN);

	DEBUG("Sending Accounting Ack of id %d to %lx (%s)\n",
		authreq->id, authreq->ipaddr, ip_hostname(authreq->ipaddr));

	total_length = AUTH_HDR_LEN;

	/* Load up the configuration values for the user */
	ptr = auth->data;
	while(reply != (VALUE_PAIR *)NULL) {
		debug_pair(stdout, reply);
		*ptr++ = reply->attribute;

		switch(reply->type) {

		case PW_TYPE_STRING:
			len = strlen(reply->strvalue);
			*ptr++ = len + 2;
			strcpy(ptr, reply->strvalue);
			ptr += len;
			total_length += len + 2;
			break;
			
		case PW_TYPE_INTEGER:
		case PW_TYPE_IPADDR:
			*ptr++ = sizeof(UINT4) + 2;
			lvalue = htonl(reply->lvalue);
			memcpy(ptr, &lvalue, sizeof(UINT4));
			ptr += sizeof(UINT4);
			total_length += sizeof(UINT4) + 2;
			break;

		default:
			break;
		}

		reply = reply->next;
	}

	/* Append the user message */
	if(msg != (char *)NULL) {
		len = strlen(msg);
		if(len > 0 && len < AUTH_STRING_LEN) {
			*ptr++ = PW_PORT_MESSAGE;
			*ptr++ = len + 2;
			memcpy(ptr, msg, len);
			ptr += len;
			total_length += len + 2;
		}
	}

	auth->length = htons(total_length);

	/* Calculate the response digest */
	secretlen = strlen(authreq->secret);
	memcpy(send_buffer + total_length, authreq->secret, secretlen);
	md5_calc(digest, (char *)auth, total_length + secretlen);
	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
	memset(send_buffer + total_length, 0, secretlen);

	sin = (struct sockaddr_in *) &saremote;
        memset ((char *) sin, '\0', sizeof (saremote));
	sin->sin_family = AF_INET;
	sin->sin_addr.s_addr = htonl(authreq->ipaddr);
	sin->sin_port = htons(authreq->udp_port);

	/* Send it to the user */
	sendto(activefd, (char *)auth, (int)total_length, (int)0,
			(struct sockaddr *) sin, sizeof(struct sockaddr_in));
}

/*--------------------------------------*/
/* Func: forward_acct_request()		*/
/* Exp: Forwarding accounting   	*/
/*      request to remote server	*/
/*--------------------------------------*/
int forward_acct_request(AUTH_REQ *authreq, int activefd) {
	AUTH_HDR		*auth;
	char			send_buf[BUF_SIZE];
	char			recv_buf[BUF_SIZE];
	int			r_sockfd;
	int			total_length;
	struct sockaddr		saremote;
	struct sockaddr_in	*sin;	
	int			secretlen;
	char			*ptr;
	VALUE_PAIR		*pair;
	int			len;
	UINT4			lvalue;
	struct servent		*svp;
	u_short			udp_port;
	struct timeval		authtime;
	fd_set			readfds;
	int			retry;
	int			salen;
	int			result;
	int			status;
	char			digest[AUTH_VECTOR_LEN];
	
	auth = (AUTH_HDR *)send_buf;
        auth->code = authreq->code;
        auth->id = authreq->id;
        memcpy(auth->vector,authreq->vector,AUTH_VECTOR_LEN);

        total_length = AUTH_HDR_LEN;
	
	ptr = auth->data;
        pair = authreq->request;
        while(pair != (VALUE_PAIR *)NULL) {
       		*ptr++ = pair->attribute;
		switch(pair->type) {

		case PW_TYPE_STRING:
			len = strlen(pair->strvalue);
			if (len >= AUTH_STRING_LEN) {
        			len = AUTH_STRING_LEN - 1;
   			}
          		*ptr++ = len + 2;
          		memcpy(ptr, pair->strvalue,len);
          		ptr += len;
          		total_length += len + 2;
          		break;
 
               	case PW_TYPE_INTEGER:
                case PW_TYPE_IPADDR:
                       	*ptr++ = sizeof(UINT4) + 2;
                       	lvalue = htonl(pair->lvalue);
                       	memcpy(ptr, &lvalue, sizeof(UINT4));
 			ptr += sizeof(UINT4);
                        total_length += sizeof(UINT4) + 2;
                        break;

  		default:
          		break;
           	}
	       	pair = pair->next;
  	}

        auth->length = htons(total_length);

	/* Calculate the response digest */
	secretlen = strlen(authreq->r_secret);
	memcpy(send_buffer + total_length, authreq->r_secret, secretlen);
	md5_calc(digest, (char *)auth, total_length + secretlen);
	memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
	memset(send_buffer + total_length, 0, secretlen);

        r_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(r_sockfd <0) {
             	(void) perror("Auth socket");
                return(-1);
        }

        svp = getservbyname("radacct","udp");
        if(svp == (struct servent *) 0) {
            	fprintf(stderr, "Error: No such service: radius/udp\n");
           	exit(-1);
        }

        udp_port = (u_short)svp->s_port;
	sin = (struct sockaddr_in *) &saremote;
	memset ((char *) sin, '\0', sizeof (saremote));
	sin->sin_family = AF_INET;
	sin->sin_port = htons(udp_port);
	sin->sin_addr.s_addr = htonl(authreq->r_serv);

	retry=0;
	for( ; ; ) {
		/* Send it to the user */
		sendto(r_sockfd, (char *)auth, (int)total_length, (int)0 , &saremote, sizeof(struct sockaddr_in));
	
		authtime.tv_usec = 0L;
		authtime.tv_sec  = (long)MAX_REQUEST_TIME;

		FD_ZERO(&readfds);
               		if(r_sockfd >= 0) {
                        FD_SET(r_sockfd,&readfds);
              	}

               	status=select(r_sockfd+1, &readfds, NULL, NULL, &authtime);
                if(status < 0) {
                     	if(errno == EINTR)      continue;
                       	sig_fatal(101);
              	}
               	if(r_sockfd >= 0 && FD_ISSET(r_sockfd, &readfds)) {
               		break;
                }
                /* The following can define the retry times */
                if(++retry >= RETRY_MAX) {
	               	close(r_sockfd);
          		return(-1);
          	}
	}

	salen = sizeof(saremote);
        result = recvfrom(r_sockfd, recv_buf, (int)sizeof(recv_buf),(int)0,&saremote,&salen);

 	close(r_sockfd);

	if(result<=0)	return(-1);

	return(0);
}

/*------------------------------*/
/* Func: check_acct_status()	*/
/*------------------------------*/
UINT4	check_acct_status(VALUE_PAIR *pair) {
	VALUE_PAIR	*ptr;
	
	ptr = pair;
	while(ptr != (VALUE_PAIR *)NULL) {
		if(ptr->attribute == PW_ACCT_STATUS_TYPE) {
			break;
		}
		ptr = ptr->next;
	}
	
	if(ptr != (VALUE_PAIR *)NULL) {
		return(ptr->lvalue);
	}		
}

/*------------------------------*/
/* Func: modify_online()	*/
/*------------------------------*/
int	modify_online(VALUE_PAIR *pair) {
	int		fd;
	char		buffer[128];
	char		msg[128];
	USER_ONLINE	*ptr;	
	USER_ONLINE	*new_online_rec;
	VALUE_PAIR	*vp;
	char		s_id[10];
	char		u_name[32];
	long		curtime;
	int		found;
	int		nas_port;
	char		nas_ip[16];

	vp = pair;
	while(vp != (VALUE_PAIR *)NULL) {
		if(vp->attribute == PW_USER_NAME) {
			memcpy(u_name,vp->strvalue,sizeof(u_name));
		}else if(vp->attribute == PW_ACCT_SESSION_ID) {
			memcpy(s_id,vp->strvalue,sizeof(s_id));
		} else if (vp->attribute == PW_NAS_PORT) {
			nas_port = vp->lvalue;
		} else if (vp->attribute == PW_NAS_IP_ADDRESS) {
			ipaddr2str(nas_ip, vp->lvalue);
		}
		vp = vp->next;
	}		

	sprintf(buffer,"%s/%s",radius_dir,RADIUS_ONLINE);

⌨️ 快捷键说明

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