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