Annotation of src/usr.bin/ssh/pty.c, Revision 1.3
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.3 ! deraadt 17: RCSID("$Id: pty.c,v 1.2 1999/09/29 21:15:54 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: #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: /* BSD-style pty code. */
161:
162: char buf[64];
163: int i;
164: const char *ptymajors =
165: "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
166: const char *ptyminors = "0123456789abcdef";
167: int num_minors = strlen(ptyminors);
168: int num_ptys = strlen(ptymajors) * num_minors;
169:
170: for (i = 0; i < num_ptys; i++)
171: {
172: sprintf(buf, "/dev/pty%c%c", ptymajors[i / num_minors],
173: ptyminors[i % num_minors]);
174: *ptyfd = open(buf, O_RDWR|O_NOCTTY);
175: if (*ptyfd < 0)
176: continue;
177: sprintf(namebuf, "/dev/tty%c%c", ptymajors[i / num_minors],
178: ptyminors[i % num_minors]);
179:
180: /* Open the slave side. */
181: *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
182: if (*ttyfd < 0)
183: {
184: error("%.100s: %.100s", namebuf, strerror(errno));
185: close(*ptyfd);
186: return 0;
187: }
188: return 1;
189: }
190: return 0;
191: #endif /* HAVE_DEV_PTS_AND_PTC */
192: #endif /* HAVE_DEV_PTMX */
193: #endif /* HAVE__GETPTY */
194: #endif /* HAVE_OPENPTY */
195: }
196:
197: /* Releases the tty. Its ownership is returned to root, and permissions to
198: 0666. */
199:
200: void pty_release(const char *ttyname)
201: {
202: if (chown(ttyname, (uid_t)0, (gid_t)0) < 0)
203: debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
204: if (chmod(ttyname, (mode_t)0666) < 0)
205: debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
206: }
207:
208: /* Makes the tty the processes controlling tty and sets it to sane modes. */
209:
210: void pty_make_controlling_tty(int *ttyfd, const char *ttyname)
211: {
212: int fd;
213:
214: /* First disconnect from the old controlling tty. */
215: #ifdef TIOCNOTTY
216: fd = open("/dev/tty", O_RDWR|O_NOCTTY);
217: if (fd >= 0)
218: {
219: (void)ioctl(fd, TIOCNOTTY, NULL);
220: close(fd);
221: }
222: #endif /* TIOCNOTTY */
223: if (setsid() < 0)
224: error("setsid: %.100s", strerror(errno));
225:
226: /* Verify that we are successfully disconnected from the controlling tty. */
227: fd = open("/dev/tty", O_RDWR|O_NOCTTY);
228: if (fd >= 0)
229: {
230: error("Failed to disconnect from controlling tty.");
231: close(fd);
232: }
233:
234: /* Make it our controlling tty. */
235: #ifdef TIOCSCTTY
236: debug("Setting controlling tty using TIOCSCTTY.");
237: /* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns
238: EINVAL with these arguments, and there is absolutely no documentation. */
239: ioctl(*ttyfd, TIOCSCTTY, NULL);
240: #endif /* TIOCSCTTY */
241: fd = open(ttyname, O_RDWR);
242: if (fd < 0)
243: error("%.100s: %.100s", ttyname, strerror(errno));
244: else
245: close(fd);
246:
247: /* Verify that we now have a controlling tty. */
248: fd = open("/dev/tty", O_WRONLY);
249: if (fd < 0)
250: error("open /dev/tty failed - could not set controlling tty: %.100s",
251: strerror(errno));
252: else
253: {
254: close(fd);
255: #ifdef HAVE_VHANGUP
256: signal(SIGHUP, SIG_IGN);
257: vhangup();
258: signal(SIGHUP, SIG_DFL);
259: fd = open(ttyname, O_RDWR);
260: if (fd == -1)
261: error("pty_make_controlling_tty: reopening controlling tty after vhangup failed for %.100s",
262: ttyname);
263: close(*ttyfd);
264: *ttyfd = fd;
265: #endif /* HAVE_VHANGUP */
266: }
267: }
268:
269: /* Changes the window size associated with the pty. */
270:
271: void pty_change_window_size(int ptyfd, int row, int col,
272: int xpixel, int ypixel)
273: {
274: struct winsize w;
275: w.ws_row = row;
276: w.ws_col = col;
277: w.ws_xpixel = xpixel;
278: w.ws_ypixel = ypixel;
279: (void)ioctl(ptyfd, TIOCSWINSZ, &w);
280: }
281: