xref: /onnv-gate/usr/src/cmd/rexd/on.c (revision 620:70e88a3808c9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * on - user interface program for remote execution service
240Sstevel@tonic-gate  *
25*620Ssm26363  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26*620Ssm26363  * Use is subject to license terms.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
29*620Ssm26363 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*620Ssm26363 
310Sstevel@tonic-gate #define	BSD_COMP
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <netdb.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <stdio.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <unistd.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <netinet/in.h>
430Sstevel@tonic-gate #include <rpc/rpc.h>
440Sstevel@tonic-gate #include <rpc/clnt_soc.h>
450Sstevel@tonic-gate #include <rpc/key_prot.h>
460Sstevel@tonic-gate #include <sys/fcntl.h>
470Sstevel@tonic-gate #include <sys/ioctl.h>
480Sstevel@tonic-gate #include <sys/param.h>
490Sstevel@tonic-gate #include <sys/socket.h>
500Sstevel@tonic-gate #include <sys/sockio.h>
510Sstevel@tonic-gate #include <sys/stat.h>
520Sstevel@tonic-gate #include <sys/time.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #include <sys/ttold.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include "rex.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #include <stropts.h>
610Sstevel@tonic-gate #include <sys/stream.h>
620Sstevel@tonic-gate #include <sys/ttcompat.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #define	bcmp(b1, b2, len)	memcmp(b1, b2, len)
660Sstevel@tonic-gate #define	bzero(b, len)		memset(b, '\0', len)
670Sstevel@tonic-gate #define	bcopy(b1, b2, len)	memcpy(b2, b1, len)
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define	CommandName "on"	/* given as argv[0] */
700Sstevel@tonic-gate #define	AltCommandName "dbon"
710Sstevel@tonic-gate 
720Sstevel@tonic-gate extern int errno;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * Note - the following must be long enough for at least two portmap
760Sstevel@tonic-gate  * timeouts on the other side.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate struct timeval LongTimeout = { 123, 0 };
790Sstevel@tonic-gate struct timeval testtimeout = { 5, 0 };
800Sstevel@tonic-gate 
810Sstevel@tonic-gate int Debug = 0;			/* print extra debugging information */
820Sstevel@tonic-gate int Only2 = 0;			/* stdout and stderr are the same */
830Sstevel@tonic-gate int Interactive = 0;		/* use a pty on server */
840Sstevel@tonic-gate int NoInput = 0;		/* don't read standard input */
850Sstevel@tonic-gate int child = 0;			/* pid of the executed process */
860Sstevel@tonic-gate int ChildDied = 0;		/* true when above is valid */
870Sstevel@tonic-gate int HasHelper = 0;		/* must kill helpers (interactive mode) */
880Sstevel@tonic-gate 
890Sstevel@tonic-gate int InOut;			/* socket for stdin/stdout */
900Sstevel@tonic-gate int Err;			/* socket for stderr */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate struct sgttyb OldFlags;		/* saved tty flags */
930Sstevel@tonic-gate struct sgttyb NewFlags;		/* for stop/continue job control */
940Sstevel@tonic-gate CLIENT *Client;			/* RPC client handle */
950Sstevel@tonic-gate struct rex_ttysize WindowSize;	/* saved window size */
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static int Argc;
980Sstevel@tonic-gate static char **Argv;		/* saved argument vector (for ps) */
990Sstevel@tonic-gate static char *LastArgv;		/* saved end-of-argument vector */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate void	usage(void);
1020Sstevel@tonic-gate void	Die(int stat);
1030Sstevel@tonic-gate void	doaccept(int *fdp);
1040Sstevel@tonic-gate u_short makeport(int *fdp);
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * window change handler - propagate to remote server
1090Sstevel@tonic-gate  */
1100Sstevel@tonic-gate void
sigwinch(int junk)1110Sstevel@tonic-gate sigwinch(int junk)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	struct	winsize	newsize; /* the modern way to get row and col	*/
1140Sstevel@tonic-gate 	struct	rex_ttysize	size;	/* the old way no body */
1150Sstevel@tonic-gate 					/* bothered to change */
1160Sstevel@tonic-gate 	enum	clnt_stat	clstat;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	ioctl(0, TIOCGWINSZ, &newsize);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/*
1210Sstevel@tonic-gate 	 * compensate for the struct change
1220Sstevel@tonic-gate 	 */
1230Sstevel@tonic-gate 	size.ts_lines = (int)newsize.ws_row; /* typecast important! */
1240Sstevel@tonic-gate 	size.ts_cols = (int)newsize.ws_col;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	if (bcmp(&size, &WindowSize, sizeof (size)) == 0)
1270Sstevel@tonic-gate 		return;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	WindowSize = size;
1300Sstevel@tonic-gate 	if (clstat = clnt_call(Client, REXPROC_WINCH,
1310Sstevel@tonic-gate 				xdr_rex_ttysize, (caddr_t)&size, xdr_void,
1320Sstevel@tonic-gate 				NULL, LongTimeout)) {
1330Sstevel@tonic-gate 		fprintf(stderr, "on (size): ");
1340Sstevel@tonic-gate 		clnt_perrno(clstat);
1350Sstevel@tonic-gate 		fprintf(stderr, "\r\n");
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * signal handler - propagate to remote server
1410Sstevel@tonic-gate  */
1420Sstevel@tonic-gate void
sendsig(int sig)1430Sstevel@tonic-gate sendsig(int sig)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	enum clnt_stat clstat;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (clstat = clnt_call(Client, REXPROC_SIGNAL,
1480Sstevel@tonic-gate 				xdr_int, (caddr_t) &sig, xdr_void,
1490Sstevel@tonic-gate 				NULL, LongTimeout)) {
1500Sstevel@tonic-gate 		fprintf(stderr, "on (signal): ");
1510Sstevel@tonic-gate 		clnt_perrno(clstat);
1520Sstevel@tonic-gate 		fprintf(stderr, "\r\n");
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate void
cont(int junk)1580Sstevel@tonic-gate cont(int junk)
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate 	/*
1610Sstevel@tonic-gate 	 * Put tty modes back the way they were and tell the rexd server
1620Sstevel@tonic-gate 	 * to send the command a SIGCONT signal.
1630Sstevel@tonic-gate 	 */
1640Sstevel@tonic-gate 	if (Interactive) {
1650Sstevel@tonic-gate 		ioctl(0, TIOCSETN, &NewFlags);
1660Sstevel@tonic-gate 		(void) send(InOut, "", 1, MSG_OOB);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * oob -- called when the command invoked by the rexd server is stopped
1720Sstevel@tonic-gate  *	  with a SIGTSTP or SIGSTOP signal.
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate void
oob(int junk)1750Sstevel@tonic-gate oob(int junk)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	int atmark;
1780Sstevel@tonic-gate 	char waste[BUFSIZ], mark;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	for (;;) {
1810Sstevel@tonic-gate 		if (ioctl(InOut, SIOCATMARK, &atmark) < 0) {
1820Sstevel@tonic-gate 			perror("ioctl");
1830Sstevel@tonic-gate 			break;
1840Sstevel@tonic-gate 		}
1850Sstevel@tonic-gate 		if (atmark)
1860Sstevel@tonic-gate 			break;
1870Sstevel@tonic-gate 		(void) read(InOut, waste, sizeof (waste));
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	(void) recv(InOut, &mark, 1, MSG_OOB);
1900Sstevel@tonic-gate 	/*
1910Sstevel@tonic-gate 	 * Reset tty modes to something sane and stop myself
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 	if (Interactive) {
1940Sstevel@tonic-gate 		ioctl(0, TIOCSETN, &OldFlags);
1950Sstevel@tonic-gate 		printf("\r\n");
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 	kill(getpid(), SIGSTOP);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 
202*620Ssm26363 int
main(int argc,char ** argv)2030Sstevel@tonic-gate main(int argc, char **argv)
2040Sstevel@tonic-gate {
2050Sstevel@tonic-gate 	struct	winsize	newsize; /* the modern way to get row and col	*/
2060Sstevel@tonic-gate 	char *rhost, **cmdp;
2070Sstevel@tonic-gate 	char curdir[MAXPATHLEN];
2080Sstevel@tonic-gate 	char wdhost[MAXHOSTNAMELEN];
2090Sstevel@tonic-gate 	char fsname[MAXPATHLEN];
2100Sstevel@tonic-gate 	char dirwithin[MAXPATHLEN];
2110Sstevel@tonic-gate 	struct rex_start rst;
2120Sstevel@tonic-gate 	struct rex_result result;
2130Sstevel@tonic-gate 	extern char **environ;
2140Sstevel@tonic-gate 	enum clnt_stat clstat;
2150Sstevel@tonic-gate 	struct hostent *hp;
2160Sstevel@tonic-gate 	struct sockaddr_in server_addr;
2170Sstevel@tonic-gate 	int sock = RPC_ANYSOCK;
2180Sstevel@tonic-gate 	fd_set selmask, zmask, remmask;
2190Sstevel@tonic-gate 	int nfds, cc;
2200Sstevel@tonic-gate 	char *chi, *cho;
2210Sstevel@tonic-gate 	int trying_authdes;
2220Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
2230Sstevel@tonic-gate 	char hostname[MAXHOSTNAMELEN+1];
2240Sstevel@tonic-gate 	char publickey[HEXKEYBYTES+1];
2250Sstevel@tonic-gate 	int i;
2260Sstevel@tonic-gate 	char *domain;
2270Sstevel@tonic-gate 	static char buf[4096];
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/*
2300Sstevel@tonic-gate 	 * we check the invoked command name to see if it should
2310Sstevel@tonic-gate 	 * really be a host name.
2320Sstevel@tonic-gate 	 */
2330Sstevel@tonic-gate 	if ((rhost = strrchr(argv[0], '/')) == NULL) {
2340Sstevel@tonic-gate 		rhost = argv[0];
2350Sstevel@tonic-gate 	} else {
2360Sstevel@tonic-gate 		rhost++;
2370Sstevel@tonic-gate 	}
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * argv start and extent for setproctitle()
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 	Argc = argc;
2430Sstevel@tonic-gate 	Argv = argv;
2440Sstevel@tonic-gate 	if (argc > 0)
2450Sstevel@tonic-gate 		LastArgv = argv[argc-1] + strlen(argv[argc-1]);
2460Sstevel@tonic-gate 	else
2470Sstevel@tonic-gate 		LastArgv = NULL;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	while (argc > 1 && argv[1][0] == '-') {
2500Sstevel@tonic-gate 		switch (argv[1][1]) {
2510Sstevel@tonic-gate 		case 'd': Debug = 1;
2520Sstevel@tonic-gate 			break;
2530Sstevel@tonic-gate 		case 'i': Interactive = 1;
2540Sstevel@tonic-gate 			break;
2550Sstevel@tonic-gate 		case 'n': NoInput = 1;
2560Sstevel@tonic-gate 			break;
2570Sstevel@tonic-gate 		default:
2580Sstevel@tonic-gate 			printf("Unknown option %s\n", argv[1]);
2590Sstevel@tonic-gate 		}
2600Sstevel@tonic-gate 		argv++;
2610Sstevel@tonic-gate 		argc--;
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	if (strcmp(rhost, CommandName) && strcmp(rhost, AltCommandName)) {
2650Sstevel@tonic-gate 		cmdp = &argv[1];
2660Sstevel@tonic-gate 		Interactive = 1;
2670Sstevel@tonic-gate 	} else {
2680Sstevel@tonic-gate 		if (argc < 2)
2690Sstevel@tonic-gate 			usage();
2700Sstevel@tonic-gate 		rhost = argv[1];
2710Sstevel@tonic-gate 		cmdp = &argv[2];
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * Can only have one of these
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	if (Interactive && NoInput)
2780Sstevel@tonic-gate 		usage();
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	if ((hp = gethostbyname(rhost)) == NULL) {
2810Sstevel@tonic-gate 		fprintf(stderr, "on: unknown host %s\n", rhost);
2820Sstevel@tonic-gate 		exit(1);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length);
2860Sstevel@tonic-gate 	server_addr.sin_family = AF_INET;
2870Sstevel@tonic-gate 	server_addr.sin_port = 0; /* use pmapper */
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (Debug)
2900Sstevel@tonic-gate 		printf("Got the host named %s (%s)\n",
2910Sstevel@tonic-gate 			rhost, inet_ntoa(server_addr.sin_addr));
2920Sstevel@tonic-gate 	trying_authdes = 1;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate try_auth_unix:
2950Sstevel@tonic-gate 	sock = RPC_ANYSOCK;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (Debug)
2980Sstevel@tonic-gate 		printf("clnt_create: Server_Addr %u Prog %d Vers %d Sock %d\n",
2990Sstevel@tonic-gate 			&server_addr, REXPROG, REXVERS, sock);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if ((Client = clnttcp_create(&server_addr, REXPROG, REXVERS, &sock,
3020Sstevel@tonic-gate 					0, 0)) == NULL) {
3030Sstevel@tonic-gate 		fprintf(stderr, "on: cannot connect to server on %s\n",
3040Sstevel@tonic-gate 			rhost);
3050Sstevel@tonic-gate 		clnt_pcreateerror("on:");
3060Sstevel@tonic-gate 		exit(1);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if (Debug)
3100Sstevel@tonic-gate 		printf("TCP RPC connection created\n");
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (trying_authdes) {
3130Sstevel@tonic-gate 		yp_get_default_domain(&domain);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		cho =  hostname;
3160Sstevel@tonic-gate 		*cho = 0;
3170Sstevel@tonic-gate 		chi =  hp->h_name;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		for (i = 0; (*chi && (i < MAXHOSTNAMELEN)); i++)
3200Sstevel@tonic-gate 			{
3210Sstevel@tonic-gate 				if (isupper(*chi))
3220Sstevel@tonic-gate 					*cho = tolower(*chi);
3230Sstevel@tonic-gate 				else
3240Sstevel@tonic-gate 					*cho = *chi;
3250Sstevel@tonic-gate 				cho++;
3260Sstevel@tonic-gate 				chi++;
3270Sstevel@tonic-gate 			}
3280Sstevel@tonic-gate 		*cho = 0;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 		if (domain != NULL)	{
3310Sstevel@tonic-gate 			if (host2netname(netname, hostname, domain) == 0) {
3320Sstevel@tonic-gate 				trying_authdes = 0;
3330Sstevel@tonic-gate 				if (Debug)
3340Sstevel@tonic-gate 					printf("host2netname failed %s\n",
3350Sstevel@tonic-gate 						hp->h_name);
3360Sstevel@tonic-gate 			}
3370Sstevel@tonic-gate 			/* #ifdef	NOWAY */
3380Sstevel@tonic-gate 			else {
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 				if (getpublickey(netname, publickey) == 0) {
3410Sstevel@tonic-gate 					trying_authdes = 0;
3420Sstevel@tonic-gate 					cho = strchr(hostname, '.');
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 					if (cho) {
3450Sstevel@tonic-gate 						*cho = 0;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 						if (!host2netname(netname,
3480Sstevel@tonic-gate 						    hostname,
3490Sstevel@tonic-gate 						    domain)) {
3500Sstevel@tonic-gate 							if (Debug)
3510Sstevel@tonic-gate 				printf("host2netname failed %s\n", hp->h_name);
3520Sstevel@tonic-gate 						} else {
3530Sstevel@tonic-gate 							if (getpublickey(
3540Sstevel@tonic-gate 							    netname,
3550Sstevel@tonic-gate 							    publickey) != 0)
3560Sstevel@tonic-gate 							trying_authdes = 1;
3570Sstevel@tonic-gate 						}
3580Sstevel@tonic-gate 					}
3590Sstevel@tonic-gate 				}
3600Sstevel@tonic-gate 			}
3610Sstevel@tonic-gate 		} else {
3620Sstevel@tonic-gate 			trying_authdes = 0;
3630Sstevel@tonic-gate 			if (Debug)
3640Sstevel@tonic-gate 				printf("yp_get_default_domain failed \n");
3650Sstevel@tonic-gate 		}
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	if (trying_authdes) {
3690Sstevel@tonic-gate 		Client->cl_auth = (AUTH *)authdes_create(netname, 60*60,
3700Sstevel@tonic-gate 						&server_addr, NULL);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		if (Client->cl_auth == NULL) {
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 			if (Debug)
3750Sstevel@tonic-gate 				printf("authdes_create failed %s\n", netname);
3760Sstevel@tonic-gate 			trying_authdes = 0;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (trying_authdes == 0)
3820Sstevel@tonic-gate 		if ((Client->cl_auth = authsys_create_default()) == NULL) {
3830Sstevel@tonic-gate 			clnt_destroy(Client);
3840Sstevel@tonic-gate 			fprintf(stderr,"on: can't create authunix structure.\n");
3850Sstevel@tonic-gate 			exit(1);
3860Sstevel@tonic-gate 		}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * Now that we have created the TCP connection, we do some
3910Sstevel@tonic-gate 	 * work while the server daemon is being swapped in.
3920Sstevel@tonic-gate 	 */
3930Sstevel@tonic-gate 	if (getcwd(curdir, MAXPATHLEN) == (char *)NULL) {
3940Sstevel@tonic-gate 		fprintf(stderr, "on: can't find . (%s)\n", curdir);
3950Sstevel@tonic-gate 		exit(1);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if (findmount(curdir, wdhost, fsname, dirwithin) == 0) {
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		if (Debug) {
4010Sstevel@tonic-gate 			fprintf(stderr,
4020Sstevel@tonic-gate 				"findmount failed: curdir %s\twdhost %s\t",
4030Sstevel@tonic-gate 				curdir, wdhost);
4040Sstevel@tonic-gate 			fprintf(stderr, "fsname %s\tdirwithin %s\n",
4050Sstevel@tonic-gate 				fsname, dirwithin);
4060Sstevel@tonic-gate 		}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 		fprintf(stderr, "on: can't locate mount point for %s (%s)\n",
4090Sstevel@tonic-gate 			curdir, dirwithin);
4100Sstevel@tonic-gate 		exit(1);
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	if (Debug) {
4140Sstevel@tonic-gate 		printf("findmount suceeds: cwd= %s, wd host %s, fs %s,",
4150Sstevel@tonic-gate 			curdir, wdhost, fsname);
4160Sstevel@tonic-gate 		printf("dir within %s\n", dirwithin);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	Only2 = samefd(1, 2);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	rst.rst_cmd = (void *)(cmdp);
4220Sstevel@tonic-gate 	rst.rst_host = (void *)wdhost;
4230Sstevel@tonic-gate 	rst.rst_fsname = (void *)fsname;
4240Sstevel@tonic-gate 	rst.rst_dirwithin = (void *)dirwithin;
4250Sstevel@tonic-gate 	rst.rst_env = (void *)environ;
4260Sstevel@tonic-gate 	rst.rst_port0 = makeport(&InOut);
4270Sstevel@tonic-gate 	rst.rst_port1 =  rst.rst_port0;	/* same port for stdin */
4280Sstevel@tonic-gate 	rst.rst_flags = 0;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (Debug)
4310Sstevel@tonic-gate 		printf("before Interactive flags\n");
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (Interactive) {
4340Sstevel@tonic-gate 		rst.rst_flags |= REX_INTERACTIVE;
4350Sstevel@tonic-gate 		ioctl(0, TIOCGETP, &OldFlags);
4360Sstevel@tonic-gate 		NewFlags = OldFlags;
4370Sstevel@tonic-gate 		NewFlags.sg_flags |= (u_int)RAW;
4380Sstevel@tonic-gate 		NewFlags.sg_flags &= (u_int)~ECHO;
4390Sstevel@tonic-gate 		ioctl(0, TIOCSETN, &NewFlags);
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (Only2) {
4430Sstevel@tonic-gate 		rst.rst_port2 = rst.rst_port1;
4440Sstevel@tonic-gate 	} else {
4450Sstevel@tonic-gate 		rst.rst_port2 = makeport(&Err);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	if (Debug)
4490Sstevel@tonic-gate 		printf("before client call REXPROC_START\n");
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	(void) memset(&result, '\0', sizeof(result));
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if (clstat = clnt_call(Client, REXPROC_START,
4540Sstevel@tonic-gate 			       xdr_rex_start, (caddr_t)&rst,
4550Sstevel@tonic-gate 			       xdr_rex_result, (caddr_t)&result, LongTimeout)) {
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 		if (Debug)
4580Sstevel@tonic-gate 			printf("Client call failed for REXPROC_START\r\n");
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 		if (trying_authdes) {
4610Sstevel@tonic-gate 			auth_destroy(Client->cl_auth);
4620Sstevel@tonic-gate 			clnt_destroy(Client);
4630Sstevel@tonic-gate 			trying_authdes = 0;
4640Sstevel@tonic-gate 			if (Interactive)
4650Sstevel@tonic-gate 				ioctl(0, TIOCSETN, &OldFlags);
4660Sstevel@tonic-gate 			goto try_auth_unix;
4670Sstevel@tonic-gate 		} else {
4680Sstevel@tonic-gate 			fprintf(stderr, "on %s: ", rhost);
4690Sstevel@tonic-gate 			clnt_perrno(clstat);
4700Sstevel@tonic-gate 			fprintf(stderr, "\n");
4710Sstevel@tonic-gate 			Die(1);
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	if (result.rlt_stat != 0) {
4760Sstevel@tonic-gate 		fprintf(stderr, "on %s: %s\n\r", rhost, result.rlt_message);
4770Sstevel@tonic-gate 		Die(1);
4780Sstevel@tonic-gate 	}
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	clnt_freeres(Client, xdr_rex_result, (caddr_t)&result);
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	if (Debug)
4830Sstevel@tonic-gate 		printf("Client call suceeded for REXPROC_START\r\n");
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	if (Interactive) {
4860Sstevel@tonic-gate 		/*
4870Sstevel@tonic-gate 		 * Pass the tty modes along to the server
4880Sstevel@tonic-gate 		 */
4890Sstevel@tonic-gate 		struct rex_ttymode mode;
4900Sstevel@tonic-gate 		int err;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		mode.basic.sg_ispeed = OldFlags.sg_ispeed;
4930Sstevel@tonic-gate 		mode.basic.sg_ospeed = OldFlags.sg_ospeed;
4940Sstevel@tonic-gate 		mode.basic.sg_erase = OldFlags.sg_erase;
4950Sstevel@tonic-gate 		mode.basic.sg_kill = OldFlags.sg_kill;
4960Sstevel@tonic-gate 		mode.basic.sg_flags = (short) (OldFlags.sg_flags & 0xFFFF);
4970Sstevel@tonic-gate 		err =  (ioctl(0, TIOCGETC, &mode.more) < 0 ||
4980Sstevel@tonic-gate 			ioctl(0, TIOCGLTC, &mode.yetmore) < 0 ||
4990Sstevel@tonic-gate 			ioctl(0, TIOCLGET, &mode.andmore) < 0);
5000Sstevel@tonic-gate 		if (Debug)
5010Sstevel@tonic-gate 			printf("Before clnt_call(REXPROC_MODES) err=%d\n", err);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		if (!err && (clstat = clnt_call(Client, REXPROC_MODES,
5040Sstevel@tonic-gate 					xdr_rex_ttymode, (caddr_t)&mode,
5050Sstevel@tonic-gate 					xdr_void, NULL, LongTimeout))) {
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 			fprintf(stderr, "on (modes) %s: ", rhost);
5080Sstevel@tonic-gate 			clnt_perrno(clstat);
5090Sstevel@tonic-gate 			fprintf(stderr, "\r\n");
5100Sstevel@tonic-gate 		}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 		err = ioctl(0, TIOCGWINSZ, &newsize) < 0;
5130Sstevel@tonic-gate 		/* typecast important in following lines */
5140Sstevel@tonic-gate 		WindowSize.ts_lines = (int)newsize.ws_row;
5150Sstevel@tonic-gate 		WindowSize.ts_cols = (int)newsize.ws_col;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		if (Debug)
5180Sstevel@tonic-gate 			printf("Before client call REXPROC_WINCH\n");
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 		if (!err && (clstat = clnt_call(Client, REXPROC_WINCH,
5210Sstevel@tonic-gate 					xdr_rex_ttysize, (caddr_t)&WindowSize,
5220Sstevel@tonic-gate 					xdr_void, NULL, LongTimeout))) {
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 			fprintf(stderr, "on (size) %s: ", rhost);
5250Sstevel@tonic-gate 			clnt_perrno(clstat);
5260Sstevel@tonic-gate 			fprintf(stderr, "\r\n");
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 		sigset(SIGWINCH, sigwinch);
5300Sstevel@tonic-gate 		sigset(SIGINT, sendsig);
5310Sstevel@tonic-gate 		sigset(SIGQUIT, sendsig);
5320Sstevel@tonic-gate 		sigset(SIGTERM, sendsig);
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 	sigset(SIGCONT, cont);
5350Sstevel@tonic-gate 	sigset(SIGURG, oob);
5360Sstevel@tonic-gate 	doaccept(&InOut);
5370Sstevel@tonic-gate 	(void) fcntl(InOut, F_SETOWN, getpid());
5380Sstevel@tonic-gate 	FD_ZERO(&remmask);
5390Sstevel@tonic-gate 	FD_SET(InOut, &remmask);
5400Sstevel@tonic-gate 	if (Debug)
5410Sstevel@tonic-gate 		printf("accept on stdout\r\n");
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	if (!Only2) {
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		doaccept(&Err);
5460Sstevel@tonic-gate 		shutdown(Err, 1); /* 1=> further sends disallowed */
5470Sstevel@tonic-gate 		if (Debug)
5480Sstevel@tonic-gate 			printf("accept on stderr\r\n");
5490Sstevel@tonic-gate 		FD_SET(Err, &remmask);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	FD_ZERO(&zmask);
5530Sstevel@tonic-gate 	if (NoInput) {
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 		/*
5560Sstevel@tonic-gate 		 * no input - simulate end-of-file instead
5570Sstevel@tonic-gate 		 */
5580Sstevel@tonic-gate 		shutdown(InOut, 1); /* 1=> further sends disallowed */
5590Sstevel@tonic-gate 	} else {
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * set up to read standard input, send to remote
5620Sstevel@tonic-gate 		 */
5630Sstevel@tonic-gate 		FD_SET(0, &zmask);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	FD_ZERO(&selmask);
5670Sstevel@tonic-gate 	while (FD_ISSET(InOut, &remmask) || FD_ISSET(Err, &remmask)) {
5680Sstevel@tonic-gate 		if (FD_ISSET(InOut, &remmask))
5690Sstevel@tonic-gate 			FD_SET(InOut, &selmask);
5700Sstevel@tonic-gate 		else
5710Sstevel@tonic-gate 			FD_CLR(InOut, &selmask);
5720Sstevel@tonic-gate 		if (FD_ISSET(Err, &remmask))
5730Sstevel@tonic-gate 			FD_SET(Err, &selmask);
5740Sstevel@tonic-gate 		else
5750Sstevel@tonic-gate 			FD_CLR(Err, &selmask);
5760Sstevel@tonic-gate 		if (FD_ISSET(0, &zmask))
5770Sstevel@tonic-gate 			FD_SET(0, &selmask);
5780Sstevel@tonic-gate 		else
5790Sstevel@tonic-gate 			FD_CLR(0, &selmask);
5800Sstevel@tonic-gate 		nfds = select(FD_SETSIZE, &selmask, (fd_set *) 0, (fd_set *) 0,
5810Sstevel@tonic-gate 			      (struct timeval *) 0);
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate  		if (nfds <= 0) {
5850Sstevel@tonic-gate 			if (errno == EINTR) continue;
5860Sstevel@tonic-gate 			perror("on: select");
5870Sstevel@tonic-gate 			Die(1);
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 		if (FD_ISSET(InOut, &selmask)) {
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 			cc = read(InOut, buf, sizeof buf);
5920Sstevel@tonic-gate 			if (cc > 0)
5930Sstevel@tonic-gate 				write(1, buf, cc);
5940Sstevel@tonic-gate 			else
5950Sstevel@tonic-gate 				FD_CLR(InOut, &remmask);
5960Sstevel@tonic-gate 		}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		if (!Only2 && FD_ISSET(Err, &selmask)) {
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 			cc = read(Err, buf, sizeof buf);
6010Sstevel@tonic-gate 			if (cc > 0)
6020Sstevel@tonic-gate 				write(2, buf, cc);
6030Sstevel@tonic-gate 			else
6040Sstevel@tonic-gate 				FD_CLR(Err, &remmask);
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		if (!NoInput && FD_ISSET(0, &selmask)) {
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 			cc = read(0, buf, sizeof buf);
6100Sstevel@tonic-gate 			if (cc > 0)
6110Sstevel@tonic-gate 				write(InOut, buf, cc);
6120Sstevel@tonic-gate 			else {
6130Sstevel@tonic-gate 				/*
6140Sstevel@tonic-gate 				 * End of standard input - shutdown outgoing
6150Sstevel@tonic-gate 				 * direction of the TCP connection.
6160Sstevel@tonic-gate 				 */
6170Sstevel@tonic-gate 				if (Debug)
6180Sstevel@tonic-gate 					printf("Got EOF - shutting down connection\n");
6190Sstevel@tonic-gate 				FD_CLR(0, &zmask);
6200Sstevel@tonic-gate 				shutdown(InOut, 1); /* further sends disallowed */
6210Sstevel@tonic-gate 			}
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	close(InOut);
6260Sstevel@tonic-gate 	if (!Only2)
6270Sstevel@tonic-gate 		close(Err);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	(void) memset(&result, '\0', sizeof(result));
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (clstat = clnt_call(Client, REXPROC_WAIT,
6320Sstevel@tonic-gate 			       xdr_void, 0, xdr_rex_result, (caddr_t)&result,
6330Sstevel@tonic-gate 			       LongTimeout)) {
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		fprintf(stderr, "on: ");
6360Sstevel@tonic-gate 		clnt_perrno(clstat);
6370Sstevel@tonic-gate 		fprintf(stderr, "\r\n");
6380Sstevel@tonic-gate 		Die(1);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 	Die(result.rlt_stat);
641*620Ssm26363 	return (0);	/* Should never get here. */
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate /*
6450Sstevel@tonic-gate  * like exit, but resets the terminal state first
6460Sstevel@tonic-gate  */
6470Sstevel@tonic-gate void
Die(int stat)6480Sstevel@tonic-gate Die(int stat)
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate 	if (Interactive) {
6520Sstevel@tonic-gate 		ioctl(0, TIOCSETN, &OldFlags);
6530Sstevel@tonic-gate 		printf("\r\n");
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 	exit(stat);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate void
remstop()6600Sstevel@tonic-gate remstop()
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate 	Die(23);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate /*
6670Sstevel@tonic-gate  * returns true if we can safely say that the two file descriptors
6680Sstevel@tonic-gate  * are the "same" (both are same file).
6690Sstevel@tonic-gate  */
6700Sstevel@tonic-gate int
samefd(a,b)6710Sstevel@tonic-gate samefd(a, b)
6720Sstevel@tonic-gate {
6730Sstevel@tonic-gate 	struct stat astat, bstat;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (fstat(a, &astat) || fstat(b, &bstat))
6760Sstevel@tonic-gate 		return (0);
6770Sstevel@tonic-gate 	if (astat.st_ino == 0 || bstat.st_ino == 0)
6780Sstevel@tonic-gate 		return (0);
6790Sstevel@tonic-gate 	return (!bcmp(&astat, &bstat, sizeof (astat)));
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate /*
6840Sstevel@tonic-gate  * accept the incoming connection on the given
6850Sstevel@tonic-gate  * file descriptor, and return the new file descritpor
6860Sstevel@tonic-gate  */
6870Sstevel@tonic-gate void
doaccept(fdp)6880Sstevel@tonic-gate doaccept(fdp)
6890Sstevel@tonic-gate 	int *fdp;
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate 	int fd;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	fd = accept(*fdp, 0, 0);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (fd < 0) {
6960Sstevel@tonic-gate 		perror("accept");
6970Sstevel@tonic-gate 		remstop();
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 	close(*fdp);
7000Sstevel@tonic-gate 	*fdp = fd;
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate /*
7040Sstevel@tonic-gate  * create a socket, and return its the port number.
7050Sstevel@tonic-gate  */
7060Sstevel@tonic-gate u_short
makeport(fdp)7070Sstevel@tonic-gate makeport(fdp)
7080Sstevel@tonic-gate 	int *fdp;
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate 	struct sockaddr_in sin;
7110Sstevel@tonic-gate 	socklen_t len = (socklen_t)sizeof (sin);
7120Sstevel@tonic-gate 	int fd;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	fd = socket(AF_INET, SOCK_STREAM, 0);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	if (fd < 0) {
7170Sstevel@tonic-gate 		perror("socket");
7180Sstevel@tonic-gate 		exit(1);
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	bzero((char *)&sin, sizeof (sin));
7220Sstevel@tonic-gate 	sin.sin_family = AF_INET;
7230Sstevel@tonic-gate 	bind(fd, (struct sockaddr *)&sin, sizeof (sin));
7240Sstevel@tonic-gate 	getsockname(fd, (struct sockaddr *)&sin, &len);
7250Sstevel@tonic-gate 	listen(fd, 1);
7260Sstevel@tonic-gate 	*fdp = fd;
7270Sstevel@tonic-gate 	return (htons(sin.sin_port));
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate void
usage(void)7310Sstevel@tonic-gate usage(void)
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate 	fprintf(stderr, "Usage: on [-i|-n] [-d] machine cmd [args]...\n");
7340Sstevel@tonic-gate 	exit(1);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate /*
7380Sstevel@tonic-gate  *  SETPROCTITLE -- set the title of this process for "ps"
7390Sstevel@tonic-gate  *
7400Sstevel@tonic-gate  *	Does nothing if there were not enough arguments on the command
7410Sstevel@tonic-gate  * 	line for the information.
7420Sstevel@tonic-gate  *
7430Sstevel@tonic-gate  *	Side Effects:
7440Sstevel@tonic-gate  *		Clobbers argv[] of our main procedure.
7450Sstevel@tonic-gate  */
7460Sstevel@tonic-gate void
setproctitle(user,host)7470Sstevel@tonic-gate setproctitle(user, host)
7480Sstevel@tonic-gate 	char *user, *host;
7490Sstevel@tonic-gate {
7500Sstevel@tonic-gate 	register char *tohere;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	tohere = Argv[0];
7530Sstevel@tonic-gate 	if ((int)LastArgv == (int)((char *)NULL) ||
7540Sstevel@tonic-gate 	    (int)(strlen(user) + strlen(host)+3) > (int)(LastArgv - tohere))
7550Sstevel@tonic-gate 		return;
7560Sstevel@tonic-gate 	*tohere++ = '-';		/* So ps prints (rpc.rexd) */
7570Sstevel@tonic-gate 	sprintf(tohere, "%s@%s", user, host);
7580Sstevel@tonic-gate 	while (*tohere++)		/* Skip to end of printf output	*/
7590Sstevel@tonic-gate 		;
7600Sstevel@tonic-gate 	while (tohere < LastArgv)	/* Avoid confusing ps		*/
7610Sstevel@tonic-gate 		*tohere++ = ' ';
7620Sstevel@tonic-gate }
763