kdelibs/kpty/kgrantpty.c
Ivailo Monev 5600c15dec generic: misc cleanups
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2016-04-11 08:06:16 +00:00

212 lines
5.6 KiB
C

/* 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 <unistd.h>
#ifdef HAVE_PTY_H
# include <pty.h>
#endif
#include <sys/param.h>
#if defined(__FreeBSD__)
# define BSD_PTY_HACK
# include <paths.h>
# include <dirent.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;
int fd;
#if !defined(HAVE_PTSNAME) && defined(TIOCGPTN)
int ptyno;
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 *********/
#ifdef HAVE_PTSNAME
tty = ptsname(fd);
if (!tty)
#elif defined(TIOCGPTN)
if (!ioctl(fd, TIOCGPTN, &ptyno)) {
sprintf(ttyb, "/dev/pts/%d", ptyno);
tty = ttyb;
} else
#endif
{
/* Check that fd is a valid master pseudo terminal. */
char *pty = ttyname(fd);
#ifdef BSD_PTY_HACK
if (pty == NULL)
{
/*
Hack to make kgrantpty work on some versions of FreeBSD (and possibly
other systems): ttyname(3) does not work with a file descriptor opened
on a /dev/pty?? device.
Instead, this code looks through all the devices in /dev for a device
which has the same inode as our PTY_FILENO descriptor... if found, we
have the name for our pty.
*/
struct dirent *dirp;
DIR *dp;
struct stat dsb;
if (fstat(fd, &dsb) != -1) {
if ((dp = opendir(_PATH_DEV)) != NULL) {
while ((dirp = readdir(dp))) {
if (dirp->d_fileno != dsb.st_ino)
continue;
pty = malloc(sizeof(_PATH_DEV) + strlen(dirp->d_name));
if (pty) {
strcpy(pty, _PATH_DEV);
strcat(pty, dirp->d_name);
}
break;
}
(void) closedir(dp);
}
}
}
#endif
if (pty == NULL)
{
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);
free(pty);
return 1; /* FAIL */
}
tty = malloc(strlen(pty) + 1);
strcpy(tty,"/dev/tty");
strcat(tty,pty+8);
free(pty);
}
/* 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 */
}