Annotation of src/usr.bin/ssh/sshpty.c, Revision 1.20
1.20 ! stevesk 1: /* $OpenBSD: sshpty.c,v 1.19 2006/03/25 13:17:03 djm Exp $ */
1.1 djm 2: /*
3: * Author: Tatu Ylonen <ylo@cs.hut.fi>
4: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5: * All rights reserved
6: * Allocating a pseudo-terminal, and making it the controlling tty.
7: *
8: * As far as I am concerned, the code I have written for this software
9: * can be used freely for any purpose. Any derived versions of this
10: * software must be clearly marked as such, and if the derived work is
11: * incompatible with the protocol description in the RFC file, it must be
12: * called by a name other than "ssh" or "Secure Shell".
13: */
14:
15: #include "includes.h"
1.15 stevesk 16:
17: #include <sys/ioctl.h>
1.16 stevesk 18: #include <sys/types.h>
19: #include <sys/stat.h>
1.1 djm 20:
1.20 ! stevesk 21: #include <grp.h>
1.14 stevesk 22: #include <paths.h>
1.13 stevesk 23: #include <termios.h>
1.1 djm 24: #include <util.h>
1.13 stevesk 25:
1.1 djm 26: #include "sshpty.h"
27: #include "log.h"
28:
29: /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
30: #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
31: #undef HAVE_DEV_PTMX
32: #endif
33:
34: #ifndef O_NOCTTY
35: #define O_NOCTTY 0
36: #endif
37:
38: /*
39: * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
40: * nonzero if a pty was successfully allocated. On success, open file
41: * descriptors for the pty and tty sides and the name of the tty side are
42: * returned (the buffer must be able to hold at least 64 characters).
43: */
44:
45: int
1.18 deraadt 46: pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
1.1 djm 47: {
48: char buf[64];
49: int i;
50:
51: i = openpty(ptyfd, ttyfd, buf, NULL, NULL);
52: if (i < 0) {
53: error("openpty: %.100s", strerror(errno));
54: return 0;
55: }
56: strlcpy(namebuf, buf, namebuflen); /* possible truncation */
57: return 1;
58: }
59:
60: /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
61:
62: void
1.12 avsm 63: pty_release(const char *tty)
1.1 djm 64: {
1.12 avsm 65: if (chown(tty, (uid_t) 0, (gid_t) 0) < 0)
66: error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno));
67: if (chmod(tty, (mode_t) 0666) < 0)
68: error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno));
1.1 djm 69: }
70:
1.10 markus 71: /* Makes the tty the process's controlling tty and sets it to sane modes. */
1.1 djm 72:
73: void
1.12 avsm 74: pty_make_controlling_tty(int *ttyfd, const char *tty)
1.1 djm 75: {
76: int fd;
77:
78: /* First disconnect from the old controlling tty. */
79: #ifdef TIOCNOTTY
80: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
81: if (fd >= 0) {
82: (void) ioctl(fd, TIOCNOTTY, NULL);
83: close(fd);
84: }
85: #endif /* TIOCNOTTY */
86: if (setsid() < 0)
87: error("setsid: %.100s", strerror(errno));
88:
89: /*
90: * Verify that we are successfully disconnected from the controlling
91: * tty.
92: */
93: fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
94: if (fd >= 0) {
95: error("Failed to disconnect from controlling tty.");
96: close(fd);
97: }
98: /* Make it our controlling tty. */
99: #ifdef TIOCSCTTY
100: debug("Setting controlling tty using TIOCSCTTY.");
101: if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
102: error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
103: #endif /* TIOCSCTTY */
1.12 avsm 104: fd = open(tty, O_RDWR);
1.1 djm 105: if (fd < 0)
1.12 avsm 106: error("%.100s: %.100s", tty, strerror(errno));
1.1 djm 107: else
108: close(fd);
109:
110: /* Verify that we now have a controlling tty. */
111: fd = open(_PATH_TTY, O_WRONLY);
112: if (fd < 0)
113: error("open /dev/tty failed - could not set controlling tty: %.100s",
1.4 deraadt 114: strerror(errno));
1.6 deraadt 115: else
1.1 djm 116: close(fd);
117: }
118:
119: /* Changes the window size associated with the pty. */
120:
121: void
1.18 deraadt 122: pty_change_window_size(int ptyfd, u_int row, u_int col,
123: u_int xpixel, u_int ypixel)
1.1 djm 124: {
125: struct winsize w;
1.6 deraadt 126:
1.18 deraadt 127: /* may truncate u_int -> u_short */
1.1 djm 128: w.ws_row = row;
129: w.ws_col = col;
130: w.ws_xpixel = xpixel;
131: w.ws_ypixel = ypixel;
132: (void) ioctl(ptyfd, TIOCSWINSZ, &w);
133: }
134:
135: void
1.12 avsm 136: pty_setowner(struct passwd *pw, const char *tty)
1.1 djm 137: {
138: struct group *grp;
139: gid_t gid;
140: mode_t mode;
141: struct stat st;
142:
143: /* Determine the group to make the owner of the tty. */
144: grp = getgrnam("tty");
145: if (grp) {
146: gid = grp->gr_gid;
147: mode = S_IRUSR | S_IWUSR | S_IWGRP;
148: } else {
149: gid = pw->pw_gid;
150: mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
151: }
152:
153: /*
154: * Change owner and mode of the tty as required.
1.3 markus 155: * Warn but continue if filesystem is read-only and the uids match/
156: * tty is owned by root.
1.1 djm 157: */
1.12 avsm 158: if (stat(tty, &st))
159: fatal("stat(%.100s) failed: %.100s", tty,
1.1 djm 160: strerror(errno));
161:
162: if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
1.12 avsm 163: if (chown(tty, pw->pw_uid, gid) < 0) {
1.4 deraadt 164: if (errno == EROFS &&
1.6 deraadt 165: (st.st_uid == pw->pw_uid || st.st_uid == 0))
1.8 markus 166: debug("chown(%.100s, %u, %u) failed: %.100s",
1.12 avsm 167: tty, (u_int)pw->pw_uid, (u_int)gid,
1.4 deraadt 168: strerror(errno));
1.1 djm 169: else
1.5 deraadt 170: fatal("chown(%.100s, %u, %u) failed: %.100s",
1.12 avsm 171: tty, (u_int)pw->pw_uid, (u_int)gid,
1.4 deraadt 172: strerror(errno));
1.1 djm 173: }
174: }
175:
176: if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
1.12 avsm 177: if (chmod(tty, mode) < 0) {
1.1 djm 178: if (errno == EROFS &&
179: (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
1.8 markus 180: debug("chmod(%.100s, 0%o) failed: %.100s",
1.12 avsm 181: tty, (u_int)mode, strerror(errno));
1.1 djm 182: else
183: fatal("chmod(%.100s, 0%o) failed: %.100s",
1.12 avsm 184: tty, (u_int)mode, strerror(errno));
1.1 djm 185: }
186: }
187: }