/*
* $Id: do_acct.c,v 1.11 2006/12/13 01:11:37 heas Exp $
*
* Copyright (c) 1995-1998 by Cisco systems, Inc.
*
* Permission to use, copy, modify, and distribute this software for
* any purpose and without fee is hereby granted, provided that this
* copyright and permission notice appear on all copies of the
* software and supporting documentation, the name of Cisco Systems,
* Inc. not be used in advertising or publicity pertaining to
* distribution of the program without specific prior permission, and
* notice be given in supporting documentation that modification,
* copying and distribution is by permission of Cisco Systems, Inc.
*
* Cisco Systems, Inc. makes no representations about the suitability
* of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
* IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "tac_plus.h"
#include <time.h>
#if defined(__DragonFly__) && !defined(O_SYNC)
#define O_SYNC O_FSYNC
#endif
static int acctfd = 0;
/*
* Make a acct entry into the accounting file for accounting.
* Return 1 on error
*/
static int
acct_write(char *string)
{
if (write(acctfd, string, strlen(string)) != strlen(string)) {
report(LOG_ERR, "%s: couldn't write acct file %s %s",
session.peer,
session.acctfile, strerror(errno));
return(1);
}
if (debug & DEBUG_ACCT_FLAG)
report(LOG_DEBUG, "'%s'", string);
return(0);
}
/*
* Write a string or "unknown" into the accounting file.
* Return 1 on error
*/
static int
acct_write_field(char *string)
{
if (string && string[0]) {
if (acct_write(string))
return(1);
} else {
if (acct_write("unknown"))
return(1);
}
return(0);
}
int
do_acct(struct acct_rec *rec)
{
int i, errors;
time_t t = time(NULL);
char *ct = ctime(&t);
ct[24] = '\0';
if (!acctfd) {
acctfd = open(session.acctfile, O_CREAT | O_WRONLY | O_APPEND, 0644);
if (acctfd < 0) {
report(LOG_ERR, "Can't open acct file %s -- %s",
session.acctfile, strerror(errno));
return(1);
}
}
if (!tac_lockfd(session.acctfile, acctfd)) {
rec->admin_msg = tac_strdup("Cannot lock log file");
report(LOG_ERR, "%s: Cannot lock %s",
session.peer, session.acctfile);
return(1);
}
errors = 0;
errors += acct_write(ct);
errors += acct_write("\t");
errors += acct_write_field(rec->identity->NAS_name);
errors += acct_write("\t");
errors += acct_write_field(rec->identity->username);
errors += acct_write("\t");
errors += acct_write_field(rec->identity->NAS_port);
errors += acct_write("\t");
errors += acct_write_field(rec->identity->NAC_address);
errors += acct_write("\t");
switch(rec->acct_type) {
case ACCT_TYPE_UPDATE:
errors += acct_write("update\t");
break;
case ACCT_TYPE_START:
errors += acct_write("start\t");
break;
case ACCT_TYPE_STOP:
errors += acct_write("stop\t");
break;
default:
errors += acct_write("unknown\t");
break;
}
for (i=0; i < rec->num_args; i++) {
errors += acct_write(rec->args[i]);
if (i < (rec->num_args-1))
errors += acct_write("\t");
}
errors += acct_write("\n");
close(acctfd);
acctfd = 0;
if (errors) {
return(1);
}
return(0);
}
int
wtmp_entry(char *line, char *name, char *host, time_t utime)
{
struct utmp entry;
if (!wtmpfile) {
return(1);
}
bzero(&entry, sizeof entry);
if (strlen(line) < sizeof entry.ut_line)
strcpy(entry.ut_line, line);
else bcopy(line, entry.ut_line, sizeof entry.ut_line);
if (strlen(name) < sizeof entry.ut_name)
strcpy(entry.ut_name, name);
else bcopy(name, entry.ut_name, sizeof entry.ut_name);
#ifndef SOLARIS
if (strlen(host) < sizeof entry.ut_host)
strcpy(entry.ut_host, host);
else
bcopy(host, entry.ut_host, sizeof entry.ut_host);
#endif
entry.ut_time = utime;
#ifdef FREEBSD
wtmpfd = open(wtmpfile, O_CREAT | O_WRONLY | O_APPEND, 0644);
#else
wtmpfd = open(wtmpfile, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0644);
#endif
if (wtmpfd < 0) {
report(LOG_ERR, "Can't open wtmp file %s -- %s",
wtmpfile, strerror(errno));
return(1);
}
if (!tac_lockfd(wtmpfile, wtmpfd)) {
report(LOG_ERR, "%s: Cannot lock %s", session.peer, wtmpfile);
return(1);
}
if (write(wtmpfd, &entry, sizeof entry) != (sizeof entry)) {
report(LOG_ERR, "%s: couldn't write wtmp file %s %s",
session.peer, wtmpfile, strerror(errno));
return(1);
}
close(wtmpfd);
if (debug & DEBUG_ACCT_FLAG) {
report(LOG_DEBUG, "wtmp: %s, %s %s %d", line, name, host, utime);
}
return(0);
}
char *
find_attr_value(char *attr, char **args, int cnt)
{
int i;
for (i=0; i < cnt; i++) {
if (!strncmp(attr, args[i], strlen(attr))) {
char *ptr;
for (ptr = args[i]; ptr && *ptr; ptr++) {
if ((*ptr == '*') || (*ptr == '=')) {
return(ptr+1);
}
}
return(NULL);
}
}
return(NULL);
}
int
do_wtmp(struct acct_rec *rec)
{
time_t now = time(NULL);
char *service;
char *elapsed_time, *start_time;
time_t start_utime = 0, stop_utime = 0, elapsed_utime = 0;
switch(rec->acct_type) {
case ACCT_TYPE_START:
case ACCT_TYPE_STOP:
break;
case ACCT_TYPE_UPDATE:
default:
return(0);
}
service = find_attr_value("service", rec->args, rec->num_args);
if (!service) {
/* An error */
return(1);
}
if (STREQ(service, "system")) {
if (rec->acct_type == ACCT_TYPE_START) {
/* A reload */
wtmp_entry("~", "", session.peer, now);
}
return(0);
}
if (rec->acct_type != ACCT_TYPE_STOP) {
return(0);
}
/*
* Since xtacacs logged start records containing the peer address
* for a connection, we have to generate them from T+ stop records.
* Might as well do this for exec records too.
*/
elapsed_time = find_attr_value("elapsed_time", rec->args, rec->num_args);
if (elapsed_time) {
elapsed_utime = strtol(elapsed_time, NULL, 10);
}
start_time = find_attr_value("start_time", rec->args, rec->num_args);
/*
* Use the start_time if there is one. If not (e.g. the NAS may
* not know the time), assume the stop time is now, and calculate
* the rest
*/
if (start_time) {
start_utime = strtol(start_time, NULL, 10);
stop_utime = start_utime + elapsed_utime;
} else {
start_utime = now - elapsed_utime;
stop_utime = now;
}
if (STREQ(service, "slip") || STREQ(service, "ppp")) {
char *dest_addr = find_attr_value("addr", rec->args, rec->num_args);
/* The start record */
wtmp_entry(rec->identity->NAS_port, rec->identity->username, dest_addr,
start_utime);
/* The stop record */
wtmp_entry(rec->identity->NAS_port, "", dest_addr, stop_utime);
return(0);
}
if (STREQ(service, "shell")) {
/* Start */
wtmp_entry(rec->identity->NAS_port, rec->identity->username,
session.peer, start_utime);
/* Stop */
wtmp_entry(rec->identity->NAS_port, "", session.peer, stop_utime);
return(0);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1