mirror of
https://github.com/openssh/openssh-portable.git
synced 2026-11-06 05:16:43 +00:00
used in sshd, and sshd is the only thing that calls this function. Move it into sshd.c and we no longer need to compile sshd against sshpty.c Part of bz3996 from Colin Watson OpenBSD-Commit-ID: cbfb0ecba5c63852d33e930d01f00586ce15ad1d
211 lines
5.3 KiB
C
211 lines
5.3 KiB
C
/* $OpenBSD: sshpty.c,v 1.36 2026/09/15 06:30:58 djm Exp $ */
|
|
/*
|
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
|
* All rights reserved
|
|
* Allocating a pseudo-terminal, and making it the controlling tty.
|
|
*
|
|
* As far as I am concerned, the code I have written for this software
|
|
* can be used freely for any purpose. Any derived versions of this
|
|
* software must be clearly marked as such, and if the derived work is
|
|
* incompatible with the protocol description in the RFC file, it must be
|
|
* called by a name other than "ssh" or "Secure Shell".
|
|
*/
|
|
|
|
#include "includes.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <grp.h>
|
|
#include <paths.h>
|
|
#include <pwd.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <util.h>
|
|
|
|
#include "sshpty.h"
|
|
#include "log.h"
|
|
#include "misc.h"
|
|
|
|
#ifdef HAVE_PTY_H
|
|
# include <pty.h>
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
# include <AvailabilityMacros.h>
|
|
# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
|
# define __APPLE_PRIVPTY__
|
|
# endif
|
|
#endif
|
|
|
|
/*
|
|
* Allocates and opens a pty. Returns 0 if no pty could be allocated, or
|
|
* nonzero if a pty was successfully allocated. On success, open file
|
|
* descriptors for the pty and tty sides and the name of the tty side are
|
|
* returned (the buffer must be able to hold at least 64 characters).
|
|
*/
|
|
|
|
int
|
|
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
|
|
{
|
|
/* openpty(3) exists in OSF/1 and some other os'es */
|
|
char *name;
|
|
int i;
|
|
|
|
i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
|
|
if (i == -1) {
|
|
error("openpty: %.100s", strerror(errno));
|
|
return 0;
|
|
}
|
|
name = ttyname(*ttyfd);
|
|
if (!name)
|
|
fatal("openpty returns device for which ttyname fails.");
|
|
|
|
strlcpy(namebuf, name, namebuflen); /* possible truncation */
|
|
return 1;
|
|
}
|
|
|
|
/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
|
|
|
|
void
|
|
pty_release(const char *tty)
|
|
{
|
|
#if !defined(__APPLE_PRIVPTY__) && !defined(HAVE_OPENPTY)
|
|
if (chown(tty, (uid_t) 0, (gid_t) 0) == -1)
|
|
error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno));
|
|
if (chmod(tty, (mode_t) 0666) == -1)
|
|
error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno));
|
|
#endif /* !__APPLE_PRIVPTY__ && !HAVE_OPENPTY */
|
|
}
|
|
|
|
/* Makes the tty the process's controlling tty and sets it to sane modes. */
|
|
|
|
void
|
|
pty_make_controlling_tty(int *ttyfd, const char *tty)
|
|
{
|
|
int fd;
|
|
|
|
/* First disconnect from the old controlling tty. */
|
|
#ifdef TIOCNOTTY
|
|
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
|
|
if (fd >= 0) {
|
|
(void) ioctl(fd, TIOCNOTTY, NULL);
|
|
close(fd);
|
|
}
|
|
#endif /* TIOCNOTTY */
|
|
if (setsid() == -1)
|
|
error("setsid: %.100s", strerror(errno));
|
|
|
|
/*
|
|
* Verify that we are successfully disconnected from the controlling
|
|
* tty.
|
|
*/
|
|
fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
|
|
if (fd >= 0) {
|
|
error("Failed to disconnect from controlling tty.");
|
|
close(fd);
|
|
}
|
|
/* Make it our controlling tty. */
|
|
#ifdef TIOCSCTTY
|
|
debug("Setting controlling tty using TIOCSCTTY.");
|
|
if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
|
|
error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
|
|
#endif /* TIOCSCTTY */
|
|
#ifdef NEED_SETPGRP
|
|
if (setpgrp(0,0) < 0)
|
|
error("SETPGRP %s",strerror(errno));
|
|
#endif /* NEED_SETPGRP */
|
|
fd = open(tty, O_RDWR);
|
|
if (fd == -1)
|
|
error("%.100s: %.100s", tty, strerror(errno));
|
|
else
|
|
close(fd);
|
|
|
|
/* Verify that we now have a controlling tty. */
|
|
fd = open(_PATH_TTY, O_WRONLY);
|
|
if (fd == -1)
|
|
error("open /dev/tty failed - could not set controlling tty: %.100s",
|
|
strerror(errno));
|
|
else
|
|
close(fd);
|
|
}
|
|
|
|
/* Changes the window size associated with the pty. */
|
|
|
|
void
|
|
pty_change_window_size(int ptyfd, u_int row, u_int col,
|
|
u_int xpixel, u_int ypixel)
|
|
{
|
|
struct winsize w;
|
|
|
|
/* may truncate u_int -> u_short */
|
|
w.ws_row = row;
|
|
w.ws_col = col;
|
|
w.ws_xpixel = xpixel;
|
|
w.ws_ypixel = ypixel;
|
|
(void) ioctl(ptyfd, TIOCSWINSZ, &w);
|
|
}
|
|
|
|
void
|
|
pty_setowner(struct passwd *pw, const char *tty)
|
|
{
|
|
struct group *grp;
|
|
gid_t gid;
|
|
mode_t mode;
|
|
struct stat st;
|
|
|
|
/* Determine the group to make the owner of the tty. */
|
|
grp = getgrnam("tty");
|
|
if (grp == NULL)
|
|
debug_f("no tty group");
|
|
gid = (grp != NULL) ? grp->gr_gid : pw->pw_gid;
|
|
mode = (grp != NULL) ? 0620 : 0600;
|
|
|
|
/*
|
|
* Change owner and mode of the tty as required.
|
|
* Warn but continue if filesystem is read-only and the uids match/
|
|
* tty is owned by root.
|
|
*/
|
|
if (stat(tty, &st) == -1)
|
|
fatal("stat(%.100s) failed: %.100s", tty,
|
|
strerror(errno));
|
|
|
|
#ifdef WITH_SELINUX
|
|
ssh_selinux_setup_pty(pw->pw_name, tty);
|
|
#endif
|
|
|
|
if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
|
|
if (chown(tty, pw->pw_uid, gid) == -1) {
|
|
if (errno == EROFS &&
|
|
(st.st_uid == pw->pw_uid || st.st_uid == 0))
|
|
debug("chown(%.100s, %u, %u) failed: %.100s",
|
|
tty, (u_int)pw->pw_uid, (u_int)gid,
|
|
strerror(errno));
|
|
else
|
|
fatal("chown(%.100s, %u, %u) failed: %.100s",
|
|
tty, (u_int)pw->pw_uid, (u_int)gid,
|
|
strerror(errno));
|
|
}
|
|
}
|
|
|
|
if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
|
|
if (chmod(tty, mode) == -1) {
|
|
if (errno == EROFS &&
|
|
(st.st_mode & (S_IRGRP | S_IROTH)) == 0)
|
|
debug("chmod(%.100s, 0%o) failed: %.100s",
|
|
tty, (u_int)mode, strerror(errno));
|
|
else
|
|
fatal("chmod(%.100s, 0%o) failed: %.100s",
|
|
tty, (u_int)mode, strerror(errno));
|
|
}
|
|
}
|
|
}
|