summaryrefslogtreecommitdiffstats
path: root/kdecore/kgrantpty.c
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore/kgrantpty.c')
-rw-r--r--kdecore/kgrantpty.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/kdecore/kgrantpty.c b/kdecore/kgrantpty.c
new file mode 100644
index 000000000..7d16f5b68
--- /dev/null
+++ b/kdecore/kgrantpty.c
@@ -0,0 +1,179 @@
+/* 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 */
+}