/* * aulastlog.c - A lastlog program based on audit logs * 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 <stdio.h> #include <locale.h> #include <string.h> #include <errno.h> #include <pwd.h> #include "auparse.h" #include "aulastlog-llist.h" void usage(void) { fprintf(stderr, "usage: aulastlog [--user name]\n"); } int main(int argc, char *argv[]) { int i; char *user = NULL; struct passwd *p; auparse_state_t *au; llist l; for (i=1; i<argc; i++) { if ((strcmp(argv[i], "--user") == 0) || (strcmp(argv[i], "-u") == 0)) { i++; if (i<argc) user = argv[i]; else { usage(); return 1; } } else { usage(); return 1; } } setlocale (LC_ALL, ""); list_create(&l); // Stuff linked lists with all users while ((p = getpwent()) != NULL) { lnode n; n.sec = 0; n.uid = p->pw_uid; n.name = p->pw_name; n.host = NULL; n.term = NULL; if (user == NULL) list_append(&l, &n); else if (strcmp(user, p->pw_name) == 0) list_append(&l, &n); } endpwent(); if (user && list_get_cnt(&l) == 0) { printf("Unknown User: %s\n", user); return 1; } // Search for successful user logins au = auparse_init(AUSOURCE_LOGS, NULL); if (au == NULL) { printf("Error - %s\n", strerror(errno)); goto error_exit_1; } if (ausearch_add_item(au, "type", "=", "USER_LOGIN", AUSEARCH_RULE_CLEAR)){ printf("ausearch_add_item error - %s\n", strerror(errno)); goto error_exit_2; } if (ausearch_add_item(au, "res", "=", "success", AUSEARCH_RULE_AND)){ printf("ausearch_add_item error - %s\n", strerror(errno)); goto error_exit_2; } if (ausearch_set_stop(au, AUSEARCH_STOP_RECORD)){ printf("ausearch_set_stop error - %s\n", strerror(errno)); goto error_exit_2; } // Now scan the logs and append events while (ausearch_next_event(au) > 0) { const au_event_t *e = auparse_get_timestamp(au); if (auparse_find_field(au, "auid")) { uid_t u = auparse_get_field_int(au); list_first(&l); if (list_find_uid(&l, u)) { const char *str; list_update_login(&l, e->sec); str = auparse_find_field(au, "hostname"); if (str) list_update_host(&l, str); str = auparse_find_field(au, "terminal"); if (str) list_update_term(&l, str); } } auparse_next_event(au); } auparse_destroy(au); // Now output the report printf( "Username Port From" " Latest\n"); list_first(&l); do { char tmp[48]; const char *c, *h, *t; lnode *cur = list_get_cur(&l); if (cur->sec == 0) c = "**Never logged in**"; else { struct tm *btm; btm = localtime(&cur->sec); strftime(tmp, sizeof(tmp), "%x %T", btm); c = tmp; } h = cur->host; if (h == NULL) h = ""; t = cur->term; if (t == NULL) t = ""; printf("%-16s %-12.12s %-26.26s %s\n", cur->name, t, h, c); } while (list_next(&l)); list_clear(&l); return 0; error_exit_2: auparse_destroy(au); error_exit_1: list_clear(&l); return 1; }