aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/audit/tools/aulast
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/audit/tools/aulast')
-rw-r--r--framework/src/audit/tools/aulast/Makefile.am34
-rw-r--r--framework/src/audit/tools/aulast/aulast-llist.c196
-rw-r--r--framework/src/audit/tools/aulast/aulast-llist.h75
-rw-r--r--framework/src/audit/tools/aulast/aulast.847
-rw-r--r--framework/src/audit/tools/aulast/aulast.c610
5 files changed, 962 insertions, 0 deletions
diff --git a/framework/src/audit/tools/aulast/Makefile.am b/framework/src/audit/tools/aulast/Makefile.am
new file mode 100644
index 00000000..b20987f9
--- /dev/null
+++ b/framework/src/audit/tools/aulast/Makefile.am
@@ -0,0 +1,34 @@
+# Makefile.am --
+# Copyright 2008,2010,2015 Red Hat Inc., Durham, North Carolina.
+# All Rights Reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Authors:
+# Steve Grubb <sgrubb@redhat.com>
+#
+
+CONFIG_CLEAN_FILES = *.loT *.rej *.orig
+AUTOMAKE_OPTIONS = no-dependencies
+EXTRA_DIST = $(man_MANS)
+AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse
+LIBS = -L${top_builddir}/auparse -lauparse
+AM_CFLAGS = -D_GNU_SOURCE
+bin_PROGRAMS = aulast
+noinst_HEADERS = aulast-llist.h
+man_MANS = aulast.8
+
+aulast_SOURCES = aulast.c aulast-llist.c
+
diff --git a/framework/src/audit/tools/aulast/aulast-llist.c b/framework/src/audit/tools/aulast/aulast-llist.c
new file mode 100644
index 00000000..be05e976
--- /dev/null
+++ b/framework/src/audit/tools/aulast/aulast-llist.c
@@ -0,0 +1,196 @@
+/*
+* aulast-llist.c - Minimal linked list library
+* Copyright (c) 2008 Red Hat Inc., Durham, North Carolina.
+* All Rights Reserved.
+*
+* This software may be freely redistributed and/or modified under the
+* terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; see the file COPYING. If not, write to the
+* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+* Authors:
+* Steve Grubb <sgrubb@redhat.com>
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "aulast-llist.h"
+
+void list_create(llist *l)
+{
+ l->head = NULL;
+ l->cur = NULL;
+}
+
+lnode *list_next(llist *l)
+{
+ if (l->cur == NULL)
+ return NULL;
+ l->cur = l->cur->next;
+ return l->cur;
+}
+
+static void list_append(llist *l, lnode *node)
+{
+ node->next = NULL;
+
+ // if we are at top, fix this up
+ if (l->head == NULL)
+ l->head = node;
+ else if (l->cur) {
+ // Make sure we are at the end
+ while (l->cur->next)
+ l->cur = l->cur->next;
+
+ l->cur->next = node;
+ }
+
+ // make newnode current
+ l->cur = node;
+}
+
+void list_clear(llist* l)
+{
+ lnode* nextnode;
+ register lnode* current;
+
+ current = l->head;
+ while (current) {
+ nextnode=current->next;
+ free((void *)current->name);
+ free((void *)current->term);
+ free((void *)current->host);
+ free(current);
+ current=nextnode;
+ }
+ l->head = NULL;
+ l->cur = NULL;
+}
+
+int list_create_session(llist *l, uid_t auid, int pid, int session,
+ unsigned long serial)
+{
+ lnode *n = malloc(sizeof(lnode));
+ if (n == NULL)
+ return 0;
+ n->session = session;
+ n->start = 0;
+ n->end = 0;
+ n->auid = auid;
+ n->pid = pid;
+ n->result = -1;
+ n->name = NULL;
+ n->term = NULL;
+ n->host = NULL;
+ n->status = LOG_IN;
+ n->loginuid_proof = serial;
+ n->user_login_proof = 0;
+ n->user_end_proof = 0;
+ list_append(l, n);
+ return 1;
+}
+
+int list_update_start(llist* l, time_t start, const char *host,
+ const char *term, int res, unsigned long serial)
+{
+ register lnode* cur;
+ if (l == NULL)
+ return 0;
+
+ cur=list_get_cur(l);
+ cur->start = start;
+ cur->status = SESSION_START;
+ if (term)
+ cur->term = strdup(term);
+ if (host)
+ cur->host = strdup(host);
+ cur->result = res;
+ cur->user_login_proof = serial;
+ return 1;
+}
+
+int list_update_logout(llist* l, time_t t, unsigned long serial)
+{
+ register lnode* cur;
+ if (l == NULL)
+ return 0;
+
+ cur=list_get_cur(l);
+ cur->end = t;
+ cur->status = LOG_OUT;
+ cur->user_end_proof = serial;
+ return 1;
+}
+
+lnode *list_delete_cur(llist *l)
+{
+ register lnode *cur, *prev;
+
+ prev = cur = l->head; /* start at the beginning */
+ while (cur) {
+ if (cur == l->cur) {
+ if (cur == prev && cur == l->head) {
+ l->head = cur->next;
+ l->cur = cur->next;
+ free((void *)cur->name);
+ free((void *)cur->term);
+ free((void *)cur->host);
+ free(cur);
+ prev = NULL;
+ } else {
+ prev->next = cur->next;
+ free((void *)cur->name);
+ free((void *)cur->term);
+ free((void *)cur->host);
+ free(cur);
+ l->cur = prev;
+ }
+ return prev;
+ } else {
+ prev = cur;
+ cur = cur->next;
+ }
+ }
+ return NULL;
+}
+
+lnode *list_find_auid(llist *l, uid_t auid, int pid, unsigned int session)
+{
+ register lnode* cur;
+
+ cur = l->head; /* start at the beginning */
+ while (cur) {
+ if (cur->pid == pid && cur->auid == auid &&
+ cur->session == session) {
+ l->cur = cur;
+ return cur;
+ } else
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+lnode *list_find_session(llist *l, unsigned int session)
+{
+ register lnode* cur;
+
+ cur = l->head; /* start at the beginning */
+ while (cur) {
+ if (cur->session == session) {
+ l->cur = cur;
+ return cur;
+ } else
+ cur = cur->next;
+ }
+ return NULL;
+}
+
diff --git a/framework/src/audit/tools/aulast/aulast-llist.h b/framework/src/audit/tools/aulast/aulast-llist.h
new file mode 100644
index 00000000..a56cace2
--- /dev/null
+++ b/framework/src/audit/tools/aulast/aulast-llist.h
@@ -0,0 +1,75 @@
+/*
+* aulast-llist.h - Header file for aulastlog-llist.c
+* Copyright (c) 2008 Red Hat Inc., Durham, North Carolina.
+* All Rights Reserved.
+*
+* This software may be freely redistributed and/or modified under the
+* terms of the GNU General Public License as published by the Free
+* Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; see the file COPYING. If not, write to the
+* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+* Authors:
+* Steve Grubb <sgrubb@redhat.com>
+*/
+
+#ifndef AULASTLIST_HEADER
+#define AULASTLIST_HEADER
+
+#include <sys/types.h>
+
+
+typedef enum { LOG_IN, SESSION_START, LOG_OUT, DOWN, CRASH, GONE } status_t;
+
+/* This is the node of the linked list. message & item are the only elements
+ * at this time. Any data elements that are per item goes here. */
+typedef struct _lnode{
+ unsigned int session; // The kernel login session id
+ time_t start; // first time uid logged in
+ time_t end; // last time uid logged in
+ uid_t auid; // user ID
+ int pid; // pid of program logging in
+ const char *name; // user name
+ const char *term; // terminal name
+ const char *host; // host where logging in from
+ int result; // login results
+ status_t status; // Current status of this session
+ unsigned long loginuid_proof; // audit serial number for loginuid change
+ unsigned long user_login_proof; // audit serial number for user login event
+ unsigned long user_end_proof; // audit serial number for user log out event
+ struct _lnode* next; // Next node pointer
+} lnode;
+
+/* This is the linked list head. Only data elements that are 1 per
+ * event goes here. */
+typedef struct {
+ lnode *head; // List head
+ lnode *cur; // Pointer to current node
+} llist;
+
+void list_create(llist *l);
+static inline void list_first(llist *l) { l->cur = l->head; }
+lnode *list_next(llist *l);
+static inline lnode *list_get_cur(llist *l) { return l->cur; }
+void list_clear(llist* l);
+int list_create_session(llist* l, uid_t auid, int pid, int session,
+ unsigned long serial);
+int list_update_start(llist* l, time_t start, const char *host,
+ const char *term, int res, unsigned long serial);
+int list_update_logout(llist* l, time_t t, unsigned long serial);
+lnode *list_delete_cur(llist *l);
+
+/* Given a uid, find that record. */
+lnode *list_find_auid(llist *l, uid_t auid, int pid, unsigned int session);
+lnode *list_find_session(llist *l, unsigned int session);
+
+#endif
+
diff --git a/framework/src/audit/tools/aulast/aulast.8 b/framework/src/audit/tools/aulast/aulast.8
new file mode 100644
index 00000000..25705f95
--- /dev/null
+++ b/framework/src/audit/tools/aulast/aulast.8
@@ -0,0 +1,47 @@
+.TH AULAST: "8" "Nov 2008" "Red Hat" "System Administration Utilities"
+.SH NAME
+aulast \- a program similar to last
+.SH SYNOPSIS
+.B aulast [ options ] [ user ] [ tty ]
+
+.SH DESCRIPTION
+\fBaulast\fP is a program that prints out a listing of the last logged in users similarly to the program \fBlast\fP and \fBlastb\fP. Aulast searches back through the audit logs or the given audit log file and displays a list of all users logged in (and out) based on the range of time in the audit logs. Names of users and tty’s can be given, in which case aulast will show only those entries matching the arguments. Names of ttys can be abbreviated, thus aulast 0 is the same as last tty0.
+
+The pseudo user reboot logs in each time the system is rebooted. Thus last reboot will show a log of all reboots since the log file was created.
+
+The main difference that a user will notice is that \fBaulast\fP print events from oldest to newest, while \fBlast\fP prints records from newest to oldest. Also, the audit system is not notified each time a tty or pty is allocated, so you may not see quite as many records indicating users and their tty's.
+
+.SH OPTIONS
+.TP
+.B \-\-bad
+Report on the bad logins.
+
+.TP
+.B \-\-extract
+Write raw audit records used to create the displayed report into a file aulast.log in the current working directory.
+
+.TP
+.BI \-f file
+Use the file instead of the audit logs for input.
+
+.TP
+.B \-\-proof
+Print out the audit event serial numbers used to determine the preceding line of the report. A Serial number of 0 is a place holder and not an actual event serial number. The serial numbers can be used to examine the actual audit records in more detail. Also an ausearch query is printed that will let you find the audit records associated with that session.
+
+.TP
+.B \-\-stdin
+Take audit records from stdin.
+
+.SH "EXAMPLES"
+.nf
+To see this month's logins
+.B ausearch \-\-start this-month \-\-raw | aulast \-\-stdin
+
+.SH "SEE ALSO"
+.BR last (1),
+.BR lastb (1),
+.BR ausearch (8),
+.BR aureport (8).
+
+.SH AUTHOR
+Steve Grubb
diff --git a/framework/src/audit/tools/aulast/aulast.c b/framework/src/audit/tools/aulast/aulast.c
new file mode 100644
index 00000000..00ae055a
--- /dev/null
+++ b/framework/src/audit/tools/aulast/aulast.c
@@ -0,0 +1,610 @@
+/*
+ * aulast.c - A last program based on audit logs
+ * Copyright (c) 2008-2009,2011 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This software may be freely redistributed and/or modified under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors:
+ * Steve Grubb <sgrubb@redhat.com>
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <locale.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include "libaudit.h"
+#include "auparse.h"
+#include "aulast-llist.h"
+
+
+static llist l;
+static FILE *f = NULL;
+static char *kernel = NULL;
+
+/* command line params */
+static int cuid = -1, bad = 0, proof = 0, debug = 0;
+static char *cterm = NULL;
+
+void usage(void)
+{
+ fprintf(stderr,
+ "usage: aulast [--stdin] [--proof] [--extract] [-f file] [user name] [tty]\n");
+}
+
+/* This outputs a line of text reporting the login/out times */
+static void report_session(lnode* cur)
+{
+ int notime = 0;
+
+ // Don't list failed logins
+ if (cur == NULL)
+ return;
+
+ if (cur->result != bad)
+ return;
+
+ if (cur->name) {
+ // This is a reboot record
+ printf("%-8.8s ", cur->name);
+ if (cur->end == 0) {
+ cur->end = time(NULL);
+ notime = 1;
+ }
+ } else {
+ struct passwd *p = getpwuid(cur->auid);
+ if (p)
+ printf("%-8.8s ", p->pw_name);
+ else
+ printf("%-8.u ", cur->auid);
+ }
+ if (strncmp("/dev/", cur->term, 5) == 0)
+ printf("%-12.12s ", cur->term+5);
+ else
+ printf("%-12.12s ", cur->term);
+ printf("%-16.16s ", cur->host ? cur->host : "?");
+ printf("%-16.16s ", ctime(&cur->start));
+ switch(cur->status)
+ {
+ case SESSION_START:
+ printf(" still logged in\n");
+ break;
+ case DOWN:
+ printf("- down\n");
+ break;
+ case CRASH:
+ printf("- crash\n");
+ break;
+ case GONE:
+ printf(" gone - no logout\n");
+ break;
+ case LOG_OUT: {
+ time_t secs;
+ int mins, hours, days;
+ if (notime)
+ printf("- %-7.5s", " ");
+ else
+ printf("- %-7.5s", ctime(&cur->end) + 11);
+ secs = cur->end - cur->start;
+ mins = (secs / 60) % 60;
+ hours = (secs / 3600) % 24;
+ days = secs / 86400;
+ if (days)
+ printf("(%d+%02d:%02d)\n", days, hours, mins);
+ else
+ printf("(%02d:%02d)\n", hours, mins);
+ }
+ break;
+ default:
+ printf("\n");
+ break;
+ }
+ if (proof) {
+ char start[32], end[32];
+ struct tm *btm;
+
+ if (cur->loginuid_proof == 0 && cur->result == 1) // Bad login
+ printf(" audit event proof serial number:"
+ " %lu\n", cur->user_login_proof);
+ else
+ printf(" audit event proof serial numbers:"
+ " %lu, %lu, %lu\n", cur->loginuid_proof,
+ cur->user_login_proof, cur->user_end_proof);
+ printf(" Session data can be found with this search:\n");
+ btm = localtime(&cur->start);
+ strftime(start, sizeof(start), "%x %T", btm);
+ if (cur->end != 0) {
+ btm = localtime(&cur->end);
+ strftime(end, sizeof(end), "%x %T", btm);
+ printf(" ausearch --start %s --end %s",
+ start, end);
+ } else {
+ printf(" ausearch --start %s", start);
+ }
+ if (cur->name == NULL)
+ printf(" --session %d", cur->session);
+ if (cur->loginuid_proof == 0 && cur->result == 1) // Bad login
+ printf(" -a %lu", cur->user_login_proof);
+ printf("\n\n");
+ }
+}
+
+static void extract_record(auparse_state_t *au)
+{
+ if (f == NULL)
+ return;
+
+ fprintf(f, "%s\n", auparse_get_record_text(au));
+}
+
+static void create_new_session(auparse_state_t *au)
+{
+ const char *tpid, *tses, *tauid;
+ int pid = -1, auid = -1, ses = -1;
+ lnode *cur;
+
+ // Get pid
+ tpid = auparse_find_field(au, "pid");
+ if (tpid)
+ pid = auparse_get_field_int(au);
+
+ // Get second auid field
+ tauid = auparse_find_field(au, "old-auid");
+ if (tauid)
+ tauid = auparse_find_field(au, "auid");
+ else { // kernel 3.13 or older
+ auparse_first_record(au);
+ auparse_find_field(au, "auid");
+ auparse_next_field(au);
+ tauid = auparse_find_field(au, "auid");
+ }
+ if (tauid)
+ auid = auparse_get_field_int(au);
+
+ // Get second ses field
+ tses = auparse_find_field(au, "old-ses");
+ if (tses)
+ tses = auparse_find_field(au, "ses");
+ else { // kernel 3.13 or older
+ auparse_first_record(au);
+ auparse_find_field(au, "ses");
+ auparse_next_field(au);
+ tses = auparse_find_field(au, "ses");
+ }
+ if (tses)
+ ses = auparse_get_field_int(au);
+
+ // Check that they are valid
+ if (pid == -1 || auid ==-1 || ses == -1) {
+ if (debug)
+ fprintf(stderr, "Bad login for event: %lu\n",
+ auparse_get_serial(au));
+ return;
+ }
+
+ // See if this session is already open
+ //cur = list_find_auid(&l, auid, pid, ses);
+ cur = list_find_session(&l, ses);
+ if (cur) {
+ // This means we have an open session close it out
+ cur->status = GONE;
+ cur->end = auparse_get_time(au);
+ report_session(cur);
+ list_delete_cur(&l);
+ }
+
+ // If this is supposed to be limited to a specific
+ // uid and we don't have that record, skip creating it
+ if (cuid != -1 && cuid != auid) {
+ if (debug)
+ fprintf(stderr,
+ "login reporting limited to %d for event: %lu\n",
+ cuid, auparse_get_serial(au));
+ return;
+ }
+
+ list_create_session(&l, auid, pid, ses, auparse_get_serial(au));
+}
+
+static void update_session_login(auparse_state_t *au)
+{
+ const char *tpid, *tses, *tuid, *tacct=NULL, *host, *term, *tres;
+ int pid = -1, uid = -1, ses = -1, result = -1;
+ time_t start;
+ lnode *cur;
+
+ // Get pid
+ tpid = auparse_find_field(au, "pid");
+ if (tpid)
+ pid = auparse_get_field_int(au);
+
+ // Get ses field - skipping first uid
+ tses = auparse_find_field(au, "ses");
+ if (tses)
+ ses = auparse_get_field_int(au);
+
+ // Get second uid field - we should be positioned past the first one
+ // gdm sends uid, everything else sends id, we try acct as last resort
+ tuid = auparse_find_field(au, "uid");
+ if (tuid)
+ uid = auparse_get_field_int(au);
+ else {
+ auparse_first_record(au);
+ tuid = auparse_find_field(au, "id");
+ if (tuid)
+ uid = auparse_get_field_int(au);
+ else {
+ auparse_first_record(au);
+ tuid = auparse_find_field(au, "acct");
+ if (tuid) {
+ const char *tacct = auparse_interpret_field(au);
+ struct passwd *pw = getpwnam (tacct);
+ if (pw != NULL)
+ uid = pw->pw_uid;
+ } else
+ auparse_first_record(au);
+ }
+ }
+
+ start = auparse_get_time(au);
+
+ host = auparse_find_field(au, "hostname");
+ if (host && strcmp(host, "?") == 0)
+ host = auparse_find_field(au, "addr");
+
+ term = auparse_find_field(au, "terminal");
+ if (term == NULL)
+ term = "?";
+ tres = auparse_find_field(au, "res");
+ if (tres)
+ tres = auparse_interpret_field(au);
+ if (tres) {
+ if (strcmp(tres, "success") == 0)
+ result = 0;
+ else
+ result = 1;
+ }
+ // We only get tacct when its a bad login
+ if (result == 1) {
+ auparse_first_record(au);
+ tacct = auparse_find_field(au, "acct");
+ if (tacct)
+ tacct = auparse_interpret_field(au);
+ } else {
+ // Check that they are valid
+ if (pid == -1 || uid ==-1 || ses == -1) {
+ if (debug)
+ fprintf(stderr,
+ "Bad user login for event: %lu\n",
+ auparse_get_serial(au));
+ return;
+ }
+ }
+
+ // See if this session is already open
+ if (result == 0)
+ cur = list_find_auid(&l, uid, pid, ses);
+ else
+ cur = NULL;
+ if (cur) {
+ // If we are limited to a specific terminal and
+ // we find out the session is not associated with
+ // the terminal of interest, delete the current node
+ if (cterm && strstr(term, cterm) == NULL) {
+ list_delete_cur(&l);
+ if (debug)
+ fprintf(stderr,
+ "User login limited to %s for event: %lu\n",
+ cterm, auparse_get_serial(au));
+ return;
+ }
+
+ // This means we have an open session - update it
+ list_update_start(&l, start, host, term, result,
+ auparse_get_serial(au));
+
+ // If the results were failed, we can close it out
+ /* FIXME: result cannot be true. This is dead code.
+ if (result) {
+ report_session(cur);
+ list_delete_cur(&l);
+ } */
+ } else if (bad == 1 && result == 1) {
+ // If it were a bad login and we are wanting bad logins
+ // create the record and report it.
+ lnode n;
+
+ n.start = start;
+ n.end = start;
+ n.auid = uid;
+ n.name = tacct;
+ n.term = term;
+ n.host = host;
+ n.result = result;
+ n.status = LOG_OUT;
+ n.loginuid_proof = 0;
+ n.user_login_proof = auparse_get_serial(au);
+ n.user_end_proof = 0;
+ report_session(&n);
+ } else if (debug)
+ printf("Session not found or updated\n");
+}
+
+static void update_session_logout(auparse_state_t *au)
+{
+ const char *tses, *tauid, *tpid;
+ int pid = -1, auid = -1, ses = -1;
+ lnode *cur;
+
+ // Get pid field
+ tpid = auparse_find_field(au, "pid");
+ if (tpid)
+ pid = auparse_get_field_int(au);
+
+ // Get auid field
+ tauid = auparse_find_field(au, "auid");
+ if (tauid)
+ auid = auparse_get_field_int(au);
+
+ // Get ses field
+ tses = auparse_find_field(au, "ses");
+ if (tses)
+ ses = auparse_get_field_int(au);
+
+ // Check that they are valid
+ if (pid == -1 || auid ==-1 || ses == -1) {
+ if (debug)
+ fprintf(stderr, "Bad user logout for event: %lu\n",
+ auparse_get_serial(au));
+ return;
+ }
+
+ // See if this session is already open
+ cur = list_find_auid(&l, auid, pid, ses);
+ if (cur) {
+ // if time never got updated, this must be a cron or su
+ // session...so we will just delete it.
+ if (cur->start) {
+ // This means we have an open session close it out
+ time_t end = auparse_get_time(au);
+ list_update_logout(&l, end, auparse_get_serial(au));
+ report_session(cur);
+ } else if (debug)
+ fprintf(stderr, "start time error for event: %lu\n",
+ auparse_get_serial(au));
+ list_delete_cur(&l);
+ }
+}
+
+static void process_bootup(auparse_state_t *au)
+{
+ lnode *cur;
+ int start;
+
+ // See if we have unclosed boot up and make into CRASH record
+ list_first(&l);
+ cur = list_get_cur(&l);
+ while (cur) {
+ if (cur->name) {
+ cur->user_end_proof = auparse_get_serial(au);
+ cur->status = CRASH;
+ cur->end = auparse_get_time(au);
+ report_session(cur);
+ }
+ cur = list_next(&l);
+ }
+
+ // Logout and process anyone still left in the machine
+ list_first(&l);
+ cur = list_get_cur(&l);
+ while (cur) {
+ if (cur->status != CRASH) {
+ cur->user_end_proof = auparse_get_serial(au);
+ cur->status = DOWN;
+ cur->end = auparse_get_time(au);
+ report_session(cur);
+ }
+ cur = list_next(&l);
+ }
+
+ // Since this is a boot message, all old entries should be gone
+ list_clear(&l);
+ list_create(&l);
+
+ // make reboot record - user:reboot, tty:system boot, host: kernel
+ start = auparse_get_time(au);
+ list_create_session(&l, 0, 0, 0, auparse_get_serial(au));
+ cur = list_get_cur(&l);
+ cur->start = start;
+ cur->name = strdup("reboot");
+ cur->term = strdup("system boot");
+ if (kernel)
+ cur->host = strdup(kernel);
+ cur->result = 0;
+}
+
+static void process_kernel(auparse_state_t *au)
+{
+ const char *kernel_str = auparse_find_field(au, "kernel");
+ if (kernel_str == NULL)
+ return;
+
+ free(kernel);
+ kernel = strdup(kernel_str);
+}
+
+static void process_shutdown(auparse_state_t *au)
+{
+ lnode *cur;
+
+ // Find reboot record
+ list_first(&l);
+ cur = list_get_cur(&l);
+ while (cur) {
+ if (cur->name) {
+ // Found it - close it out and display it
+ time_t end = auparse_get_time(au);
+ list_update_logout(&l, end, auparse_get_serial(au));
+ report_session(cur);
+ list_delete_cur(&l);
+ return;
+ }
+ cur = list_next(&l);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i, use_stdin = 0;
+ char *user = NULL, *file = NULL;
+ struct passwd *p;
+ auparse_state_t *au;
+
+ setlocale (LC_ALL, "");
+ for (i=1; i<argc; i++) {
+ if (argv[i][0] != '-') {
+ //take input and lookup as if it were a user name
+ //if that fails assume its a tty
+ if (user == NULL) {
+ p = getpwnam(argv[i]);
+ if (p) {
+ cuid = p->pw_uid;
+ user = argv[i];
+ continue;
+ }
+ }
+ if (cterm == NULL) {
+ cterm = argv[i];
+ } else {
+ usage();
+ return 1;
+ }
+ } else {
+ if (strcmp(argv[i], "-f") == 0) {
+ if (use_stdin == 0) {
+ i++;
+ file = argv[i];
+ } else {
+ fprintf(stderr,"stdin already given\n");
+ return 1;
+ }
+ } else if (strcmp(argv[i], "--bad") == 0) {
+ bad = 1;
+ } else if (strcmp(argv[i], "--proof") == 0) {
+ proof = 1;
+ } else if (strcmp(argv[i], "--extract") == 0) {
+ f = fopen("aulast.log", "wt");
+ } else if (strcmp(argv[i], "--stdin") == 0) {
+ if (file == NULL)
+ use_stdin = 1;
+ else {
+ fprintf(stderr, "file already given\n");
+ return 1;
+ }
+ } else if (strcmp(argv[i], "--debug") == 0) {
+ debug = 1;
+ } else {
+ usage();
+ return 1;
+ }
+ }
+ }
+ list_create(&l);
+
+ // Search for successful user logins
+ if (file)
+ au = auparse_init(AUSOURCE_FILE, file);
+ else if (use_stdin)
+ au = auparse_init(AUSOURCE_FILE_POINTER, stdin);
+ else {
+ if (getuid()) {
+ fprintf(stderr, "You probably need to be root for this to work\n");
+ }
+ au = auparse_init(AUSOURCE_LOGS, NULL);
+ }
+ if (au == NULL) {
+ fprintf(stderr, "Error - %s\n", strerror(errno));
+ goto error_exit_1;
+ }
+
+ // The theory: iterate though events
+ // 1) when LOGIN is found, create a new session node
+ // 2) if that session number exists, close out the old one
+ // 3) when USER_LOGIN is found, update session node
+ // 4) When USER_END is found update session node and close it out
+ // 5) When BOOT record found make new record and check for previous
+ // 6) If previous boot found, set status to crash and logout everyone
+ // 7) When SHUTDOWN found, close out reboot record
+
+ while (auparse_next_event(au) > 0) {
+ // We will take advantage of the fact that all events
+ // of interest are one record long
+ int type = auparse_get_type(au);
+ if (type < 0)
+ continue;
+ switch (type)
+ {
+ case AUDIT_LOGIN:
+ create_new_session(au);
+ extract_record(au);
+ break;
+ case AUDIT_USER_LOGIN:
+ update_session_login(au);
+ extract_record(au);
+ break;
+ case AUDIT_USER_END:
+ update_session_logout(au);
+ extract_record(au);
+ break;
+ case AUDIT_SYSTEM_BOOT:
+ process_bootup(au);
+ extract_record(au);
+ break;
+ case AUDIT_SYSTEM_SHUTDOWN:
+ process_shutdown(au);
+ extract_record(au);
+ break;
+ case AUDIT_DAEMON_START:
+ process_kernel(au);
+ extract_record(au);
+ break;
+ }
+ }
+ auparse_destroy(au);
+
+ // Now output the leftovers
+ list_first(&l);
+ do {
+ lnode *cur = list_get_cur(&l);
+ report_session(cur);
+ } while (list_next(&l));
+
+ free(kernel);
+ list_clear(&l);
+ if (f)
+ fclose(f);
+ return 0;
+
+error_exit_1:
+ list_clear(&l);
+ if (f)
+ fclose(f);
+ return 1;
+}
+