Annotation of src/usr.bin/ssh/pty.c, Revision 1.18
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".
1.7 deraadt 12: */
1.1 deraadt 13:
14: #include "includes.h"
1.18 ! deraadt 15: RCSID("$OpenBSD: pty.c,v 1.17 2000/12/12 22:50:21 ho Exp $");
1.1 deraadt 16:
1.10 deraadt 17: #include <util.h>
1.1 deraadt 18: #include "pty.h"
19: #include "ssh.h"
20:
21: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
22: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
23: #undef HAVE_DEV_PTMX
24: #endif
25:
26: #ifndef O_NOCTTY
27: #define O_NOCTTY 0
28: #endif
29:
1.8 markus 30: /*
31: * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
32: * 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: */
1.1 deraadt 36:
1.13 markus 37: int
1.9 deraadt 38: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
1.1 deraadt 39: {
1.9 deraadt 40: #if defined(HAVE_OPENPTY) || defined(BSD4_4)
1.6 markus 41: /* openpty(3) exists in OSF/1 and some other os'es */
1.9 deraadt 42: char buf[64];
1.6 markus 43: int i;
1.1 deraadt 44:
1.9 deraadt 45: i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
1.6 markus 46: if (i < 0) {
47: error("openpty: %.100s", strerror(errno));
48: return 0;
49: }
1.9 deraadt 50: strlcpy(namebuf, buf, namebuflen); /* possible truncation */
1.6 markus 51: return 1;
1.1 deraadt 52: #else /* HAVE_OPENPTY */
53: #ifdef HAVE__GETPTY
1.8 markus 54: /*
55: * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
56: * pty's automagically when needed
57: */
1.6 markus 58: char *slave;
59:
60: slave = _getpty(ptyfd, O_RDWR, 0622, 0);
61: if (slave == NULL) {
62: error("_getpty: %.100s", strerror(errno));
63: return 0;
64: }
1.9 deraadt 65: strlcpy(namebuf, slave, namebuflen);
1.6 markus 66: /* Open the slave side. */
67: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
68: if (*ttyfd < 0) {
69: error("%.200s: %.100s", namebuf, strerror(errno));
70: close(*ptyfd);
71: return 0;
72: }
73: return 1;
1.1 deraadt 74: #else /* HAVE__GETPTY */
75: #ifdef HAVE_DEV_PTMX
1.8 markus 76: /*
77: * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
78: * also has bsd-style ptys, but they simply do not work.)
79: */
1.6 markus 80: int ptm;
81: char *pts;
82:
83: ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
84: if (ptm < 0) {
85: error("/dev/ptmx: %.100s", strerror(errno));
86: return 0;
87: }
88: if (grantpt(ptm) < 0) {
89: error("grantpt: %.100s", strerror(errno));
90: return 0;
91: }
92: if (unlockpt(ptm) < 0) {
93: error("unlockpt: %.100s", strerror(errno));
94: return 0;
95: }
96: pts = ptsname(ptm);
97: if (pts == NULL)
98: error("Slave pty side name could not be obtained.");
1.9 deraadt 99: strlcpy(namebuf, pts, namebuflen);
1.6 markus 100: *ptyfd = ptm;
101:
102: /* Open the slave side. */
103: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
104: if (*ttyfd < 0) {
105: error("%.100s: %.100s", namebuf, strerror(errno));
106: close(*ptyfd);
107: return 0;
108: }
1.8 markus 109: /* Push the appropriate streams modules, as described in Solaris pts(7). */
1.6 markus 110: if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
111: error("ioctl I_PUSH ptem: %.100s", strerror(errno));
112: if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
113: error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
114: if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
115: error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
116: return 1;
1.1 deraadt 117: #else /* HAVE_DEV_PTMX */
118: #ifdef HAVE_DEV_PTS_AND_PTC
1.6 markus 119: /* AIX-style pty code. */
120: const char *name;
1.1 deraadt 121:
1.6 markus 122: *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
123: if (*ptyfd < 0) {
124: error("Could not open /dev/ptc: %.100s", strerror(errno));
125: return 0;
126: }
127: name = ttyname(*ptyfd);
128: if (!name)
129: fatal("Open of /dev/ptc returns device for which ttyname fails.");
1.9 deraadt 130: strlcpy(namebuf, name, namebuflen);
1.6 markus 131: *ttyfd = open(name, O_RDWR | O_NOCTTY);
132: if (*ttyfd < 0) {
133: error("Could not open pty slave side %.100s: %.100s",
134: name, strerror(errno));
135: close(*ptyfd);
136: return 0;
137: }
138: return 1;
1.1 deraadt 139: #else /* HAVE_DEV_PTS_AND_PTC */
1.6 markus 140: /* BSD-style pty code. */
141: char buf[64];
142: int i;
1.8 markus 143: const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
1.6 markus 144: const char *ptyminors = "0123456789abcdef";
145: int num_minors = strlen(ptyminors);
146: int num_ptys = strlen(ptymajors) * num_minors;
147:
148: for (i = 0; i < num_ptys; i++) {
149: snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
150: ptyminors[i % num_minors]);
151: *ptyfd = open(buf, O_RDWR | O_NOCTTY);
152: if (*ptyfd < 0)
153: continue;
1.11 markus 154: snprintf(namebuf, namebuflen, "/dev/tty%c%c",
1.9 deraadt 155: ptymajors[i / num_minors], ptyminors[i % num_minors]);
1.6 markus 156:
157: /* Open the slave side. */
158: *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
159: if (*ttyfd < 0) {
160: error("%.100s: %.100s", namebuf, strerror(errno));
161: close(*ptyfd);
162: return 0;
163: }
164: return 1;
165: }
166: return 0;
1.1 deraadt 167: #endif /* HAVE_DEV_PTS_AND_PTC */
168: #endif /* HAVE_DEV_PTMX */
169: #endif /* HAVE__GETPTY */
170: #endif /* HAVE_OPENPTY */
171: }
172:
1.6 markus 173: /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
1.1 deraadt 174:
1.13 markus 175: void
1.6 markus 176: pty_release(const char *ttyname)
1.1 deraadt 177: {
1.6 markus 178: if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
1.12 markus 179: error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
1.6 markus 180: if (chmod(ttyname, (mode_t) 0666) < 0)
1.12 markus 181: error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
1.1 deraadt 182: }
183:
184: /* Makes the tty the processes controlling tty and sets it to sane modes. */
185:
1.13 markus 186: void
1.6 markus 187: pty_make_controlling_tty(int *ttyfd, const char *ttyname)
1.1 deraadt 188: {
1.6 markus 189: int fd;
1.1 deraadt 190:
1.6 markus 191: /* First disconnect from the old controlling tty. */
1.1 deraadt 192: #ifdef TIOCNOTTY
1.6 markus 193: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
194: if (fd >= 0) {
195: (void) ioctl(fd, TIOCNOTTY, NULL);
196: close(fd);
197: }
1.1 deraadt 198: #endif /* TIOCNOTTY */
1.6 markus 199: if (setsid() < 0)
200: error("setsid: %.100s", strerror(errno));
1.1 deraadt 201:
1.8 markus 202: /*
203: * Verify that we are successfully disconnected from the controlling
204: * tty.
205: */
1.6 markus 206: fd = open("/dev/tty", O_RDWR | O_NOCTTY);
207: if (fd >= 0) {
208: error("Failed to disconnect from controlling tty.");
209: close(fd);
210: }
211: /* Make it our controlling tty. */
1.1 deraadt 212: #ifdef TIOCSCTTY
1.6 markus 213: debug("Setting controlling tty using TIOCSCTTY.");
1.8 markus 214: /*
215: * We ignore errors from this, because HPSUX defines TIOCSCTTY, but
216: * returns EINVAL with these arguments, and there is absolutely no
217: * documentation.
218: */
1.6 markus 219: ioctl(*ttyfd, TIOCSCTTY, NULL);
1.1 deraadt 220: #endif /* TIOCSCTTY */
1.6 markus 221: fd = open(ttyname, O_RDWR);
222: if (fd < 0)
223: error("%.100s: %.100s", ttyname, strerror(errno));
224: else
225: close(fd);
226:
227: /* Verify that we now have a controlling tty. */
228: fd = open("/dev/tty", O_WRONLY);
229: if (fd < 0)
230: error("open /dev/tty failed - could not set controlling tty: %.100s",
231: strerror(errno));
232: else {
233: close(fd);
234: }
1.1 deraadt 235: }
236:
237: /* Changes the window size associated with the pty. */
238:
1.13 markus 239: void
1.6 markus 240: pty_change_window_size(int ptyfd, int row, int col,
241: int xpixel, int ypixel)
1.1 deraadt 242: {
1.6 markus 243: struct winsize w;
244: w.ws_row = row;
245: w.ws_col = col;
246: w.ws_xpixel = xpixel;
247: w.ws_ypixel = ypixel;
248: (void) ioctl(ptyfd, TIOCSWINSZ, &w);
1.12 markus 249: }
250:
251: void
252: pty_setowner(struct passwd *pw, const char *ttyname)
253: {
254: struct group *grp;
255: gid_t gid;
256: mode_t mode;
1.17 ho 257: struct stat st;
1.12 markus 258:
259: /* Determine the group to make the owner of the tty. */
260: grp = getgrnam("tty");
261: if (grp) {
262: gid = grp->gr_gid;
263: mode = S_IRUSR | S_IWUSR | S_IWGRP;
264: } else {
265: gid = pw->pw_gid;
266: mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
267: }
268:
1.17 ho 269: /*
270: * Change owner and mode of the tty as required.
271: * Warn but continue if filesystem is read-only and the uids match.
272: */
1.18 ! deraadt 273: if (stat(ttyname, &st))
1.17 ho 274: fatal("stat(%.100s) failed: %.100s", ttyname,
275: strerror(errno));
276:
277: if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
1.18 ! deraadt 278: if (chown(ttyname, pw->pw_uid, gid) < 0) {
! 279: if (errno == EROFS && st.st_uid == pw->pw_uid)
1.17 ho 280: error("chown(%.100s, %d, %d) failed: %.100s",
281: ttyname, pw->pw_uid, gid,
282: strerror(errno));
283: else
284: fatal("chown(%.100s, %d, %d) failed: %.100s",
285: ttyname, pw->pw_uid, gid,
286: strerror(errno));
287: }
288: }
289:
290: if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
1.18 ! deraadt 291: if (chmod(ttyname, mode) < 0) {
! 292: if (errno == EROFS &&
! 293: (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
1.17 ho 294: error("chmod(%.100s, 0%o) failed: %.100s",
295: ttyname, mode, strerror(errno));
296: else
297: fatal("chmod(%.100s, 0%o) failed: %.100s",
298: ttyname, mode, strerror(errno));
299: }
300: }
1.1 deraadt 301: }