1d4af9e69SDag-Erling Smørgrav /* $OpenBSD: sshpty.c,v 1.28 2007/09/11 23:49:09 stevesk Exp $ */ 21e8db6e2SBrian Feldman /* 31e8db6e2SBrian Feldman * Author: Tatu Ylonen <ylo@cs.hut.fi> 41e8db6e2SBrian Feldman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 51e8db6e2SBrian Feldman * All rights reserved 61e8db6e2SBrian Feldman * Allocating a pseudo-terminal, and making it the controlling tty. 71e8db6e2SBrian Feldman * 81e8db6e2SBrian Feldman * As far as I am concerned, the code I have written for this software 91e8db6e2SBrian Feldman * can be used freely for any purpose. Any derived versions of this 101e8db6e2SBrian Feldman * software must be clearly marked as such, and if the derived work is 111e8db6e2SBrian Feldman * incompatible with the protocol description in the RFC file, it must be 121e8db6e2SBrian Feldman * called by a name other than "ssh" or "Secure Shell". 131e8db6e2SBrian Feldman */ 141e8db6e2SBrian Feldman 151e8db6e2SBrian Feldman #include "includes.h" 161e8db6e2SBrian Feldman 17333ee039SDag-Erling Smørgrav #include <sys/types.h> 18333ee039SDag-Erling Smørgrav #include <sys/ioctl.h> 19333ee039SDag-Erling Smørgrav #include <sys/stat.h> 20333ee039SDag-Erling Smørgrav #include <signal.h> 21333ee039SDag-Erling Smørgrav 22333ee039SDag-Erling Smørgrav #include <errno.h> 23333ee039SDag-Erling Smørgrav #include <fcntl.h> 24333ee039SDag-Erling Smørgrav #include <grp.h> 25333ee039SDag-Erling Smørgrav #ifdef HAVE_PATHS_H 26333ee039SDag-Erling Smørgrav # include <paths.h> 27333ee039SDag-Erling Smørgrav #endif 28333ee039SDag-Erling Smørgrav #include <pwd.h> 29333ee039SDag-Erling Smørgrav #include <stdarg.h> 30333ee039SDag-Erling Smørgrav #include <string.h> 31333ee039SDag-Erling Smørgrav #include <termios.h> 32989dd127SDag-Erling Smørgrav #ifdef HAVE_UTIL_H 33989dd127SDag-Erling Smørgrav # include <util.h> 34333ee039SDag-Erling Smørgrav #endif 35333ee039SDag-Erling Smørgrav #include <unistd.h> 36989dd127SDag-Erling Smørgrav 371e8db6e2SBrian Feldman #include "sshpty.h" 381e8db6e2SBrian Feldman #include "log.h" 39989dd127SDag-Erling Smørgrav #include "misc.h" 401e8db6e2SBrian Feldman 41989dd127SDag-Erling Smørgrav #ifdef HAVE_PTY_H 42989dd127SDag-Erling Smørgrav # include <pty.h> 43989dd127SDag-Erling Smørgrav #endif 44989dd127SDag-Erling Smørgrav 451e8db6e2SBrian Feldman #ifndef O_NOCTTY 461e8db6e2SBrian Feldman #define O_NOCTTY 0 471e8db6e2SBrian Feldman #endif 481e8db6e2SBrian Feldman 49cce7d346SDag-Erling Smørgrav #ifdef __APPLE__ 50cce7d346SDag-Erling Smørgrav # include <AvailabilityMacros.h> 51cce7d346SDag-Erling Smørgrav # if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) 52cce7d346SDag-Erling Smørgrav # define __APPLE_PRIVPTY__ 53cce7d346SDag-Erling Smørgrav # endif 54cce7d346SDag-Erling Smørgrav #endif 55cce7d346SDag-Erling Smørgrav 561e8db6e2SBrian Feldman /* 571e8db6e2SBrian Feldman * Allocates and opens a pty. Returns 0 if no pty could be allocated, or 581e8db6e2SBrian Feldman * nonzero if a pty was successfully allocated. On success, open file 591e8db6e2SBrian Feldman * descriptors for the pty and tty sides and the name of the tty side are 601e8db6e2SBrian Feldman * returned (the buffer must be able to hold at least 64 characters). 611e8db6e2SBrian Feldman */ 621e8db6e2SBrian Feldman 631e8db6e2SBrian Feldman int 64333ee039SDag-Erling Smørgrav pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) 651e8db6e2SBrian Feldman { 661e8db6e2SBrian Feldman /* openpty(3) exists in OSF/1 and some other os'es */ 67989dd127SDag-Erling Smørgrav char *name; 681e8db6e2SBrian Feldman int i; 691e8db6e2SBrian Feldman 70989dd127SDag-Erling Smørgrav i = openpty(ptyfd, ttyfd, NULL, NULL, NULL); 711e8db6e2SBrian Feldman if (i < 0) { 721e8db6e2SBrian Feldman error("openpty: %.100s", strerror(errno)); 731e8db6e2SBrian Feldman return 0; 741e8db6e2SBrian Feldman } 75989dd127SDag-Erling Smørgrav name = ttyname(*ttyfd); 76989dd127SDag-Erling Smørgrav if (!name) 77989dd127SDag-Erling Smørgrav fatal("openpty returns device for which ttyname fails."); 78989dd127SDag-Erling Smørgrav 79989dd127SDag-Erling Smørgrav strlcpy(namebuf, name, namebuflen); /* possible truncation */ 801e8db6e2SBrian Feldman return 1; 811e8db6e2SBrian Feldman } 821e8db6e2SBrian Feldman 831e8db6e2SBrian Feldman /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */ 841e8db6e2SBrian Feldman 851e8db6e2SBrian Feldman void 8621e764dfSDag-Erling Smørgrav pty_release(const char *tty) 871e8db6e2SBrian Feldman { 88cce7d346SDag-Erling Smørgrav #ifndef __APPLE_PRIVPTY__ 8921e764dfSDag-Erling Smørgrav if (chown(tty, (uid_t) 0, (gid_t) 0) < 0) 9021e764dfSDag-Erling Smørgrav error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno)); 9121e764dfSDag-Erling Smørgrav if (chmod(tty, (mode_t) 0666) < 0) 9221e764dfSDag-Erling Smørgrav error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno)); 93cce7d346SDag-Erling Smørgrav #endif /* __APPLE_PRIVPTY__ */ 941e8db6e2SBrian Feldman } 951e8db6e2SBrian Feldman 96cf2b5f3bSDag-Erling Smørgrav /* Makes the tty the process's controlling tty and sets it to sane modes. */ 971e8db6e2SBrian Feldman 981e8db6e2SBrian Feldman void 9921e764dfSDag-Erling Smørgrav pty_make_controlling_tty(int *ttyfd, const char *tty) 1001e8db6e2SBrian Feldman { 1011e8db6e2SBrian Feldman int fd; 102989dd127SDag-Erling Smørgrav #ifdef USE_VHANGUP 103989dd127SDag-Erling Smørgrav void *old; 104989dd127SDag-Erling Smørgrav #endif /* USE_VHANGUP */ 105989dd127SDag-Erling Smørgrav 106f388f5efSDag-Erling Smørgrav #ifdef _UNICOS 107989dd127SDag-Erling Smørgrav if (setsid() < 0) 108989dd127SDag-Erling Smørgrav error("setsid: %.100s", strerror(errno)); 109989dd127SDag-Erling Smørgrav 11021e764dfSDag-Erling Smørgrav fd = open(tty, O_RDWR|O_NOCTTY); 111989dd127SDag-Erling Smørgrav if (fd != -1) { 112cf2b5f3bSDag-Erling Smørgrav signal(SIGHUP, SIG_IGN); 113989dd127SDag-Erling Smørgrav ioctl(fd, TCVHUP, (char *)NULL); 114cf2b5f3bSDag-Erling Smørgrav signal(SIGHUP, SIG_DFL); 115989dd127SDag-Erling Smørgrav setpgid(0, 0); 116989dd127SDag-Erling Smørgrav close(fd); 117989dd127SDag-Erling Smørgrav } else { 118989dd127SDag-Erling Smørgrav error("Failed to disconnect from controlling tty."); 119989dd127SDag-Erling Smørgrav } 120989dd127SDag-Erling Smørgrav 121989dd127SDag-Erling Smørgrav debug("Setting controlling tty using TCSETCTTY."); 122989dd127SDag-Erling Smørgrav ioctl(*ttyfd, TCSETCTTY, NULL); 123989dd127SDag-Erling Smørgrav fd = open("/dev/tty", O_RDWR); 124989dd127SDag-Erling Smørgrav if (fd < 0) 12521e764dfSDag-Erling Smørgrav error("%.100s: %.100s", tty, strerror(errno)); 126989dd127SDag-Erling Smørgrav close(*ttyfd); 127989dd127SDag-Erling Smørgrav *ttyfd = fd; 128f388f5efSDag-Erling Smørgrav #else /* _UNICOS */ 1291e8db6e2SBrian Feldman 1301e8db6e2SBrian Feldman /* First disconnect from the old controlling tty. */ 1311e8db6e2SBrian Feldman #ifdef TIOCNOTTY 1321e8db6e2SBrian Feldman fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); 1331e8db6e2SBrian Feldman if (fd >= 0) { 1341e8db6e2SBrian Feldman (void) ioctl(fd, TIOCNOTTY, NULL); 1351e8db6e2SBrian Feldman close(fd); 1361e8db6e2SBrian Feldman } 1371e8db6e2SBrian Feldman #endif /* TIOCNOTTY */ 1381e8db6e2SBrian Feldman if (setsid() < 0) 1391e8db6e2SBrian Feldman error("setsid: %.100s", strerror(errno)); 1401e8db6e2SBrian Feldman 1411e8db6e2SBrian Feldman /* 1421e8db6e2SBrian Feldman * Verify that we are successfully disconnected from the controlling 1431e8db6e2SBrian Feldman * tty. 1441e8db6e2SBrian Feldman */ 1451e8db6e2SBrian Feldman fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); 1461e8db6e2SBrian Feldman if (fd >= 0) { 1471e8db6e2SBrian Feldman error("Failed to disconnect from controlling tty."); 1481e8db6e2SBrian Feldman close(fd); 1491e8db6e2SBrian Feldman } 1501e8db6e2SBrian Feldman /* Make it our controlling tty. */ 1511e8db6e2SBrian Feldman #ifdef TIOCSCTTY 1521e8db6e2SBrian Feldman debug("Setting controlling tty using TIOCSCTTY."); 1531e8db6e2SBrian Feldman if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) 1541e8db6e2SBrian Feldman error("ioctl(TIOCSCTTY): %.100s", strerror(errno)); 1551e8db6e2SBrian Feldman #endif /* TIOCSCTTY */ 156d4ecd108SDag-Erling Smørgrav #ifdef NEED_SETPGRP 157989dd127SDag-Erling Smørgrav if (setpgrp(0,0) < 0) 158989dd127SDag-Erling Smørgrav error("SETPGRP %s",strerror(errno)); 159d4ecd108SDag-Erling Smørgrav #endif /* NEED_SETPGRP */ 160989dd127SDag-Erling Smørgrav #ifdef USE_VHANGUP 161cf2b5f3bSDag-Erling Smørgrav old = signal(SIGHUP, SIG_IGN); 162989dd127SDag-Erling Smørgrav vhangup(); 163cf2b5f3bSDag-Erling Smørgrav signal(SIGHUP, old); 164989dd127SDag-Erling Smørgrav #endif /* USE_VHANGUP */ 16521e764dfSDag-Erling Smørgrav fd = open(tty, O_RDWR); 166989dd127SDag-Erling Smørgrav if (fd < 0) { 16721e764dfSDag-Erling Smørgrav error("%.100s: %.100s", tty, strerror(errno)); 168989dd127SDag-Erling Smørgrav } else { 169989dd127SDag-Erling Smørgrav #ifdef USE_VHANGUP 170989dd127SDag-Erling Smørgrav close(*ttyfd); 171989dd127SDag-Erling Smørgrav *ttyfd = fd; 172989dd127SDag-Erling Smørgrav #else /* USE_VHANGUP */ 1731e8db6e2SBrian Feldman close(fd); 174989dd127SDag-Erling Smørgrav #endif /* USE_VHANGUP */ 175989dd127SDag-Erling Smørgrav } 1761e8db6e2SBrian Feldman /* Verify that we now have a controlling tty. */ 1771e8db6e2SBrian Feldman fd = open(_PATH_TTY, O_WRONLY); 1781e8db6e2SBrian Feldman if (fd < 0) 1791e8db6e2SBrian Feldman error("open /dev/tty failed - could not set controlling tty: %.100s", 1801e8db6e2SBrian Feldman strerror(errno)); 181a82e551fSDag-Erling Smørgrav else 1821e8db6e2SBrian Feldman close(fd); 183f388f5efSDag-Erling Smørgrav #endif /* _UNICOS */ 1841e8db6e2SBrian Feldman } 1851e8db6e2SBrian Feldman 1861e8db6e2SBrian Feldman /* Changes the window size associated with the pty. */ 1871e8db6e2SBrian Feldman 1881e8db6e2SBrian Feldman void 189333ee039SDag-Erling Smørgrav pty_change_window_size(int ptyfd, u_int row, u_int col, 190333ee039SDag-Erling Smørgrav u_int xpixel, u_int ypixel) 1911e8db6e2SBrian Feldman { 1921e8db6e2SBrian Feldman struct winsize w; 193a82e551fSDag-Erling Smørgrav 194333ee039SDag-Erling Smørgrav /* may truncate u_int -> u_short */ 1951e8db6e2SBrian Feldman w.ws_row = row; 1961e8db6e2SBrian Feldman w.ws_col = col; 1971e8db6e2SBrian Feldman w.ws_xpixel = xpixel; 1981e8db6e2SBrian Feldman w.ws_ypixel = ypixel; 1991e8db6e2SBrian Feldman (void) ioctl(ptyfd, TIOCSWINSZ, &w); 2001e8db6e2SBrian Feldman } 2011e8db6e2SBrian Feldman 2021e8db6e2SBrian Feldman void 20321e764dfSDag-Erling Smørgrav pty_setowner(struct passwd *pw, const char *tty) 2041e8db6e2SBrian Feldman { 2051e8db6e2SBrian Feldman struct group *grp; 2061e8db6e2SBrian Feldman gid_t gid; 2071e8db6e2SBrian Feldman mode_t mode; 2081e8db6e2SBrian Feldman struct stat st; 2091e8db6e2SBrian Feldman 2101e8db6e2SBrian Feldman /* Determine the group to make the owner of the tty. */ 2111e8db6e2SBrian Feldman grp = getgrnam("tty"); 2121e8db6e2SBrian Feldman if (grp) { 2131e8db6e2SBrian Feldman gid = grp->gr_gid; 2141e8db6e2SBrian Feldman mode = S_IRUSR | S_IWUSR | S_IWGRP; 2151e8db6e2SBrian Feldman } else { 2161e8db6e2SBrian Feldman gid = pw->pw_gid; 2171e8db6e2SBrian Feldman mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH; 2181e8db6e2SBrian Feldman } 2191e8db6e2SBrian Feldman 2201e8db6e2SBrian Feldman /* 2211e8db6e2SBrian Feldman * Change owner and mode of the tty as required. 222af12a3e7SDag-Erling Smørgrav * Warn but continue if filesystem is read-only and the uids match/ 223af12a3e7SDag-Erling Smørgrav * tty is owned by root. 2241e8db6e2SBrian Feldman */ 22521e764dfSDag-Erling Smørgrav if (stat(tty, &st)) 22621e764dfSDag-Erling Smørgrav fatal("stat(%.100s) failed: %.100s", tty, 2271e8db6e2SBrian Feldman strerror(errno)); 2281e8db6e2SBrian Feldman 229333ee039SDag-Erling Smørgrav #ifdef WITH_SELINUX 230333ee039SDag-Erling Smørgrav ssh_selinux_setup_pty(pw->pw_name, tty); 231333ee039SDag-Erling Smørgrav #endif 232333ee039SDag-Erling Smørgrav 2331e8db6e2SBrian Feldman if (st.st_uid != pw->pw_uid || st.st_gid != gid) { 23421e764dfSDag-Erling Smørgrav if (chown(tty, pw->pw_uid, gid) < 0) { 235af12a3e7SDag-Erling Smørgrav if (errno == EROFS && 236af12a3e7SDag-Erling Smørgrav (st.st_uid == pw->pw_uid || st.st_uid == 0)) 237e73e9afaSDag-Erling Smørgrav debug("chown(%.100s, %u, %u) failed: %.100s", 23821e764dfSDag-Erling Smørgrav tty, (u_int)pw->pw_uid, (u_int)gid, 2391e8db6e2SBrian Feldman strerror(errno)); 2401e8db6e2SBrian Feldman else 241a82e551fSDag-Erling Smørgrav fatal("chown(%.100s, %u, %u) failed: %.100s", 24221e764dfSDag-Erling Smørgrav tty, (u_int)pw->pw_uid, (u_int)gid, 2431e8db6e2SBrian Feldman strerror(errno)); 2441e8db6e2SBrian Feldman } 2451e8db6e2SBrian Feldman } 2461e8db6e2SBrian Feldman 2471e8db6e2SBrian Feldman if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { 24821e764dfSDag-Erling Smørgrav if (chmod(tty, mode) < 0) { 2491e8db6e2SBrian Feldman if (errno == EROFS && 2501e8db6e2SBrian Feldman (st.st_mode & (S_IRGRP | S_IROTH)) == 0) 251e73e9afaSDag-Erling Smørgrav debug("chmod(%.100s, 0%o) failed: %.100s", 25221e764dfSDag-Erling Smørgrav tty, (u_int)mode, strerror(errno)); 2531e8db6e2SBrian Feldman else 2541e8db6e2SBrian Feldman fatal("chmod(%.100s, 0%o) failed: %.100s", 25521e764dfSDag-Erling Smørgrav tty, (u_int)mode, strerror(errno)); 2561e8db6e2SBrian Feldman } 2571e8db6e2SBrian Feldman } 2581e8db6e2SBrian Feldman } 259