X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/be4f86de25d315f3beaf1dc21f87c61dfae1c6a7..39baeaa47a957eefe6eb00296ff8b753e3bf4868:/unix/pty.c diff --git a/unix/pty.c b/unix/pty.c index 9774deaf..2a7abb68 100644 --- a/unix/pty.c +++ b/unix/pty.c @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -23,9 +26,41 @@ #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 + +/* + * Set up a default for vaguely sane systems. The idea is that if + * OMIT_UTMP is not defined, then at least one of the symbols which + * enable particular forms of utmp processing should be, if only so + * that a link error can warn you that you should have defined + * OMIT_UTMP if you didn't want any. Currently HAVE_PUTUTLINE is + * the only such symbol. + */ +#ifndef OMIT_UTMP +#if !defined HAVE_PUTUTLINE +#define HAVE_PUTUTLINE +#endif +#endif + int pty_master_fd; +static int pty_stamped_utmp = 0; 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 +70,91 @@ 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; + FILE *wtmp; + + if (!cfg.stamp_utmp) + return; + + pw = getpwuid(getuid()); + location = get_x_display(); + 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 + + pty_stamped_utmp = 1; + +#endif +} + +static void cleanup_utmp(void) +{ +#ifndef OMIT_UTMP + FILE *wtmp; + + if (!cfg.stamp_utmp || !pty_stamped_utmp) + return; + + 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 + + pty_stamped_utmp = 0; /* ensure we never double-cleanup */ +#endif +} + static void sigchld_handler(int signum) { pid_t pid; @@ -44,6 +164,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 +236,64 @@ static char *pty_init(char *host, int port, char **realhost, int nodelay) #endif /* + * Set the backspace character to be whichever of ^H and ^? is + * specified by bksp_is_delete. + */ + { + struct termios attrs; + tcgetattr(pty_master_fd, &attrs); + attrs.c_cc[VERASE] = cfg.bksp_is_delete ? '\177' : '\010'; + tcsetattr(pty_master_fd, TCSANOW, &attrs); + } + + /* + * 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(); @@ -165,8 +351,19 @@ static char *pty_init(char *host, int port, char **realhost, int nodelay) } if (pty_argv) execvp(pty_argv[0], pty_argv); - else - execl(getenv("SHELL"), getenv("SHELL"), NULL); + else { + char *shell = getenv("SHELL"); + char *shellname; + if (cfg.login_shell) { + char *p = strrchr(shell, '/'); + shellname = smalloc(2+strlen(shell)); + p = p ? p+1 : shell; + sprintf(shellname, "-%s", p); + } else + shellname = shell; + execl(getenv("SHELL"), shellname, NULL); + } + /* * If we're here, exec has gone badly foom. */ @@ -216,6 +413,8 @@ static void pty_size(void) size.ws_row = (unsigned short)rows; size.ws_col = (unsigned short)cols; + size.ws_xpixel = (unsigned short) cols * font_dimension(0); + size.ws_ypixel = (unsigned short) rows * font_dimension(1); ioctl(pty_master_fd, TIOCSWINSZ, (void *)&size); return; }