📄 acct.c
字号:
/*
* 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 + -