1a2eb7b567692e7a3f435b1ee8ed26c63d395d5eaGreg Hartman/* $OpenBSD: sshpty.c,v 1.30 2015/07/30 23:09:15 djm Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Author: Tatu Ylonen <ylo@cs.hut.fi>
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *                    All rights reserved
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Allocating a pseudo-terminal, and making it the controlling tty.
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * As far as I am concerned, the code I have written for this software
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * can be used freely for any purpose.  Any derived versions of this
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * software must be clearly marked as such, and if the derived work is
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * incompatible with the protocol description in the RFC file, it must be
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * called by a name other than "ssh" or "Secure Shell".
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/ioctl.h>
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h>
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <signal.h>
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <errno.h>
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h>
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <grp.h>
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_PATHS_H
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <paths.h>
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <pwd.h>
29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdarg.h>
30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <termios.h>
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_UTIL_H
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <util.h>
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
35bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h>
36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "sshpty.h"
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h"
39bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "misc.h"
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_PTY_H
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <pty.h>
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifndef O_NOCTTY
46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define O_NOCTTY 0
47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
49bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef __APPLE__
50bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# include <AvailabilityMacros.h>
51bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#  define __APPLE_PRIVPTY__
53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman# endif
54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
57bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Allocates and opens a pty.  Returns 0 if no pty could be allocated, or
58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * nonzero if a pty was successfully allocated.  On success, open file
59bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * descriptors for the pty and tty sides and the name of the tty side are
60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * returned (the buffer must be able to hold at least 64 characters).
61bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
62bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
63bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
64bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
65bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* openpty(3) exists in OSF/1 and some other os'es */
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *name;
68bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int i;
69bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
70bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (i < 0) {
72bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("openpty: %.100s", strerror(errno));
73bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		return 0;
74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef ANDROID
760199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman	if (ptsname_r(*ptyfd, namebuf, namebuflen)) {
770199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman		fatal("openpty ptsname failed.");
780199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman		close(*ptyfd);
790199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman		*ptyfd = -1;
800199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman		return -1;
810199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman	}
820199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman	return 1;
83bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#else
84bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	name = ttyname(*ttyfd);
85bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (!name)
86bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		fatal("openpty returns device for which ttyname fails.");
87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
88bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	strlcpy(namebuf, name, namebuflen);	/* possible truncation */
89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	return 1;
900199da83f61c7a951b6e05ec844dabc0d3e04cd7Greg Hartman#endif
91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
92bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
93bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
95bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
96bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpty_release(const char *tty)
97bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
98a2eb7b567692e7a3f435b1ee8ed26c63d395d5eaGreg Hartman#if !defined(__APPLE_PRIVPTY__) && !defined(HAVE_OPENPTY)
99bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (chown(tty, (uid_t) 0, (gid_t) 0) < 0)
100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno));
101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (chmod(tty, (mode_t) 0666) < 0)
102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno));
103a2eb7b567692e7a3f435b1ee8ed26c63d395d5eaGreg Hartman#endif /* !__APPLE_PRIVPTY__ && !HAVE_OPENPTY */
104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
105bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
106bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Makes the tty the process's controlling tty and sets it to sane modes. */
107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
108bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
109bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpty_make_controlling_tty(int *ttyfd, const char *tty)
110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	int fd;
112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef _UNICOS
114bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (setsid() < 0)
115bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("setsid: %.100s", strerror(errno));
116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
117bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open(tty, O_RDWR|O_NOCTTY);
118bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd != -1) {
119bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		signal(SIGHUP, SIG_IGN);
120bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		ioctl(fd, TCVHUP, (char *)NULL);
121bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		signal(SIGHUP, SIG_DFL);
122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		setpgid(0, 0);
123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else {
125bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("Failed to disconnect from controlling tty.");
126bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
127bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	debug("Setting controlling tty using TCSETCTTY.");
129bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	ioctl(*ttyfd, TCSETCTTY, NULL);
130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open("/dev/tty", O_RDWR);
131bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd < 0)
132bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("%.100s: %.100s", tty, strerror(errno));
133bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	close(*ttyfd);
134bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	*ttyfd = fd;
135bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#else /* _UNICOS */
136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* First disconnect from the old controlling tty. */
138bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef TIOCNOTTY
139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd >= 0) {
141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		(void) ioctl(fd, TIOCNOTTY, NULL);
142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
144bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* TIOCNOTTY */
145bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (setsid() < 0)
146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("setsid: %.100s", strerror(errno));
147bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
148bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Verify that we are successfully disconnected from the controlling
150bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * tty.
151bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
152bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd >= 0) {
154bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("Failed to disconnect from controlling tty.");
155bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
156bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
157bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Make it our controlling tty. */
158bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef TIOCSCTTY
159bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	debug("Setting controlling tty using TIOCSCTTY.");
160bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
161bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
162bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* TIOCSCTTY */
163bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef NEED_SETPGRP
164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (setpgrp(0,0) < 0)
165bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("SETPGRP %s",strerror(errno));
166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* NEED_SETPGRP */
167bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open(tty, O_RDWR);
168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd < 0) {
169bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("%.100s: %.100s", tty, strerror(errno));
170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	} else {
171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Verify that we now have a controlling tty. */
174bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fd = open(_PATH_TTY, O_WRONLY);
175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fd < 0)
176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("open /dev/tty failed - could not set controlling tty: %.100s",
177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    strerror(errno));
178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	else
179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif /* _UNICOS */
181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Changes the window size associated with the pty. */
184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpty_change_window_size(int ptyfd, u_int row, u_int col,
187bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_int xpixel, u_int ypixel)
188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
189bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct winsize w;
190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
191bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* may truncate u_int -> u_short */
192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	w.ws_row = row;
193bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	w.ws_col = col;
194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	w.ws_xpixel = xpixel;
195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	w.ws_ypixel = ypixel;
196bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	(void) ioctl(ptyfd, TIOCSWINSZ, &w);
197bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
198bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
199bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanvoid
200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanpty_setowner(struct passwd *pw, const char *tty)
201bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct group *grp;
203bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	gid_t gid;
204bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	mode_t mode;
205bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct stat st;
206bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
207bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Determine the group to make the owner of the tty. */
208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	grp = getgrnam("tty");
209d059297112922cabb0c674840589be8db821fd9aAdam Langley	gid = (grp != NULL) ? grp->gr_gid : pw->pw_gid;
210a2eb7b567692e7a3f435b1ee8ed26c63d395d5eaGreg Hartman	mode = (grp != NULL) ? 0620 : 0600;
211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
212bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Change owner and mode of the tty as required.
214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * Warn but continue if filesystem is read-only and the uids match/
215bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * tty is owned by root.
216bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (stat(tty, &st))
218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		fatal("stat(%.100s) failed: %.100s", tty,
219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    strerror(errno));
220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
221bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef WITH_SELINUX
222bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	ssh_selinux_setup_pty(pw->pw_name, tty);
223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
224bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (chown(tty, pw->pw_uid, gid) < 0) {
227bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (errno == EROFS &&
228bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    (st.st_uid == pw->pw_uid || st.st_uid == 0))
229bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				debug("chown(%.100s, %u, %u) failed: %.100s",
230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    tty, (u_int)pw->pw_uid, (u_int)gid,
231bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    strerror(errno));
232bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			else
233bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				fatal("chown(%.100s, %u, %u) failed: %.100s",
234bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    tty, (u_int)pw->pw_uid, (u_int)gid,
235bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    strerror(errno));
236bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
238bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
239bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
240bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (chmod(tty, mode) < 0) {
241bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (errno == EROFS &&
242bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			    (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
243bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				debug("chmod(%.100s, 0%o) failed: %.100s",
244bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    tty, (u_int)mode, strerror(errno));
245bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			else
246bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				fatal("chmod(%.100s, 0%o) failed: %.100s",
247bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				    tty, (u_int)mode, strerror(errno));
248bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
249bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
251