jcs's openbsd hax
openbsd
at jcs 197 lines 5.0 kB view raw
1/* $OpenBSD: sshpty.c,v 1.35 2026/02/11 17:05:32 dtucker Exp $ */ 2/* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Allocating a pseudo-terminal, and making it the controlling tty. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 */ 14 15#include <sys/types.h> 16#include <sys/ioctl.h> 17#include <sys/stat.h> 18 19#include <errno.h> 20#include <fcntl.h> 21#include <grp.h> 22#include <paths.h> 23#include <pwd.h> 24#include <signal.h> 25#include <stdarg.h> 26#include <stdio.h> 27#include <string.h> 28#include <termios.h> 29#include <unistd.h> 30#include <util.h> 31 32#include "sshpty.h" 33#include "log.h" 34 35#ifndef O_NOCTTY 36#define O_NOCTTY 0 37#endif 38 39/* 40 * Allocates and opens a pty. Returns 0 if no pty could be allocated, or 41 * nonzero if a pty was successfully allocated. On success, open file 42 * descriptors for the pty and tty sides and the name of the tty side are 43 * returned (the buffer must be able to hold at least 64 characters). 44 */ 45 46int 47pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) 48{ 49 char buf[64]; 50 int i; 51 52 i = openpty(ptyfd, ttyfd, buf, NULL, NULL); 53 if (i == -1) { 54 error("openpty: %.100s", strerror(errno)); 55 return 0; 56 } 57 strlcpy(namebuf, buf, namebuflen); /* possible truncation */ 58 return 1; 59} 60 61/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */ 62 63void 64pty_release(const char *tty) 65{ 66 if (chown(tty, (uid_t) 0, (gid_t) 0) == -1) 67 error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno)); 68 if (chmod(tty, (mode_t) 0666) == -1) 69 error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno)); 70} 71 72/* Makes the tty the process's controlling tty and sets it to sane modes. */ 73 74void 75pty_make_controlling_tty(int *ttyfd, const char *tty) 76{ 77 int fd; 78 79 /* First disconnect from the old controlling tty. */ 80#ifdef TIOCNOTTY 81 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); 82 if (fd >= 0) { 83 (void) ioctl(fd, TIOCNOTTY, NULL); 84 close(fd); 85 } 86#endif /* TIOCNOTTY */ 87 if (setsid() == -1) 88 error("setsid: %.100s", strerror(errno)); 89 90 /* 91 * Verify that we are successfully disconnected from the controlling 92 * tty. 93 */ 94 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); 95 if (fd >= 0) { 96 error("Failed to disconnect from controlling tty."); 97 close(fd); 98 } 99 /* Make it our controlling tty. */ 100#ifdef TIOCSCTTY 101 debug("Setting controlling tty using TIOCSCTTY."); 102 if (ioctl(*ttyfd, TIOCSCTTY, NULL) == -1) 103 error("ioctl(TIOCSCTTY): %.100s", strerror(errno)); 104#endif /* TIOCSCTTY */ 105 fd = open(tty, O_RDWR); 106 if (fd == -1) 107 error("%.100s: %.100s", tty, strerror(errno)); 108 else 109 close(fd); 110 111 /* Verify that we now have a controlling tty. */ 112 fd = open(_PATH_TTY, O_WRONLY); 113 if (fd == -1) 114 error("open /dev/tty failed - could not set controlling tty: %.100s", 115 strerror(errno)); 116 else 117 close(fd); 118} 119 120/* Changes the window size associated with the pty. */ 121 122void 123pty_change_window_size(int ptyfd, u_int row, u_int col, 124 u_int xpixel, u_int ypixel) 125{ 126 struct winsize w; 127 128 /* may truncate u_int -> u_short */ 129 w.ws_row = row; 130 w.ws_col = col; 131 w.ws_xpixel = xpixel; 132 w.ws_ypixel = ypixel; 133 (void) ioctl(ptyfd, TIOCSWINSZ, &w); 134} 135 136void 137pty_setowner(struct passwd *pw, const char *tty) 138{ 139 struct group *grp; 140 gid_t gid; 141 mode_t mode; 142 struct stat st; 143 144 /* Determine the group to make the owner of the tty. */ 145 grp = getgrnam("tty"); 146 if (grp == NULL) 147 fatal("no tty group"); 148 gid = (grp != NULL) ? grp->gr_gid : pw->pw_gid; 149 mode = (grp != NULL) ? 0620 : 0600; 150 151 /* 152 * Change owner and mode of the tty as required. 153 * Warn but continue if filesystem is read-only and the uids match/ 154 * tty is owned by root. 155 */ 156 if (stat(tty, &st) == -1) 157 fatal("stat(%.100s) failed: %.100s", tty, 158 strerror(errno)); 159 160 if (st.st_uid != pw->pw_uid || st.st_gid != gid) { 161 if (chown(tty, pw->pw_uid, gid) == -1) { 162 if (errno == EROFS && 163 (st.st_uid == pw->pw_uid || st.st_uid == 0)) 164 debug("chown(%.100s, %u, %u) failed: %.100s", 165 tty, (u_int)pw->pw_uid, (u_int)gid, 166 strerror(errno)); 167 else 168 fatal("chown(%.100s, %u, %u) failed: %.100s", 169 tty, (u_int)pw->pw_uid, (u_int)gid, 170 strerror(errno)); 171 } 172 } 173 174 if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { 175 if (chmod(tty, mode) == -1) { 176 if (errno == EROFS && 177 (st.st_mode & (S_IRGRP | S_IROTH)) == 0) 178 debug("chmod(%.100s, 0%o) failed: %.100s", 179 tty, (u_int)mode, strerror(errno)); 180 else 181 fatal("chmod(%.100s, 0%o) failed: %.100s", 182 tty, (u_int)mode, strerror(errno)); 183 } 184 } 185} 186 187/* Disconnect from the controlling tty. */ 188void 189disconnect_controlling_tty(void) 190{ 191 int fd; 192 193 if ((fd = open(_PATH_TTY, O_RDWR | O_NOCTTY)) >= 0) { 194 (void) ioctl(fd, TIOCNOTTY, NULL); 195 close(fd); 196 } 197}