#include #include #include #include #include #include #include #include #include #include #include #include #include #include "pterm.h" #include "log.h" #ifndef _PATH_TTY #define _PATH_TTY "/dev/tty" #endif #ifndef O_NOCTTY #define O_NOCTTY 0 #endif int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) { /* openpty(3) exists in OSF/1 and some other os'es */ char *name; int i; i = openpty(ptyfd, ttyfd, NULL, NULL, NULL); if (i < 0) { E_STRERR("%s", "Allocate pseudo terminal"); return 1; } name = ttyname(*ttyfd); if (!name) { E_STRERR("%s", "Invalid ttyname for pseudo terminal"); abort(); } strncpy(namebuf, name, namebuflen); /* possible truncation */ return 0; } void pty_release(const char *tty) { if (chown(tty, (uid_t) 0, (gid_t) 0) < 0) { E_STRERR("Change tty owner for '%s'", tty); } if (chmod(tty, (mode_t) 0666) < 0) { E_STRERR("Change tty mode for '%s'", tty); } } void pty_make_controlling_tty(int *ttyfd, const char *tty) { int fd; /* First disconnect from the old controlling tty. */ fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); } if (setsid() < 0) E_STRERR("%s", "New session"); /* * Verify that we are successfully disconnected from the controlling * tty. */ fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); if (fd >= 0) { E2("%s", "Failed to disconnect from controlling tty."); close(fd); } /* Make it our controlling tty. */ D("%s", "Setting controlling tty using TIOCSCTTY."); if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) E_STRERR("%s", "ioctl(TIOCSCTTY)"); if (setpgrp() < 0) E_STRERR("%s", "Set new process group"); fd = open(tty, O_RDWR); if (fd < 0) E_STRERR("Open tty '%s'", tty); else close(fd); /* Verify that we now have a controlling tty. */ fd = open(_PATH_TTY, O_WRONLY); if (fd < 0) E_STRERR("Could not set controlling tty - Open '%s'", tty); else close(fd); } /* Changes the window size associated with the pty. */ void pty_change_window_size(int ptyfd, unsigned int row, unsigned int col, unsigned int xpixel, unsigned int ypixel) { struct winsize w; /* may truncate unsigned int -> unsigned short */ w.ws_row = row; w.ws_col = col; w.ws_xpixel = xpixel; w.ws_ypixel = ypixel; (void) ioctl(ptyfd, TIOCSWINSZ, &w); } void pty_setowner(struct passwd *pw, const char *tty) { struct group *grp; gid_t gid; mode_t mode; struct stat st; /* Determine the group to make the owner of the tty. */ grp = getgrnam("tty"); gid = (grp != NULL) ? grp->gr_gid : pw->pw_gid; mode = (grp != NULL) ? 0620 : 0600; /* * Change owner and mode of the tty as required. * Warn but continue if filesystem is read-only and the uids match/ * tty is owned by root. */ if (stat(tty, &st)) FATAL("Change owner of %s", tty); #ifdef WITH_SELINUX ssh_selinux_setup_pty(pw->pw_name, tty); #endif if (st.st_uid != pw->pw_uid || st.st_gid != gid) { if (chown(tty, pw->pw_uid, gid) < 0) { if (errno == EROFS && (st.st_uid == pw->pw_uid || st.st_uid == 0)) { D("Change owner of '%s' to %u:%u", tty, (unsigned) pw->pw_uid, (unsigned) gid); } else { FATAL("Change owner of '%s' to %u:%u", tty, (unsigned) pw->pw_uid, (unsigned) gid); } } } if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { if (chmod(tty, mode) < 0) { if (errno == EROFS && (st.st_mode & (S_IRGRP | S_IROTH)) == 0) { D("Change mode of '%s' to 0%o", tty, (unsigned) mode); } else { FATAL("Change mode of '%s' to 0%o", tty, (unsigned) mode); } } } } /* Disconnect from the controlling tty. */ void disconnect_controlling_tty(void) { int fd; if ((fd = open(_PATH_TTY, O_RDWR | O_NOCTTY)) >= 0) { (void) ioctl(fd, TIOCNOTTY, NULL); close(fd); } }