|
Home - Old Man Programmer
| Displaying projects/sac/gronk.c
/* $Copyright: $
* Copyright (c) 1995 - 2001 by Steve Baker (ice@mama.indstate.edu)
* All Rights reserved
*
* This software is provided as is without any express or implied
* warranties, including, without limitation, the implied warranties
* of merchant-ability and fitness for a particular purpose.
*/
#undef MAIN
#include "sac.h"
/*
extern char **month;
extern char radhost, hosttoo, verbose;
extern int sd, ed;
extern time_t lastent;
extern signed int sm;
extern char *buf;
*/
#define FUDGE_FACTOR 3600 /* 1 hour */
void try_fastseek(int fd, struct file *f)
{
struct utmp start, end, cur;
struct stat st;
u_long s, e, m, t;
if (f->ftype == ACCT_RADIUS || fd == 0) return;
if (fstat(fd,&st) < 0) return;
if ((st.st_size % sizeof(struct utmp)) != 0) return;
if (lseek(fd,0,SEEK_SET) < 0) return;
if (read(fd,&start,sizeof(struct utmp)) != sizeof(struct utmp)) return restore(fd);
if ((t = lseek(fd,-sizeof(struct utmp),SEEK_END)) < 0) return restore(fd);
if (read(fd,&end,sizeof(struct utmp)) != sizeof(struct utmp)) return restore(fd);
s = 0;
e = t/sizeof(struct utmp);
m = e/2;
if (!sd) {
if (!sm) return restore(fd);
}
if (start.ut_time >= sd) return restore(fd);
while(s < e) {
if (lseek(fd,m*sizeof(struct utmp),SEEK_SET) < 0) return restore(fd);
if (read(fd,&cur,sizeof(struct utmp)) < 0) return restore(fd);
if (cur.ut_time < sd) {
if (cur.ut_time+FUDGE_FACTOR >= sd) return;
s = m;
m += (e-s)/2;
} else {
e = m;
m -= (e-s)/2;
}
}
}
void restore(int fd)
{
if (verbose) fprintf(stderr,"sac: fastseek failed, rewinding input.\n");
lseek(fd,0,SEEK_SET);
return;
}
#ifdef USER_PROCESS
void gronk_sysv(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &su.u;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct utmp));n < (int)sizeof(struct utmp);n+=m=read(fd,ut+n,sizeof(struct utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
/* Do we have this day allocated? */
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
/* Q: Why does the following bother me? */
/* A: It may not handle all possible cases. Wtmp documentation sucks.
* Programs are also pretty free to put whatever the hell they want
* in wtmp.
*/
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time);
else if (u->ut_type == USER_PROCESS && strncmp("ftp",u->ut_line,3)) saclogin(su);
else if (u->ut_type == DEAD_PROCESS && strncmp("ftp",u->ut_line,3)) saclogout(su,FALSE);
else if (u->ut_type == LOGIN_PROCESS) saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else saclogout(su,FALSE);
}
}
}
}
#endif
/*
* Do it the bsd way, where u.ut_type is invalid or doesn't get used or
* doesn't even exist.
* This is also for non-standard wtmp's kept by programs such as tacacs.
* Note: Versions of Xterm may write a wtmp entry on exit that looks like
* a login entry if we ignore the ut_type field (which is "dead
* process" in this case). This will obviously screw things up.
*
* This may not be 100%.
*/
void gronk_bsd(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &su.u;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct utmp));n < (int)sizeof(struct utmp);n+=m=read(fd,ut+n,sizeof(struct utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time);
else if (strcmp("LOGIN",u->ut_user) && strcmp("~",u->ut_line) && strncmp("ftp",u->ut_line,3)) saclogin(su);
else saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else saclogout(su,FALSE);
}
}
}
}
/*
* Do it the tacacs 3.4-3.5 way, with tacacs ancient utmp format, which may work
* for other ancient (such as old BSD) programs.
* This too may not be 100%.
*/
void gronk_tacacs3(int fd)
{
struct tacacs3_utmp t;
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &t;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct tacacs3_utmp));n < (int)sizeof(struct tacacs3_utmp);n+=m=read(fd,ut+n,sizeof(struct tacacs3_utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
/* put tacacs_utmp into a normal utmp for the rest of this */
u->ut_time = t.ut_tactime;
strncpy(u->ut_line,t.ut_line,8);
strncpy(u->ut_user,t.ut_user,8);
strncpy(u->ut_host,t.ut_host,16);
/* u->ut_line[8] = u->ut_user[8] = 0; */
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time);
else if (strcmp("LOGIN",u->ut_user) && strcmp("~",u->ut_line) && strncmp("ftp",u->ut_line,3)) saclogin(su);
else saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else saclogout(su,FALSE);
}
}
}
}
/*
* Do it the new 4.x xtacacs way... Added the comment field -- 16 bytes to store
* the PID?
* This too may not be 100%. Should be merged with above.
*/
void gronk_tacacs4(int fd)
{
struct tacacs4_utmp t;
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &t;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct tacacs4_utmp));n < (int)sizeof(struct tacacs4_utmp);n+=m=read(fd,ut+n,sizeof(struct tacacs4_utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
/* put tacacs_utmp into a normal utmp for the rest of this */
u->ut_time = t.ut_tactime;
strncpy(u->ut_line,t.ut_line,8);
strncpy(u->ut_user,t.ut_user,8);
strncpy(u->ut_host,t.ut_host,16);
/* u->ut_line[8] = u->ut_user[8] = 0; */
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (u->ut_user[0] == '?') saclogout(su,FALSE);
else if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time);
else if (strcmp("LOGIN",u->ut_user) && strcmp("~",u->ut_line) && strncmp("ftp",u->ut_line,3)) saclogin(su);
else saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
saclogout(su,FALSE);
}
}
}
}
/*
* Perform accounting on ftp logins only. This handles ftp entries generated
* from wu-ftpd at least.
*/
void gronk_ftp(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &su.u;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct utmp));n < (int)sizeof(struct utmp);n+=m=read(fd,ut+n,sizeof(struct utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strcmp("shutdown",u->ut_user))) do_reboot(u->ut_time);
else if (!strncmp("ftp",u->ut_line,3)) saclogin(su);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else if (!strncmp("ftp",u->ut_line,3)) saclogout(su,FALSE);
}
}
}
}
/*
* Perform accounting on both normal logins and ftp simultaneously.
*/
#ifdef USER_PROCESS
void gronk_both(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &su.u;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct utmp));n < (int)sizeof(struct utmp);n+=m=read(fd,ut+n,sizeof(struct utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time);
else if (u->ut_type == USER_PROCESS || !strncmp("ftp",u->ut_line,3)) saclogin(su);
else if (u->ut_type == DEAD_PROCESS) saclogout(su,FALSE);
else if (u->ut_type == LOGIN_PROCESS) saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else saclogout(su,FALSE);
}
}
}
}
#else
void gronk_both(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
void *ut = &su.u;
int n, m;
lastent = 0;
while (1) {
for(n=m=read(fd,ut,sizeof(struct utmp));n < (int)sizeof(struct utmp);n+=m=read(fd,ut+n,sizeof(struct utmp)-n)) {
if (m < 0) {
perror("sac");
return;
}
if (!m) return;
}
/* corrupted (zapped) wtmp entry! Could be an 3l33t3 h4kk0r. */
if (u->ut_time == 0) {
time_t t,h,m,s;
if (!end) {
if (verbose) fprintf(stderr,"sac: corrupted entry at beginning of wtmp.\n");
continue;
}
t = lastent - end->start;
h=t/3600;
m=(t-(h*3600))/60;
s=t-(h*3600)-(m*60);
if (verbose) fprintf(stderr,"sac: corrupted (zapped) entry after %s %d %2ld:%02ld:%02ld.\n",month[end->month],end->day,h,m,s);
continue;
}
lastent = u->ut_time;
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time,FALSE);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry, possible wtmp corruption.\n");
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) {
if (!strncmp("~",u->ut_line,1) && (!strcmp("reboot",u->ut_user) || !strncmp("shutdown",u->ut_user,8))) do_reboot(u->ut_time,FALSE);
else if (strcmp("LOGIN",u->ut_user) && strcmp("~",u->ut_line)) saclogin(su,FALSE);
else saclogout(su,FALSE);
} else {
if (!strcmp("|",u->ut_line) || !strcmp("{",u->ut_line)) changetime(u->ut_time,u->ut_line);
else saclogout(su,FALSE);
}
}
}
}
#endif
/* Modify this to be as large as you like. */
/* The linux kernel may give a bias towards 32k */
#define RADIUS_BUFFER_SIZE 32768
#define RADIUS_HASH_SIZE 256
#define radhash(x) (x%RADIUS_HASH_SIZE)
struct ltable {
int port;
struct utmp last;
struct ltable *nxt;
} *ltable[RADIUS_HASH_SIZE];
/*
* Perform accounting for radius log files for livingston portmasters.
*/
void gronk_radius(int fd)
{
struct sactmp su;
struct utmp *u = &su.u;
struct ltable *lp, *cp;
FILE *rfd;
int r;
static char buffer[RADIUS_BUFFER_SIZE];
/* I don't want to re-invent the wheel, until I know it works, cause no one
may want to use this anyway. */
rfd = fdopen(fd,"r");
/* This seems to make things fast enough for most people. Faster by far than perl */
setvbuf(rfd,buffer,_IOFBF,RADIUS_BUFFER_SIZE);
/* Comment out above to reduce sac memory usage. */
for(r=0;r<RADIUS_HASH_SIZE;r++) ltable[r] = NULL;
do {
r = read_radius(rfd,&su);
if (r < 0) break;
if (checkday(u->ut_time) < 0) {
u->ut_time = lastent;
do_reboot(u->ut_time);
if (verbose) fprintf(stderr,"sac: processing stopped due to bad time entry (before %.24s), possible detail corruption.\n",ctime(&lastent));
return;
}
if (u->ut_line[0]) {
if (u->ut_user[0]) saclogin(su);
else saclogout(su,TRUE);
}
lastent = u->ut_time;
} while(r >= 0);
for(r=0;r<RADIUS_HASH_SIZE;r++) {
for(lp=cp=ltable[r];cp;lp=cp) {
cp=cp->nxt;
free(lp);
}
}
fclose(rfd);
}
/*
* Reads a radius entry.
* <rant mode=on>
* Radius logs suck suck suck... It would be nice if you had the option of
* storing the logs in a nice machine readable format since it would probably
* make cutting through the log 100 times faster at least.
*
* There are at least 5 different radius detail log formats, all slightly
* different. Sac tries to support them all.
* Using the Acct-Session-Time field is problematic, although not impossible,
* because at least some radius entries will sometimes write multiple stop
* records for a single logout. The only way to detect this is to check the
* current record against the last (for that particular port) and if it
* matches, ignore it.
* </rant>
* In this function we read forward until we get to a date entry, then parse
* the date, and read the info block.
*/
int read_radius(FILE *rfd, struct sactmp *su)
{
char **s, name[UT_NAMESIZE];
int n, i, r;
struct tm t;
time_t st;
struct sactmp tu;
struct ltable *lp;
int port;
memset(su,0,sizeof(struct sactmp));
while(fgets(buf,1024,rfd) != NULL) {
if (buf[0] == '\n' || buf[0] == ' ') continue;
s = split(buf, " \f\n\r\t\v:\"", &n);
if (n < 4) continue;
if (n == 7) {
for(i=0;i<12;i++)
if (!strcmp(s[1],month[i])) t.tm_mon = i;
t.tm_mday = stoi(s[2]);
t.tm_hour = stoi(s[3]);
t.tm_min = stoi(s[4]);
t.tm_sec = stoi(s[5]);
t.tm_year = stoi(s[6]) - 1900;
t.tm_isdst = -1;
} else if (n == 4){
s[0][2] = 0;
t.tm_mday = stoi(s[0]);
s[0][5] = 0;
t.tm_mon = stoi(s[0]+3)-1;
t.tm_year = stoi(s[0]+6) - 1900;
t.tm_hour = stoi(s[1]);
t.tm_min = stoi(s[2]);
t.tm_sec = stoi(s[3]);
t.tm_isdst = -1;
}
su->u.ut_time = mktime(&t);
r = read_block(rfd,su,&port,&st,name);
/* printf("%ld: [%-8.8s] %-8.8s %.16s\n",su->u.ut_time,su->u.ut_user,su->u.ut_line,su->u.ut_host); */
for(lp=ltable[radhash(port)];lp;lp=lp->nxt)
if (lp->port == port) break;
if (st) {
struct user *p;
for(p=usr;p;p=p->nxt)
if (!strncmp(su->u.ut_line,p->line,UT_LINESIZE) && (hosttoo? !strncmp(su->u.ut_host,p->host,UT_HOSTSIZE) : TRUE)) goto found_one;
if (lp && !strncmp(lp->last.ut_user,su->u.ut_user,UT_NAMESIZE) && (hosttoo? !strncmp(lp->last.ut_host,su->u.ut_host,UT_HOSTSIZE) : TRUE)) {
/* printf("Extraneous stop ignored.\n"); */
goto found_one;
}
/*
printf("Stop entry with no start [%ld seconds]:\n",st);
printf("%ld: [%-8.8s] %-8.8s %.16s\n",su->u.ut_time,name,su->u.ut_line,su->u.ut_host);
*/
tu.u.ut_time = su->u.ut_time - st;
strncpy(tu.u.ut_user,name,UT_NAMESIZE);
strncpy(tu.u.ut_host,su->u.ut_host,UT_HOSTSIZE);
strncpy(tu.u.ut_line,su->u.ut_line,UT_LINESIZE);
if (!checkday(tu.u.ut_time))
saclogin(tu);
}
found_one:
if (!lp) {
lp = bmalloc(sizeof(struct ltable));
lp->port = port;
lp->nxt = ltable[radhash(port)];
ltable[radhash(port)] = lp;
}
memcpy(&lp->last,&su->u,sizeof(struct utmp));
if (r < 0) return -1;
if (r == 0) continue;
return 0;
}
return -1;
}
enum {
USER_NAME, CLIENT_ID, CLIENT_PORT_ID, ACCT_STATUS_TYPE, ACCT_SESSION_TIME,
ACCT_INPUT_OCTETS, ACCT_OUTPUT_OCTETS, ACCT_INPUT_PACKETS, ACCT_OUTPUT_PACKETS,
DATA_RATE, FRAMED_IP_ADDRESS, CALLED_STATION_ID, USELESS
};
/* This ought to be initialized into a tree or hash table for speed. */
struct radius_str {
char *id;
char use;
} radius_strs[] = {
{"User-Name", USER_NAME},
{"Client-Id", CLIENT_ID},
{"NAS-IP-Address", CLIENT_ID},
{"NAS-Identifier", CLIENT_ID},
{"Client-Port-Id", CLIENT_PORT_ID},
{"NAS-Port", CLIENT_PORT_ID},
{"NAS-Port-Id", CLIENT_PORT_ID},
{"Acct-Status-Type", ACCT_STATUS_TYPE},
{"Acct-Session-Time", ACCT_SESSION_TIME},
{"Acct-Input-Octets", ACCT_INPUT_OCTETS},
{"Acct-Output-Octets", ACCT_OUTPUT_OCTETS},
{"Acct-Input-Packets", ACCT_INPUT_PACKETS},
{"Acct-Output-Packets", ACCT_OUTPUT_PACKETS},
{"Ascend-Data-Rate", DATA_RATE},
{"Framed-IP-Address", FRAMED_IP_ADDRESS},
{"Called-Station-Id", CALLED_STATION_ID},
{NULL, USELESS}
};
/*
* Check the ID strings in the block against those above, if it's one of them,
* then process it. Exit when we hit a blank line.
*/
int read_block(FILE *rfd, struct sactmp *su, int *port, time_t *st, char *name)
{
char **s, *p, stopflg;
int i, n, flg = FALSE;
int framed = FALSE, callid = FALSE;
*st = 0;
for(stopflg = FALSE;fgets(buf,1024,rfd) != NULL;) {
if (buf[0] == '\n') {
if (stopflg) {
strncpy(name,su->u.ut_user,UT_NAMESIZE);
su->u.ut_user[0] = 0;
}
return 1;
}
s = split(buf, " \f\n\r\t\v:\"", &n);
for(i=0;radius_strs[i].id;i++)
if (!strcmp(radius_strs[i].id,s[0]))
switch(radius_strs[i].use) {
case USER_NAME:
if (s[2] == NULL) {
strncpy(su->u.ut_user,"UNKNOWN",UT_NAMESIZE);
break;
}
if (s[2][0] == '!') s[2]++;
else if ((p=index(s[2],'@'))) {
*p++ = 0;
if (radhost) strncpy(su->u.ut_host,p,UT_HOSTSIZE);
}
strncpy(su->u.ut_user,s[2],UT_NAMESIZE);
flg = TRUE;
break;
#if USE_CALLED_STATION_ID != 0
case CALLED_STATION_ID:
strncpy(su->u.ut_host,s[2],UT_HOSTSIZE);
callid = TRUE;
break;
#endif
#if USE_FRAMED_IP_ADDR != 0
case FRAMED_IP_ADDRESS:
if (!radhost && !callid) strncpy(su->u.ut_host,s[2],UT_HOSTSIZE);
framed = TRUE;
break;
#endif
case CLIENT_ID:
if (!framed && !radhost && !callid) strncpy(su->u.ut_host,s[2],UT_HOSTSIZE);
break;
case CLIENT_PORT_ID:
*port = stoi(s[2]);
strncpy(su->u.ut_line,s[2],UT_LINESIZE);
break;
case ACCT_STATUS_TYPE:
if (!strcmp("Stop",s[2])) stopflg = TRUE;
break;
case ACCT_SESSION_TIME:
*st = stoi(s[2]);
break;
case ACCT_INPUT_OCTETS:
su->inoct = (double)stoi(s[2]);
break;
case ACCT_OUTPUT_OCTETS:
su->outoct = (double)stoi(s[2]);
break;
case ACCT_INPUT_PACKETS:
su->inpkt = (double)stoi(s[2]);
break;
case ACCT_OUTPUT_PACKETS:
su->outpkt = (double)stoi(s[2]);
break;
case DATA_RATE:
su->datarate = stoi(s[2]);
break;
}
}
if (stopflg) {
strncpy(name,su->u.ut_user,UT_NAMESIZE);
su->u.ut_user[0] = 0;
}
if (flg) return 1;
return -1;
}
/*
* split the line into words broken by whitespace, colons, and quotes
*/
/*
char **split(s, n)
char *s;
int *n;
{
static char *w[256];
int i;
for(i=0;*s;) {
while (*s && (isspace(*s) || *s == ':' || *s == '"')) s++;
if (!*s) break;
w[i++] = s;
while (*s && !isspace(*s) && *s != ':' && *s != '"') s++;
if (!*s) break;
*s = 0;
s++;
}
w[*n = i] = NULL;
return w;
}
*/
char **split(char *str, char *delim, int *nwrds)
{
static char *w[256];
*nwrds = 0;
w[*nwrds = 0] = strtok(str,delim);
while (w[*nwrds] && *nwrds < 99) w[++(*nwrds)] = strtok(NULL,delim);
w[*nwrds] = NULL;
return w;
}
/*
* This will probably not be supported unless there is some demand for it.
*/
void gronk_radiuslogfile(int fd)
{
}
/*
* A simple atoi, for speed.
* Atoi() might actually be faster. Ought to test that.
*/
u_long stoi(char *s)
{
u_long n,i;
if (s[1] == 0) {
return s[0] - '0';
} else if (s[2] == 0) {
return ((s[0]-'0')*10) + (s[1]-'0');
} else {
for(i=n=0;s[i];i++)
n = (n*10) + (s[i]-'0');
return n;
}
}
|