mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-23 10:22:48 +00:00
kpty: assume grantpt() and unlockpt() are available
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
parent
3764d9fa40
commit
87d3f0455d
6 changed files with 5 additions and 280 deletions
|
@ -119,8 +119,6 @@ if (UNIX)
|
|||
set(HAVE_OPENPTY 0)
|
||||
|
||||
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)
|
||||
|
||||
check_function_exists(ptsname_r HAVE_PTSNAME_R)
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
#cmakedefine PTM_DEVICE "${PTM_DEVICE}"
|
||||
|
||||
#cmakedefine HAVE_LIBUTIL_H 1
|
||||
#cmakedefine HAVE_GRANTPT 1
|
||||
#cmakedefine HAVE_OPENPTY 1
|
||||
#cmakedefine HAVE_PTSNAME_R 1
|
||||
#cmakedefine HAVE_REVOKE 1
|
||||
#cmakedefine HAVE_UNLOCKPT 1
|
||||
|
||||
#cmakedefine HAVE_PTY_H 1
|
||||
#cmakedefine HAVE_TERMIO_H 1
|
||||
|
|
|
@ -42,12 +42,6 @@ install(
|
|||
|
||||
########### 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)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
180
kpty/kgrantpty.c
180
kpty/kgrantpty.c
|
@ -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 */
|
||||
}
|
|
@ -80,13 +80,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include <kdebug.h>
|
||||
#include <kstandarddirs.h> // findExe
|
||||
#include <kde_file.h>
|
||||
|
||||
#include <QtCore/qprocess.h>
|
||||
|
||||
#define TTY_GROUP "tty"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX _POSIX_PATH_MAX
|
||||
#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 //
|
||||
/////////////////////////////
|
||||
|
@ -176,97 +163,29 @@ bool KPty::open()
|
|||
#ifdef HAVE_PTSNAME_R
|
||||
char ptsn[32];
|
||||
::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;
|
||||
#else // HAVE_PTSNAME_R
|
||||
char *ptsn = ptsname(d->masterFd);
|
||||
char *ptsn = ::ptsname(d->masterFd);
|
||||
if (ptsn) {
|
||||
d->ttyName = ptsn;
|
||||
#endif // HAVE_PTSNAME_R
|
||||
#ifdef HAVE_GRANTPT
|
||||
if (!grantpt(d->masterFd))
|
||||
if (::grantpt(d->masterFd) == 0)
|
||||
goto grantedpt;
|
||||
#else // HAVE_GRANTPT
|
||||
goto gotpty;
|
||||
#endif // HAVE_GRANTPT
|
||||
}
|
||||
::close(d->masterFd);
|
||||
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";
|
||||
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:
|
||||
|
||||
#ifdef HAVE_REVOKE
|
||||
revoke(d->ttyName.data());
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNLOCKPT
|
||||
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);
|
||||
if (d->slaveFd < 0)
|
||||
|
@ -375,15 +294,14 @@ void KPty::close()
|
|||
#ifndef HAVE_OPENPTY
|
||||
// don't bother resetting unix98 pty, it will go away after closing master anyway.
|
||||
if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
|
||||
if (!geteuid()) {
|
||||
if (geteuid() == 0) {
|
||||
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);
|
||||
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
}
|
||||
} else {
|
||||
fcntl(d->masterFd, F_SETFD, 0);
|
||||
d->chownpty(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -33,9 +33,6 @@ class KPtyPrivate {
|
|||
public:
|
||||
KPtyPrivate(KPty* parent);
|
||||
virtual ~KPtyPrivate();
|
||||
#ifndef HAVE_OPENPTY
|
||||
bool chownpty(bool grant);
|
||||
#endif
|
||||
|
||||
int masterFd;
|
||||
int slaveFd;
|
||||
|
|
Loading…
Add table
Reference in a new issue