/* 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 , 1998. * Copyright (c) 1999 by Lars Doelle . * GPL applies. */ #include #include #include #include #include #include #include #include #include #include #if defined(__FreeBSD__) || defined(__DragonFly__) # define BSD_PTY_HACK # include # include #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) \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 */ }