diff options
Diffstat (limited to 'src/pterm.c')
-rw-r--r-- | src/pterm.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/src/pterm.c b/src/pterm.c new file mode 100644 index 0000000..47f433c --- /dev/null +++ b/src/pterm.c @@ -0,0 +1,184 @@ +#include <unistd.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <grp.h> +#include <pwd.h> +#include <stdarg.h> +#include <string.h> +#include <termios.h> +#include <pty.h> + +#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, u_int row, u_int col, + u_int xpixel, u_int ypixel) +{ + struct winsize w; + + /* may truncate u_int -> u_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); + } +} |