Support for utmp, wtmp and lastlog. Probably not terribly portable
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 15 Oct 2002 12:29:52 +0000 (12:29 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 15 Oct 2002 12:29:52 +0000 (12:29 +0000)
as yet, but seems to work plausibly on Linux.

git-svn-id: svn://svn.tartarus.org/sgt/putty@2058 cda61777-01e9-0310-a592-d414129be87e

unix/pterm.c
unix/pty.c
unix/unix.h

index 58f9846..0a72d3b 100644 (file)
@@ -1275,6 +1275,11 @@ void modalfatalbox(char *p, ...)
     exit(1);
 }
 
+char *get_x_display(void)
+{
+    return gdk_get_display();
+}
+
 int main(int argc, char **argv)
 {
     extern int pty_master_fd;         /* declared in pty.c */
@@ -1338,9 +1343,6 @@ int main(int argc, char **argv)
 
     init_ucs();
 
-    back = &pty_backend;
-    back->init(NULL, 0, NULL, 0);
-
     inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
     if (cfg.wintitle[0])
@@ -1404,7 +1406,6 @@ int main(int argc, char **argv)
     gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
                       GTK_SIGNAL_FUNC(scrollbar_moved), inst);
     gtk_timeout_add(20, timer_func, inst);
-    gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
     gtk_widget_add_events(GTK_WIDGET(inst->area),
                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
@@ -1422,6 +1423,11 @@ int main(int argc, char **argv)
     inst->currcursor = inst->textcursor;
     show_mouseptr(1);
 
+    back = &pty_backend;
+    back->init(NULL, 0, NULL, 0);
+
+    gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
+
     term_init();
     term_size(24, 80, 2000);
 
index 9774dea..8edbe48 100644 (file)
@@ -10,6 +10,9 @@
 #include <fcntl.h>
 #include <termios.h>
 #include <grp.h>
+#include <utmp.h>
+#include <pwd.h>
+#include <time.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/ioctl.h>
 #define TRUE 1
 #endif
 
+#ifndef UTMP_FILE
+#define UTMP_FILE "/var/run/utmp"
+#endif
+#ifndef WTMP_FILE
+#define WTMP_FILE "/var/log/wtmp"
+#endif
+#ifndef LASTLOG_FILE
+#ifdef _PATH_LASTLOG
+#define LASTLOG_FILE _PATH_LASTLOG
+#else
+#define LASTLOG_FILE "/var/log/lastlog"
+#endif
+#endif
+
 int pty_master_fd;
 static int pty_child_pid;
 static sig_atomic_t pty_child_dead;
+#ifndef OMIT_UTMP
+static struct utmp utmp_entry;
+#endif
 char **pty_argv;
 
 int pty_child_is_dead(void)
@@ -35,6 +55,81 @@ int pty_child_is_dead(void)
 
 static void pty_size(void);
 
+static void setup_utmp(char *ttyname)
+{
+#ifndef OMIT_UTMP
+#ifdef HAVE_LASTLOG
+    struct lastlog lastlog_entry;
+    FILE *lastlog;
+#endif
+    struct passwd *pw;
+    char *location = get_x_display();
+    FILE *wtmp;
+
+    pw = getpwuid(getuid());
+    memset(&utmp_entry, 0, sizeof(utmp_entry));
+    utmp_entry.ut_type = USER_PROCESS;
+    utmp_entry.ut_pid = getpid();
+    strncpy(utmp_entry.ut_line, ttyname+5, lenof(utmp_entry.ut_line));
+    strncpy(utmp_entry.ut_id, ttyname+8, lenof(utmp_entry.ut_id));
+    strncpy(utmp_entry.ut_user, pw->pw_name, lenof(utmp_entry.ut_user));
+    strncpy(utmp_entry.ut_host, location, lenof(utmp_entry.ut_host));
+    time(&utmp_entry.ut_time);
+
+#if defined HAVE_PUTUTLINE
+    utmpname(UTMP_FILE);
+    setutent();
+    pututline(&utmp_entry);
+    endutent();
+#endif
+
+    if ((wtmp = fopen(WTMP_FILE, "a")) != NULL) {
+       fwrite(&utmp_entry, 1, sizeof(utmp_entry), wtmp);
+       fclose(wtmp);
+    }
+
+#ifdef HAVE_LASTLOG
+    memset(&lastlog_entry, 0, sizeof(lastlog_entry));
+    strncpy(lastlog_entry.ll_line, ttyname+5, lenof(lastlog_entry.ll_line));
+    strncpy(lastlog_entry.ll_host, location, lenof(lastlog_entry.ll_host));
+    time(&lastlog_entry.ll_time);
+    if ((lastlog = fopen(LASTLOG_FILE, "r+")) != NULL) {
+       fseek(lastlog, sizeof(lastlog_entry) * getuid(), SEEK_SET);
+       fwrite(&lastlog_entry, 1, sizeof(lastlog_entry), lastlog);
+       fclose(lastlog);
+    }
+#endif
+
+#endif
+}
+
+static void cleanup_utmp(void)
+{
+#ifndef OMIT_UTMP
+    FILE *wtmp;
+
+    utmp_entry.ut_type = DEAD_PROCESS;
+    memset(utmp_entry.ut_user, 0, lenof(utmp_entry.ut_user));
+    time(&utmp_entry.ut_time);
+
+    if ((wtmp = fopen(WTMP_FILE, "a")) != NULL) {
+       fwrite(&utmp_entry, 1, sizeof(utmp_entry), wtmp);
+       fclose(wtmp);
+    }
+
+    memset(utmp_entry.ut_line, 0, lenof(utmp_entry.ut_line));
+    utmp_entry.ut_time = 0;
+
+#if defined HAVE_PUTUTLINE
+    utmpname(UTMP_FILE);
+    setutent();
+    pututline(&utmp_entry);
+    endutent();
+#endif
+
+#endif
+}
+
 static void sigchld_handler(int signum)
 {
     pid_t pid;
@@ -44,6 +139,14 @@ static void sigchld_handler(int signum)
        pty_child_dead = TRUE;  
 }
 
+static void fatal_sig_handler(int signum)
+{
+    signal(signum, SIG_DFL);
+    cleanup_utmp();
+    setuid(getuid());
+    raise(signum);
+}
+
 /*
  * Called to set up the pty.
  * 
@@ -108,6 +211,53 @@ static char *pty_init(char *host, int port, char **realhost, int nodelay)
 #endif
 
     /*
+     * Trap as many fatal signals as we can in the hope of having
+     * the best chance to clean up utmp before termination.
+     */
+    signal(SIGHUP, fatal_sig_handler);
+    signal(SIGINT, fatal_sig_handler);
+    signal(SIGQUIT, fatal_sig_handler);
+    signal(SIGILL, fatal_sig_handler);
+    signal(SIGABRT, fatal_sig_handler);
+    signal(SIGFPE, fatal_sig_handler);
+    signal(SIGPIPE, fatal_sig_handler);
+    signal(SIGALRM, fatal_sig_handler);
+    signal(SIGTERM, fatal_sig_handler);
+    signal(SIGSEGV, fatal_sig_handler);
+    signal(SIGUSR1, fatal_sig_handler);
+    signal(SIGUSR2, fatal_sig_handler);
+#ifdef SIGBUS
+    signal(SIGBUS, fatal_sig_handler);
+#endif
+#ifdef SIGPOLL
+    signal(SIGPOLL, fatal_sig_handler);
+#endif
+#ifdef SIGPROF
+    signal(SIGPROF, fatal_sig_handler);
+#endif
+#ifdef SIGSYS
+    signal(SIGSYS, fatal_sig_handler);
+#endif
+#ifdef SIGTRAP
+    signal(SIGTRAP, fatal_sig_handler);
+#endif
+#ifdef SIGVTALRM
+    signal(SIGVTALRM, fatal_sig_handler);
+#endif
+#ifdef SIGXCPU
+    signal(SIGXCPU, fatal_sig_handler);
+#endif
+#ifdef SIGXFSZ
+    signal(SIGXFSZ, fatal_sig_handler);
+#endif
+#ifdef SIGIO
+    signal(SIGIO, fatal_sig_handler);
+#endif
+    /* Also clean up utmp on normal exit. */
+    atexit(cleanup_utmp);
+    setup_utmp(name);
+
+    /*
      * Fork and execute the command.
      */
     pid = fork();
index d4c3328..8e645a2 100644 (file)
@@ -37,6 +37,8 @@ int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen,
             char *mbstr, int mblen, char *defchr, int *defused);
 void init_ucs(void);
 
+char *get_x_display(void);
+
 #define DEFAULT_CODEPAGE 0            /* FIXME: no idea how to do this */
 
 #endif