kpty: assume grantpt() and unlockpt() are available

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-02-25 02:14:11 +02:00
parent 3764d9fa40
commit 87d3f0455d
6 changed files with 5 additions and 280 deletions

View file

@ -119,8 +119,6 @@ if (UNIX)
set(HAVE_OPENPTY 0) set(HAVE_OPENPTY 0)
check_function_exists(revoke HAVE_REVOKE) check_function_exists(revoke HAVE_REVOKE)
check_function_exists(grantpt HAVE_GRANTPT)
check_function_exists(unlockpt HAVE_UNLOCKPT)
endif (openpty_in_libc OR openpty_in_libutil) endif (openpty_in_libc OR openpty_in_libutil)
check_function_exists(ptsname_r HAVE_PTSNAME_R) check_function_exists(ptsname_r HAVE_PTSNAME_R)

View file

@ -2,11 +2,9 @@
#cmakedefine PTM_DEVICE "${PTM_DEVICE}" #cmakedefine PTM_DEVICE "${PTM_DEVICE}"
#cmakedefine HAVE_LIBUTIL_H 1 #cmakedefine HAVE_LIBUTIL_H 1
#cmakedefine HAVE_GRANTPT 1
#cmakedefine HAVE_OPENPTY 1 #cmakedefine HAVE_OPENPTY 1
#cmakedefine HAVE_PTSNAME_R 1 #cmakedefine HAVE_PTSNAME_R 1
#cmakedefine HAVE_REVOKE 1 #cmakedefine HAVE_REVOKE 1
#cmakedefine HAVE_UNLOCKPT 1
#cmakedefine HAVE_PTY_H 1 #cmakedefine HAVE_PTY_H 1
#cmakedefine HAVE_TERMIO_H 1 #cmakedefine HAVE_TERMIO_H 1

View file

@ -42,12 +42,6 @@ install(
########### next target ############### ########### next target ###############
if(NOT HAVE_OPENPTY)
add_executable(kgrantpty kgrantpty.c)
target_link_libraries(kgrantpty)
install(TARGETS kgrantpty DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR})
endif()
if(ENABLE_TESTING) if(ENABLE_TESTING)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()

View file

