You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/tdecore/kgrantpty.c

180 lines
4.6 KiB

/* 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
* 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 passed 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>.
* GPL applies.
*/
#include <config.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 <unistd.h>
#include <sys/param.h>
#if defined(__FreeBSD__) || defined(__DragonFly__)
# define BSD_PTY_HACK
# include <paths.h>
# include <dirent.h>
#endif
#define TTY_GROUP "tty"
int main (int argc, char *argv[])
{
struct stat st;
struct group* p;
gid_t gid;
uid_t uid;
mode_t mod;
char* tty;
int fd;
/* 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)
#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);
return 1; /* FAIL */
}
tty = malloc(strlen(pty) + 1);
strcpy(tty,"/dev/tty");
strcat(tty,pty+8);
}
/* 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);
return 1; /* FAIL */
}
/* setup parameters for the operation ***********************************/
if (!strcmp(argv[1],"--grant"))
{
uid = getuid();
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));
return 1; /* FAIL */
}
if (chmod(tty, mod) < 0)
{
fprintf(stderr,"%s: cannot chmod %s: %s\n",argv[0],tty,strerror(errno));
return 1; /* FAIL */
}
return 0; /* OK */
}