xref: /titanic_53/usr/src/cmd/rexd/rpc.rexd.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * rexd - a remote execution daemon based on SUN Remote Procedure Calls
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 1985-2003 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <errno.h>
32*7c478bd9Sstevel@tonic-gate #include <netdb.h>
33*7c478bd9Sstevel@tonic-gate #include <signal.h>
34*7c478bd9Sstevel@tonic-gate #include <stdio.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <unistd.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
40*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
41*7c478bd9Sstevel@tonic-gate #include <rpc/svc_soc.h>
42*7c478bd9Sstevel@tonic-gate #include <rpc/key_prot.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
52*7c478bd9Sstevel@tonic-gate #include <wait.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #include <sys/ttold.h>
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #include "rex.h"
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
60*7c478bd9Sstevel@tonic-gate #include <stropts.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
62*7c478bd9Sstevel@tonic-gate /*	#include <sys/termios.h>	XXX	*/
63*7c478bd9Sstevel@tonic-gate #include <sys/ttcompat.h>
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #include <bsm/audit.h>
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate /* #define	stderr	stdout */		/* XXX		*/
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	ListnerTimeout 300	/* seconds listner stays alive */
70*7c478bd9Sstevel@tonic-gate #define	WaitLimit 10		/* seconds to wait after io is closed */
71*7c478bd9Sstevel@tonic-gate #define	MOUNTED "/etc/mnttab"
72*7c478bd9Sstevel@tonic-gate #define	TempDir "/tmp_rex"	/* directory to hold temp mounts */
73*7c478bd9Sstevel@tonic-gate static	char TempName[] = "/tmp_rex/rexdXXXXXX";
74*7c478bd9Sstevel@tonic-gate 				/* name template for temp mount points */
75*7c478bd9Sstevel@tonic-gate #define	TempMatch 13		/* unique prefix of above */
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate SVCXPRT	*ListnerTransp;		/* non-null means still a listner */
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate static	char **Argv;		/* saved argument vector (for ps) */
80*7c478bd9Sstevel@tonic-gate static char *LastArgv;		/* saved end-of-argument vector */
81*7c478bd9Sstevel@tonic-gate int OutputSocket;		/* socket for stop/cont notification */
82*7c478bd9Sstevel@tonic-gate int MySocket;			/* transport socket */
83*7c478bd9Sstevel@tonic-gate int HasHelper = 0;		/* must kill helpers (interactive mode) */
84*7c478bd9Sstevel@tonic-gate int DesOnly  =  0;		/* unix credentials too weak */
85*7c478bd9Sstevel@tonic-gate int confd;			/* console fd */
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate int	Debug = 0;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate pam_handle_t *pamh;		/* PAM handle */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate time_t time_now;
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate extern int Master;		/* half of the pty */
94*7c478bd9Sstevel@tonic-gate extern char **environ;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate int child = 0;			/* pid of the executed process */
97*7c478bd9Sstevel@tonic-gate int ChildStatus = 0;		/* saved return status of child */
98*7c478bd9Sstevel@tonic-gate int ChildDied = 0;		/* true when above is valid */
99*7c478bd9Sstevel@tonic-gate char nfsdir[MAXPATHLEN];	/* file system we mounted */
100*7c478bd9Sstevel@tonic-gate char *tmpdir;			/* where above is mounted, NULL if none */
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate extern	void	rex_cleanup(void);
103*7c478bd9Sstevel@tonic-gate extern	int	ValidUser(char *host, uid_t uid, gid_t gid,
104*7c478bd9Sstevel@tonic-gate 			char *error, char *shell,
105*7c478bd9Sstevel@tonic-gate 			char *dir, struct rex_start *rst);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate extern void audit_rexd_fail(char *, char *, char *, uid_t, gid_t,
108*7c478bd9Sstevel@tonic-gate 				char *, char **);
109*7c478bd9Sstevel@tonic-gate extern void audit_rexd_success(char *, char *, uid_t, gid_t,
110*7c478bd9Sstevel@tonic-gate 				char *, char **);
111*7c478bd9Sstevel@tonic-gate extern void audit_rexd_setup();
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate extern int audit_settid(int);
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /* process rex requests */
116*7c478bd9Sstevel@tonic-gate void		dorex(struct svc_req *rqstp, SVCXPRT *transp);
117*7c478bd9Sstevel@tonic-gate void		ListnerTimer(int);		/* destroy listener	*/
118*7c478bd9Sstevel@tonic-gate void		CatchChild(int);		/* handle child signals	*/
119*7c478bd9Sstevel@tonic-gate void		oob(int);			/* out of band signals	*/
120*7c478bd9Sstevel@tonic-gate void		sigwinch(int);	/* window change signals -- dummy */
121*7c478bd9Sstevel@tonic-gate FILE		*setmntent(char *fname, char *flag);
122*7c478bd9Sstevel@tonic-gate extern void	HelperRead(pollfd_t *fdp, int, int *);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate void
125*7c478bd9Sstevel@tonic-gate main(argc, argv)
126*7c478bd9Sstevel@tonic-gate int argc;
127*7c478bd9Sstevel@tonic-gate char **argv;
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	/*
130*7c478bd9Sstevel@tonic-gate 	 * the server is a typical RPC daemon, except that we only
131*7c478bd9Sstevel@tonic-gate 	 * accept TCP connections.
132*7c478bd9Sstevel@tonic-gate 	 */
133*7c478bd9Sstevel@tonic-gate 	int pollretval;
134*7c478bd9Sstevel@tonic-gate 	int npollfds = 0;
135*7c478bd9Sstevel@tonic-gate 	pollfd_t *pollset = NULL;
136*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in addr;
137*7c478bd9Sstevel@tonic-gate 	int maxrecsz = RPC_MAXDATASIZE;
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 	audit_rexd_setup();	/* BSM */
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	/*
142*7c478bd9Sstevel@tonic-gate 	 * Remember the start and extent of argv for setproctitle().
143*7c478bd9Sstevel@tonic-gate 	 * Open the console for error printouts, but don't let it be
144*7c478bd9Sstevel@tonic-gate 	 * our controlling terminal.
145*7c478bd9Sstevel@tonic-gate 	 */
146*7c478bd9Sstevel@tonic-gate 	if (argc > 1) {
147*7c478bd9Sstevel@tonic-gate 		if (strcmp("-s", argv[1]) == 0)
148*7c478bd9Sstevel@tonic-gate 			DesOnly = 1;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 		if (strcmp("-d", argv[1]) == 0)
151*7c478bd9Sstevel@tonic-gate 			Debug = 1;
152*7c478bd9Sstevel@tonic-gate 	}
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	if (argc > 2) {
155*7c478bd9Sstevel@tonic-gate 		if (strcmp("-s", argv[2]) == 0)
156*7c478bd9Sstevel@tonic-gate 			DesOnly = 1;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 		if (strcmp("-d", argv[2]) == 0)
159*7c478bd9Sstevel@tonic-gate 			Debug = 1;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * argv start and extent for setproctitle()
164*7c478bd9Sstevel@tonic-gate 	 */
165*7c478bd9Sstevel@tonic-gate 	Argv = argv;
166*7c478bd9Sstevel@tonic-gate 	if (argc > 0)
167*7c478bd9Sstevel@tonic-gate 		LastArgv = argv[argc-1] + strlen(argv[argc-1]);
168*7c478bd9Sstevel@tonic-gate 	else
169*7c478bd9Sstevel@tonic-gate 		LastArgv = NULL;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	/*
172*7c478bd9Sstevel@tonic-gate 	 * console open for errors w/o being the controlling terminal
173*7c478bd9Sstevel@tonic-gate 	 */
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	if ((confd = open("/dev/console", 1)) > 0) {
176*7c478bd9Sstevel@tonic-gate 		close(1);
177*7c478bd9Sstevel@tonic-gate 		close(2);
178*7c478bd9Sstevel@tonic-gate 		confd = dup2(confd, 1); /* console fd copied to stdout */
179*7c478bd9Sstevel@tonic-gate 		dup(1);		/* console fd copied to stderr */
180*7c478bd9Sstevel@tonic-gate 	}
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	setsid();		/* get rid of controlling terminal	*/
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	/*
185*7c478bd9Sstevel@tonic-gate 	 * setup signals
186*7c478bd9Sstevel@tonic-gate 	 */
187*7c478bd9Sstevel@tonic-gate 	sigset(SIGCHLD, CatchChild);
188*7c478bd9Sstevel@tonic-gate 	sigset(SIGPIPE, SIG_IGN);
189*7c478bd9Sstevel@tonic-gate 	sigset(SIGALRM, ListnerTimer);
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	/*
192*7c478bd9Sstevel@tonic-gate 	 * Enable non-blocking mode and maximum record size checks for
193*7c478bd9Sstevel@tonic-gate 	 * connection oriented transports.
194*7c478bd9Sstevel@tonic-gate 	 */
195*7c478bd9Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
196*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: unable to set RPC max record size\n");
197*7c478bd9Sstevel@tonic-gate 	}
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	/*
200*7c478bd9Sstevel@tonic-gate 	 * determine how we started to see if we are already in the background
201*7c478bd9Sstevel@tonic-gate 	 * and get appropriately registered with rpcbind (portmapper)
202*7c478bd9Sstevel@tonic-gate 	 */
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (isfrominetd(0)) {
205*7c478bd9Sstevel@tonic-gate 		/*
206*7c478bd9Sstevel@tonic-gate 		 * Started from inetd: use fd 0 as socket
207*7c478bd9Sstevel@tonic-gate 		 */
208*7c478bd9Sstevel@tonic-gate 		if (Debug)
209*7c478bd9Sstevel@tonic-gate 			printf("Started from inetd\n");
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		if ((ListnerTransp = svctcp_create(0, 0, 0)) == NULL) {
212*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: svctcp_create error\n");
213*7c478bd9Sstevel@tonic-gate 			exit(1);
214*7c478bd9Sstevel@tonic-gate 		}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 		if (!svc_register(ListnerTransp, REXPROG, REXVERS, dorex, 0)) {
217*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: service register error\n");
218*7c478bd9Sstevel@tonic-gate 			exit(1);
219*7c478bd9Sstevel@tonic-gate 		}
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		alarm(ListnerTimeout);
222*7c478bd9Sstevel@tonic-gate 	} else {
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 		if (Debug)
225*7c478bd9Sstevel@tonic-gate 			printf("started from shell\n");
226*7c478bd9Sstevel@tonic-gate 		if (!Debug) {
227*7c478bd9Sstevel@tonic-gate 			/*
228*7c478bd9Sstevel@tonic-gate 			 * Started from shell, background
229*7c478bd9Sstevel@tonic-gate 			 * thyself and run forever.
230*7c478bd9Sstevel@tonic-gate 			 */
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 			int pid = fork();
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 			if (pid < 0) { /* fork error	*/
235*7c478bd9Sstevel@tonic-gate 				perror("rpc.rexd: can't fork");
236*7c478bd9Sstevel@tonic-gate 				exit(1);
237*7c478bd9Sstevel@tonic-gate 			}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 			if (pid) { /* parent terminates	*/
240*7c478bd9Sstevel@tonic-gate 				exit(0);
241*7c478bd9Sstevel@tonic-gate 			}
242*7c478bd9Sstevel@tonic-gate 		}
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 		/*
245*7c478bd9Sstevel@tonic-gate 		 * child process continues to establish connections
246*7c478bd9Sstevel@tonic-gate 		 */
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		if (Debug)
249*7c478bd9Sstevel@tonic-gate 			printf("before svctcp_create() call\n");
250*7c478bd9Sstevel@tonic-gate 		if ((ListnerTransp = svctcp_create(RPC_ANYSOCK, 0, 0))
251*7c478bd9Sstevel@tonic-gate 		    == NULL) {
252*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: svctcp_create: error\n");
253*7c478bd9Sstevel@tonic-gate 			exit(1);
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 		pmap_unset(REXPROG, REXVERS);
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate 		if (!svc_register(ListnerTransp, REXPROG, REXVERS,
259*7c478bd9Sstevel@tonic-gate 				dorex, IPPROTO_TCP)) {
260*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: service rpc register: error\n");
261*7c478bd9Sstevel@tonic-gate 			exit(1);
262*7c478bd9Sstevel@tonic-gate 		}
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	/*
266*7c478bd9Sstevel@tonic-gate 	 * Create a private temporary directory to hold rexd's mounts
267*7c478bd9Sstevel@tonic-gate 	 */
268*7c478bd9Sstevel@tonic-gate 	if (mkdir(TempDir, 0777) < 0)
269*7c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
270*7c478bd9Sstevel@tonic-gate 			perror("rexd: mkdir");
271*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
272*7c478bd9Sstevel@tonic-gate 				"rexd: can't create temp directory %s\n",
273*7c478bd9Sstevel@tonic-gate 				TempDir);
274*7c478bd9Sstevel@tonic-gate 			exit(1);
275*7c478bd9Sstevel@tonic-gate 		}
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (Debug)
278*7c478bd9Sstevel@tonic-gate 		printf("created temporary directory\n");
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/*
282*7c478bd9Sstevel@tonic-gate 	 * normally we would call svc_run() at this point, but we need to be
283*7c478bd9Sstevel@tonic-gate 	 * informed of when the RPC connection is broken, in case the other
284*7c478bd9Sstevel@tonic-gate 	 * side crashes.
285*7c478bd9Sstevel@tonic-gate 	 */
286*7c478bd9Sstevel@tonic-gate 	while (TRUE) {
287*7c478bd9Sstevel@tonic-gate 		if (Debug)
288*7c478bd9Sstevel@tonic-gate 			printf("Entered While loop\n");
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 		if (MySocket) {
291*7c478bd9Sstevel@tonic-gate 			int i;
292*7c478bd9Sstevel@tonic-gate 			char *waste;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 			/* try to find MySocket in the pollfd set */
295*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < svc_max_pollfd; i++)
296*7c478bd9Sstevel@tonic-gate 				if (svc_pollfd[i].fd == MySocket)
297*7c478bd9Sstevel@tonic-gate 					break;
298*7c478bd9Sstevel@tonic-gate 			/*
299*7c478bd9Sstevel@tonic-gate 			 * If we didn't find it, the connection died for
300*7c478bd9Sstevel@tonic-gate 			 * some random reason, e.g. client crashed.
301*7c478bd9Sstevel@tonic-gate 			 */
302*7c478bd9Sstevel@tonic-gate 			if (i == svc_max_pollfd) {
303*7c478bd9Sstevel@tonic-gate 				if (Debug)
304*7c478bd9Sstevel@tonic-gate 					printf("Connection died\n");
305*7c478bd9Sstevel@tonic-gate 				(void) rex_wait(&waste);
306*7c478bd9Sstevel@tonic-gate 				rex_cleanup();
307*7c478bd9Sstevel@tonic-gate 				exit(1);
308*7c478bd9Sstevel@tonic-gate 			}
309*7c478bd9Sstevel@tonic-gate 		}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 		/*
312*7c478bd9Sstevel@tonic-gate 		 * Get existing array of pollfd's, should really compress
313*7c478bd9Sstevel@tonic-gate 		 * this but it shouldn't get very large (or sparse).
314*7c478bd9Sstevel@tonic-gate 		 */
315*7c478bd9Sstevel@tonic-gate 		if (npollfds != svc_max_pollfd) {
316*7c478bd9Sstevel@tonic-gate 			pollset = realloc(pollset,
317*7c478bd9Sstevel@tonic-gate 					sizeof (pollfd_t) * svc_max_pollfd);
318*7c478bd9Sstevel@tonic-gate 			npollfds = svc_max_pollfd;
319*7c478bd9Sstevel@tonic-gate 		}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		if (npollfds == 0)
322*7c478bd9Sstevel@tonic-gate 			break;	/* None waiting, hence return */
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		(void) memcpy(pollset, svc_pollfd,
325*7c478bd9Sstevel@tonic-gate 					sizeof (pollfd_t) * svc_max_pollfd);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 		if (Debug)
328*7c478bd9Sstevel@tonic-gate 			printf("Before select readfds\n");
329*7c478bd9Sstevel@tonic-gate 		switch (pollretval = poll(pollset, npollfds, -1)) {
330*7c478bd9Sstevel@tonic-gate 		case -1:
331*7c478bd9Sstevel@tonic-gate 			if (Debug)
332*7c478bd9Sstevel@tonic-gate 				printf("Poll failed\n");
333*7c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
334*7c478bd9Sstevel@tonic-gate 				continue;
335*7c478bd9Sstevel@tonic-gate 			perror("rexd: poll failed");
336*7c478bd9Sstevel@tonic-gate 			exit(1);
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 		case 0:
339*7c478bd9Sstevel@tonic-gate 			if (Debug)
340*7c478bd9Sstevel@tonic-gate 				printf("Poll returned zero\n");
341*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: poll returned zero\r\n");
342*7c478bd9Sstevel@tonic-gate 			continue;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 		default:
345*7c478bd9Sstevel@tonic-gate 			if (Debug)
346*7c478bd9Sstevel@tonic-gate 				printf("Before HelperRead\n");
347*7c478bd9Sstevel@tonic-gate 			if (HasHelper)
348*7c478bd9Sstevel@tonic-gate 				HelperRead(pollset, npollfds, &pollretval);
349*7c478bd9Sstevel@tonic-gate 			if (Debug)
350*7c478bd9Sstevel@tonic-gate 				printf("After HelperRead\n");
351*7c478bd9Sstevel@tonic-gate 			time_now = time((time_t *)0);
352*7c478bd9Sstevel@tonic-gate 			if (Debug)
353*7c478bd9Sstevel@tonic-gate 				printf("before svc_getreq_poll\n");
354*7c478bd9Sstevel@tonic-gate 			svc_getreq_poll(pollset, pollretval);
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 		if (Debug)
357*7c478bd9Sstevel@tonic-gate 			printf("After switch\n");
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate }
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate  * This function gets called after the listner has timed out waiting
363*7c478bd9Sstevel@tonic-gate  * for any new connections coming in.
364*7c478bd9Sstevel@tonic-gate  */
365*7c478bd9Sstevel@tonic-gate void
366*7c478bd9Sstevel@tonic-gate ListnerTimer(int junk)
367*7c478bd9Sstevel@tonic-gate {
368*7c478bd9Sstevel@tonic-gate 	/*
369*7c478bd9Sstevel@tonic-gate 	 * svc_destroy not done here due to problems with M_ERROR
370*7c478bd9Sstevel@tonic-gate 	 * on stream head and inetd
371*7c478bd9Sstevel@tonic-gate 	 */
372*7c478bd9Sstevel@tonic-gate 	exit(0);
373*7c478bd9Sstevel@tonic-gate }
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate struct authunix_parms
376*7c478bd9Sstevel@tonic-gate *authdes_to_unix(des_cred)
377*7c478bd9Sstevel@tonic-gate struct authdes_cred *des_cred;
378*7c478bd9Sstevel@tonic-gate {
379*7c478bd9Sstevel@tonic-gate 	struct authunix_parms *unix_cred;
380*7c478bd9Sstevel@tonic-gate 	static struct authunix_parms au;
381*7c478bd9Sstevel@tonic-gate 	static uint_t    stuff[32];
382*7c478bd9Sstevel@tonic-gate 	char publickey[HEXKEYBYTES+1];
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	unix_cred = &au;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	unix_cred->aup_gids = (gid_t *)stuff;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	unix_cred->aup_machname = "";
390*7c478bd9Sstevel@tonic-gate 	if (getpublickey(des_cred->adc_fullname.name, publickey) == 0)
391*7c478bd9Sstevel@tonic-gate 		return (NULL);
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	if (netname2user(des_cred->adc_fullname.name,
394*7c478bd9Sstevel@tonic-gate 			&(unix_cred->aup_uid),
395*7c478bd9Sstevel@tonic-gate 			&(unix_cred->aup_gid),
396*7c478bd9Sstevel@tonic-gate 			(int *)&(unix_cred->aup_len),
397*7c478bd9Sstevel@tonic-gate 			unix_cred->aup_gids) == FALSE)
398*7c478bd9Sstevel@tonic-gate 		return (NULL);
399*7c478bd9Sstevel@tonic-gate 	else
400*7c478bd9Sstevel@tonic-gate 		return (unix_cred);
401*7c478bd9Sstevel@tonic-gate }
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate /*
404*7c478bd9Sstevel@tonic-gate  * dorex - handle one of the rex procedure calls, dispatching to the
405*7c478bd9Sstevel@tonic-gate  *	correct function.
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate void
408*7c478bd9Sstevel@tonic-gate dorex(rqstp, transp)
409*7c478bd9Sstevel@tonic-gate struct svc_req *rqstp;
410*7c478bd9Sstevel@tonic-gate SVCXPRT *transp;
411*7c478bd9Sstevel@tonic-gate {
412*7c478bd9Sstevel@tonic-gate 	struct rex_start *rst;
413*7c478bd9Sstevel@tonic-gate 	struct rex_result result;
414*7c478bd9Sstevel@tonic-gate 	struct authunix_parms *unix_cred;
415*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *calleraddr;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	if (ListnerTransp) {
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 		/*
421*7c478bd9Sstevel@tonic-gate 		 * First call - fork a server for this connection
422*7c478bd9Sstevel@tonic-gate 		 */
423*7c478bd9Sstevel@tonic-gate 		int fd, pid, count;
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 		for (count = 0; (pid = fork()) < 0; count++) {
426*7c478bd9Sstevel@tonic-gate 			if (count > 4)
427*7c478bd9Sstevel@tonic-gate 				{
428*7c478bd9Sstevel@tonic-gate 					perror("rexd: cannot fork");
429*7c478bd9Sstevel@tonic-gate 					break;
430*7c478bd9Sstevel@tonic-gate 				}
431*7c478bd9Sstevel@tonic-gate 			sleep(5);
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if (pid != 0) {
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 			/*
437*7c478bd9Sstevel@tonic-gate 			 * Parent - return to service loop to accept further
438*7c478bd9Sstevel@tonic-gate 			 * connections.
439*7c478bd9Sstevel@tonic-gate 			 */
440*7c478bd9Sstevel@tonic-gate 			alarm(ListnerTimeout);
441*7c478bd9Sstevel@tonic-gate 			svc_destroy(transp);
442*7c478bd9Sstevel@tonic-gate 			return;
443*7c478bd9Sstevel@tonic-gate 		}
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		/*
446*7c478bd9Sstevel@tonic-gate 		 * child - close listner transport to avoid confusion
447*7c478bd9Sstevel@tonic-gate 		 * Also need to close all other service transports
448*7c478bd9Sstevel@tonic-gate 		 * besides the one we are interested in.
449*7c478bd9Sstevel@tonic-gate 		 * Save ours so that we know when it goes away.
450*7c478bd9Sstevel@tonic-gate 		 */
451*7c478bd9Sstevel@tonic-gate 		if (Debug)
452*7c478bd9Sstevel@tonic-gate 			printf("child server process\n");
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 		alarm(0);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		if (transp != ListnerTransp) {
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 			close(ListnerTransp->xp_sock);
461*7c478bd9Sstevel@tonic-gate 			xprt_unregister(ListnerTransp);
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 		ListnerTransp = NULL;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 		MySocket = transp->xp_sock;
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 		/* temp workaround to restore sanity in TLI state */
468*7c478bd9Sstevel@tonic-gate 		if (transp->xp_sock != 0)
469*7c478bd9Sstevel@tonic-gate 			t_close(0); /* opened in parent possibly by inetd */
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 		/*
472*7c478bd9Sstevel@tonic-gate 		 * XXX: svc_pollfd[] is a read-only structure. This
473*7c478bd9Sstevel@tonic-gate 		 * appears to be dead code, which should be removed.
474*7c478bd9Sstevel@tonic-gate 		 * However, until it can be clearly understood, leaving
475*7c478bd9Sstevel@tonic-gate 		 * in.
476*7c478bd9Sstevel@tonic-gate 		 */
477*7c478bd9Sstevel@tonic-gate 		for (fd = 1; fd < svc_max_pollfd; fd++) {
478*7c478bd9Sstevel@tonic-gate 			if (fd != transp->xp_sock && svc_pollfd[fd].fd == fd) {
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 				printf("close of fd %d\n", fd);
481*7c478bd9Sstevel@tonic-gate 				close(fd);
482*7c478bd9Sstevel@tonic-gate 				svc_pollfd[fd].fd = -1;
483*7c478bd9Sstevel@tonic-gate 				svc_pollfd[fd].events = 0;
484*7c478bd9Sstevel@tonic-gate 				svc_pollfd[fd].revents = 0;
485*7c478bd9Sstevel@tonic-gate 			}
486*7c478bd9Sstevel@tonic-gate 		}
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	/*
490*7c478bd9Sstevel@tonic-gate 	 * execute the requested prodcedure
491*7c478bd9Sstevel@tonic-gate 	 */
492*7c478bd9Sstevel@tonic-gate 	switch (rqstp->rq_proc)	{
493*7c478bd9Sstevel@tonic-gate 	case NULLPROC:
494*7c478bd9Sstevel@tonic-gate 		if (Debug)	/*	XXX	*/
495*7c478bd9Sstevel@tonic-gate 			printf("dorex: call to NULLPROC\n");
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 		if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: nullproc err");
500*7c478bd9Sstevel@tonic-gate 			exit(1);
501*7c478bd9Sstevel@tonic-gate 		}
502*7c478bd9Sstevel@tonic-gate 		return;
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	case REXPROC_START:
505*7c478bd9Sstevel@tonic-gate 		if (Debug)	/*	XXX	*/
506*7c478bd9Sstevel@tonic-gate 			printf("dorex: call to REXPROC_START\n");
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		rst = (struct rex_start *)malloc(sizeof (struct rex_start));
510*7c478bd9Sstevel@tonic-gate 		memset((char *)rst, '\0', sizeof (*rst));
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 		if (svc_getargs(transp, xdr_rex_start, (char *)rst) == FALSE) {
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 			svcerr_decode(transp);
515*7c478bd9Sstevel@tonic-gate 			exit(1);
516*7c478bd9Sstevel@tonic-gate 		}
517*7c478bd9Sstevel@tonic-gate 		if (Debug)
518*7c478bd9Sstevel@tonic-gate 			printf("svc_getargs: suceeded\n");
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 		if (rqstp->rq_cred.oa_flavor == AUTH_DES) {
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 			unix_cred = authdes_to_unix(rqstp->rq_clntcred);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 		} else if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) {
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 			if (DesOnly) {
527*7c478bd9Sstevel@tonic-gate 				fprintf(stderr,
528*7c478bd9Sstevel@tonic-gate 					"Unix too weak auth(DesOnly)!\n");
529*7c478bd9Sstevel@tonic-gate 				unix_cred = NULL;
530*7c478bd9Sstevel@tonic-gate 			} else
531*7c478bd9Sstevel@tonic-gate 				unix_cred =
532*7c478bd9Sstevel@tonic-gate 				(struct authunix_parms *)rqstp->rq_clntcred;
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 		} else {
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "Unknown weak auth!\n");
537*7c478bd9Sstevel@tonic-gate 			svcerr_weakauth(transp);
538*7c478bd9Sstevel@tonic-gate 			sleep(5);
539*7c478bd9Sstevel@tonic-gate 			exit(1);
540*7c478bd9Sstevel@tonic-gate 		}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 		if (unix_cred == NULL) {
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 			svcerr_weakauth(transp);
545*7c478bd9Sstevel@tonic-gate 			sleep(5);
546*7c478bd9Sstevel@tonic-gate 			exit(1);
547*7c478bd9Sstevel@tonic-gate 		}
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 		calleraddr = svc_getcaller(transp);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		result.rlt_stat = (int)rex_startup(rst,
552*7c478bd9Sstevel@tonic-gate 						unix_cred,
553*7c478bd9Sstevel@tonic-gate 						(char **)&result.rlt_message,
554*7c478bd9Sstevel@tonic-gate 						calleraddr);
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 		if (Debug)
557*7c478bd9Sstevel@tonic-gate 			printf("rex_startup: completed\n");
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		if (svc_sendreply(transp, xdr_rex_result, (char *)&result)
560*7c478bd9Sstevel@tonic-gate 		    == FALSE) {
561*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: reply failed\n");
562*7c478bd9Sstevel@tonic-gate 			rex_cleanup();
563*7c478bd9Sstevel@tonic-gate 			exit(1);
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		if (Debug)
567*7c478bd9Sstevel@tonic-gate 			printf("svc_sendreply: suceeded\n");
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 		if (result.rlt_stat) {
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 			rex_cleanup();
572*7c478bd9Sstevel@tonic-gate 			exit(0);
573*7c478bd9Sstevel@tonic-gate 		}
574*7c478bd9Sstevel@tonic-gate 		return;
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	case REXPROC_MODES:
577*7c478bd9Sstevel@tonic-gate 		{
578*7c478bd9Sstevel@tonic-gate 			struct rex_ttymode mode;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 			if (Debug) /*	XXX	*/
581*7c478bd9Sstevel@tonic-gate 				printf("dorex: call to REXPROC_MODES\n");
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 			if (svc_getargs(transp, xdr_rex_ttymode,
584*7c478bd9Sstevel@tonic-gate 					(char *)&mode) == FALSE) {
585*7c478bd9Sstevel@tonic-gate 				svcerr_decode(transp);
586*7c478bd9Sstevel@tonic-gate 				exit(1);
587*7c478bd9Sstevel@tonic-gate 			}
588*7c478bd9Sstevel@tonic-gate 			if (Debug)
589*7c478bd9Sstevel@tonic-gate 				printf("svc_getargs succ REXPROC_MODES call\n");
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 			SetPtyMode(&mode); /* XXX	Fix?	*/
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 			if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "rexd: mode reply failed");
596*7c478bd9Sstevel@tonic-gate 				exit(1);
597*7c478bd9Sstevel@tonic-gate 			}
598*7c478bd9Sstevel@tonic-gate 		}
599*7c478bd9Sstevel@tonic-gate 		return;
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	case REXPROC_WINCH: /* XXX	Fix?	*/
602*7c478bd9Sstevel@tonic-gate 		{
603*7c478bd9Sstevel@tonic-gate 			struct rex_ttysize size;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 			if (Debug) /*	XXX	*/
606*7c478bd9Sstevel@tonic-gate 				printf("dorex: call to REXPROC_WINCH\n");
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 			if (svc_getargs(transp, xdr_rex_ttysize, (char *)&size)
609*7c478bd9Sstevel@tonic-gate 			    == FALSE) {
610*7c478bd9Sstevel@tonic-gate 				svcerr_decode(transp);
611*7c478bd9Sstevel@tonic-gate 				exit(1);
612*7c478bd9Sstevel@tonic-gate 			}
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 			SetPtySize(&size);
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 			if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 				fprintf(stderr,
619*7c478bd9Sstevel@tonic-gate 					"rexd: window change reply failed");
620*7c478bd9Sstevel@tonic-gate 				exit(1);
621*7c478bd9Sstevel@tonic-gate 			}
622*7c478bd9Sstevel@tonic-gate 		}
623*7c478bd9Sstevel@tonic-gate 		return;
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	case REXPROC_SIGNAL:
626*7c478bd9Sstevel@tonic-gate 		{
627*7c478bd9Sstevel@tonic-gate 			int sigNumber;
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 			if (Debug) /*	XXX	*/
630*7c478bd9Sstevel@tonic-gate 				printf("dorex: call to REXPROC_SIGNAL\n");
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 			if (svc_getargs(transp, xdr_int,
633*7c478bd9Sstevel@tonic-gate 					(char *)&sigNumber) == FALSE) {
634*7c478bd9Sstevel@tonic-gate 				svcerr_decode(transp);
635*7c478bd9Sstevel@tonic-gate 				exit(1);
636*7c478bd9Sstevel@tonic-gate 			}
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 			SendSignal(sigNumber);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 			if (svc_sendreply(transp, xdr_void, 0) == FALSE) {
641*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "rexd: signal reply failed");
642*7c478bd9Sstevel@tonic-gate 				exit(1);
643*7c478bd9Sstevel@tonic-gate 			}
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 		return;
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	case REXPROC_WAIT:
648*7c478bd9Sstevel@tonic-gate 		if (Debug)	/*	XXX	*/
649*7c478bd9Sstevel@tonic-gate 			printf("dorex: call to REXPROC_WAIT\n");
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		result.rlt_stat = rex_wait(&result.rlt_message);
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 		if (svc_sendreply(transp, xdr_rex_result, (char *)&result)
654*7c478bd9Sstevel@tonic-gate 		    == FALSE) {
655*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: reply failed\n");
656*7c478bd9Sstevel@tonic-gate 			exit(1);
657*7c478bd9Sstevel@tonic-gate 		}
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 		rex_cleanup();
660*7c478bd9Sstevel@tonic-gate 		exit(0);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
663*7c478bd9Sstevel@tonic-gate 	default:
664*7c478bd9Sstevel@tonic-gate 		if (Debug)
665*7c478bd9Sstevel@tonic-gate 			printf("dorex: call to bad process!\n");
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 		svcerr_noproc(transp);
668*7c478bd9Sstevel@tonic-gate 		exit(1);
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate }
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate /*
673*7c478bd9Sstevel@tonic-gate  * signal handler for SIGCHLD - called when user process dies or is stopped
674*7c478bd9Sstevel@tonic-gate  */
675*7c478bd9Sstevel@tonic-gate void
676*7c478bd9Sstevel@tonic-gate CatchChild(int junk)
677*7c478bd9Sstevel@tonic-gate {
678*7c478bd9Sstevel@tonic-gate 	pid_t	pid;
679*7c478bd9Sstevel@tonic-gate 	int	status;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	if (Debug)
682*7c478bd9Sstevel@tonic-gate 		printf("Enter Catchild\n");
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 	while ((pid = waitpid((pid_t)-1, &status, WNOHANG|WUNTRACED)) > 0) {
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 		if (Debug) printf("After waitpid\n");
687*7c478bd9Sstevel@tonic-gate 		if (pid == child) {
688*7c478bd9Sstevel@tonic-gate 			if (Debug)
689*7c478bd9Sstevel@tonic-gate 				printf("pid==child\n");
690*7c478bd9Sstevel@tonic-gate 			if (WIFSTOPPED(status)) {
691*7c478bd9Sstevel@tonic-gate 				sigset_t nullsigset;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 				if (Debug)
694*7c478bd9Sstevel@tonic-gate 					printf("WIFSTOPPED\n");
695*7c478bd9Sstevel@tonic-gate 				/* tell remote client to stop */
696*7c478bd9Sstevel@tonic-gate 				send(OutputSocket, "", 1, MSG_OOB);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 				sigemptyset(&nullsigset);
699*7c478bd9Sstevel@tonic-gate 				/* port of BSD sigpause(0); */
700*7c478bd9Sstevel@tonic-gate 				sigsuspend(&nullsigset);
701*7c478bd9Sstevel@tonic-gate 				/* restart child */
702*7c478bd9Sstevel@tonic-gate 				/* killpg() of SunOS 4.1.1 */
703*7c478bd9Sstevel@tonic-gate 				kill((-child), SIGCONT);
704*7c478bd9Sstevel@tonic-gate 				return;
705*7c478bd9Sstevel@tonic-gate 			}
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 			/*
708*7c478bd9Sstevel@tonic-gate 			 * XXX this probably does not cover all interesting
709*7c478bd9Sstevel@tonic-gate 			 * exit cases hence reread the man page to determine
710*7c478bd9Sstevel@tonic-gate 			 * if we need more data or more test cases
711*7c478bd9Sstevel@tonic-gate 			 */
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 			ChildStatus = status;
714*7c478bd9Sstevel@tonic-gate 			ChildDied = 1;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 			if (HasHelper && svc_pollfd[Master].fd == -1) {
717*7c478bd9Sstevel@tonic-gate 				if (Debug)
718*7c478bd9Sstevel@tonic-gate 					printf("Within If HasHelper\n");
719*7c478bd9Sstevel@tonic-gate 				KillHelper(child);
720*7c478bd9Sstevel@tonic-gate 				HasHelper = 0;
721*7c478bd9Sstevel@tonic-gate 			}
722*7c478bd9Sstevel@tonic-gate 		}
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate }
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate /*
727*7c478bd9Sstevel@tonic-gate  * oob -- called when we should restart the stopped child.
728*7c478bd9Sstevel@tonic-gate  */
729*7c478bd9Sstevel@tonic-gate void
730*7c478bd9Sstevel@tonic-gate oob(int junk)
731*7c478bd9Sstevel@tonic-gate {
732*7c478bd9Sstevel@tonic-gate 	int atmark;
733*7c478bd9Sstevel@tonic-gate 	char waste[BUFSIZ], mark;
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	for (;;) {
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 		if (ioctl(OutputSocket, SIOCATMARK, &atmark) < 0) {
738*7c478bd9Sstevel@tonic-gate 			perror("ioctl");
739*7c478bd9Sstevel@tonic-gate 			break;
740*7c478bd9Sstevel@tonic-gate 		}
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 		if (atmark)
743*7c478bd9Sstevel@tonic-gate 			break;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 		(void) read(OutputSocket, waste, sizeof (waste));
746*7c478bd9Sstevel@tonic-gate 	}
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	(void) recv(OutputSocket, &mark, 1, MSG_OOB);
749*7c478bd9Sstevel@tonic-gate }
750*7c478bd9Sstevel@tonic-gate 
751*7c478bd9Sstevel@tonic-gate /*
752*7c478bd9Sstevel@tonic-gate  * rex_wait - wait for command to finish, unmount the file system,
753*7c478bd9Sstevel@tonic-gate  * and return the exit status.
754*7c478bd9Sstevel@tonic-gate  * message gets an optional string error message.
755*7c478bd9Sstevel@tonic-gate  */
756*7c478bd9Sstevel@tonic-gate int
757*7c478bd9Sstevel@tonic-gate rex_wait(message)
758*7c478bd9Sstevel@tonic-gate char **message;
759*7c478bd9Sstevel@tonic-gate {
760*7c478bd9Sstevel@tonic-gate 	static char error[1024];
761*7c478bd9Sstevel@tonic-gate 	int count;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	*message = error;
764*7c478bd9Sstevel@tonic-gate 	strcpy(error, "");
765*7c478bd9Sstevel@tonic-gate 	if (child == 0) {
766*7c478bd9Sstevel@tonic-gate 		errprintf(error, "No process to wait for!\n");
767*7c478bd9Sstevel@tonic-gate 		rex_cleanup();
768*7c478bd9Sstevel@tonic-gate 		return (1);
769*7c478bd9Sstevel@tonic-gate 	}
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	kill(child, SIGHUP);
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	for (count = 0; !ChildDied && count < WaitLimit; count++)
774*7c478bd9Sstevel@tonic-gate 		sleep(1);
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	if (ChildStatus & 0xFF)
777*7c478bd9Sstevel@tonic-gate 		return (ChildStatus);
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	return (ChildStatus >> 8);
780*7c478bd9Sstevel@tonic-gate }
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate /*
784*7c478bd9Sstevel@tonic-gate  * cleanup - unmount and remove our temporary directory
785*7c478bd9Sstevel@tonic-gate  */
786*7c478bd9Sstevel@tonic-gate void
787*7c478bd9Sstevel@tonic-gate rex_cleanup()
788*7c478bd9Sstevel@tonic-gate {
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	if (tmpdir) {
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 		if (child && !ChildDied) {
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
795*7c478bd9Sstevel@tonic-gate 				"rexd: child killed to unmount %s\r\n",
796*7c478bd9Sstevel@tonic-gate 				nfsdir);
797*7c478bd9Sstevel@tonic-gate 			kill(child, SIGKILL);
798*7c478bd9Sstevel@tonic-gate 		}
799*7c478bd9Sstevel@tonic-gate 		chdir("/");
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 		if (nfsdir[0] && umount_nfs(nfsdir, tmpdir))
802*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "rexd: couldn't umount %s from %s\r\n",
803*7c478bd9Sstevel@tonic-gate 				nfsdir,
804*7c478bd9Sstevel@tonic-gate 				tmpdir);
805*7c478bd9Sstevel@tonic-gate 		if (rmdir(tmpdir) < 0)
806*7c478bd9Sstevel@tonic-gate 			if (errno != EBUSY)
807*7c478bd9Sstevel@tonic-gate 				perror("rmdir");
808*7c478bd9Sstevel@tonic-gate 		tmpdir = NULL;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	if (Debug)
813*7c478bd9Sstevel@tonic-gate 		printf("rex_cleaup: HasHelper=%d\n", HasHelper);
814*7c478bd9Sstevel@tonic-gate 	if (HasHelper)
815*7c478bd9Sstevel@tonic-gate 		KillHelper(child);
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	HasHelper = 0;
818*7c478bd9Sstevel@tonic-gate }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate /*
822*7c478bd9Sstevel@tonic-gate  * This function does the server work to get a command executed
823*7c478bd9Sstevel@tonic-gate  * Returns 0 if OK, nonzero if error
824*7c478bd9Sstevel@tonic-gate  */
825*7c478bd9Sstevel@tonic-gate int
826*7c478bd9Sstevel@tonic-gate rex_startup(rst, ucred, message, calleraddr)
827*7c478bd9Sstevel@tonic-gate struct rex_start *rst;
828*7c478bd9Sstevel@tonic-gate struct authunix_parms *ucred;
829*7c478bd9Sstevel@tonic-gate char **message;
830*7c478bd9Sstevel@tonic-gate struct sockaddr_in *calleraddr;
831*7c478bd9Sstevel@tonic-gate {
832*7c478bd9Sstevel@tonic-gate 	char hostname[255];
833*7c478bd9Sstevel@tonic-gate 	char *p, *wdhost, *fsname, *subdir;
834*7c478bd9Sstevel@tonic-gate 	char dirbuf[1024];
835*7c478bd9Sstevel@tonic-gate 	static char error[1024];
836*7c478bd9Sstevel@tonic-gate 	char defaultShell[1024]; /* command executed if none given */
837*7c478bd9Sstevel@tonic-gate 	char defaultDir[1024];	/* directory used if none given */
838*7c478bd9Sstevel@tonic-gate 	int len;
839*7c478bd9Sstevel@tonic-gate 	int fd0, fd1, fd2;
840*7c478bd9Sstevel@tonic-gate 	extern pam_handle_t *pamh;
841*7c478bd9Sstevel@tonic-gate 	char *user = NULL;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	if (Debug)
844*7c478bd9Sstevel@tonic-gate 		printf("Beginning of Rex_Startup\n");
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	if (child) {		/* already started */
847*7c478bd9Sstevel@tonic-gate 		if (Debug)
848*7c478bd9Sstevel@tonic-gate 			printf("Killing \"child\" process\n");
849*7c478bd9Sstevel@tonic-gate 		kill((-child), SIGKILL); /* killpg() of SunOS 4.1.1 */
850*7c478bd9Sstevel@tonic-gate 		return (1);
851*7c478bd9Sstevel@tonic-gate 	}
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	*message = error;
855*7c478bd9Sstevel@tonic-gate 	(void) strcpy(error, "");
856*7c478bd9Sstevel@tonic-gate /*	sigset(SIGCHLD, CatchChild); */
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	if (ValidUser(ucred->aup_machname,
860*7c478bd9Sstevel@tonic-gate 		(uid_t)ucred->aup_uid,
861*7c478bd9Sstevel@tonic-gate 		(gid_t)ucred->aup_gid,
862*7c478bd9Sstevel@tonic-gate 		error,
863*7c478bd9Sstevel@tonic-gate 		defaultShell, defaultDir, rst))
864*7c478bd9Sstevel@tonic-gate 		return (1);
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	if (rst->rst_fsname && strlen(rst->rst_fsname)) {
867*7c478bd9Sstevel@tonic-gate 		fsname = rst->rst_fsname;
868*7c478bd9Sstevel@tonic-gate 		subdir = rst->rst_dirwithin;
869*7c478bd9Sstevel@tonic-gate 		wdhost = rst->rst_host;
870*7c478bd9Sstevel@tonic-gate 	} else {
871*7c478bd9Sstevel@tonic-gate 		fsname = defaultDir;
872*7c478bd9Sstevel@tonic-gate 		subdir = "";
873*7c478bd9Sstevel@tonic-gate 		wdhost = hostname;
874*7c478bd9Sstevel@tonic-gate 	}
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	sysinfo(SI_HOSTNAME, hostname, 255);
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate 	if (Debug)
879*7c478bd9Sstevel@tonic-gate 		printf("rexd: errno %d after gethostname\n", errno);
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 	if (Debug) {
882*7c478bd9Sstevel@tonic-gate 		printf("rex_startup on host %s:\nrequests fsname=%s",
883*7c478bd9Sstevel@tonic-gate 			hostname, fsname);
884*7c478bd9Sstevel@tonic-gate 		printf("\t\tsubdir=%s\t\twdhost=%s\n", subdir, wdhost);
885*7c478bd9Sstevel@tonic-gate 	}
886*7c478bd9Sstevel@tonic-gate 	if (strcmp(wdhost, hostname) == 0) {
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 		/*
889*7c478bd9Sstevel@tonic-gate 		 * The requested directory is local to our machine,
890*7c478bd9Sstevel@tonic-gate 		 * so just change to it.
891*7c478bd9Sstevel@tonic-gate 		 */
892*7c478bd9Sstevel@tonic-gate 		strcpy(dirbuf, fsname);
893*7c478bd9Sstevel@tonic-gate 	} else {
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 		static char wanted[1024];
896*7c478bd9Sstevel@tonic-gate 		static char mountedon[1024];
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 		strcpy(wanted, wdhost);
899*7c478bd9Sstevel@tonic-gate 		strcat(wanted, ":");
900*7c478bd9Sstevel@tonic-gate 		strcat(wanted, fsname);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 		if (AlreadyMounted(wanted, mountedon)) {
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 			if (Debug)
905*7c478bd9Sstevel@tonic-gate 				printf("AlreadyMounted (%d)\n", errno);
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 			/*
908*7c478bd9Sstevel@tonic-gate 			 * The requested directory is already mounted.  If the
909*7c478bd9Sstevel@tonic-gate 			 * mount is not by another rexd, just change to it.
910*7c478bd9Sstevel@tonic-gate 			 * Otherwise, mount it again.  If just changing to
911*7c478bd9Sstevel@tonic-gate 			 * the mounted directy, be careful. It might be mounted
912*7c478bd9Sstevel@tonic-gate 			 * in a different place.
913*7c478bd9Sstevel@tonic-gate 			 * (dirbuf is modified in place!)
914*7c478bd9Sstevel@tonic-gate 			 */
915*7c478bd9Sstevel@tonic-gate 			if (strncmp(mountedon, TempName, TempMatch) == 0) {
916*7c478bd9Sstevel@tonic-gate 				tmpdir = mktemp(TempName);
917*7c478bd9Sstevel@tonic-gate 				/*
918*7c478bd9Sstevel@tonic-gate 				 * XXX errno is set to ENOENT on success
919*7c478bd9Sstevel@tonic-gate 				 * of mktemp because of accesss checks for file
920*7c478bd9Sstevel@tonic-gate 				 */
921*7c478bd9Sstevel@tonic-gate 				if (errno == ENOENT)
922*7c478bd9Sstevel@tonic-gate 					errno = 0;
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 				if (mkdir(tmpdir, 0777)) {
925*7c478bd9Sstevel@tonic-gate 					perror("Already Mounted");
926*7c478bd9Sstevel@tonic-gate 					if (pamh) {
927*7c478bd9Sstevel@tonic-gate 						pam_end(pamh, PAM_ABORT);
928*7c478bd9Sstevel@tonic-gate 						pamh = NULL;
929*7c478bd9Sstevel@tonic-gate 					}
930*7c478bd9Sstevel@tonic-gate 					return (1);
931*7c478bd9Sstevel@tonic-gate 				}
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 				if (Debug)
934*7c478bd9Sstevel@tonic-gate 					printf("created %s (%d)\n",
935*7c478bd9Sstevel@tonic-gate 						tmpdir, errno);
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 				strcpy(nfsdir, wanted);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 				if (mount_nfs(wanted, tmpdir, error)) {
940*7c478bd9Sstevel@tonic-gate 					if (Debug)
941*7c478bd9Sstevel@tonic-gate 					printf("mount_nfs:error return\n");
942*7c478bd9Sstevel@tonic-gate 					if (pamh) {
943*7c478bd9Sstevel@tonic-gate 						pam_end(pamh, PAM_ABORT);
944*7c478bd9Sstevel@tonic-gate 						pamh = NULL;
945*7c478bd9Sstevel@tonic-gate 					}
946*7c478bd9Sstevel@tonic-gate 					return (1);
947*7c478bd9Sstevel@tonic-gate 				}
948*7c478bd9Sstevel@tonic-gate 				if (Debug)
949*7c478bd9Sstevel@tonic-gate 					printf("mount_nfs: success return\n");
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 				strcpy(dirbuf, tmpdir);
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 			} else
954*7c478bd9Sstevel@tonic-gate 				strcpy(dirbuf, mountedon);
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 		} else {
957*7c478bd9Sstevel@tonic-gate 			if (Debug)
958*7c478bd9Sstevel@tonic-gate 				printf("not AlreadyMounted (%d)\n", errno);
959*7c478bd9Sstevel@tonic-gate 			/*
960*7c478bd9Sstevel@tonic-gate 			 * The requested directory is not mounted anywhere,
961*7c478bd9Sstevel@tonic-gate 			 * so try to mount our own copy of it.  We set nfsdir
962*7c478bd9Sstevel@tonic-gate 			 * so that it gets unmounted later, and tmpdir so that
963*7c478bd9Sstevel@tonic-gate 			 * it also gets removed when we are done.
964*7c478bd9Sstevel@tonic-gate 			 */
965*7c478bd9Sstevel@tonic-gate 			tmpdir = mktemp(TempName);
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 			/*
968*7c478bd9Sstevel@tonic-gate 			 * XXX errno is set to ENOENT on success of mktemp
969*7c478bd9Sstevel@tonic-gate 			 * becuase of accesss checks for file
970*7c478bd9Sstevel@tonic-gate 			 */
971*7c478bd9Sstevel@tonic-gate 			if (errno == ENOENT)
972*7c478bd9Sstevel@tonic-gate 				errno = 0;
973*7c478bd9Sstevel@tonic-gate 			if (mkdir(tmpdir, 0777)) {
974*7c478bd9Sstevel@tonic-gate 				perror("Not Already Mounted");
975*7c478bd9Sstevel@tonic-gate 				if (pamh) {
976*7c478bd9Sstevel@tonic-gate 					pam_end(pamh, PAM_ABORT);
977*7c478bd9Sstevel@tonic-gate 					pamh = NULL;
978*7c478bd9Sstevel@tonic-gate 				}
979*7c478bd9Sstevel@tonic-gate 				return (1);
980*7c478bd9Sstevel@tonic-gate 			}
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 			if (Debug)
983*7c478bd9Sstevel@tonic-gate 				printf("created %s (%d)\n", tmpdir, errno);
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate 			strcpy(nfsdir, wanted);
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 			if (mount_nfs(wanted, tmpdir, error)) {
988*7c478bd9Sstevel@tonic-gate 				if (Debug)
989*7c478bd9Sstevel@tonic-gate 					printf("mount_nfs:error return\n");
990*7c478bd9Sstevel@tonic-gate 				if (pamh) {
991*7c478bd9Sstevel@tonic-gate 					pam_end(pamh, PAM_ABORT);
992*7c478bd9Sstevel@tonic-gate 					pamh = NULL;
993*7c478bd9Sstevel@tonic-gate 				}
994*7c478bd9Sstevel@tonic-gate 				return (1);
995*7c478bd9Sstevel@tonic-gate 			}
996*7c478bd9Sstevel@tonic-gate 			if (Debug)
997*7c478bd9Sstevel@tonic-gate 				printf("mount_nfs: success return\n");
998*7c478bd9Sstevel@tonic-gate 			strcpy(dirbuf, tmpdir);
999*7c478bd9Sstevel@tonic-gate 		}
1000*7c478bd9Sstevel@tonic-gate 	}
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	/*
1003*7c478bd9Sstevel@tonic-gate 	 * "dirbuf" now contains the local mount point, so just tack on
1004*7c478bd9Sstevel@tonic-gate 	 * the subdirectory to get the pathname to which we "chdir"
1005*7c478bd9Sstevel@tonic-gate 	 */
1006*7c478bd9Sstevel@tonic-gate 	strcat(dirbuf, subdir);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	fd0 = socket(AF_INET, SOCK_STREAM, 0);
1010*7c478bd9Sstevel@tonic-gate 	if (Debug)
1011*7c478bd9Sstevel@tonic-gate 		printf("Before doconnect\n");
1012*7c478bd9Sstevel@tonic-gate 	fd0 = doconnect(calleraddr, rst->rst_port0, fd0);
1013*7c478bd9Sstevel@tonic-gate 	OutputSocket = fd0;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	/*
1016*7c478bd9Sstevel@tonic-gate 	 * Arrange for fd0 to send the SIGURG signal when out-of-band data
1017*7c478bd9Sstevel@tonic-gate 	 * arrives, which indicates that we should send the stopped child a
1018*7c478bd9Sstevel@tonic-gate 	 * SIGCONT signal so that we can resume work.
1019*7c478bd9Sstevel@tonic-gate 	 */
1020*7c478bd9Sstevel@tonic-gate 	(void) fcntl(fd0, F_SETOWN, getpid());
1021*7c478bd9Sstevel@tonic-gate 	/*	ioctl(fd0, SIOCSPGRP, ?X?); */
1022*7c478bd9Sstevel@tonic-gate 	sigset(SIGURG, oob);
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate 	if (Debug)
1025*7c478bd9Sstevel@tonic-gate 		printf("Before \"use same port\"\n");
1026*7c478bd9Sstevel@tonic-gate 	if (rst->rst_port0 == rst->rst_port1) {
1027*7c478bd9Sstevel@tonic-gate 		/*
1028*7c478bd9Sstevel@tonic-gate 		 * use the same connection for both stdin and stdout
1029*7c478bd9Sstevel@tonic-gate 		 */
1030*7c478bd9Sstevel@tonic-gate 		fd1 = fd0;
1031*7c478bd9Sstevel@tonic-gate 	}
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	if (rst->rst_flags & REX_INTERACTIVE) {
1034*7c478bd9Sstevel@tonic-gate 		/*
1035*7c478bd9Sstevel@tonic-gate 		 * allocate a pseudo-terminal if necessary
1036*7c478bd9Sstevel@tonic-gate 		 */
1037*7c478bd9Sstevel@tonic-gate 		if (Debug)
1038*7c478bd9Sstevel@tonic-gate 			printf("Before AllocatePty call\n");
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 		/* AllocatePty has grantpt() call which has bug */
1041*7c478bd9Sstevel@tonic-gate 		/* Hence clear SIGCHLD handler setting */
1042*7c478bd9Sstevel@tonic-gate 		sigset(SIGCHLD, SIG_DFL);
1043*7c478bd9Sstevel@tonic-gate 		if (AllocatePty(fd0, fd1)) {
1044*7c478bd9Sstevel@tonic-gate 			errprintf(error, "rexd: cannot allocate a pty\n");
1045*7c478bd9Sstevel@tonic-gate 			if (pamh) {
1046*7c478bd9Sstevel@tonic-gate 				pam_end(pamh, PAM_ABORT);
1047*7c478bd9Sstevel@tonic-gate 				pamh = NULL;
1048*7c478bd9Sstevel@tonic-gate 			}
1049*7c478bd9Sstevel@tonic-gate 			return (1);
1050*7c478bd9Sstevel@tonic-gate 		}
1051*7c478bd9Sstevel@tonic-gate 		HasHelper = 1;
1052*7c478bd9Sstevel@tonic-gate 	}
1053*7c478bd9Sstevel@tonic-gate 	/*
1054*7c478bd9Sstevel@tonic-gate 	 * this sigset()call moved to after AllocatePty() call
1055*7c478bd9Sstevel@tonic-gate 	 * because a bug in waitpid() inside grantpt()
1056*7c478bd9Sstevel@tonic-gate 	 * causes CatchChild() to be invoked.
1057*7c478bd9Sstevel@tonic-gate 	 */
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	sigset(SIGCHLD, CatchChild);
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	if (rst->rst_flags & REX_INTERACTIVE) {
1062*7c478bd9Sstevel@tonic-gate 		sigset(SIGWINCH, sigwinch); /* a dummy signal handler */
1063*7c478bd9Sstevel@tonic-gate 		/* block the sigpause until signal in */
1064*7c478bd9Sstevel@tonic-gate 		/* child releases the signal */
1065*7c478bd9Sstevel@tonic-gate 		sighold(SIGWINCH);
1066*7c478bd9Sstevel@tonic-gate 	}
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	if (Debug)
1069*7c478bd9Sstevel@tonic-gate 		printf("Before a \"child\" fork\n");
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	child = fork();
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	if (child < 0) {
1074*7c478bd9Sstevel@tonic-gate 		errprintf(error, "rexd: can't fork\n");
1075*7c478bd9Sstevel@tonic-gate 		if (pamh) {
1076*7c478bd9Sstevel@tonic-gate 			pam_end(pamh, PAM_ABORT);
1077*7c478bd9Sstevel@tonic-gate 			pamh = NULL;
1078*7c478bd9Sstevel@tonic-gate 		}
1079*7c478bd9Sstevel@tonic-gate 		return (1);
1080*7c478bd9Sstevel@tonic-gate 	}
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	if (child) {
1083*7c478bd9Sstevel@tonic-gate 		/*
1084*7c478bd9Sstevel@tonic-gate 		 * parent rexd: close network connections if needed,
1085*7c478bd9Sstevel@tonic-gate 		 * then return to the main loop.
1086*7c478bd9Sstevel@tonic-gate 		 */
1087*7c478bd9Sstevel@tonic-gate 		if ((rst->rst_flags & REX_INTERACTIVE) == 0) {
1088*7c478bd9Sstevel@tonic-gate 			close(fd0);
1089*7c478bd9Sstevel@tonic-gate 			close(fd1);
1090*7c478bd9Sstevel@tonic-gate 		}
1091*7c478bd9Sstevel@tonic-gate 		if (Debug)
1092*7c478bd9Sstevel@tonic-gate 			printf("Parent ret to main loop, child does startup\n");
1093*7c478bd9Sstevel@tonic-gate 		if (pamh) {
1094*7c478bd9Sstevel@tonic-gate 			pam_end(pamh, PAM_SUCCESS);
1095*7c478bd9Sstevel@tonic-gate 			pamh = NULL;
1096*7c478bd9Sstevel@tonic-gate 		}
1097*7c478bd9Sstevel@tonic-gate 		return (0);
1098*7c478bd9Sstevel@tonic-gate 	}
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	/* child rexd */
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	if (Debug)
1103*7c478bd9Sstevel@tonic-gate 		printf("Child rexd\n");
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	/* setpgrp(0, 0) */
1106*7c478bd9Sstevel@tonic-gate 	setsid();		/* make session leader */
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	if (Debug)
1109*7c478bd9Sstevel@tonic-gate 		printf("After setsid\n");
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	if (rst->rst_flags & REX_INTERACTIVE) {
1112*7c478bd9Sstevel@tonic-gate 		if (Debug)
1113*7c478bd9Sstevel@tonic-gate 			printf("Before OpenPtySlave\n");
1114*7c478bd9Sstevel@tonic-gate 		/* reopen slave so that child has controlling tty */
1115*7c478bd9Sstevel@tonic-gate 		OpenPtySlave();
1116*7c478bd9Sstevel@tonic-gate 		if (Debug)
1117*7c478bd9Sstevel@tonic-gate 			printf("After OpenPtySlave\n");
1118*7c478bd9Sstevel@tonic-gate 	}
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	if (rst->rst_port0 != rst->rst_port1) {
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 		if (Debug)
1123*7c478bd9Sstevel@tonic-gate 			printf("rst_port0 != rst_port1\n"); /*	XXX	*/
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 		fd1 = socket(AF_INET, SOCK_STREAM, 0);
1126*7c478bd9Sstevel@tonic-gate 		shutdown(fd0, 1); /* 1=>further sends disallowed */
1127*7c478bd9Sstevel@tonic-gate 		fd1 = doconnect(calleraddr, rst->rst_port1, fd1);
1128*7c478bd9Sstevel@tonic-gate 		shutdown(fd1, 0); /* 0=>further receives disallowed */
1129*7c478bd9Sstevel@tonic-gate 	}
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	if (rst->rst_port1 == rst->rst_port2) {
1132*7c478bd9Sstevel@tonic-gate 		if (Debug)
1133*7c478bd9Sstevel@tonic-gate 			printf("rst_port1 == rst_port2\n"); /*	XXX	*/
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 		/*
1136*7c478bd9Sstevel@tonic-gate 		 * Use the same connection for both stdout and stderr
1137*7c478bd9Sstevel@tonic-gate 		 */
1138*7c478bd9Sstevel@tonic-gate 		fd2 = fd1;
1139*7c478bd9Sstevel@tonic-gate 	} else {
1140*7c478bd9Sstevel@tonic-gate 		if (Debug)
1141*7c478bd9Sstevel@tonic-gate 			printf("rst_port1 != rst_port2\n"); /*	XXX	*/
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate 		fd2 = socket(AF_INET, SOCK_STREAM, 0);
1144*7c478bd9Sstevel@tonic-gate 		fd2 = doconnect(calleraddr, rst->rst_port2, fd2);
1145*7c478bd9Sstevel@tonic-gate 		shutdown(fd2, 0); /* 0=>further receives disallowed */
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	if (rst->rst_flags & REX_INTERACTIVE) {
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 		/*
1151*7c478bd9Sstevel@tonic-gate 		 * use ptys instead of sockets in interactive mode
1152*7c478bd9Sstevel@tonic-gate 		 */
1153*7c478bd9Sstevel@tonic-gate 		DoHelper(&fd0, &fd1, &fd2);
1154*7c478bd9Sstevel@tonic-gate 		LoginUser();
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	dup2(fd0, 0);
1158*7c478bd9Sstevel@tonic-gate 	dup2(fd1, 1);
1159*7c478bd9Sstevel@tonic-gate 	dup2(fd2, 2);
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	/* setup terminal ID (use read file descriptor) */
1162*7c478bd9Sstevel@tonic-gate 	if (audit_settid(fd0) != 0) {
1163*7c478bd9Sstevel@tonic-gate 		errprintf("cannot set audit characteristics\n");
1164*7c478bd9Sstevel@tonic-gate 		return (1);
1165*7c478bd9Sstevel@tonic-gate 	}
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	closefrom(3);
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	if (Debug)
1170*7c478bd9Sstevel@tonic-gate 		printf("After close-all-fds-loop-- errno=%d\n", errno);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	environ = rst->rst_env;
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS) {
1175*7c478bd9Sstevel@tonic-gate 		audit_rexd_fail("user id is not valid",
1176*7c478bd9Sstevel@tonic-gate 				ucred->aup_machname,
1177*7c478bd9Sstevel@tonic-gate 				user,
1178*7c478bd9Sstevel@tonic-gate 				ucred->aup_uid,
1179*7c478bd9Sstevel@tonic-gate 				ucred->aup_gid,
1180*7c478bd9Sstevel@tonic-gate 				defaultShell,
1181*7c478bd9Sstevel@tonic-gate 				rst->rst_cmd);	    /* BSM */
1182*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: invalid uid/gid.\n");
1183*7c478bd9Sstevel@tonic-gate 		exit(1);
1184*7c478bd9Sstevel@tonic-gate 	}
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 	/* set the real (and effective) GID */
1187*7c478bd9Sstevel@tonic-gate 	if (setgid(ucred->aup_gid) == -1) {
1188*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: invalid gid.\n");
1189*7c478bd9Sstevel@tonic-gate 		exit(1);
1190*7c478bd9Sstevel@tonic-gate 	}
1191*7c478bd9Sstevel@tonic-gate 	/* Set the supplementary group access list. */
1192*7c478bd9Sstevel@tonic-gate 	if (setgroups(ucred->aup_len, (gid_t *)ucred->aup_gids) == -1) {
1193*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: invalid group list.\n");
1194*7c478bd9Sstevel@tonic-gate 		exit(1);
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) {
1198*7c478bd9Sstevel@tonic-gate 		audit_rexd_fail("user id is not valid",
1199*7c478bd9Sstevel@tonic-gate 				ucred->aup_machname,
1200*7c478bd9Sstevel@tonic-gate 				user,
1201*7c478bd9Sstevel@tonic-gate 				ucred->aup_uid,
1202*7c478bd9Sstevel@tonic-gate 				ucred->aup_gid,
1203*7c478bd9Sstevel@tonic-gate 				defaultShell,
1204*7c478bd9Sstevel@tonic-gate 				rst->rst_cmd);	    /* BSM */
1205*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: invalid uid/gid.\n");
1206*7c478bd9Sstevel@tonic-gate 		exit(1);
1207*7c478bd9Sstevel@tonic-gate 	}
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	audit_rexd_success(ucred->aup_machname,
1210*7c478bd9Sstevel@tonic-gate 				user,
1211*7c478bd9Sstevel@tonic-gate 				ucred->aup_uid,
1212*7c478bd9Sstevel@tonic-gate 				ucred->aup_gid,
1213*7c478bd9Sstevel@tonic-gate 				defaultShell,
1214*7c478bd9Sstevel@tonic-gate 				rst->rst_cmd);	/* BSM */
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	/* set the real (and effective) UID */
1217*7c478bd9Sstevel@tonic-gate 	if (setuid(ucred->aup_uid) == -1) {
1218*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: invalid uid.\n");
1219*7c478bd9Sstevel@tonic-gate 		exit(1);
1220*7c478bd9Sstevel@tonic-gate 	}
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	if (pamh) {
1223*7c478bd9Sstevel@tonic-gate 		pam_end(pamh, PAM_SUCCESS);
1224*7c478bd9Sstevel@tonic-gate 		pamh = NULL;
1225*7c478bd9Sstevel@tonic-gate 	}
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	if (Debug)	/*	XXX	*/
1228*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "uid %d gid %d (%d)\n",
1229*7c478bd9Sstevel@tonic-gate 			ucred->aup_uid, ucred->aup_gid, errno);
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	if (chdir(dirbuf)) {
1232*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: can't chdir to %s\n", dirbuf);
1233*7c478bd9Sstevel@tonic-gate 		exit(1);
1234*7c478bd9Sstevel@tonic-gate 	}
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	sigset(SIGINT, SIG_DFL);
1237*7c478bd9Sstevel@tonic-gate 	sigset(SIGHUP, SIG_DFL);
1238*7c478bd9Sstevel@tonic-gate 	sigset(SIGQUIT, SIG_DFL);
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	if (rst->rst_flags & REX_INTERACTIVE) {
1241*7c478bd9Sstevel@tonic-gate 		/* pause to sync with first SIGWINCH sent as part of */
1242*7c478bd9Sstevel@tonic-gate 		sigpause(SIGWINCH);
1243*7c478bd9Sstevel@tonic-gate 		/* protocol and handled by parent doing other rex primitves */
1244*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGWINCH);
1245*7c478bd9Sstevel@tonic-gate 		sigset(SIGWINCH, SIG_DFL);
1246*7c478bd9Sstevel@tonic-gate 	}
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate 	if (rst->rst_cmd == (char **)NULL) {
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 		/*
1251*7c478bd9Sstevel@tonic-gate 		 * Null command means execute the default shell for this user
1252*7c478bd9Sstevel@tonic-gate 		 */
1253*7c478bd9Sstevel@tonic-gate 		char *args[2];
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 		args[0] = defaultShell;
1256*7c478bd9Sstevel@tonic-gate 		args[1] = NULL;
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 		execvp(defaultShell, args);
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rexd: can't exec shell %s\n", defaultShell);
1261*7c478bd9Sstevel@tonic-gate 		exit(1);
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	if (Debug)
1265*7c478bd9Sstevel@tonic-gate 		for (len = 0; rst->rst_cmd[len] != (char *)NULL &&
1266*7c478bd9Sstevel@tonic-gate 			*rst->rst_cmd[len] != NULL; len++)
1267*7c478bd9Sstevel@tonic-gate 			printf("cmds: %s (%d)\n", rst->rst_cmd[len], errno);
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	/*	XXX	*/
1271*7c478bd9Sstevel@tonic-gate 	if (Debug)
1272*7c478bd9Sstevel@tonic-gate 		for (len = 0; rst->rst_env[len] != (char *)NULL &&
1273*7c478bd9Sstevel@tonic-gate 			*rst->rst_env[len] != NULL; len++)
1274*7c478bd9Sstevel@tonic-gate 			printf("envs: %s\n", rst->rst_env[len]);
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 	execvp(rst->rst_cmd[0], rst->rst_cmd);
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	/*	XXX	get rid of errno in parens	*/
1280*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "rexd: can't exec %s (%d)\n", *rst->rst_cmd, errno);
1281*7c478bd9Sstevel@tonic-gate 	exit(1);
1282*7c478bd9Sstevel@tonic-gate }
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate /*
1285*7c478bd9Sstevel@tonic-gate  * Search the mount table to see if the given file system is already
1286*7c478bd9Sstevel@tonic-gate  * mounted.  If so, return the place that it is mounted on.
1287*7c478bd9Sstevel@tonic-gate  */
1288*7c478bd9Sstevel@tonic-gate int
1289*7c478bd9Sstevel@tonic-gate AlreadyMounted(fsname, mountedon)
1290*7c478bd9Sstevel@tonic-gate char *fsname;
1291*7c478bd9Sstevel@tonic-gate char *mountedon;
1292*7c478bd9Sstevel@tonic-gate {
1293*7c478bd9Sstevel@tonic-gate 	FILE		*table;
1294*7c478bd9Sstevel@tonic-gate 	struct mnttab	 mt;
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	table = setmntent(MOUNTED, "r");
1297*7c478bd9Sstevel@tonic-gate 	if (table == NULL)
1298*7c478bd9Sstevel@tonic-gate 		return (0);
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	while ((getmntent(table, &mt)) != (-1)) {
1301*7c478bd9Sstevel@tonic-gate 
1302*7c478bd9Sstevel@tonic-gate 		if (strcmp(mt.mnt_special, fsname) == 0) {
1303*7c478bd9Sstevel@tonic-gate 			strcpy(mountedon, mt.mnt_mountp);
1304*7c478bd9Sstevel@tonic-gate 			endmntent(table);
1305*7c478bd9Sstevel@tonic-gate 			return (1);
1306*7c478bd9Sstevel@tonic-gate 		}
1307*7c478bd9Sstevel@tonic-gate 	}
1308*7c478bd9Sstevel@tonic-gate 	endmntent(table);
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	return (0);
1311*7c478bd9Sstevel@tonic-gate }
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate /*
1315*7c478bd9Sstevel@tonic-gate  * connect to the indicated IP address/port, and return the
1316*7c478bd9Sstevel@tonic-gate  * resulting file descriptor.
1317*7c478bd9Sstevel@tonic-gate  */
1318*7c478bd9Sstevel@tonic-gate int
1319*7c478bd9Sstevel@tonic-gate doconnect(sin, port, fd)
1320*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
1321*7c478bd9Sstevel@tonic-gate short port;
1322*7c478bd9Sstevel@tonic-gate int fd;
1323*7c478bd9Sstevel@tonic-gate {
1324*7c478bd9Sstevel@tonic-gate 	sin->sin_port = ntohs(port);
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	if (connect(fd, (struct sockaddr *)sin, sizeof (*sin))) {
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 		perror("rexd: connect");
1329*7c478bd9Sstevel@tonic-gate 		exit(1);
1330*7c478bd9Sstevel@tonic-gate 	}
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	return (fd);
1333*7c478bd9Sstevel@tonic-gate }
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate void
1336*7c478bd9Sstevel@tonic-gate sigwinch(int junk)
1337*7c478bd9Sstevel@tonic-gate {
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate /*
1341*7c478bd9Sstevel@tonic-gate  *  SETPROCTITLE -- set the title of this process for "ps"
1342*7c478bd9Sstevel@tonic-gate  *
1343*7c478bd9Sstevel@tonic-gate  *	Does nothing if there were not enough arguments on the command
1344*7c478bd9Sstevel@tonic-gate  *	line for the information.
1345*7c478bd9Sstevel@tonic-gate  *
1346*7c478bd9Sstevel@tonic-gate  *	Side Effects:
1347*7c478bd9Sstevel@tonic-gate  *		Clobbers argv[] of our main procedure.
1348*7c478bd9Sstevel@tonic-gate  */
1349*7c478bd9Sstevel@tonic-gate void
1350*7c478bd9Sstevel@tonic-gate setproctitle(user, host)
1351*7c478bd9Sstevel@tonic-gate char *user, *host;
1352*7c478bd9Sstevel@tonic-gate {
1353*7c478bd9Sstevel@tonic-gate 	register char *tohere;
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	tohere = Argv[0];
1356*7c478bd9Sstevel@tonic-gate 	if ((int)(LastArgv == NULL) ||
1357*7c478bd9Sstevel@tonic-gate 	    (int)(strlen(user)+strlen(host)+3) >
1358*7c478bd9Sstevel@tonic-gate 	    (int)(LastArgv - tohere))
1359*7c478bd9Sstevel@tonic-gate 		return;
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate 	*tohere++ = '-';		/* So ps prints (rpc.rexd)	*/
1362*7c478bd9Sstevel@tonic-gate 	sprintf(tohere, "%s@%s", user, host);
1363*7c478bd9Sstevel@tonic-gate 	while (*tohere++)		/* Skip to end of printf output	*/
1364*7c478bd9Sstevel@tonic-gate 		;
1365*7c478bd9Sstevel@tonic-gate 	while (tohere < LastArgv)	/* Avoid confusing ps		*/
1366*7c478bd9Sstevel@tonic-gate 		*tohere++ = ' ';
1367*7c478bd9Sstevel@tonic-gate }
1368*7c478bd9Sstevel@tonic-gate 
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate /*
1371*7c478bd9Sstevel@tonic-gate  * Determine if started from inetd or not
1372*7c478bd9Sstevel@tonic-gate  */
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate int
1375*7c478bd9Sstevel@tonic-gate isfrominetd(fd)
1376*7c478bd9Sstevel@tonic-gate int fd;
1377*7c478bd9Sstevel@tonic-gate {
1378*7c478bd9Sstevel@tonic-gate 	/*
1379*7c478bd9Sstevel@tonic-gate 	 * If fd looks like a TLI endpoint, we assume
1380*7c478bd9Sstevel@tonic-gate 	 * that we were started by a port monitor. If
1381*7c478bd9Sstevel@tonic-gate 	 * t_getstate fails with TBADF, this is not a
1382*7c478bd9Sstevel@tonic-gate 	 * TLI endpoint.
1383*7c478bd9Sstevel@tonic-gate 	 */
1384*7c478bd9Sstevel@tonic-gate 	if (t_getstate(0) != -1 || t_errno != TBADF)
1385*7c478bd9Sstevel@tonic-gate 		return (1);
1386*7c478bd9Sstevel@tonic-gate 	return (0);
1387*7c478bd9Sstevel@tonic-gate }
1388