1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 31 32 33 #pragma weak ptsname = _ptsname 34 #pragma weak grantpt = _grantpt 35 #pragma weak unlockpt = _unlockpt 36 #pragma weak posix_openpt = _posix_openpt 37 38 #include "synonyms.h" 39 #include <mtlib.h> 40 #include <sys/types.h> 41 #include <signal.h> 42 #include <sys/param.h> 43 #include <sys/mkdev.h> 44 #include <sys/fs/ufs_fsdir.h> 45 #include <sys/stream.h> 46 #include <sys/stropts.h> 47 #include <sys/wait.h> 48 #include <sys/signal.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <sys/stat.h> 52 #include <sys/ptms.h> 53 #include <string.h> 54 #include <stdlib.h> 55 #include <unistd.h> 56 #include <wait.h> 57 #include <synch.h> 58 #include <thread.h> 59 #include <spawn.h> 60 #include <libc.h> 61 #include "tsd.h" 62 63 #define PTSNAME "/dev/pts/" /* slave name */ 64 #define PTLEN 32 /* slave name length */ 65 #define PTPATH "/usr/lib/pt_chmod" /* setuid root program */ 66 #define PTPGM "pt_chmod" /* setuid root program */ 67 68 static void itoa(int, char *); 69 static int grantpt_u(int, int); 70 71 /* 72 * Check that fd argument is a file descriptor of an opened master. 73 * Do this by sending an ISPTM ioctl message down stream. Ioctl() 74 * will fail if:(1) fd is not a valid file descriptor.(2) the file 75 * represented by fd does not understand ISPTM(not a master device). 76 * If we have a valid master, get its minor number via fstat(). 77 * Concatenate it to PTSNAME and return it as the name of the slave 78 * device. 79 */ 80 static dev_t 81 ptsdev(int fd) 82 { 83 struct stat64 status; 84 struct strioctl istr; 85 86 istr.ic_cmd = ISPTM; 87 istr.ic_len = 0; 88 istr.ic_timout = 0; 89 istr.ic_dp = NULL; 90 91 if (ioctl(fd, I_STR, &istr) < 0 || fstat64(fd, &status) < 0) 92 return (NODEV); 93 94 return (minor(status.st_rdev)); 95 } 96 97 static int 98 ptscreate(void) 99 { 100 static mutex_t clk = DEFAULTMUTEX; 101 int ret; 102 103 lmutex_lock(&clk); 104 ret = grantpt_u(-1, 1); 105 lmutex_unlock(&clk); 106 return (ret); 107 } 108 109 char * 110 ptsname(int fd) 111 { 112 dev_t dev; 113 char *sname; 114 115 if ((dev = ptsdev(fd)) == NODEV) 116 return (NULL); 117 118 sname = tsdalloc(_T_PTSNAME, PTLEN, NULL); 119 if (sname == NULL) 120 return (NULL); 121 (void) strcpy(sname, PTSNAME); 122 itoa(dev, sname + strlen(PTSNAME)); 123 124 /* 125 * devfsadm synchronization: if the node does not exist, 126 * attempt to synchronize with slave device node creation. 127 */ 128 if (access(sname, F_OK) == 0 || 129 (ptscreate() == 0 && access(sname, F_OK) == 0)) 130 return (sname); 131 return (NULL); 132 } 133 134 /* 135 * Send an ioctl down to the master device requesting the 136 * master/slave pair be unlocked. 137 */ 138 int 139 unlockpt(int fd) 140 { 141 struct strioctl istr; 142 143 istr.ic_cmd = UNLKPT; 144 istr.ic_len = 0; 145 istr.ic_timout = 0; 146 istr.ic_dp = NULL; 147 148 if (ioctl(fd, I_STR, &istr) < 0) 149 return (-1); 150 151 return (0); 152 } 153 154 155 /* 156 * Execute a setuid root program to change the mode, ownership and 157 * group of the slave device. The parent forks a child process that 158 * executes the setuid program. It then waits for the child to return. 159 * 160 * When create is 1, execute the setuid root program without arguments, 161 * to create minor nodes and symlinks for all slave devices. 162 */ 163 static int 164 grantpt_u(int fd, int create) 165 { 166 extern char **environ; 167 char *argvec[3]; 168 int st_loc; 169 pid_t pid; 170 int w; 171 char fds[24]; 172 sigset_t oset, nset; 173 int error; 174 175 /* validate the file descriptor before proceeding */ 176 if (create != 1 && ptsdev(fd) == NODEV) 177 return (-1); 178 179 if (sigemptyset(&nset) == -1) 180 return (-1); 181 if (sigaddset(&nset, SIGCHLD) == -1) 182 return (-1); 183 if (sigprocmask(SIG_BLOCK, &nset, &oset) == -1) 184 return (-1); 185 186 itoa(fd, fds); 187 argvec[0] = PTPGM; 188 argvec[1] = create == 1 ? NULL : fds; 189 argvec[2] = NULL; 190 error = posix_spawn(&pid, PTPATH, NULL, NULL, argvec, environ); 191 if (error) { 192 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 193 errno = error; 194 return (-1); 195 } 196 197 /* 198 * waitpid() returns the process id for the child process 199 * on success or -1 on failure. 200 */ 201 while ((w = waitpid(pid, &st_loc, 0)) < 0 && errno == EINTR) 202 continue; 203 204 /* Restore signal mask */ 205 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 206 207 /* 208 * If SIGCHLD is currently ignored, waitpid() fails with 209 * ECHILD after the child terminates. 210 * This is not a failure; assume the child succeded. 211 */ 212 if (w == -1) { 213 if (errno != ECHILD) 214 return (-1); 215 st_loc = 0; 216 } 217 218 /* 219 * If child terminated due to exit() and the exit status is zero 220 * return success 221 * else it was an exit(-1) or it was struck by a signal 222 * return failure (EACCES) 223 */ 224 if (WIFEXITED(st_loc) && WEXITSTATUS(st_loc) == 0) 225 return (0); 226 errno = EACCES; 227 return (-1); 228 } 229 230 int 231 grantpt(int fd) 232 { 233 static mutex_t glk = DEFAULTMUTEX; 234 int ret; 235 236 lmutex_lock(&glk); 237 ret = grantpt_u(fd, 0); 238 lmutex_unlock(&glk); 239 return (ret); 240 } 241 242 /* 243 * Send an ioctl down to the master device requesting the master/slave pair 244 * be assigned to the given zone. 245 */ 246 int 247 zonept(int fd, zoneid_t zoneid) 248 { 249 struct strioctl istr; 250 251 istr.ic_cmd = ZONEPT; 252 istr.ic_len = sizeof (zoneid); 253 istr.ic_timout = 0; 254 istr.ic_dp = (char *)&zoneid; 255 256 if (ioctl(fd, I_STR, &istr) != 0) { 257 return (-1); 258 } 259 return (0); 260 } 261 262 263 static void 264 itoa(int i, char *ptr) 265 { 266 int dig = 0; 267 int tempi; 268 269 tempi = i; 270 do { 271 dig++; 272 tempi /= 10; 273 } while (tempi); 274 275 ptr += dig; 276 *ptr = '\0'; 277 while (--dig >= 0) { 278 *(--ptr) = i % 10 + '0'; 279 i /= 10; 280 } 281 } 282 283 284 /* 285 * added for SUSv3 standard 286 * 287 * Open a pseudo-terminal device. External interface. 288 */ 289 290 int 291 posix_openpt(int oflag) 292 { 293 return (open("/dev/ptmx", oflag)); 294 } 295