Patches for wtmp-like accounting

Matt Zimmerman (mdz@netrail.net)
Mon, 19 Feb 1996 14:44:05 -0500 (EST)

These patches to the Merit accounting code should log wtmp-like information
(readable by last(1) and other such programs) to /var/log/rtmp for logins
and logouts. The ut_line field (normally the tty) is filled with a
truncated hostname, followed by a colon, followed by the port number.
ut_host is Framed-IP-Address or a resolved hostname (or the string
"LOGIN" for non-framed users). The result is something like this (last
output):

ut_user ut_line ut_host ut_time
---------------------------------------------------------------------------
netrail ts-arl-1:3 LOGIN Mon Feb 19 14:04 still logged in
patrick ts-arl-1:2 ppp-arl-1-04.net Mon Feb 19 14:03 still logged in
csnyder ts-arl-1:2 ppp-arl-1-03.net Mon Feb 19 13:59 - 14:03 (00:03)
sasi ts-arl-1:5 sasi.netrail.net Mon Feb 19 13:54 - 13:55 (00:00)
---------------------------------------------------------------------------
^ ^ ^
| | |
| | Framed-IP-Address
| |
| NAS-Identifier:NAS-Port
|
User-Name

I've been using it for a few days here without a hitch.

Notes:
======
- I tried to make it reasonably portable, but I've only tested it under
Linux and FreeBSD so far.
- If your NAS hostnames aren't unique when comparing the first
(UT_LINESIZE - 3) characters there will be problems if you depend on
the wtmp login/logout format
- It should be probably be expanded to use Login-IP-Host rather than a
constant string for Login-Users, but I've no need for it here.

Redistribute at will, modify and redistribute at will, no warranties,
express or implied.

// Matt Zimmerman Chief of System Management NetRail, Inc.
// mdz@netrail.net sales@netrail.net
// (703) 524-4800 [voice] (703) 524-4802 [data] (703) 534-5033 [fax]

---

*** src/rad.accounting.c.orig Fri Feb 16 16:10:07 1996 --- src/rad.accounting.c Mon Feb 19 14:31:37 1996 *************** *** 29,34 **** --- 29,36 ---- static char rcsid[] = "$Id: rad.accounting.c,v 1.9 1996/01/19 22:36:31 web Exp $"; + #define NR_WTMP + #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> *************** *** 43,48 **** --- 45,54 ---- #include <sys/wait.h> #include <syslog.h> + #ifdef NR_WTMP + #include <utmp.h> + #endif + #include "radius.h" extern char send_buffer[4096]; *************** *** 93,98 **** --- 99,111 ---- char buffer[MAXPATHLEN]; char clientname[AUTH_ID_LEN]; static char *func = "rad_acct_action"; + #ifdef NR_WTMP + struct utmp utmp_entry; + struct hostent *host; + char *cp; + char port[3]; + struct in_addr inaddr; + #endif /* NR_WTMP */ dprintf(2, (LOG_AUTH, LOG_DEBUG, "%s: entered", func)); *************** *** 133,138 **** --- 146,218 ---- fputs ("\n", outfd); fclose (outfd); + + #ifdef NR_WTMP + /* + * Write wtmp + */ + if ((outfd = fopen("/var/log/rtmp","a")) == (FILE *)NULL) + { + logit (LOG_DAEMON, LOG_ERR, + "%s: Couldn't open file %s", + buffer); + return EV_ERROR; + } + + #ifdef USER_PROCESS + utmp_entry.ut_type = USER_PROCESS; + utmp_entry.ut_pid = 0; + #endif + time(&utmp_entry.ut_time); + utmp_entry.ut_line[0] = '\0'; + strcpy(utmp_entry.ut_host,"LOGIN"); + + /* Write appropriate attributes/values to wtmp */ + pair = authreq->request; + while (pair != (VALUE_PAIR *) NULL) + { + if (strcmp(pair->name,"User-Name") == 0) + { + strncpy(utmp_entry.ut_name,pair->strvalue,UT_NAMESIZE); + } + else if (strcmp(pair->name,"Framed-IP-Address") == 0) + { + inaddr.s_addr = htonl(pair->lvalue); + /* attempt hostname resolution */ + host = gethostbyaddr((char *)&inaddr.s_addr,4,AF_INET); + if (host == (struct hostent *)NULL) + { + strncpy(utmp_entry.ut_host,(const char *)inet_ntoa(inaddr.s_addr),UT_HOSTSIZE); + } + else + { + strncpy(utmp_entry.ut_host,host->h_name,UT_HOSTSIZE); + } + } + else if (strcmp(pair->name,"NAS-Identifier") == 0) + { + strncpy(utmp_entry.ut_line,strtok(pair->strvalue,"."), + UT_HOSTSIZE - 3); /* Leave room for port */ + } + else if (strcmp(pair->name,"NAS-Port") == 0) + { + sprintf(port,":%ld",pair->lvalue); + } + else if (strcmp(pair->name,"Acct-Status-Type") == 0) + { + if (pair->lvalue == 2) /* Stop */ + utmp_entry.ut_name[0] = '\0'; + } + pair = pair->next; + } + + strcat(utmp_entry.ut_line,port); + /* ut_line should now be [host_abbrev:port] */ + + fwrite(&utmp_entry,sizeof(utmp_entry),1,outfd); + fclose(outfd); + + #endif /* NR_WTMP */ return EV_ACK; } /* end of rad_acct_action () */