summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--configure.ac8
-rw-r--r--login-utils/Makemodule.am7
-rw-r--r--login-utils/utmpdump.166
-rw-r--r--login-utils/utmpdump.c316
5 files changed, 398 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index c37ba3069..76da76351 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,6 +158,7 @@ tunelp
ul
umount
unshare
+utmpdump
uuidd
uuidgen
vipw
diff --git a/configure.ac b/configure.ac
index 37d5fa4c3..198366a3d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -998,6 +998,14 @@ UL_BUILD_INIT([last])
AM_CONDITIONAL(BUILD_LAST, test "x$build_last" = xyes)
+AC_ARG_ENABLE([utmpdump],
+ AS_HELP_STRING([--disable-utmpdump], [build utmpdump]),
+ [], enable_utmpdump=yes
+)
+UL_BUILD_INIT([utmpdump])
+AM_CONDITIONAL(BUILD_UTMPDUMP, test "x$build_utmpdump" = xyes)
+
+
AC_ARG_ENABLE([line],
AS_HELP_STRING([--enable-line], [build line]),
[], enable_line=no
diff --git a/login-utils/Makemodule.am b/login-utils/Makemodule.am
index 42507e46c..71331f9c2 100644
--- a/login-utils/Makemodule.am
+++ b/login-utils/Makemodule.am
@@ -37,6 +37,13 @@ endif
endif # BUILD_LOGIN
+if BUILD_UTMPDUMP
+usrbin_exec_PROGRAMS += utmpdump
+dist_man_MANS += login-utils/utmpdump.1
+utmpdump_SOURCES = login-utils/utmpdump.c
+endif
+
+
if BUILD_CHFN_CHSH
usrbin_exec_PROGRAMS += chfn chsh
dist_man_MANS += \
diff --git a/login-utils/utmpdump.1 b/login-utils/utmpdump.1
new file mode 100644
index 000000000..1b5730d92
--- /dev/null
+++ b/login-utils/utmpdump.1
@@ -0,0 +1,66 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 2010 Michael Krapp
+.\"
+.\" This program is free software; you can redistribute it and/or modify
+.\" it under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation; either version 2 of the License, 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; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH UTMPDUMP 1 "Februar 8, 2010" "" "Linux System Administrator's Manual"
+.SH NAME
+utmpdump \- dump UTMP and WTMP files in raw format
+.SH SYNOPSIS
+.B utmpdump
+.RB [ \-froh ]
+.I filename
+.SH DESCRIPTION
+\fButmpdump\fP is a simple program to dump UTMP and WTMP files
+in raw format, so they can be examined.
+.SH OPTIONS
+.IP \fB\-f\fP
+output appended data as the file grows.
+.IP "\fB\-r\fP"
+reverse. Write back edited login information into utmp or wtmp files.
+.IP \fB\-o\fP
+use old libc5 format.
+.IP \fB\-h\fP
+usage information.
+.PP
+utmpdump can be useful in cases of corrupted utmp or wtmp entries.
+It can dump out utmp/wtmp to an ASCII file, then that file can
+be edited to remove bogus entries and reintegrated, using
+.PP
+.sp 1
+.in +1c
+.nf
+\fButmpdump -r < ascii file > wtmp\fP
+.fi
+.in -1c
+.sp 1
+but be warned as
+.B utmpdump
+was written for debugging purpose only.
+.SH BUGS
+You may
+.B not
+use the option \fB\-r\fP as the format for the
+utmp/wtmp files strongly depends on the
+input format. This tool was
+.B not
+written for normal use but for debugging.
+.SH AUTHOR
+Michael Krapp
+.SH "SEE ALSO"
+.BR last (1),
+.BR w (1),
+.BR who (1),
+.BR utmp (5),
diff --git a/login-utils/utmpdump.c b/login-utils/utmpdump.c
new file mode 100644
index 000000000..4db978ebf
--- /dev/null
+++ b/login-utils/utmpdump.c
@@ -0,0 +1,316 @@
+/*
+ * utmpdump Simple program to dump UTMP and WTMP files in
+ * raw format, so they can be examined.
+ *
+ * Author: Miquel van Smoorenburg, <miquels@cistron.nl>
+ * Danek Duvall <duvall@alumni.princeton.edu>
+ *
+ * Version: @(#)utmpdump 2.79 12-Sep-2000
+ *
+ * This file is part of the sysvinit suite,
+ * Copyright (C) 1991-2000 Miquel van Smoorenburg.
+ *
+ * Additional Copyright on this file 1998 Danek Duvall.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define OLD_LINESIZE 12
+#define OLD_NAMESIZE 8
+#define OLD_HOSTSIZE 16
+
+struct oldutmp {
+ short ut_type;
+ int ut_pid;
+ char ut_line[OLD_LINESIZE];
+ char ut_id[4];
+ long ut_oldtime;
+ char ut_user[OLD_NAMESIZE];
+ char ut_host[OLD_HOSTSIZE];
+ long ut_oldaddr;
+};
+
+struct utmp
+oldtonew(struct oldutmp src)
+{
+ struct utmp dest;
+
+ memset(&dest, 0, sizeof dest);
+ dest.ut_type = src.ut_type;
+ dest.ut_pid = src.ut_pid;
+ dest.ut_time = src.ut_oldtime;
+ dest.ut_addr = src.ut_oldaddr;
+ strncpy(dest.ut_id, src.ut_id, 4);
+ strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
+ strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
+ strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
+
+ return dest;
+}
+
+struct oldutmp
+newtoold(struct utmp src)
+{
+ struct oldutmp dest;
+
+ memset(&dest, 0, sizeof dest);
+ dest.ut_type = src.ut_type;
+ dest.ut_pid = src.ut_pid;
+ dest.ut_oldtime = src.ut_time;
+ dest.ut_oldaddr = src.ut_addr;
+ strncpy(dest.ut_id, src.ut_id, 4);
+ strncpy(dest.ut_line, src.ut_line, OLD_LINESIZE);
+ strncpy(dest.ut_user, src.ut_user, OLD_NAMESIZE);
+ strncpy(dest.ut_host, src.ut_host, OLD_HOSTSIZE);
+
+ return dest;
+}
+
+char *
+timetostr(const time_t time)
+{
+ static char s[29]; /* [Sun Sep 01 00:00:00 1998 PST] */
+
+ if (time != 0)
+ strftime(s, 29, "%a %b %d %T %Y %Z", localtime(&time));
+ else
+ s[0] = '\0';
+
+ return s;
+}
+
+time_t
+strtotime(const char *s_time)
+{
+ struct tm tm;
+
+ memset(&tm, '\0', sizeof(struct tm));
+
+ if (s_time[0] == ' ' || s_time[0] == '\0')
+ return (time_t)0;
+
+ strptime(s_time, "%a %b %d %T %Y", &tm);
+
+ /* Cheesy way of checking for DST */
+ if (s_time[26] == 'D')
+ tm.tm_isdst = 1;
+
+ return mktime(&tm);
+}
+
+#define cleanse(x) xcleanse(x, sizeof(x))
+void
+xcleanse(char *s, int len)
+{
+ for ( ; *s && len-- > 0; s++)
+ if (!isprint(*s) || *s == '[' || *s == ']')
+ *s = '?';
+}
+
+void
+unspace(char *s, int len)
+{
+ while (*s && *s != ' ' && len--)
+ ++s;
+
+ if (len > 0)
+ *s = '\0';
+}
+
+void
+print_utline(struct utmp ut)
+{
+ char *addr_string, *time_string;
+ struct in_addr in;
+
+ in.s_addr = ut.ut_addr;
+ addr_string = inet_ntoa(in);
+ time_string = timetostr(ut.ut_time);
+ cleanse(ut.ut_id);
+ cleanse(ut.ut_user);
+ cleanse(ut.ut_line);
+ cleanse(ut.ut_host);
+
+ /* pid id user line host addr time */
+ printf("[%d] [%05d] [%-4.4s] [%-*.*s] [%-*.*s] [%-*.*s] [%-15.15s] [%-28.28s]\n",
+ ut.ut_type, ut.ut_pid, ut.ut_id, 8, UT_NAMESIZE, ut.ut_user,
+ 12, UT_LINESIZE, ut.ut_line, 20, UT_HOSTSIZE, ut.ut_host,
+ addr_string, time_string);
+}
+
+void
+dump(FILE *fp, int forever, int oldfmt)
+{
+ struct utmp ut;
+ struct oldutmp uto;
+
+ if (forever)
+ fseek(fp, -10 * (oldfmt ? sizeof uto : sizeof ut), SEEK_END);
+
+ do {
+ if (oldfmt)
+ while (fread(&uto, sizeof uto, 1, fp) == 1)
+ print_utline(oldtonew(uto));
+ else
+ while (fread(&ut, sizeof ut, 1, fp) == 1)
+ print_utline(ut);
+ if (forever) sleep(1);
+ } while (forever);
+}
+
+/* This function won't work properly if there's a ']' or a ' ' in the real
+ * token. Thankfully, this should never happen. */
+int
+gettok(char *line, char *dest, int size, int eatspace)
+{
+ int bpos, epos, eaten;
+ char *t;
+
+ bpos = strchr(line, '[') - line;
+ if (bpos < 0) {
+ fprintf(stderr, "Extraneous newline in file. Exiting.");
+ exit(1);
+ }
+ line += 1 + bpos;
+
+ epos = strchr(line, ']') - line;
+ if (epos < 0) {
+ fprintf(stderr, "Extraneous newline in file. Exiting.");
+ exit(1);
+ }
+ line[epos] = '\0';
+
+ eaten = bpos + epos + 1;
+
+ if (eatspace)
+ if ((t = strchr(line, ' ')))
+ *t = 0;
+
+ strncpy(dest, line, size);
+
+ return eaten + 1;
+}
+
+void
+# ifdef __GNUC__
+undump(FILE *fp, int forever __attribute__((unused)), int oldfmt)
+#else
+undump(FILE *fp, int forever, int oldfmt)
+#endif
+{
+ struct utmp ut;
+ struct oldutmp uto;
+ char s_addr[16], s_time[29], *linestart, *line;
+ int count = 0;
+
+ line = linestart = malloc(1024 * sizeof *linestart);
+ s_addr[15] = 0;
+ s_time[28] = 0;
+
+ while(fgets(linestart, 1023, fp))
+ {
+ line = linestart;
+ memset(&ut, '\0', sizeof(ut));
+ sscanf(line, "[%hd] [%d] [%4c] ", &ut.ut_type, &ut.ut_pid, ut.ut_id);
+
+ line += 19;
+ line += gettok(line, ut.ut_user, sizeof(ut.ut_user), 1);
+ line += gettok(line, ut.ut_line, sizeof(ut.ut_line), 1);
+ line += gettok(line, ut.ut_host, sizeof(ut.ut_host), 1);
+ line += gettok(line, s_addr, sizeof(s_addr)-1, 1);
+ line += gettok(line, s_time, sizeof(s_time)-1, 0);
+
+ ut.ut_addr = inet_addr(s_addr);
+ ut.ut_time = strtotime(s_time);
+
+ if (oldfmt) {
+ uto = newtoold(ut);
+ fwrite(&uto, sizeof(uto), 1, stdout);
+ } else
+ fwrite(&ut, sizeof(ut), 1, stdout);
+
+ ++count;
+ }
+
+ free(linestart);
+}
+
+void
+usage(int result)
+{
+ printf("Usage: utmpdump [ -froh ] [ filename ]\n");
+ exit(result);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ FILE *fp;
+ int reverse = 0, forever = 0, oldfmt = 0;
+
+ while ((c = getopt(argc, argv, "froh")) != EOF) {
+ switch (c) {
+ case 'r':
+ reverse = 1;
+ break;
+
+ case 'f':
+ forever = 1;
+ break;
+
+ case 'o':
+ oldfmt = 1;
+ break;
+
+ case 'h':
+ usage(0);
+ break;
+
+ default:
+ usage(1);
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Utmp %sdump of %s\n", reverse ? "un" : "", argv[optind]);
+ if ((fp = fopen(argv[optind], "r")) == NULL) {
+ perror("Unable to open file");
+ exit(1);
+ }
+ }
+ else {
+ fprintf(stderr, "Utmp %sdump of stdin\n", reverse ? "un" : "");
+ fp = stdin;
+ }
+
+ if (reverse)
+ undump(fp, forever, oldfmt);
+ else
+ dump(fp, forever, oldfmt);
+
+ fclose(fp);
+
+ return 0;
+}