--- pty.c.orig Thu Dec 16 11:04:19 2004 +++ pty.c Thu Dec 16 11:24:21 2004 @@ -14,8 +14,11 @@ #define _XOPEN_SOURCE #define _XOPEN_SOURCE_EXTENDED #define _GNU_SOURCE +#ifndef __FreeBSD__ #include +#endif +#include #include #include #include @@ -32,6 +35,10 @@ #include #include +#ifdef __FreeBSD__ +#include +#endif + #include "putty.h" #ifndef FALSE @@ -68,6 +75,12 @@ #define HAVE_PUTUTLINE #endif #endif +#ifdef BSD +#define RESTORE_PTY_PERM +#endif +#if !defined(OMIT_UTMP) || defined(RESTORE_PTY_PERM) +#define FORK_HELPER +#endif static Config pty_cfg; static int pty_master_fd; @@ -76,7 +89,7 @@ static int pty_signal_pipe[2]; static int pty_stamped_utmp = 0; static int pty_child_pid; -static int pty_utmp_helper_pid, pty_utmp_helper_pipe; +static int pty_utmp_helper_pid, pty_utmp_helper_pipe = -1; static int pty_term_width, pty_term_height; static int pty_child_dead, pty_finished; static int pty_exit_code; @@ -174,6 +187,16 @@ #endif } +static void restore_pty_perm(void) +{ +#ifdef RESTORE_PTY_PERM + if (pty_name[0] == '\0') + return; + chown(pty_name, 0, 0); + chmod(pty_name, 0666); +#endif +} + static void sigchld_handler(int signum) { write(pty_signal_pipe[1], "x", 1); @@ -183,6 +206,7 @@ { putty_signal(signum, SIG_DFL); cleanup_utmp(); + restore_pty_perm(); setuid(getuid()); raise(signum); } @@ -190,8 +214,13 @@ static void pty_open_master(void) { #ifdef BSD_PTYS +#ifdef BSD + const char chars1[] = "pqrsPQRS"; + const char chars2[] = "0123456789abcdefghijklmnopqrstuv"; +#else const char chars1[] = "pqrstuvwxyz"; const char chars2[] = "0123456789abcdef"; +#endif const char *p1, *p2; char master_name[20]; struct group *gp; @@ -201,6 +230,7 @@ sprintf(master_name, "/dev/pty%c%c", *p1, *p2); pty_master_fd = open(master_name, O_RDWR); if (pty_master_fd >= 0) { + master_name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */ if (geteuid() == 0 || access(master_name, R_OK | W_OK) == 0) goto got_one; @@ -214,7 +244,6 @@ got_one: strcpy(pty_name, master_name); - pty_name[5] = 't'; /* /dev/ptyXX -> /dev/ttyXX */ /* We need to chown/chmod the /dev/ttyXX device. */ gp = getgrnam("tty"); @@ -270,17 +299,19 @@ pty_open_master(); } -#ifndef OMIT_UTMP +#ifdef FORK_HELPER /* * Fork off the utmp helper. */ if (pipe(pipefd) < 0) { perror("pterm: pipe"); + restore_pty_perm(); exit(1); } pid = fork(); if (pid < 0) { perror("pterm: fork"); + restore_pty_perm(); exit(1); } else if (pid == 0) { char display[128], buffer[128]; @@ -288,6 +319,52 @@ close(pipefd[1]); /* + * Trap as many fatal signals as we can in the + * hope of having the best possible chance to + * clean up utmp and restore the pty permissions + * before termination. We are unfortunately + * unprotected against SIGKILL, but that's life. + */ + putty_signal(SIGHUP, fatal_sig_handler); + putty_signal(SIGINT, fatal_sig_handler); + putty_signal(SIGQUIT, fatal_sig_handler); + putty_signal(SIGILL, fatal_sig_handler); + putty_signal(SIGABRT, fatal_sig_handler); + putty_signal(SIGFPE, fatal_sig_handler); + putty_signal(SIGPIPE, fatal_sig_handler); + putty_signal(SIGALRM, fatal_sig_handler); + putty_signal(SIGTERM, fatal_sig_handler); + putty_signal(SIGSEGV, fatal_sig_handler); + putty_signal(SIGUSR1, fatal_sig_handler); + putty_signal(SIGUSR2, fatal_sig_handler); +#ifdef SIGBUS + putty_signal(SIGBUS, fatal_sig_handler); +#endif +#ifdef SIGPOLL + putty_signal(SIGPOLL, fatal_sig_handler); +#endif +#ifdef SIGPROF + putty_signal(SIGPROF, fatal_sig_handler); +#endif +#ifdef SIGSYS + putty_signal(SIGSYS, fatal_sig_handler); +#endif +#ifdef SIGTRAP + putty_signal(SIGTRAP, fatal_sig_handler); +#endif +#ifdef SIGVTALRM + putty_signal(SIGVTALRM, fatal_sig_handler); +#endif +#ifdef SIGXCPU + putty_signal(SIGXCPU, fatal_sig_handler); +#endif +#ifdef SIGXFSZ + putty_signal(SIGXFSZ, fatal_sig_handler); +#endif +#ifdef SIGIO + putty_signal(SIGIO, fatal_sig_handler); +#endif + /* * Now sit here until we receive a display name from the * other end of the pipe, and then stamp utmp. Unstamp utmp * again, and exit, when the pipe closes. @@ -299,6 +376,7 @@ ret = read(pipefd[0], buffer, lenof(buffer)); if (ret <= 0) { cleanup_utmp(); + restore_pty_perm(); _exit(0); } else if (!pty_stamped_utmp) { if (dlen < lenof(display)) @@ -310,52 +388,6 @@ * it, and stamp utmp. */ display[lenof(display)-1] = '\0'; - /* - * Trap as many fatal signals as we can in the - * hope of having the best possible chance to - * clean up utmp before termination. We are - * unfortunately unprotected against SIGKILL, - * but that's life. - */ - putty_signal(SIGHUP, fatal_sig_handler); - putty_signal(SIGINT, fatal_sig_handler); - putty_signal(SIGQUIT, fatal_sig_handler); - putty_signal(SIGILL, fatal_sig_handler); - putty_signal(SIGABRT, fatal_sig_handler); - putty_signal(SIGFPE, fatal_sig_handler); - putty_signal(SIGPIPE, fatal_sig_handler); - putty_signal(SIGALRM, fatal_sig_handler); - putty_signal(SIGTERM, fatal_sig_handler); - putty_signal(SIGSEGV, fatal_sig_handler); - putty_signal(SIGUSR1, fatal_sig_handler); - putty_signal(SIGUSR2, fatal_sig_handler); -#ifdef SIGBUS - putty_signal(SIGBUS, fatal_sig_handler); -#endif -#ifdef SIGPOLL - putty_signal(SIGPOLL, fatal_sig_handler); -#endif -#ifdef SIGPROF - putty_signal(SIGPROF, fatal_sig_handler); -#endif -#ifdef SIGSYS - putty_signal(SIGSYS, fatal_sig_handler); -#endif -#ifdef SIGTRAP - putty_signal(SIGTRAP, fatal_sig_handler); -#endif -#ifdef SIGVTALRM - putty_signal(SIGVTALRM, fatal_sig_handler); -#endif -#ifdef SIGXCPU - putty_signal(SIGXCPU, fatal_sig_handler); -#endif -#ifdef SIGXFSZ - putty_signal(SIGXFSZ, fatal_sig_handler); -#endif -#ifdef SIGIO - putty_signal(SIGIO, fatal_sig_handler); -#endif setup_utmp(pty_name, display); } } @@ -510,21 +542,15 @@ pty_open_master(); /* - * 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); - } - - /* * Stamp utmp (that is, tell the utmp helper process to do so), * or not. */ +#ifdef FORK_HELPER +#ifndef RESTORE_PTY_PERM if (!cfg->stamp_utmp) { +#else + if (0) { +#endif close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; } else { @@ -541,10 +567,28 @@ pos += ret; } } +#endif windowid = get_windowid(pty_frontend); /* + * Open the slave in the parent process, that way it is open before we + * attempt to tcsetattr() or TIOCSWINSZ. FreeBSD requires this. + */ + slavefd = open(pty_name, O_RDWR); + + /* + * 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); + } + + /* * Fork and execute the command. */ pid = fork(); @@ -559,7 +603,6 @@ * We are the child. */ - slavefd = open(pty_name, O_RDWR); if (slavefd < 0) { perror("slave pty: open"); _exit(1); @@ -574,9 +617,9 @@ ioctl(slavefd, TIOCSCTTY, 1); pgrp = getpid(); tcsetpgrp(slavefd, pgrp); - setpgrp(); + setpgrp( pgrp, -1 ); close(open(pty_name, O_WRONLY, 0)); - setpgrp(); + setpgrp( pgrp, -1 ); /* Close everything _else_, for tidiness. */ for (i = 3; i < 1024; i++) close(i); @@ -641,6 +684,7 @@ perror("exec"); _exit(127); } else { + close(slavefd); pty_child_pid = pid; pty_child_dead = FALSE; pty_finished = FALSE;