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