@ -1,180 +0,0 @@
/* kgrantpty - helper program for KPty. */
/* This program is based on the glibc2.1 pt_chmod.
* It was pulled out from there since both Linux
* distributors and other OSes are not able to make
* use of the glibc for different reasons.
*
* THIS IS A ROOT SUID PROGRAM
*
* Things work as following:
*
* In konsole we open a master pty. This can be opened
* done by at most one process. Prior to opening the
* master pty, the slave pty cannot be opened. Then, in
* grantpty, we fork to this program. The trick is, that
* the parameter is passes as a file handle, which cannot
* be faked, so that we get a secure setuid root chmod/chown
* with this program.
*
* We have to chown/chmod the slave pty to prevent eavesdroping.
*
* Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
* Copyright (c) 1999 by Lars Doelle <lars.doelle@on-line.de>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA
*/
#include <config.h>
#include <config-pty.h>
#include <sys/types.h>
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <unistd.h>
#ifdef HAVE_PTY_H
# include <pty.h>
#endif
#define TTY_GROUP "tty"
int main (int argc, char *argv[])
{
struct stat st;
gid_t gid;
uid_t uid;
mode_t mod;
char* tty = 0;
int fd;
#if defined(HAVE_PTSNAME_R)
char ttyb[32];
#endif
/* check preconditions **************************************************/
if (argc != 3 || (strcmp(argv[1],"--grant") && strcmp(argv[1],"--revoke")))
{
printf("usage: %s (--grant|--revoke) <file descriptor>\n"
"%s is a helper for the KDE core libraries.\n"
"It is not intended to be called from the command line.\n"
"It needs to be installed setuid root to function.\n",
argv[0], argv[0]);
return 1; /* FAIL */
}
if (geteuid () != 0)
{
fprintf(stderr, "%s not installed setuid root\n", argv[0]);
return 1; /* FAIL */
}
fd = atoi(argv[2]);
/* get slave pty name from master pty file handle *********/
#if defined(HAVE_PTSNAME_R)
memset(ttyb, '\0', sizeof(ttyb) * sizeof(char));
if (ptsname_r(fd, ttyb, sizeof(ttyb)) == 0) {
tty = ttyb;
if (!tty)
#else
tty = ptsname(fd);
if (!tty)
#endif
{
/* Check that fd is a valid master pseudo terminal. */
#if defined(HAVE_TTYNAME_R)
char pty[32];
memset(pty, '\0', sizeof(pty) * sizeof(char));
if (ttyname_r(fd, pty, sizeof(pty)) != 0)
#else
char *pty = ttyname(fd);
if (pty == NULL)
#endif
{
fprintf(stderr,"%s: cannot determine pty name.\n",argv[0]);
return 1; /* FAIL */
}
/* matches /dev/pty?? */
if (memcmp(pty,"/dev/pty",8))
{
fprintf(stderr,"%s: determined a strange pty name '%s'.\n",argv[0],pty);
#if !defined(HAVE_TTYNAME_R)
free(pty);
#endif
return 1; /* FAIL */
}
tty = malloc(strlen(pty) + 1);
strcpy(tty,"/dev/tty");
strcat(tty,pty+8);
#if !defined(HAVE_TTYNAME_R)
free(pty);
#endif
}
/* Check that the returned slave pseudo terminal is a character device. */
if (stat(tty, &st) < 0 || !S_ISCHR(st.st_mode))
{
fprintf(stderr,"%s: found '%s' not to be a character device.\n",argv[0],tty);
free(tty);
return 1; /* FAIL */
}
/* setup parameters for the operation ***********************************/
if (!strcmp(argv[1],"--grant"))
{
uid = getuid();
struct group* p = getgrnam(TTY_GROUP);
if (!p)
p = getgrnam("wheel");
gid = p ? p->gr_gid : getgid ();
mod = S_IRUSR | S_IWUSR | S_IWGRP;
}
else
{
uid = 0;
gid = st.st_gid == getgid () ? 0 : -1;
mod = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
}
/* Perform the actual chown/chmod ************************************/
if (chown(tty, uid, gid) < 0)
{
fprintf(stderr,"%s: cannot chown %s: %s\n",argv[0],tty,strerror(errno));
free(tty);
return 1; /* FAIL */
}
if (chmod(tty, mod) < 0)
{
fprintf(stderr,"%s: cannot chmod %s: %s\n",argv[0],tty,strerror(errno));
free(tty);
return 1; /* FAIL */
}
free(tty);
return 0; /* OK */
}

View file

@ -80,13 +80,8 @@ extern "C" {
#endif #endif
#include <kdebug.h> #include <kdebug.h>
#include <kstandarddirs.h> // findExe
#include <kde_file.h> #include <kde_file.h>
#include <QtCore/qprocess.h>
#define TTY_GROUP "tty"
#ifndef PATH_MAX #ifndef PATH_MAX
# define PATH_MAX _POSIX_PATH_MAX # define PATH_MAX _POSIX_PATH_MAX
#endif #endif
@ -108,14 +103,6 @@ KPtyPrivate::~KPtyPrivate()
{ {
} }
#ifndef HAVE_OPENPTY
bool KPtyPrivate::chownpty(bool grant)
{
return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
}
#endif
///////////////////////////// /////////////////////////////
// public member functions // // public member functions //
///////////////////////////// /////////////////////////////
@ -176,97 +163,29 @@ bool KPty::open()
#ifdef HAVE_PTSNAME_R #ifdef HAVE_PTSNAME_R
char ptsn[32]; char ptsn[32];
::memset(ptsn, '\0', sizeof(ptsn) * sizeof(char)); ::memset(ptsn, '\0', sizeof(ptsn) * sizeof(char));
if (ptsname_r(d->masterFd, ptsn, sizeof(ptsn)) == 0) { if (::ptsname_r(d->masterFd, ptsn, sizeof(ptsn)) == 0) {
d->ttyName = ptsn; d->ttyName = ptsn;
#else // HAVE_PTSNAME_R #else // HAVE_PTSNAME_R
char *ptsn = ptsname(d->masterFd); char *ptsn = ::ptsname(d->masterFd);
if (ptsn) { if (ptsn) {
d->ttyName = ptsn; d->ttyName = ptsn;
#endif // HAVE_PTSNAME_R #endif // HAVE_PTSNAME_R
#ifdef HAVE_GRANTPT if (::grantpt(d->masterFd) == 0)
if (!grantpt(d->masterFd))
goto grantedpt; goto grantedpt;
#else // HAVE_GRANTPT
goto gotpty;
#endif // HAVE_GRANTPT
} }
::close(d->masterFd); ::close(d->masterFd);
d->masterFd = -1; d->masterFd = -1;
} }
// Linux device names, FIXME: Trouble on other systems?
for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
{
for (const char* s4 = "0123456789abcdef"; *s4; s4++)
{
ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toLatin1();
d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toLatin1();
d->masterFd = KDE_open(ptyName.data(), O_RDWR);
if (d->masterFd >= 0)
{
#ifdef Q_OS_SOLARIS
/* Need to check the process group of the pty.
* If it exists, then the slave pty is in use,
* and we need to get another one.
*/
int pgrp_rtn;
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
::close(d->masterFd);
d->masterFd = -1;
continue;
}
#endif /// Q_OS_SOLARIS
if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
{
if (!geteuid())
{
struct group* p = getgrnam(TTY_GROUP);
if (!p)
p = getgrnam("wheel");
gid_t gid = p ? p->gr_gid : getgid ();
chown(d->ttyName.data(), getuid(), gid);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
}
goto gotpty;
}
::close(d->masterFd);
d->masterFd = -1;
}
}
}
kWarning(175) << "Can't open a pseudo teletype"; kWarning(175) << "Can't open a pseudo teletype";
return false; return false;
gotpty:
KDE_struct_stat st;
if (KDE_stat(d->ttyName.data(), &st))
return false; // this just cannot happen ... *cough* Yeah right, I just
// had it happen when pty #349 was allocated. I guess
// there was some sort of leak? I only had a few open.
if (((st.st_uid != getuid()) ||
(st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
!d->chownpty(true))
{
kWarning(175)
<< "chownpty failed for device " << ptyName << "::" << d->ttyName
<< "\nThis means the communication can be eavesdropped." << endl;
}
grantedpt: grantedpt:
#ifdef HAVE_REVOKE #ifdef HAVE_REVOKE
revoke(d->ttyName.data()); revoke(d->ttyName.data());
#endif #endif
#ifdef HAVE_UNLOCKPT
unlockpt(d->masterFd); unlockpt(d->masterFd);
#elif defined(TIOCSPTLCK)
int flag = 0;
ioctl(d->masterFd, TIOCSPTLCK, &flag);
#endif
d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY); d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY);
if (d->slaveFd < 0) if (d->slaveFd < 0)
@ -375,15 +294,14 @@ void KPty::close()
#ifndef HAVE_OPENPTY #ifndef HAVE_OPENPTY
// don't bother resetting unix98 pty, it will go away after closing master anyway. // don't bother resetting unix98 pty, it will go away after closing master anyway.
if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) { if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
if (!geteuid()) { if (geteuid() == 0) {
KDE_struct_stat st; KDE_struct_stat st;
if (!KDE_stat(d->ttyName.data(), &st)) { if (KDE_stat(d->ttyName.data(), &st) == 0) {
chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1); chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
} }
} else { } else {
fcntl(d->masterFd, F_SETFD, 0); fcntl(d->masterFd, F_SETFD, 0);
d->chownpty(false);
} }
} }
#endif #endif

View file

@ -33,9 +33,6 @@ class KPtyPrivate {
public: public:
KPtyPrivate(KPty* parent); KPtyPrivate(KPty* parent);
virtual ~KPtyPrivate(); virtual ~KPtyPrivate();
#ifndef HAVE_OPENPTY
bool chownpty(bool grant);
#endif
int masterFd; int masterFd;
int slaveFd; int slaveFd;