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