Annotation of src/usr.bin/ssh/pty.c, Revision 1.6
1.1 deraadt 1: /*
2:
3: pty.c
4:
5: Author: Tatu Ylonen <ylo@cs.hut.fi>
6:
7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8: All rights reserved
9:
10: Created: Fri Mar 17 04:37:25 1995 ylo
11:
12: Allocating a pseudo-terminal, and making it the controlling tty.
13:
14: */
15:
16: #include "includes.h"
1.6 ! markus 17: RCSID("$Id: pty.c,v 1.5 1999/10/16 20:57:52 deraadt Exp $");
1.1 deraadt 18:
19: #include "pty.h"
20: #include "ssh.h"
21:
22: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
23: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
24: #undef HAVE_DEV_PTMX
25: #endif
26:
27: #ifndef O_NOCTTY
28: #define O_NOCTTY 0
29: #endif
30:
31: /* Allocates and opens a pty. Returns 0 if no pty could be allocated,
32: or nonzero if a pty was successfully allocated. On success, open file
1.6 ! markus 33: descriptors for the pty and tty sides and the name of the tty side are
1.1 deraadt 34: returned (the buffer must be able to hold at least 64 characters). */
35:
1.6 ! markus 36: int
! 37: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
1.1 deraadt 38: {
39: #ifdef HAVE_OPENPTY
1.6 ! markus 40: /* openpty(3) exists in OSF/1 and some other os'es */
! 41: int i;
1.1 deraadt 42:
1.6 ! markus 43: i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
! 44: if (i < 0) {
! 45: error("openpty: %.100s", strerror(errno));
! 46: return 0;
! 47: }
! 48: return 1;
1.1 deraadt 49: #else /* HAVE_OPENPTY */
50: #ifdef HAVE__GETPTY
1.6 ! markus 51: /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
! 52: more pty's automagically when needed */
! 53: char *slave;
! 54:
! 55: slave = _getpty(ptyfd, O_RDWR, 0622, 0);
! 56: if (slave == NULL) {
! 57: error("_getpty: %.100s", strerror(errno));
! 58: return 0;
! 59: }
! 60: strcpy(namebuf, slave);
! 61: /* Open the slave side. */
! 62: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
! 63: if (*ttyfd < 0) {
! 64: error("%.200s: %.100s", namebuf, strerror(errno));
! 65: close(*ptyfd);
! 66: return 0;
! 67: }
! 68: return 1;
1.1 deraadt 69: #else /* HAVE__GETPTY */
70: #ifdef HAVE_DEV_PTMX
1.6 ! markus 71: /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
! 72: also has bsd-style ptys, but they simply do not work.) */
! 73: int ptm;
! 74: char *pts;
! 75:
! 76: ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
! 77: if (ptm < 0) {
! 78: error("/dev/ptmx: %.100s", strerror(errno));
! 79: return 0;
! 80: }
! 81: if (grantpt(ptm) < 0) {
! 82: error("grantpt: %.100s", strerror(errno));
! 83: return 0;
! 84: }
! 85: if (unlockpt(ptm) < 0) {
! 86: error("unlockpt: %.100s", strerror(errno));
! 87: return 0;
! 88: }
! 89: pts = ptsname(ptm);
! 90: if (pts == NULL)
! 91: error("Slave pty side name could not be obtained.");
! 92: strcpy(namebuf, pts);
! 93: *ptyfd = ptm;
! 94:
! 95: /* Open the slave side. */
! 96: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
! 97: if (*ttyfd < 0) {
! 98: error("%.100s: %.100s", namebuf, strerror(errno));
! 99: close(*ptyfd);
! 100: return 0;
! 101: }
! 102: /* Push the appropriate streams modules, as described in Solaris
! 103: pts(7). */
! 104: if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
! 105: error("ioctl I_PUSH ptem: %.100s", strerror(errno));
! 106: if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
! 107: error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
! 108: if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
! 109: error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
! 110: return 1;
1.1 deraadt 111: #else /* HAVE_DEV_PTMX */
112: #ifdef HAVE_DEV_PTS_AND_PTC
1.6 ! markus 113: /* AIX-style pty code. */
! 114: const char *name;
1.1 deraadt 115:
1.6 ! markus 116: *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
! 117: if (*ptyfd < 0) {
! 118: error("Could not open /dev/ptc: %.100s", strerror(errno));
! 119: return 0;
! 120: }
! 121: name = ttyname(*ptyfd);
! 122: if (!name)
! 123: fatal("Open of /dev/ptc returns device for which ttyname fails.");
! 124: strcpy(namebuf, name);
! 125: *ttyfd = open(name, O_RDWR | O_NOCTTY);
! 126: if (*ttyfd < 0) {
! 127: error("Could not open pty slave side %.100s: %.100s",
! 128: name, strerror(errno));
! 129: close(*ptyfd);
! 130: return 0;
! 131: }
! 132: return 1;
1.1 deraadt 133: #else /* HAVE_DEV_PTS_AND_PTC */
1.6 ! markus 134: /* BSD-style pty code. */
! 135: char buf[64];
! 136: int i;
! 137: const char *ptymajors =
! 138: "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
! 139: const char *ptyminors = "0123456789abcdef";
! 140: int num_minors = strlen(ptyminors);
! 141: int num_ptys = strlen(ptymajors) * num_minors;
! 142:
! 143: for (i = 0; i < num_ptys; i++) {
! 144: snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
! 145: ptyminors[i % num_minors]);
! 146: *ptyfd = open(buf, O_RDWR | O_NOCTTY);
! 147: if (*ptyfd < 0)
! 148: continue;
! 149: snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
! 150: ptyminors[i % num_minors]);
! 151:
! 152: /* Open the slave side. */
! 153: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
! 154: if (*ttyfd < 0) {
! 155: error("%.100s: %.100s", namebuf, strerror(errno));
! 156: close(*ptyfd);
! 157: return 0;
! 158: }
! 159: return 1;
! 160: }
! 161: return 0;
1.1 deraadt 162: #endif /* HAVE_DEV_PTS_AND_PTC */
163: #endif /* HAVE_DEV_PTMX */
164: #endif /* HAVE__GETPTY */
165: #endif /* HAVE_OPENPTY */
166: }
167:
1.6 ! markus 168: /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
1.1 deraadt 169:
1.6 ! markus 170: void
! 171: pty_release(const char *ttyname)
1.1 deraadt 172: {
1.6 ! markus 173: if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
! 174: debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
! 175: if (chmod(ttyname, (mode_t) 0666) < 0)
! 176: debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
1.1 deraadt 177: }
178:
179: /* Makes the tty the processes controlling tty and sets it to sane modes. */
180:
1.6 ! markus 181: void
! 182: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
1.1 deraadt 183: {
1.6 ! markus 184: int fd;
1.1 deraadt 185:
1.6 ! markus 186: /* First disconnect from the old controlling tty. */
1.1 deraadt 187: #ifdef TIOCNOTTY
1.6 ! markus 188: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
! 189: if (fd >= 0) {
! 190: (void) ioctl(fd, TIOCNOTTY, NULL);
! 191: close(fd);
! 192: }
1.1 deraadt 193: #endif /* TIOCNOTTY */
1.6 ! markus 194: if (setsid() < 0)
! 195: error("setsid: %.100s", strerror(errno));
1.1 deraadt 196:
1.6 ! markus 197: /* Verify that we are successfully disconnected from the
! 198: controlling tty. */
! 199: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
! 200: if (fd >= 0) {
! 201: error("Failed to disconnect from controlling tty.");
! 202: close(fd);
! 203: }
! 204: /* Make it our controlling tty. */
1.1 deraadt 205: #ifdef TIOCSCTTY
1.6 ! markus 206: debug("Setting controlling tty using TIOCSCTTY.");
! 207: /* We ignore errors from this, because HPSUX defines TIOCSCTTY,
! 208: but returns EINVAL with these arguments, and there is
! 209: absolutely no documentation. */
! 210: ioctl(*ttyfd, TIOCSCTTY, NULL);
1.1 deraadt 211: #endif /* TIOCSCTTY */
1.6 ! markus 212: fd = open(ttyname, O_RDWR);
! 213: if (fd < 0)
! 214: error("%.100s: %.100s", ttyname, strerror(errno));
! 215: else
! 216: close(fd);
! 217:
! 218: /* Verify that we now have a controlling tty. */
! 219: fd = open("/dev/tty", O_WRONLY);
! 220: if (fd < 0)
! 221: error("open /dev/tty failed - could not set controlling tty: %.100s",
! 222: strerror(errno));
! 223: else {
! 224: close(fd);
! 225: }
1.1 deraadt 226: }
227:
228: /* Changes the window size associated with the pty. */
229:
1.6 ! markus 230: void
! 231: pty_change_window_size(int ptyfd, int row, int col,
! 232: int xpixel, int ypixel)
1.1 deraadt 233: {
1.6 ! markus 234: struct winsize w;
! 235: w.ws_row = row;
! 236: w.ws_col = col;
! 237: w.ws_xpixel = xpixel;
! 238: w.ws_ypixel = ypixel;
! 239: (void) ioctl(ptyfd, TIOCSWINSZ, &w);
1.1 deraadt 240: }