Annotation of src/usr.bin/ssh/pty.c, Revision 1.15
1.1 deraadt 1: /*
1.7 deraadt 2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: * Allocating a pseudo-terminal, and making it the controlling tty.
1.13 markus 6: *
1.15 ! deraadt 7: * As far as I am concerned, the code I have written for this software
! 8: * can be used freely for any purpose. Any derived versions of this
! 9: * software must be clearly marked as such, and if the derived work is
! 10: * incompatible with the protocol description in the RFC file, it must be
! 11: * called by a name other than "ssh" or "Secure Shell".
! 12: *
! 13: *
! 14: * Copyright (c) 2000 Markus Friedl. All rights reserved.
! 15: *
! 16: * Redistribution and use in source and binary forms, with or without
! 17: * modification, are permitted provided that the following conditions
! 18: * are met:
! 19: * 1. Redistributions of source code must retain the above copyright
! 20: * notice, this list of conditions and the following disclaimer.
! 21: * 2. Redistributions in binary form must reproduce the above copyright
! 22: * notice, this list of conditions and the following disclaimer in the
! 23: * documentation and/or other materials provided with the distribution.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 28: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 29: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 30: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 31: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 32: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 33: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 34: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.7 deraadt 35: */
1.1 deraadt 36:
37: #include "includes.h"
1.15 ! deraadt 38: RCSID("$OpenBSD: pty.c,v 1.14 2000/06/20 01:39:43 markus Exp $");
1.1 deraadt 39:
1.10 deraadt 40: #include <util.h>
1.1 deraadt 41: #include "pty.h"
42: #include "ssh.h"
43:
44: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
45: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
46: #undef HAVE_DEV_PTMX
47: #endif
48:
49: #ifndef O_NOCTTY
50: #define O_NOCTTY 0
51: #endif
52:
1.8 markus 53: /*
54: * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
55: * nonzero if a pty was successfully allocated. On success, open file
56: * descriptors for the pty and tty sides and the name of the tty side are
57: * returned (the buffer must be able to hold at least 64 characters).
58: */
1.1 deraadt 59:
1.13 markus 60: int
1.9 deraadt 61: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
1.1 deraadt 62: {
1.9 deraadt 63: #if defined(HAVE_OPENPTY) || defined(BSD4_4)
1.6 markus 64: /* openpty(3) exists in OSF/1 and some other os'es */
1.9 deraadt 65: char buf[64];
1.6 markus 66: int i;
1.1 deraadt 67:
1.9 deraadt 68: i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
1.6 markus 69: if (i < 0) {
70: error("openpty: %.100s", strerror(errno));
71: return 0;
72: }
1.9 deraadt 73: strlcpy(namebuf, buf, namebuflen); /* possible truncation */
1.6 markus 74: return 1;
1.1 deraadt 75: #else /* HAVE_OPENPTY */
76: #ifdef HAVE__GETPTY
1.8 markus 77: /*
78: * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
79: * pty's automagically when needed
80: */
1.6 markus 81: char *slave;
82:
83: slave = _getpty(ptyfd, O_RDWR, 0622, 0);
84: if (slave == NULL) {
85: error("_getpty: %.100s", strerror(errno));
86: return 0;
87: }
1.9 deraadt 88: strlcpy(namebuf, slave, namebuflen);
1.6 markus 89: /* Open the slave side. */
90: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
91: if (*ttyfd < 0) {
92: error("%.200s: %.100s", namebuf, strerror(errno));
93: close(*ptyfd);
94: return 0;
95: }
96: return 1;
1.1 deraadt 97: #else /* HAVE__GETPTY */
98: #ifdef HAVE_DEV_PTMX
1.8 markus 99: /*
100: * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
101: * also has bsd-style ptys, but they simply do not work.)
102: */
1.6 markus 103: int ptm;
104: char *pts;
105:
106: ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
107: if (ptm < 0) {
108: error("/dev/ptmx: %.100s", strerror(errno));
109: return 0;
110: }
111: if (grantpt(ptm) < 0) {
112: error("grantpt: %.100s", strerror(errno));
113: return 0;
114: }
115: if (unlockpt(ptm) < 0) {
116: error("unlockpt: %.100s", strerror(errno));
117: return 0;
118: }
119: pts = ptsname(ptm);
120: if (pts == NULL)
121: error("Slave pty side name could not be obtained.");
1.9 deraadt 122: strlcpy(namebuf, pts, namebuflen);
1.6 markus 123: *ptyfd = ptm;
124:
125: /* Open the slave side. */
126: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
127: if (*ttyfd < 0) {
128: error("%.100s: %.100s", namebuf, strerror(errno));
129: close(*ptyfd);
130: return 0;
131: }
1.8 markus 132: /* Push the appropriate streams modules, as described in Solaris pts(7). */
1.6 markus 133: if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
134: error("ioctl I_PUSH ptem: %.100s", strerror(errno));
135: if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
136: error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
137: if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
138: error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
139: return 1;
1.1 deraadt 140: #else /* HAVE_DEV_PTMX */
141: #ifdef HAVE_DEV_PTS_AND_PTC
1.6 markus 142: /* AIX-style pty code. */
143: const char *name;
1.1 deraadt 144:
1.6 markus 145: *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
146: if (*ptyfd < 0) {
147: error("Could not open /dev/ptc: %.100s", strerror(errno));
148: return 0;
149: }
150: name = ttyname(*ptyfd);
151: if (!name)
152: fatal("Open of /dev/ptc returns device for which ttyname fails.");
1.9 deraadt 153: strlcpy(namebuf, name, namebuflen);
1.6 markus 154: *ttyfd = open(name, O_RDWR | O_NOCTTY);
155: if (*ttyfd < 0) {
156: error("Could not open pty slave side %.100s: %.100s",
157: name, strerror(errno));
158: close(*ptyfd);
159: return 0;
160: }
161: return 1;
1.1 deraadt 162: #else /* HAVE_DEV_PTS_AND_PTC */
1.6 markus 163: /* BSD-style pty code. */
164: char buf[64];
165: int i;
1.8 markus 166: const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
1.6 markus 167: const char *ptyminors = "0123456789abcdef";
168: int num_minors = strlen(ptyminors);
169: int num_ptys = strlen(ptymajors) * num_minors;
170:
171: for (i = 0; i < num_ptys; i++) {
172: snprintf(buf, sizeof 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;
1.11 markus 177: snprintf(namebuf, namebuflen, "/dev/tty%c%c",
1.9 deraadt 178: ptymajors[i / num_minors], ptyminors[i % num_minors]);
1.6 markus 179:
180: /* Open the slave side. */
181: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
182: if (*ttyfd < 0) {
183: error("%.100s: %.100s", namebuf, strerror(errno));
184: close(*ptyfd);
185: return 0;
186: }
187: return 1;
188: }
189: return 0;
1.1 deraadt 190: #endif /* HAVE_DEV_PTS_AND_PTC */
191: #endif /* HAVE_DEV_PTMX */
192: #endif /* HAVE__GETPTY */
193: #endif /* HAVE_OPENPTY */
194: }
195:
1.6 markus 196: /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
1.1 deraadt 197:
1.13 markus 198: void
1.6 markus 199: pty_release(const char *ttyname)
1.1 deraadt 200: {
1.6 markus 201: if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
1.12 markus 202: error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
1.6 markus 203: if (chmod(ttyname, (mode_t) 0666) < 0)
1.12 markus 204: error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
1.1 deraadt 205: }
206:
207: /* Makes the tty the processes controlling tty and sets it to sane modes. */
208:
1.13 markus 209: void
1.6 markus 210: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
1.1 deraadt 211: {
1.6 markus 212: int fd;
1.1 deraadt 213:
1.6 markus 214: /* First disconnect from the old controlling tty. */
1.1 deraadt 215: #ifdef TIOCNOTTY
1.6 markus 216: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
217: if (fd >= 0) {
218: (void) ioctl(fd, TIOCNOTTY, NULL);
219: close(fd);
220: }
1.1 deraadt 221: #endif /* TIOCNOTTY */
1.6 markus 222: if (setsid() < 0)
223: error("setsid: %.100s", strerror(errno));
1.1 deraadt 224:
1.8 markus 225: /*
226: * Verify that we are successfully disconnected from the controlling
227: * tty.
228: */
1.6 markus 229: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
230: if (fd >= 0) {
231: error("Failed to disconnect from controlling tty.");
232: close(fd);
233: }
234: /* Make it our controlling tty. */
1.1 deraadt 235: #ifdef TIOCSCTTY
1.6 markus 236: debug("Setting controlling tty using TIOCSCTTY.");
1.8 markus 237: /*
238: * We ignore errors from this, because HPSUX defines TIOCSCTTY, but
239: * returns EINVAL with these arguments, and there is absolutely no
240: * documentation.
241: */
1.6 markus 242: ioctl(*ttyfd, TIOCSCTTY, NULL);
1.1 deraadt 243: #endif /* TIOCSCTTY */
1.6 markus 244: fd = open(ttyname, O_RDWR);
245: if (fd < 0)
246: error("%.100s: %.100s", ttyname, strerror(errno));
247: else
248: close(fd);
249:
250: /* Verify that we now have a controlling tty. */
251: fd = open("/dev/tty", O_WRONLY);
252: if (fd < 0)
253: error("open /dev/tty failed - could not set controlling tty: %.100s",
254: strerror(errno));
255: else {
256: close(fd);
257: }
1.1 deraadt 258: }
259:
260: /* Changes the window size associated with the pty. */
261:
1.13 markus 262: void
1.6 markus 263: pty_change_window_size(int ptyfd, int row, int col,
264: int xpixel, int ypixel)
1.1 deraadt 265: {
1.6 markus 266: struct winsize w;
267: w.ws_row = row;
268: w.ws_col = col;
269: w.ws_xpixel = xpixel;
270: w.ws_ypixel = ypixel;
271: (void) ioctl(ptyfd, TIOCSWINSZ, &w);
1.12 markus 272: }
273:
274: void
275: pty_setowner(struct passwd *pw, const char *ttyname)
276: {
277: struct group *grp;
278: gid_t gid;
279: mode_t mode;
280:
281: /* Determine the group to make the owner of the tty. */
282: grp = getgrnam("tty");
283: if (grp) {
284: gid = grp->gr_gid;
285: mode = S_IRUSR | S_IWUSR | S_IWGRP;
286: } else {
287: gid = pw->pw_gid;
288: mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
289: }
290:
291: /* Change ownership of the tty. */
292: if (chown(ttyname, pw->pw_uid, gid) < 0)
293: fatal("chown(%.100s, %d, %d) failed: %.100s",
294: ttyname, pw->pw_uid, gid, strerror(errno));
295: if (chmod(ttyname, mode) < 0)
296: fatal("chmod(%.100s, 0%o) failed: %.100s",
297: ttyname, mode, strerror(errno));
1.1 deraadt 298: }