xref: /onnv-gate/usr/src/lib/libc/port/gen/pt.c (revision 0:68f95e015346)
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