blob: 34ed48d617037ec60ffa32db65ea6f68ade0bb62 [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 Miller95def091999-11-25 00:26:21 +110017RCSID("$Id: pty.c,v 1.4 1999/11/24 13:26:22 damien Exp $");
18
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
35/* Allocates and opens a pty. Returns 0 if no pty could be allocated,
36 or nonzero if a pty was successfully allocated. On success, open file
Damien Miller95def091999-11-25 00:26:21 +110037 descriptors for the pty and tty sides and the name of the tty side are
Damien Millerd4a8b7e1999-10-27 13:42:43 +100038 returned (the buffer must be able to hold at least 64 characters). */
39
Damien Miller95def091999-11-25 00:26:21 +110040int
41pty_allocate(int *ptyfd, int *ttyfd, char *namebuf)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100042{
43#ifdef HAVE_OPENPTY
Damien Miller95def091999-11-25 00:26:21 +110044 /* openpty(3) exists in OSF/1 and some other os'es */
45 int i;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100046
Damien Miller95def091999-11-25 00:26:21 +110047 i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL);
48 if (i < 0) {
49 error("openpty: %.100s", strerror(errno));
50 return 0;
51 }
52 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100053#else /* HAVE_OPENPTY */
54#ifdef HAVE__GETPTY
Damien Miller95def091999-11-25 00:26:21 +110055 /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates
56 more pty's automagically when needed */
57 char *slave;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100058
Damien Miller95def091999-11-25 00:26:21 +110059 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;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100073#else /* HAVE__GETPTY */
74#ifdef HAVE_DEV_PTMX
Damien Miller95def091999-11-25 00:26:21 +110075 /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
76 also has bsd-style ptys, but they simply do not work.) */
77 int ptm;
78 char *pts;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100079
Damien Miller95def091999-11-25 00:26:21 +110080 ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
81 if (ptm < 0) {
82 error("/dev/ptmx: %.100s", strerror(errno));
83 return 0;
84 }
85 if (grantpt(ptm) < 0) {
86 error("grantpt: %.100s", strerror(errno));
87 return 0;
88 }
89 if (unlockpt(ptm) < 0) {
90 error("unlockpt: %.100s", strerror(errno));
91 return 0;
92 }
93 pts = ptsname(ptm);
94 if (pts == NULL)
95 error("Slave pty side name could not be obtained.");
96 strcpy(namebuf, pts);
97 *ptyfd = ptm;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100098
Damien Miller95def091999-11-25 00:26:21 +110099 /* Open the slave side. */
100 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
101 if (*ttyfd < 0) {
102 error("%.100s: %.100s", namebuf, strerror(errno));
103 close(*ptyfd);
104 return 0;
105 }
106 /* Push the appropriate streams modules, as described in Solaris
107 pts(7). */
108 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
109 error("ioctl I_PUSH ptem: %.100s", strerror(errno));
110 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
111 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
112 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
113 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
114 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000115#else /* HAVE_DEV_PTMX */
116#ifdef HAVE_DEV_PTS_AND_PTC
Damien Miller95def091999-11-25 00:26:21 +1100117 /* AIX-style pty code. */
118 const char *name;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000119
Damien Miller95def091999-11-25 00:26:21 +1100120 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
121 if (*ptyfd < 0) {
122 error("Could not open /dev/ptc: %.100s", strerror(errno));
123 return 0;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000124 }
Damien Miller95def091999-11-25 00:26:21 +1100125 name = ttyname(*ptyfd);
126 if (!name)
127 fatal("Open of /dev/ptc returns device for which ttyname fails.");
128 strcpy(namebuf, name);
129 *ttyfd = open(name, O_RDWR | O_NOCTTY);
130 if (*ttyfd < 0) {
131 error("Could not open pty slave side %.100s: %.100s",
132 name, strerror(errno));
133 close(*ptyfd);
134 return 0;
135 }
136 return 1;
137#else /* HAVE_DEV_PTS_AND_PTC */
138 /* BSD-style pty code. */
139 char buf[64];
140 int i;
141 const char *ptymajors =
142 "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
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;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000166#endif /* HAVE_DEV_PTS_AND_PTC */
167#endif /* HAVE_DEV_PTMX */
168#endif /* HAVE__GETPTY */
169#endif /* HAVE_OPENPTY */
170}
171
Damien Miller95def091999-11-25 00:26:21 +1100172/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000173
Damien Miller95def091999-11-25 00:26:21 +1100174void
175pty_release(const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000176{
Damien Miller95def091999-11-25 00:26:21 +1100177 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));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000181}
182
183/* Makes the tty the processes controlling tty and sets it to sane modes. */
184
Damien Miller95def091999-11-25 00:26:21 +1100185void
186pty_make_controlling_tty(int *ttyfd, const char *ttyname)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000187{
Damien Miller95def091999-11-25 00:26:21 +1100188 int fd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000189
Damien Miller95def091999-11-25 00:26:21 +1100190 /* First disconnect from the old controlling tty. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000191#ifdef TIOCNOTTY
Damien Miller95def091999-11-25 00:26:21 +1100192 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
193 if (fd >= 0) {
194 (void) ioctl(fd, TIOCNOTTY, NULL);
195 close(fd);
196 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000197#endif /* TIOCNOTTY */
Damien Miller95def091999-11-25 00:26:21 +1100198 if (setsid() < 0)
199 error("setsid: %.100s", strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000200
Damien Miller95def091999-11-25 00:26:21 +1100201 /* Verify that we are successfully disconnected from the
202 controlling tty. */
203 fd = open("/dev/tty", O_RDWR | O_NOCTTY);
204 if (fd >= 0) {
205 error("Failed to disconnect from controlling tty.");
206 close(fd);
207 }
208 /* Make it our controlling tty. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000209#ifdef TIOCSCTTY
Damien Miller95def091999-11-25 00:26:21 +1100210 debug("Setting controlling tty using TIOCSCTTY.");
211 /* We ignore errors from this, because HPSUX defines TIOCSCTTY,
212 but returns EINVAL with these arguments, and there is
213 absolutely no documentation. */
214 ioctl(*ttyfd, TIOCSCTTY, NULL);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000215#endif /* TIOCSCTTY */
Damien Miller95def091999-11-25 00:26:21 +1100216 fd = open(ttyname, O_RDWR);
217 if (fd < 0)
218 error("%.100s: %.100s", ttyname, strerror(errno));
219 else
220 close(fd);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000221
Damien Miller95def091999-11-25 00:26:21 +1100222 /* Verify that we now have a controlling tty. */
223 fd = open("/dev/tty", O_WRONLY);
224 if (fd < 0)
225 error("open /dev/tty failed - could not set controlling tty: %.100s",
226 strerror(errno));
227 else {
228 close(fd);
229 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000230}
231
232/* Changes the window size associated with the pty. */
233
Damien Miller95def091999-11-25 00:26:21 +1100234void
235pty_change_window_size(int ptyfd, int row, int col,
236 int xpixel, int ypixel)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000237{
Damien Miller95def091999-11-25 00:26:21 +1100238 struct winsize w;
239 w.ws_row = row;
240 w.ws_col = col;
241 w.ws_xpixel = xpixel;
242 w.ws_ypixel = ypixel;
243 (void) ioctl(ptyfd, TIOCSWINSZ, &w);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000244}