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