blob: e468421380ed40d3bac37f3162561cdd8c05d8eb [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
Damien Miller95def091999-11-25 00:26:21 +11002 *
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 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100015
16#include "includes.h"
Damien Miller5428f641999-11-25 11:54:57 +110017RCSID("$Id: pty.c,v 1.5 1999/11/25 00:54:59 damien Exp $");
Damien Miller95def091999-11-25 00:26:21 +110018
19#include "pty.h"
20#include "ssh.h"
Damien Miller356a0b01999-11-08 15:30:59 +110021
22#ifdef HAVE_PTY_H
Damien Miller356a0b01999-11-08 15:30:59 +110023#include <pty.h>
24#endif /* HAVE_PTY_H */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100025
Damien Millerd4a8b7e1999-10-27 13:42:43 +100026/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
27#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
28#undef HAVE_DEV_PTMX
29#endif
30
31#ifndef O_NOCTTY
32#define O_NOCTTY 0
33#endif
34
Damien Miller5428f641999-11-25 11:54:57 +110035/*
36 * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
37 * nonzero if a pty was successfully allocated. On success, open file
38 * descriptors for the pty and tty sides and the name of the tty side are
39 * returned (the buffer must be able to hold at least 64 characters).
40 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100041
Damien Miller95def091999-11-25 00:26:21 +110042int
43pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100044{
45#ifdef HAVE_OPENPTY
Damien Miller95def091999-11-25 00:26:21 +110046 /* openpty(3) exists in OSF/1 and some other os'es */
47 int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100048
Damien Miller95def091999-11-25 00:26:21 +110049 i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
50 if (i < 0) {
51 error("openpty: %.100s", strerror(errno));
52 return 0;
53 }
54 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100055#else /* HAVE_OPENPTY */
56#ifdef HAVE__GETPTY
Damien Miller5428f641999-11-25 11:54:57 +110057 /*
58 * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
59 * pty's automagically when needed
60 */
Damien Miller95def091999-11-25 00:26:21 +110061 char *slave;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100062
Damien Miller95def091999-11-25 00:26:21 +110063 slave = _getpty(ptyfd, O_RDWR, 0622, 0);
64 if (slave == NULL) {
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 error("%.200s: %.100s", namebuf, strerror(errno));
73 close(*ptyfd);
74 return 0;
75 }
76 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100077#else /* HAVE__GETPTY */
78#ifdef HAVE_DEV_PTMX
Damien Miller5428f641999-11-25 11:54:57 +110079 /*
80 * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
81 * also has bsd-style ptys, but they simply do not work.)
82 */
Damien Miller95def091999-11-25 00:26:21 +110083 int ptm;
84 char *pts;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100085
Damien Miller95def091999-11-25 00:26:21 +110086 ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
87 if (ptm < 0) {
88 error("/dev/ptmx: %.100s", strerror(errno));
89 return 0;
90 }
91 if (grantpt(ptm) < 0) {
92 error("grantpt: %.100s", strerror(errno));
93 return 0;
94 }
95 if (unlockpt(ptm) < 0) {
96 error("unlockpt: %.100s", strerror(errno));
97 return 0;
98 }
99 pts = ptsname(ptm);
100 if (pts == NULL)
101 error("Slave pty side name could not be obtained.");
102 strcpy(namebuf, pts);
103 *ptyfd = ptm;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000104
Damien Miller95def091999-11-25 00:26:21 +1100105 /* Open the slave side. */
106 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
107 if (*ttyfd < 0) {
108 error("%.100s: %.100s", namebuf, strerror(errno));
109 close(*ptyfd);
110 return 0;
111 }
Damien Miller5428f641999-11-25 11:54:57 +1100112 /* Push the appropriate streams modules, as described in Solaris pts(7). */
Damien Miller95def091999-11-25 00:26:21 +1100113 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
114 error("ioctl I_PUSH ptem: %.100s", strerror(errno));
115 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
116 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
117 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
118 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
119 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000120#else /* HAVE_DEV_PTMX */
121#ifdef HAVE_DEV_PTS_AND_PTC
Damien Miller95def091999-11-25 00:26:21 +1100122 /* AIX-style pty code. */
123 const char *name;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000124
Damien Miller95def091999-11-25 00:26:21 +1100125 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
126 if (*ptyfd < 0) {
127 error("Could not open /dev/ptc: %.100s", strerror(errno));
128 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000129 }
Damien Miller95def091999-11-25 00:26:21 +1100130 name = ttyname(*ptyfd);
131 if (!name)
132 fatal("Open of /dev/ptc returns device for which ttyname fails.");
133 strcpy(namebuf, name);
134 *ttyfd = open(name, O_RDWR | O_NOCTTY);
135 if (*ttyfd < 0) {
136 error("Could not open pty slave side %.100s: %.100s",
137 name, strerror(errno));
138 close(*ptyfd);
139 return 0;
140 }
141 return 1;
142#else /* HAVE_DEV_PTS_AND_PTC */
143 /* BSD-style pty code. */
144 char buf[64];
145 int i;
Damien Miller5428f641999-11-25 11:54:57 +1100146 const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
Damien Miller95def091999-11-25 00:26:21 +1100147 const char *ptyminors = "0123456789abcdef";
148 int num_minors = strlen(ptyminors);
149 int num_ptys = strlen(ptymajors) * num_minors;
150
151 for (i = 0; i < num_ptys; i++) {
152 snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
153 ptyminors[i % num_minors]);
154 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
155 if (*ptyfd < 0)
156 continue;
157 snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors],
158 ptyminors[i % num_minors]);
159
160 /* Open the slave side. */
161 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
162 if (*ttyfd < 0) {
163 error("%.100s: %.100s", namebuf, strerror(errno));
164 close(*ptyfd);
165 return 0;
166 }
167 return 1;
168 }
169 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000170#endif /* HAVE_DEV_PTS_AND_PTC */
171#endif /* HAVE_DEV_PTMX */
172#endif /* HAVE__GETPTY */
173#endif /* HAVE_OPENPTY */
174}
175
Damien Miller95def091999-11-25 00:26:21 +1100176/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000177
Damien Miller95def091999-11-25 00:26:21 +1100178void
179pty_release(const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000180{
Damien Miller95def091999-11-25 00:26:21 +1100181 if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
182 debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
183 if (chmod(ttyname, (mode_t) 0666) < 0)
184 debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000185}
186
187/* Makes the tty the processes controlling tty and sets it to sane modes. */
188
Damien Miller95def091999-11-25 00:26:21 +1100189void
190pty_make_controlling_tty(int *ttyfd, const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000191{
Damien Miller95def091999-11-25 00:26:21 +1100192 int fd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000193
Damien Miller95def091999-11-25 00:26:21 +1100194 /* First disconnect from the old controlling tty. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000195#ifdef TIOCNOTTY
Damien Miller95def091999-11-25 00:26:21 +1100196 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
197 if (fd >= 0) {
198 (void) ioctl(fd, TIOCNOTTY, NULL);
199 close(fd);
200 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000201#endif /* TIOCNOTTY */
Damien Miller95def091999-11-25 00:26:21 +1100202 if (setsid() < 0)
203 error("setsid: %.100s", strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000204
Damien Miller5428f641999-11-25 11:54:57 +1100205 /*
206 * Verify that we are successfully disconnected from the controlling
207 * tty.
208 */
Damien Miller95def091999-11-25 00:26:21 +1100209 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
210 if (fd >= 0) {
211 error("Failed to disconnect from controlling tty.");
212 close(fd);
213 }
214 /* Make it our controlling tty. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000215#ifdef TIOCSCTTY
Damien Miller95def091999-11-25 00:26:21 +1100216 debug("Setting controlling tty using TIOCSCTTY.");
Damien Miller5428f641999-11-25 11:54:57 +1100217 /*
218 * We ignore errors from this, because HPSUX defines TIOCSCTTY, but
219 * returns EINVAL with these arguments, and there is absolutely no
220 * documentation.
221 */
Damien Miller95def091999-11-25 00:26:21 +1100222 ioctl(*ttyfd, TIOCSCTTY, NULL);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000223#endif /* TIOCSCTTY */
Damien Miller95def091999-11-25 00:26:21 +1100224 fd = open(ttyname, O_RDWR);
225 if (fd < 0)
226 error("%.100s: %.100s", ttyname, strerror(errno));
227 else
228 close(fd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000229
Damien Miller95def091999-11-25 00:26:21 +1100230 /* Verify that we now have a controlling tty. */
231 fd = open("/dev/tty", O_WRONLY);
232 if (fd < 0)
233 error("open /dev/tty failed - could not set controlling tty: %.100s",
234 strerror(errno));
235 else {
236 close(fd);
237 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000238}
239
240/* Changes the window size associated with the pty. */
241
Damien Miller95def091999-11-25 00:26:21 +1100242void
243pty_change_window_size(int ptyfd, int row, int col,
244 int xpixel, int ypixel)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000245{
Damien Miller95def091999-11-25 00:26:21 +1100246 struct winsize w;
247 w.ws_row = row;
248 w.ws_col = col;
249 w.ws_xpixel = xpixel;
250 w.ws_ypixel = ypixel;
251 (void) ioctl(ptyfd, TIOCSWINSZ, &w);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000252}