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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
  29  */
  30 
  31 /*      Copyright (c) 1988 AT&T     */
  32 /*        All Rights Reserved   */
  33 
  34 #pragma weak _ptsname = ptsname
  35 #pragma weak _grantpt = grantpt
  36 #pragma weak _unlockpt = unlockpt
  37 
  38 #include "lint.h"
  39 #include "libc.h"
  40 #include "mtlib.h"
  41 #include <sys/types.h>
  42 #include <signal.h>
  43 #include <sys/param.h>
  44 #include <sys/mkdev.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 <spawn.h>
  58 #include <grp.h>
  59 #include "tsd.h"
  60 
  61 #define PTSNAME "/dev/pts/"             /* slave name */
  62 #define PTLEN   32                      /* slave name length */
  63 #define DEFAULT_TTY_GROUP       "tty"   /* slave device group owner */
  64 
  65 static void itoa(int, char *);
  66 
  67 /*
  68  *  Check that fd argument is a file descriptor of an opened master.
  69  *  Do this by sending an ISPTM ioctl message down stream. Ioctl()
  70  *  will fail if:(1) fd is not a valid file descriptor.(2) the file
  71  *  represented by fd does not understand ISPTM(not a master device).
  72  *  If we have a valid master, get its minor number via fstat().
  73  *  Concatenate it to PTSNAME and return it as the name of the slave
  74  *  device.
  75  */
  76 static dev_t
  77 ptsdev(int fd)
  78 {
  79         struct stat64 status;
  80         struct strioctl istr;
  81 
  82         istr.ic_cmd = ISPTM;
  83         istr.ic_len = 0;
  84         istr.ic_timout = 0;
  85         istr.ic_dp = NULL;
  86 
  87         if (ioctl(fd, I_STR, &istr) < 0 || fstat64(fd, &status) < 0)
  88                 return (NODEV);
  89 
  90         return (minor(status.st_rdev));
  91 }
  92 
  93 char *
  94 ptsname(int fd)
  95 {
  96         dev_t dev;
  97         char *sname;
  98 
  99         if ((dev = ptsdev(fd)) == NODEV)
 100                 return (NULL);
 101 
 102         sname = tsdalloc(_T_PTSNAME, PTLEN, NULL);
 103         if (sname == NULL)
 104                 return (NULL);
 105         (void) strcpy(sname, PTSNAME);
 106         itoa(dev, sname + strlen(PTSNAME));
 107 
 108         /*
 109          * This lookup will create the /dev/pts node (if the corresponding
 110          * pty exists.
 111          */
 112         if (access(sname, F_OK) ==  0)
 113                 return (sname);
 114 
 115         return (NULL);
 116 }
 117 
 118 /*
 119  * Send an ioctl down to the master device requesting the
 120  * master/slave pair be unlocked.
 121  */
 122 int
 123 unlockpt(int fd)
 124 {
 125         struct strioctl istr;
 126 
 127         istr.ic_cmd = UNLKPT;
 128         istr.ic_len = 0;
 129         istr.ic_timout = 0;
 130         istr.ic_dp = NULL;
 131 
 132         if (ioctl(fd, I_STR, &istr) < 0)
 133                 return (-1);
 134 
 135         return (0);
 136 }
 137 
 138 /*
 139  * XPG4v2 requires that open of a slave pseudo terminal device
 140  * provides the process with an interface that is identical to
 141  * the terminal interface.
 142  *
 143  * To satisfy this, in strict XPG4v2 mode, this routine also sends
 144  * a message down the stream that sets a flag in the kernel module
 145  * so that additional actions are performed when opening an
 146  * associated slave PTY device. When this happens, modules are
 147  * automatically pushed onto the stream to provide terminal
 148  * semantics and those modules are then informed that they should
 149  * behave in strict XPG4v2 mode which modifies their behaviour. In
 150  * particular, in strict XPG4v2 mode, empty blocks will be sent up
 151  * the master side of the stream rather than being suppressed.
 152  *
 153  * Most applications do not expect this behaviour so it is only
 154  * enabled for programs compiled in strict XPG4v2 mode (see
 155  * stdlib.h).
 156  */
 157 int
 158 __unlockpt_xpg4(int fd)
 159 {
 160         int ret;
 161 
 162         if ((ret = unlockpt(fd)) == 0) {
 163                 struct strioctl istr;
 164 
 165                 istr.ic_cmd = PTSSTTY;
 166                 istr.ic_len = 0;
 167                 istr.ic_timout = 0;
 168                 istr.ic_dp = NULL;
 169 
 170                 if (ioctl(fd, I_STR, &istr) < 0)
 171                         ret = -1;
 172         }
 173 
 174         return (ret);
 175 }
 176 
 177 int
 178 grantpt(int fd)
 179 {
 180         struct strioctl istr;
 181         pt_own_t pto;
 182         struct group *gr_name;
 183 
 184         /* validate the file descriptor before proceeding */
 185         if (ptsdev(fd) == NODEV)
 186                 return (-1);
 187 
 188         pto.pto_ruid = getuid();
 189 
 190         gr_name = getgrnam(DEFAULT_TTY_GROUP);
 191         if (gr_name)
 192                 pto.pto_rgid = gr_name->gr_gid;
 193         else
 194                 pto.pto_rgid = getgid();
 195 
 196         istr.ic_cmd = OWNERPT;
 197         istr.ic_len = sizeof (pt_own_t);
 198         istr.ic_timout = 0;
 199         istr.ic_dp = (char *)&pto;
 200 
 201         if (ioctl(fd, I_STR, &istr) != 0) {
 202                 errno = EACCES;
 203                 return (-1);
 204         }
 205 
 206         return (0);
 207 }
 208 
 209 /*
 210  * Send an ioctl down to the master device requesting the master/slave pair
 211  * be assigned to the given zone.
 212  */
 213 int
 214 zonept(int fd, zoneid_t zoneid)
 215 {
 216         struct strioctl istr;
 217 
 218         istr.ic_cmd = ZONEPT;
 219         istr.ic_len = sizeof (zoneid);
 220         istr.ic_timout = 0;
 221         istr.ic_dp = (char *)&zoneid;
 222 
 223         if (ioctl(fd, I_STR, &istr) != 0) {
 224                 return (-1);
 225         }
 226         return (0);
 227 }
 228 
 229 
 230 static void
 231 itoa(int i, char *ptr)
 232 {
 233         int dig = 0;
 234         int tempi;
 235 
 236         tempi = i;
 237         do {
 238                 dig++;
 239                 tempi /= 10;
 240         } while (tempi);
 241 
 242         ptr += dig;
 243         *ptr = '\0';
 244         while (--dig >= 0) {
 245                 *(--ptr) = i % 10 + '0';
 246                 i /= 10;
 247         }
 248 }
 249 
 250 
 251 /*
 252  * added for SUSv3 standard
 253  *
 254  * Open a pseudo-terminal device.  External interface.
 255  */
 256 
 257 int
 258 posix_openpt(int oflag)
 259 {
 260         return (open("/dev/ptmx", oflag));
 261 }