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