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