Annotation of src/usr.bin/ssh/pty.c, Revision 1.1
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"
! 17: RCSID("$Id: pty.c,v 1.2 1999/05/04 11:58:56 bg Exp $");
! 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: #ifdef HAVE_DEV_PTMX
! 28: #include <sys/stream.h>
! 29: #include <stropts.h>
! 30: #include <sys/conf.h>
! 31: #endif /* HAVE_DEV_PTMX */
! 32:
! 33: #ifndef O_NOCTTY
! 34: #define O_NOCTTY 0
! 35: #endif
! 36:
! 37: /* Allocates and opens a pty. Returns 0 if no pty could be allocated,
! 38: or nonzero if a pty was successfully allocated. On success, open file
! 39: descriptors for the pty and tty sides and the name of the tty side are
! 40: returned (the buffer must be able to hold at least 64 characters). */
! 41:
! 42: int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
! 43: {
! 44: #ifdef HAVE_OPENPTY
! 45:
! 46: /* openpty(3) exists in OSF/1 and some other os'es */
! 47:
! 48: int i;
! 49:
! 50: i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
! 51:
! 52: if (i < 0)
! 53: {
! 54: error("openpty: %.100s", strerror(errno));
! 55: return 0;
! 56: }
! 57:
! 58: return 1;
! 59:
! 60: #else /* HAVE_OPENPTY */
! 61: #ifdef HAVE__GETPTY
! 62:
! 63: /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
! 64: pty's automagically when needed */
! 65:
! 66: char *slave;
! 67:
! 68: slave = _getpty(ptyfd, O_RDWR, 0622, 0);
! 69: if (slave == NULL)
! 70: {
! 71: error("_getpty: %.100s", strerror(errno));
! 72: return 0;
! 73: }
! 74: strcpy(namebuf, slave);
! 75: /* Open the slave side. */
! 76: *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
! 77: if (*ttyfd < 0)
! 78: {
! 79: error("%.200s: %.100s", namebuf, strerror(errno));
! 80: close(*ptyfd);
! 81: return 0;
! 82: }
! 83: return 1;
! 84:
! 85: #else /* HAVE__GETPTY */
! 86: #ifdef HAVE_DEV_PTMX
! 87: /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 also has
! 88: bsd-style ptys, but they simply do not work.) */
! 89:
! 90: int ptm;
! 91: char *pts;
! 92:
! 93: ptm = open("/dev/ptmx", O_RDWR|O_NOCTTY);
! 94: if (ptm < 0)
! 95: {
! 96: error("/dev/ptmx: %.100s", strerror(errno));
! 97: return 0;
! 98: }
! 99: if (grantpt(ptm) < 0)
! 100: {
! 101: error("grantpt: %.100s", strerror(errno));
! 102: return 0;
! 103: }
! 104: if (unlockpt(ptm) < 0)
! 105: {
! 106: error("unlockpt: %.100s", strerror(errno));
! 107: return 0;
! 108: }
! 109: pts = ptsname(ptm);
! 110: if (pts == NULL)
! 111: error("Slave pty side name could not be obtained.");
! 112: strcpy(namebuf, pts);
! 113: *ptyfd = ptm;
! 114:
! 115: /* Open the slave side. */
! 116: *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
! 117: if (*ttyfd < 0)
! 118: {
! 119: error("%.100s: %.100s", namebuf, strerror(errno));
! 120: close(*ptyfd);
! 121: return 0;
! 122: }
! 123: /* Push the appropriate streams modules, as described in Solaris pts(7). */
! 124: if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
! 125: error("ioctl I_PUSH ptem: %.100s", strerror(errno));
! 126: if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
! 127: error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
! 128: if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
! 129: error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
! 130: return 1;
! 131:
! 132: #else /* HAVE_DEV_PTMX */
! 133: #ifdef HAVE_DEV_PTS_AND_PTC
! 134:
! 135: /* AIX-style pty code. */
! 136:
! 137: const char *name;
! 138:
! 139: *ptyfd = open("/dev/ptc", O_RDWR|O_NOCTTY);
! 140: if (*ptyfd < 0)
! 141: {
! 142: error("Could not open /dev/ptc: %.100s", strerror(errno));
! 143: return 0;
! 144: }
! 145: name = ttyname(*ptyfd);
! 146: if (!name)
! 147: fatal("Open of /dev/ptc returns device for which ttyname fails.");
! 148: strcpy(namebuf, name);
! 149: *ttyfd = open(name, O_RDWR|O_NOCTTY);
! 150: if (*ttyfd < 0)
! 151: {
! 152: error("Could not open pty slave side %.100s: %.100s",
! 153: name, strerror(errno));
! 154: close(*ptyfd);
! 155: return 0;
! 156: }
! 157: return 1;
! 158:
! 159: #else /* HAVE_DEV_PTS_AND_PTC */
! 160: #ifdef CRAY
! 161: char buf[64];
! 162: int i;
! 163:
! 164: for (i = 0; i < 128; i++)
! 165: {
! 166: sprintf(buf, "/dev/pty/%03d", i);
! 167: *ptyfd = open(buf, O_RDWR|O_NOCTTY);
! 168: if (*ptyfd < 0)
! 169: continue;
! 170: sprintf(namebuf, "/dev/ttyp%03d", i);
! 171: /* Open the slave side. */
! 172: *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
! 173: if (*ttyfd < 0)
! 174: {
! 175: error("%.100s: %.100s", namebuf, strerror(errno));
! 176: close(*ptyfd);
! 177: return 0;
! 178: }
! 179: return 1;
! 180: }
! 181: return 0;
! 182:
! 183: #else /* CRAY */
! 184:
! 185: /* BSD-style pty code. */
! 186:
! 187: char buf[64];
! 188: int i;
! 189: const char *ptymajors =
! 190: "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
! 191: const char *ptyminors = "0123456789abcdef";
! 192: int num_minors = strlen(ptyminors);
! 193: int num_ptys = strlen(ptymajors) * num_minors;
! 194:
! 195: for (i = 0; i < num_ptys; i++)
! 196: {
! 197: sprintf(buf, "/dev/pty%c%c", ptymajors[i / num_minors],
! 198: ptyminors[i % num_minors]);
! 199: *ptyfd = open(buf, O_RDWR|O_NOCTTY);
! 200: if (*ptyfd < 0)
! 201: continue;
! 202: sprintf(namebuf, "/dev/tty%c%c", ptymajors[i / num_minors],
! 203: ptyminors[i % num_minors]);
! 204:
! 205: /* Open the slave side. */
! 206: *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
! 207: if (*ttyfd < 0)
! 208: {
! 209: error("%.100s: %.100s", namebuf, strerror(errno));
! 210: close(*ptyfd);
! 211: return 0;
! 212: }
! 213: return 1;
! 214: }
! 215: return 0;
! 216: #endif /* CRAY */
! 217: #endif /* HAVE_DEV_PTS_AND_PTC */
! 218: #endif /* HAVE_DEV_PTMX */
! 219: #endif /* HAVE__GETPTY */
! 220: #endif /* HAVE_OPENPTY */
! 221: }
! 222:
! 223: /* Releases the tty. Its ownership is returned to root, and permissions to
! 224: 0666. */
! 225:
! 226: void pty_release(const char *ttyname)
! 227: {
! 228: if (chown(ttyname, (uid_t)0, (gid_t)0) < 0)
! 229: debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
! 230: if (chmod(ttyname, (mode_t)0666) < 0)
! 231: debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
! 232: }
! 233:
! 234: /* Makes the tty the processes controlling tty and sets it to sane modes. */
! 235:
! 236: void pty_make_controlling_tty(int *ttyfd, const char *ttyname)
! 237: {
! 238: int fd;
! 239:
! 240: /* First disconnect from the old controlling tty. */
! 241: #ifdef TIOCNOTTY
! 242: fd = open("/dev/tty", O_RDWR|O_NOCTTY);
! 243: if (fd >= 0)
! 244: {
! 245: (void)ioctl(fd, TIOCNOTTY, NULL);
! 246: close(fd);
! 247: }
! 248: #endif /* TIOCNOTTY */
! 249: #ifdef HAVE_SETSID
! 250: #ifdef ultrix
! 251: setpgrp(0, 0);
! 252: #else /* ultrix */
! 253: if (setsid() < 0)
! 254: error("setsid: %.100s", strerror(errno));
! 255: #endif /* ultrix */
! 256: #endif /* HAVE_SETSID */
! 257:
! 258: /* Verify that we are successfully disconnected from the controlling tty. */
! 259: fd = open("/dev/tty", O_RDWR|O_NOCTTY);
! 260: if (fd >= 0)
! 261: {
! 262: error("Failed to disconnect from controlling tty.");
! 263: close(fd);
! 264: }
! 265:
! 266: /* Make it our controlling tty. */
! 267: #ifdef TIOCSCTTY
! 268: debug("Setting controlling tty using TIOCSCTTY.");
! 269: /* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns
! 270: EINVAL with these arguments, and there is absolutely no documentation. */
! 271: ioctl(*ttyfd, TIOCSCTTY, NULL);
! 272: #endif /* TIOCSCTTY */
! 273: fd = open(ttyname, O_RDWR);
! 274: if (fd < 0)
! 275: error("%.100s: %.100s", ttyname, strerror(errno));
! 276: else
! 277: close(fd);
! 278:
! 279: /* Verify that we now have a controlling tty. */
! 280: fd = open("/dev/tty", O_WRONLY);
! 281: if (fd < 0)
! 282: error("open /dev/tty failed - could not set controlling tty: %.100s",
! 283: strerror(errno));
! 284: else
! 285: {
! 286: close(fd);
! 287: #ifdef HAVE_VHANGUP
! 288: signal(SIGHUP, SIG_IGN);
! 289: vhangup();
! 290: signal(SIGHUP, SIG_DFL);
! 291: fd = open(ttyname, O_RDWR);
! 292: if (fd == -1)
! 293: error("pty_make_controlling_tty: reopening controlling tty after vhangup failed for %.100s",
! 294: ttyname);
! 295: close(*ttyfd);
! 296: *ttyfd = fd;
! 297: #endif /* HAVE_VHANGUP */
! 298: }
! 299: }
! 300:
! 301: /* Changes the window size associated with the pty. */
! 302:
! 303: void pty_change_window_size(int ptyfd, int row, int col,
! 304: int xpixel, int ypixel)
! 305: {
! 306: struct winsize w;
! 307: w.ws_row = row;
! 308: w.ws_col = col;
! 309: w.ws_xpixel = xpixel;
! 310: w.ws_ypixel = ypixel;
! 311: (void)ioctl(ptyfd, TIOCSWINSZ, &w);
! 312: }
! 313: