/* 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" static int acctfd = 0; /* Make a acct entry into the accounting file for accounting. Return 1 on error */ static int acct_write(string) 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, sys_errlist[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(string) char *string; { if (string && string[0]) { if (acct_write(string)) return(1); } else { if (acct_write("unknown")) return(1); } return(0); } int do_acct(rec) 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,0640); if (acctfd < 0) { report(LOG_ERR, "Can't open acct file %s -- %s", session.acctfile, sys_errlist[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 (line, name, host, utime) char *line, *name, *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; wtmpfd = open(wtmpfile, O_CREAT | O_WRONLY | O_APPEND | O_SYNC, 0644); if (wtmpfd < 0) { report(LOG_ERR, "Can't open wtmp file %s -- %s", wtmpfile, sys_errlist[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, sys_errlist[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 (attr, args, cnt) char *attr, **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(rec) 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); }