File indexing completed on 2024-04-28 07:45:31
0001 /* kgrantpty - helper program for KPty. */ 0002 0003 /* This program is based on the glibc2.1 pt_chmod. 0004 * It was pulled out from there since both Linux 0005 * distributors and other OSes are not able to make 0006 * use of the glibc for different reasons. 0007 * 0008 * THIS IS A ROOT SUID PROGRAM 0009 * 0010 * Things work as following: 0011 * 0012 * In konsole we open a master pty. This can be opened 0013 * done by at most one process. Prior to opening the 0014 * master pty, the slave pty cannot be opened. Then, in 0015 * grantpty, we fork to this program. The trick is, that 0016 * the parameter is passes as a file handle, which cannot 0017 * be faked, so that we get a secure setuid root chmod/chown 0018 * with this program. 0019 * 0020 * We have to chown/chmod the slave pty to prevent eavesdroping. 0021 * 0022 * SPDX-FileCopyrightText: 1998 Zack Weinberg <zack@rabi.phys.columbia.edu> 0023 * SPDX-FileCopyrightText: 1999 Lars Doelle <lars.doelle@on-line.de> 0024 * 0025 * SPDX-License-Identifier: GPL-2.0-or-later 0026 */ 0027 0028 #include <config-pty.h> 0029 0030 #include <cerrno> 0031 #include <grp.h> 0032 #include <stdio.h> 0033 #include <stdlib.h> 0034 #include <string.h> 0035 #include <sys/ioctl.h> 0036 #include <sys/stat.h> 0037 #include <sys/types.h> 0038 #include <unistd.h> 0039 #if HAVE_PTY_H 0040 #include <pty.h> 0041 #endif 0042 0043 #include <sys/param.h> 0044 #if defined(__FreeBSD__) 0045 #define BSD_PTY_HACK 0046 #include <dirent.h> 0047 #include <paths.h> 0048 #endif 0049 0050 #define TTY_GROUP "tty" 0051 0052 int main(int argc, char *argv[]) 0053 { 0054 struct stat st; 0055 struct group *p; 0056 gid_t gid; 0057 uid_t uid; 0058 mode_t mod; 0059 char *tty; 0060 int fd; 0061 #if !HAVE_PTSNAME && defined(TIOCGPTN) 0062 int ptyno; 0063 char ttyb[32]; 0064 #endif 0065 0066 /* check preconditions **************************************************/ 0067 if (argc != 3 || (strcmp(argv[1], "--grant") && strcmp(argv[1], "--revoke"))) { 0068 printf( 0069 "usage: %s (--grant|--revoke) <file descriptor>\n" 0070 "%s is a helper for the KDE core libraries.\n" 0071 "It is not intended to be called from the command line.\n" 0072 "It needs to be installed setuid root to function.\n", 0073 argv[0], 0074 argv[0]); 0075 return 1; /* FAIL */ 0076 } 0077 0078 if (geteuid() != 0) { 0079 fprintf(stderr, "%s not installed setuid root\n", argv[0]); 0080 return 1; /* FAIL */ 0081 } 0082 0083 fd = atoi(argv[2]); 0084 0085 /* get slave pty name from master pty file handle *********/ 0086 #if HAVE_PTSNAME 0087 tty = ptsname(fd); 0088 if (!tty) 0089 #elif defined(TIOCGPTN) 0090 if (!ioctl(fd, TIOCGPTN, &ptyno)) { 0091 sprintf(ttyb, "/dev/pts/%d", ptyno); 0092 tty = ttyb; 0093 } else 0094 #endif 0095 { 0096 /* Check that fd is a valid master pseudo terminal. */ 0097 char *pty = ttyname(fd); 0098 0099 #ifdef BSD_PTY_HACK 0100 if (pty == NULL) { 0101 /* 0102 Hack to make kgrantpty work on some versions of FreeBSD (and possibly 0103 other systems): ttyname(3) does not work with a file descriptor opened 0104 on a /dev/pty?? device. 0105 0106 Instead, this code looks through all the devices in /dev for a device 0107 which has the same inode as our PTY_FILENO descriptor... if found, we 0108 have the name for our pty. 0109 */ 0110 0111 struct dirent *dirp; 0112 DIR *dp; 0113 struct stat dsb; 0114 0115 if (fstat(fd, &dsb) != -1) { 0116 if ((dp = opendir(_PATH_DEV)) != NULL) { 0117 while ((dirp = readdir(dp))) { 0118 if (dirp->d_fileno != dsb.st_ino) { 0119 continue; 0120 } 0121 pty = malloc(sizeof(_PATH_DEV) + strlen(dirp->d_name)); 0122 if (pty) { 0123 strcpy(pty, _PATH_DEV); 0124 strcat(pty, dirp->d_name); 0125 } 0126 break; 0127 } 0128 0129 (void)closedir(dp); 0130 } 0131 } 0132 } 0133 #endif 0134 0135 if (pty == NULL) { 0136 fprintf(stderr, "%s: cannot determine pty name.\n", argv[0]); 0137 return 1; /* FAIL */ 0138 } 0139 0140 /* matches /dev/pty?? */ 0141 if (memcmp(pty, "/dev/pty", 8)) { 0142 fprintf(stderr, "%s: determined a strange pty name '%s'.\n", argv[0], pty); 0143 return 1; /* FAIL */ 0144 } 0145 0146 tty = malloc(strlen(pty) + 1); 0147 strcpy(tty, "/dev/tty"); 0148 strcat(tty, pty + 8); 0149 } 0150 0151 /* Check that the returned slave pseudo terminal is a character device. */ 0152 if (stat(tty, &st) < 0 || !S_ISCHR(st.st_mode)) { 0153 fprintf(stderr, "%s: found '%s' not to be a character device.\n", argv[0], tty); 0154 return 1; /* FAIL */ 0155 } 0156 0157 /* setup parameters for the operation ***********************************/ 0158 0159 if (!strcmp(argv[1], "--grant")) { 0160 uid = getuid(); 0161 p = getgrnam(TTY_GROUP); 0162 if (!p) { 0163 p = getgrnam("wheel"); 0164 } 0165 gid = p ? p->gr_gid : getgid(); 0166 mod = S_IRUSR | S_IWUSR | S_IWGRP; 0167 } else { 0168 uid = 0; 0169 gid = st.st_gid == getgid() ? 0 : -1; 0170 mod = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 0171 } 0172 0173 /* Perform the actual chown/chmod ************************************/ 0174 0175 if (chown(tty, uid, gid) < 0) { 0176 fprintf(stderr, "%s: cannot chown %s: %s\n", argv[0], tty, strerror(errno)); 0177 return 1; /* FAIL */ 0178 } 0179 0180 if (chmod(tty, mod) < 0) { 0181 fprintf(stderr, "%s: cannot chmod %s: %s\n", argv[0], tty, strerror(errno)); 0182 return 1; /* FAIL */ 0183 } 0184 0185 return 0; /* OK */ 0186 }