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