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