xref: /freebsd-src/crypto/heimdal/appl/rcp/rcp.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
15e9cd1aeSAssar Westerlund /*
25e9cd1aeSAssar Westerlund  * Copyright (c) 1983, 1990, 1992, 1993
35e9cd1aeSAssar Westerlund  *	The Regents of the University of California.  All rights reserved.
45e9cd1aeSAssar Westerlund  *
55e9cd1aeSAssar Westerlund  * Redistribution and use in source and binary forms, with or without
65e9cd1aeSAssar Westerlund  * modification, are permitted provided that the following conditions
75e9cd1aeSAssar Westerlund  * are met:
85e9cd1aeSAssar Westerlund  * 1. Redistributions of source code must retain the above copyright
95e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer.
105e9cd1aeSAssar Westerlund  * 2. Redistributions in binary form must reproduce the above copyright
115e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer in the
125e9cd1aeSAssar Westerlund  *    documentation and/or other materials provided with the distribution.
13*ae771770SStanislav Sedov  * 3. Neither the name of the University nor the names of its contributors
145e9cd1aeSAssar Westerlund  *    may be used to endorse or promote products derived from this software
155e9cd1aeSAssar Westerlund  *    without specific prior written permission.
165e9cd1aeSAssar Westerlund  *
175e9cd1aeSAssar Westerlund  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
185e9cd1aeSAssar Westerlund  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195e9cd1aeSAssar Westerlund  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
205e9cd1aeSAssar Westerlund  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
215e9cd1aeSAssar Westerlund  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
225e9cd1aeSAssar Westerlund  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
235e9cd1aeSAssar Westerlund  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245e9cd1aeSAssar Westerlund  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
255e9cd1aeSAssar Westerlund  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
265e9cd1aeSAssar Westerlund  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
275e9cd1aeSAssar Westerlund  * SUCH DAMAGE.
285e9cd1aeSAssar Westerlund  */
295e9cd1aeSAssar Westerlund 
305e9cd1aeSAssar Westerlund #include "rcp_locl.h"
31adb0ddaeSAssar Westerlund #include <getarg.h>
325e9cd1aeSAssar Westerlund 
335e9cd1aeSAssar Westerlund #define RSH_PROGRAM "rsh"
345e9cd1aeSAssar Westerlund 
355e9cd1aeSAssar Westerlund struct  passwd *pwd;
365e9cd1aeSAssar Westerlund uid_t	userid;
375e9cd1aeSAssar Westerlund int     errs, remin, remout;
385e9cd1aeSAssar Westerlund int     pflag, iamremote, iamrecursive, targetshouldbedirectory;
395e9cd1aeSAssar Westerlund int     doencrypt, noencrypt;
40bbd80c28SJacques Vidrine int     usebroken, usekrb4, usekrb5, forwardtkt;
415e9cd1aeSAssar Westerlund char    *port;
42c19800e8SDoug Rabson int     eflag = 0;
435e9cd1aeSAssar Westerlund 
445e9cd1aeSAssar Westerlund #define	CMDNEEDS	64
455e9cd1aeSAssar Westerlund char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
465e9cd1aeSAssar Westerlund 
475e9cd1aeSAssar Westerlund int	 response (void);
485e9cd1aeSAssar Westerlund void	 rsource (char *, struct stat *);
495e9cd1aeSAssar Westerlund void	 sink (int, char *[]);
505e9cd1aeSAssar Westerlund void	 source (int, char *[]);
515e9cd1aeSAssar Westerlund void	 tolocal (int, char *[]);
525e9cd1aeSAssar Westerlund void	 toremote (char *, int, char *[]);
535e9cd1aeSAssar Westerlund 
545e9cd1aeSAssar Westerlund int      do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
555e9cd1aeSAssar Westerlund 
56adb0ddaeSAssar Westerlund static int fflag, tflag;
575e9cd1aeSAssar Westerlund 
58adb0ddaeSAssar Westerlund static int version_flag, help_flag;
59adb0ddaeSAssar Westerlund 
60adb0ddaeSAssar Westerlund struct getargs args[] = {
61bbd80c28SJacques Vidrine     { NULL,	'4', arg_flag,		&usekrb4,	"use Kerberos 4 authentication" },
62adb0ddaeSAssar Westerlund     { NULL,	'5', arg_flag,		&usekrb5,	"use Kerberos 5 authentication" },
63adb0ddaeSAssar Westerlund     { NULL,	'F', arg_flag,		&forwardtkt,	"forward credentials" },
64adb0ddaeSAssar Westerlund     { NULL,	'K', arg_flag,		&usebroken,	"use BSD authentication" },
65adb0ddaeSAssar Westerlund     { NULL,	'P', arg_string,	&port,		"non-default port", "port" },
66adb0ddaeSAssar Westerlund     { NULL,	'p', arg_flag,		&pflag,	"preserve file permissions" },
67adb0ddaeSAssar Westerlund     { NULL,	'r', arg_flag,		&iamrecursive,	"recursive mode" },
68adb0ddaeSAssar Westerlund     { NULL,	'x', arg_flag,		&doencrypt,	"use encryption" },
69adb0ddaeSAssar Westerlund     { NULL,	'z', arg_flag,		&noencrypt,	"don't encrypt" },
70adb0ddaeSAssar Westerlund     { NULL,	'd', arg_flag,		&targetshouldbedirectory },
71c19800e8SDoug Rabson     { NULL,	'e', arg_flag,		&eflag, 	"passed to rsh" },
72adb0ddaeSAssar Westerlund     { NULL,	'f', arg_flag,		&fflag },
73adb0ddaeSAssar Westerlund     { NULL,	't', arg_flag,		&tflag },
74adb0ddaeSAssar Westerlund     { "version", 0,  arg_flag,		&version_flag },
75adb0ddaeSAssar Westerlund     { "help",	 0,  arg_flag,		&help_flag }
76adb0ddaeSAssar Westerlund };
77adb0ddaeSAssar Westerlund 
78adb0ddaeSAssar Westerlund static void
usage(int ret)79adb0ddaeSAssar Westerlund usage (int ret)
80adb0ddaeSAssar Westerlund {
81adb0ddaeSAssar Westerlund     arg_printusage (args,
82adb0ddaeSAssar Westerlund 		    sizeof(args) / sizeof(args[0]),
83adb0ddaeSAssar Westerlund 		    NULL,
84adb0ddaeSAssar Westerlund 		    "file1 file2|file... directory");
85adb0ddaeSAssar Westerlund     exit (ret);
865e9cd1aeSAssar Westerlund }
87adb0ddaeSAssar Westerlund 
88adb0ddaeSAssar Westerlund int
main(int argc,char ** argv)89adb0ddaeSAssar Westerlund main(int argc, char **argv)
90adb0ddaeSAssar Westerlund {
91adb0ddaeSAssar Westerlund 	char *targ;
92adb0ddaeSAssar Westerlund 	int optind = 0;
93adb0ddaeSAssar Westerlund 
944137ff4cSJacques Vidrine 	setprogname(argv[0]);
95adb0ddaeSAssar Westerlund 	if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
96adb0ddaeSAssar Westerlund 		    &optind))
97adb0ddaeSAssar Westerlund 	    usage (1);
98adb0ddaeSAssar Westerlund 	if(help_flag)
99adb0ddaeSAssar Westerlund 	    usage(0);
100adb0ddaeSAssar Westerlund 	if (version_flag) {
101adb0ddaeSAssar Westerlund 	    print_version (NULL);
102adb0ddaeSAssar Westerlund 	    return 0;
103adb0ddaeSAssar Westerlund 	}
104adb0ddaeSAssar Westerlund 
105adb0ddaeSAssar Westerlund 	iamremote = (fflag || tflag);
106adb0ddaeSAssar Westerlund 
1075e9cd1aeSAssar Westerlund 	argc -= optind;
1085e9cd1aeSAssar Westerlund 	argv += optind;
1095e9cd1aeSAssar Westerlund 
1105e9cd1aeSAssar Westerlund 	if ((pwd = getpwuid(userid = getuid())) == NULL)
1115e9cd1aeSAssar Westerlund 		errx(1, "unknown user %d", (int)userid);
1125e9cd1aeSAssar Westerlund 
1135e9cd1aeSAssar Westerlund 	remin = STDIN_FILENO;		/* XXX */
1145e9cd1aeSAssar Westerlund 	remout = STDOUT_FILENO;
1155e9cd1aeSAssar Westerlund 
1165e9cd1aeSAssar Westerlund 	if (fflag) {			/* Follow "protocol", send data. */
117*ae771770SStanislav Sedov 		(void)response();
1185e9cd1aeSAssar Westerlund 		source(argc, argv);
1195e9cd1aeSAssar Westerlund 		exit(errs);
1205e9cd1aeSAssar Westerlund 	}
1215e9cd1aeSAssar Westerlund 
1225e9cd1aeSAssar Westerlund 	if (tflag) {			/* Receive data. */
1235e9cd1aeSAssar Westerlund 		sink(argc, argv);
1245e9cd1aeSAssar Westerlund 		exit(errs);
1255e9cd1aeSAssar Westerlund 	}
1265e9cd1aeSAssar Westerlund 
1275e9cd1aeSAssar Westerlund 	if (argc < 2)
128adb0ddaeSAssar Westerlund 	    usage(1);
1295e9cd1aeSAssar Westerlund 	if (argc > 2)
1305e9cd1aeSAssar Westerlund 		targetshouldbedirectory = 1;
1315e9cd1aeSAssar Westerlund 
1325e9cd1aeSAssar Westerlund 	remin = remout = -1;
1335e9cd1aeSAssar Westerlund 	/* Command to be executed on remote system using "rsh". */
1344137ff4cSJacques Vidrine 	snprintf(cmd, sizeof(cmd),
1354137ff4cSJacques Vidrine 		 "rcp%s%s%s", iamrecursive ? " -r" : "",
1365e9cd1aeSAssar Westerlund 		 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
1375e9cd1aeSAssar Westerlund 
138adb0ddaeSAssar Westerlund 	signal(SIGPIPE, lostconn);
1395e9cd1aeSAssar Westerlund 
1405e9cd1aeSAssar Westerlund 	if ((targ = colon(argv[argc - 1])))	/* Dest is remote host. */
1415e9cd1aeSAssar Westerlund 		toremote(targ, argc, argv);
1425e9cd1aeSAssar Westerlund 	else {
1435e9cd1aeSAssar Westerlund 		tolocal(argc, argv);		/* Dest is local host. */
1445e9cd1aeSAssar Westerlund 		if (targetshouldbedirectory)
1455e9cd1aeSAssar Westerlund 			verifydir(argv[argc - 1]);
1465e9cd1aeSAssar Westerlund 	}
1475e9cd1aeSAssar Westerlund 	exit(errs);
1485e9cd1aeSAssar Westerlund }
1495e9cd1aeSAssar Westerlund 
1505e9cd1aeSAssar Westerlund void
toremote(char * targ,int argc,char ** argv)151adb0ddaeSAssar Westerlund toremote(char *targ, int argc, char **argv)
1525e9cd1aeSAssar Westerlund {
1534137ff4cSJacques Vidrine 	int i;
1545e9cd1aeSAssar Westerlund 	char *bp, *host, *src, *suser, *thost, *tuser;
1555e9cd1aeSAssar Westerlund 
1565e9cd1aeSAssar Westerlund 	*targ++ = 0;
1575e9cd1aeSAssar Westerlund 	if (*targ == 0)
1585e9cd1aeSAssar Westerlund 		targ = ".";
1595e9cd1aeSAssar Westerlund 
160*ae771770SStanislav Sedov 	if ((thost = strchr(argv[argc - 1], '@')) != NULL) {
1615e9cd1aeSAssar Westerlund 		/* user@host */
1625e9cd1aeSAssar Westerlund 		*thost++ = 0;
1635e9cd1aeSAssar Westerlund 		tuser = argv[argc - 1];
1645e9cd1aeSAssar Westerlund 		if (*tuser == '\0')
1655e9cd1aeSAssar Westerlund 			tuser = NULL;
1665e9cd1aeSAssar Westerlund 		else if (!okname(tuser))
1675e9cd1aeSAssar Westerlund 			exit(1);
1685e9cd1aeSAssar Westerlund 	} else {
1695e9cd1aeSAssar Westerlund 		thost = argv[argc - 1];
1705e9cd1aeSAssar Westerlund 		tuser = NULL;
1715e9cd1aeSAssar Westerlund 	}
172*ae771770SStanislav Sedov 	thost = unbracket(thost);
1735e9cd1aeSAssar Westerlund 
1745e9cd1aeSAssar Westerlund 	for (i = 0; i < argc - 1; i++) {
1755e9cd1aeSAssar Westerlund 		src = colon(argv[i]);
1765e9cd1aeSAssar Westerlund 		if (src) {			/* remote to remote */
177c19800e8SDoug Rabson 			int ret;
1785e9cd1aeSAssar Westerlund 			*src++ = 0;
1795e9cd1aeSAssar Westerlund 			if (*src == 0)
1805e9cd1aeSAssar Westerlund 				src = ".";
1815e9cd1aeSAssar Westerlund 			host = strchr(argv[i], '@');
1825e9cd1aeSAssar Westerlund 			if (host) {
1834137ff4cSJacques Vidrine 				*host++ = '\0';
184*ae771770SStanislav Sedov 				host = unbracket(host);
1855e9cd1aeSAssar Westerlund 				suser = argv[i];
1865e9cd1aeSAssar Westerlund 				if (*suser == '\0')
1875e9cd1aeSAssar Westerlund 					suser = pwd->pw_name;
1885e9cd1aeSAssar Westerlund 				else if (!okname(suser))
1895e9cd1aeSAssar Westerlund 					continue;
190c19800e8SDoug Rabson 				ret = asprintf(&bp,
191c19800e8SDoug Rabson 				    "%s%s %s -l %s -n %s %s '%s%s%s:%s'",
192c19800e8SDoug Rabson 					 _PATH_RSH, eflag ? " -e" : "",
193c19800e8SDoug Rabson 					 host, suser, cmd, src,
1945e9cd1aeSAssar Westerlund 				    tuser ? tuser : "", tuser ? "@" : "",
1955e9cd1aeSAssar Westerlund 				    thost, targ);
1964137ff4cSJacques Vidrine 			} else {
197*ae771770SStanislav Sedov 				host = unbracket(argv[i]);
198c19800e8SDoug Rabson 				ret = asprintf(&bp,
199c19800e8SDoug Rabson 					 "exec %s%s %s -n %s %s '%s%s%s:%s'",
200c19800e8SDoug Rabson 					 _PATH_RSH, eflag ? " -e" : "",
201*ae771770SStanislav Sedov 					 host, cmd, src,
2025e9cd1aeSAssar Westerlund 					 tuser ? tuser : "", tuser ? "@" : "",
2035e9cd1aeSAssar Westerlund 					 thost, targ);
2044137ff4cSJacques Vidrine 			}
205c19800e8SDoug Rabson 			if (ret == -1)
2064137ff4cSJacques Vidrine 				err (1, "malloc");
207*ae771770SStanislav Sedov 			susystem(bp);
208adb0ddaeSAssar Westerlund 			free(bp);
2095e9cd1aeSAssar Westerlund 		} else {			/* local to remote */
2105e9cd1aeSAssar Westerlund 			if (remin == -1) {
211c19800e8SDoug Rabson 				if (asprintf(&bp, "%s -t %s", cmd, targ) == -1)
2125e9cd1aeSAssar Westerlund 					err (1, "malloc");
2135e9cd1aeSAssar Westerlund 				host = thost;
2145e9cd1aeSAssar Westerlund 
2155e9cd1aeSAssar Westerlund 				if (do_cmd(host, tuser, bp, &remin, &remout) < 0)
2165e9cd1aeSAssar Westerlund 					exit(1);
2175e9cd1aeSAssar Westerlund 
2185e9cd1aeSAssar Westerlund 				if (response() < 0)
2195e9cd1aeSAssar Westerlund 					exit(1);
220adb0ddaeSAssar Westerlund 				free(bp);
2215e9cd1aeSAssar Westerlund 			}
2225e9cd1aeSAssar Westerlund 			source(1, argv+i);
2235e9cd1aeSAssar Westerlund 		}
2245e9cd1aeSAssar Westerlund 	}
2255e9cd1aeSAssar Westerlund }
2265e9cd1aeSAssar Westerlund 
2275e9cd1aeSAssar Westerlund void
tolocal(int argc,char ** argv)228adb0ddaeSAssar Westerlund tolocal(int argc, char **argv)
2295e9cd1aeSAssar Westerlund {
2304137ff4cSJacques Vidrine 	int i;
2315e9cd1aeSAssar Westerlund 	char *bp, *host, *src, *suser;
2325e9cd1aeSAssar Westerlund 
2335e9cd1aeSAssar Westerlund 	for (i = 0; i < argc - 1; i++) {
234c19800e8SDoug Rabson 		int ret;
235c19800e8SDoug Rabson 
2365e9cd1aeSAssar Westerlund 		if (!(src = colon(argv[i]))) {		/* Local to local. */
237c19800e8SDoug Rabson 			ret = asprintf(&bp, "exec %s%s%s %s %s", _PATH_CP,
2385e9cd1aeSAssar Westerlund 			    iamrecursive ? " -PR" : "", pflag ? " -p" : "",
2395e9cd1aeSAssar Westerlund 			    argv[i], argv[argc - 1]);
240c19800e8SDoug Rabson 			if (ret == -1)
2414137ff4cSJacques Vidrine 				err (1, "malloc");
242*ae771770SStanislav Sedov 			if (susystem(bp))
2435e9cd1aeSAssar Westerlund 				++errs;
244adb0ddaeSAssar Westerlund 			free(bp);
2455e9cd1aeSAssar Westerlund 			continue;
2465e9cd1aeSAssar Westerlund 		}
2475e9cd1aeSAssar Westerlund 		*src++ = 0;
2485e9cd1aeSAssar Westerlund 		if (*src == 0)
2495e9cd1aeSAssar Westerlund 			src = ".";
2505e9cd1aeSAssar Westerlund 		if ((host = strchr(argv[i], '@')) == NULL) {
2515e9cd1aeSAssar Westerlund 			host = argv[i];
2525e9cd1aeSAssar Westerlund 			suser = pwd->pw_name;
2535e9cd1aeSAssar Westerlund 		} else {
2545e9cd1aeSAssar Westerlund 			*host++ = 0;
2555e9cd1aeSAssar Westerlund 			suser = argv[i];
2565e9cd1aeSAssar Westerlund 			if (*suser == '\0')
2575e9cd1aeSAssar Westerlund 				suser = pwd->pw_name;
2585e9cd1aeSAssar Westerlund 			else if (!okname(suser))
2595e9cd1aeSAssar Westerlund 				continue;
2605e9cd1aeSAssar Westerlund 		}
261c19800e8SDoug Rabson 		ret = asprintf(&bp, "%s -f %s", cmd, src);
262c19800e8SDoug Rabson 		if (ret == -1)
2635e9cd1aeSAssar Westerlund 			err (1, "malloc");
2645e9cd1aeSAssar Westerlund 		if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
265adb0ddaeSAssar Westerlund 			free(bp);
2665e9cd1aeSAssar Westerlund 			++errs;
2675e9cd1aeSAssar Westerlund 			continue;
2685e9cd1aeSAssar Westerlund 		}
269adb0ddaeSAssar Westerlund 		free(bp);
2705e9cd1aeSAssar Westerlund 		sink(1, argv + argc - 1);
271adb0ddaeSAssar Westerlund 		close(remin);
2725e9cd1aeSAssar Westerlund 		remin = remout = -1;
2735e9cd1aeSAssar Westerlund 	}
2745e9cd1aeSAssar Westerlund }
2755e9cd1aeSAssar Westerlund 
2765e9cd1aeSAssar Westerlund void
source(int argc,char ** argv)277adb0ddaeSAssar Westerlund source(int argc, char **argv)
2785e9cd1aeSAssar Westerlund {
2795e9cd1aeSAssar Westerlund 	struct stat stb;
2805e9cd1aeSAssar Westerlund 	static BUF buffer;
2815e9cd1aeSAssar Westerlund 	BUF *bp;
2825e9cd1aeSAssar Westerlund 	off_t i;
283*ae771770SStanislav Sedov 	off_t amt;
284*ae771770SStanislav Sedov 	int fd, haderr, indx, result;
2855e9cd1aeSAssar Westerlund 	char *last, *name, buf[BUFSIZ];
2865e9cd1aeSAssar Westerlund 
2875e9cd1aeSAssar Westerlund 	for (indx = 0; indx < argc; ++indx) {
2885e9cd1aeSAssar Westerlund                 name = argv[indx];
2895e9cd1aeSAssar Westerlund 		if ((fd = open(name, O_RDONLY, 0)) < 0)
2905e9cd1aeSAssar Westerlund 			goto syserr;
2915e9cd1aeSAssar Westerlund 		if (fstat(fd, &stb)) {
2925e9cd1aeSAssar Westerlund syserr:			run_err("%s: %s", name, strerror(errno));
2935e9cd1aeSAssar Westerlund 			goto next;
2945e9cd1aeSAssar Westerlund 		}
295*ae771770SStanislav Sedov 		if (S_ISDIR(stb.st_mode) && iamrecursive) {
2965e9cd1aeSAssar Westerlund 			rsource(name, &stb);
2975e9cd1aeSAssar Westerlund 			goto next;
298*ae771770SStanislav Sedov 		} else if (!S_ISREG(stb.st_mode)) {
2995e9cd1aeSAssar Westerlund 			run_err("%s: not a regular file", name);
3005e9cd1aeSAssar Westerlund 			goto next;
3015e9cd1aeSAssar Westerlund 		}
3025e9cd1aeSAssar Westerlund 		if ((last = strrchr(name, '/')) == NULL)
3035e9cd1aeSAssar Westerlund 			last = name;
3045e9cd1aeSAssar Westerlund 		else
3055e9cd1aeSAssar Westerlund 			++last;
3065e9cd1aeSAssar Westerlund 		if (pflag) {
3075e9cd1aeSAssar Westerlund 			/*
3085e9cd1aeSAssar Westerlund 			 * Make it compatible with possible future
3095e9cd1aeSAssar Westerlund 			 * versions expecting microseconds.
3105e9cd1aeSAssar Westerlund 			 */
311adb0ddaeSAssar Westerlund 			snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n",
3125e9cd1aeSAssar Westerlund 			    (long)stb.st_mtime,
3135e9cd1aeSAssar Westerlund 			    (long)stb.st_atime);
314adb0ddaeSAssar Westerlund 			write(remout, buf, strlen(buf));
3155e9cd1aeSAssar Westerlund 			if (response() < 0)
3165e9cd1aeSAssar Westerlund 				goto next;
3175e9cd1aeSAssar Westerlund 		}
318c19800e8SDoug Rabson #undef MODEMASK
3195e9cd1aeSAssar Westerlund #define	MODEMASK	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
3204137ff4cSJacques Vidrine 		snprintf(buf, sizeof(buf), "C%04o %lu %s\n",
321*ae771770SStanislav Sedov 			 (unsigned int)(stb.st_mode & MODEMASK),
3224137ff4cSJacques Vidrine 			 (unsigned long)stb.st_size,
3234137ff4cSJacques Vidrine 			 last);
324adb0ddaeSAssar Westerlund 		write(remout, buf, strlen(buf));
3255e9cd1aeSAssar Westerlund 		if (response() < 0)
3265e9cd1aeSAssar Westerlund 			goto next;
3275e9cd1aeSAssar Westerlund 		if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
328adb0ddaeSAssar Westerlund next:			close(fd);
3295e9cd1aeSAssar Westerlund 			continue;
3305e9cd1aeSAssar Westerlund 		}
3315e9cd1aeSAssar Westerlund 
3325e9cd1aeSAssar Westerlund 		/* Keep writing after an error so that we stay sync'd up. */
3335e9cd1aeSAssar Westerlund 		for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
3345e9cd1aeSAssar Westerlund 			amt = bp->cnt;
3355e9cd1aeSAssar Westerlund 			if (i + amt > stb.st_size)
3365e9cd1aeSAssar Westerlund 				amt = stb.st_size - i;
3375e9cd1aeSAssar Westerlund 			if (!haderr) {
338*ae771770SStanislav Sedov 			        result = read(fd, bp->buf, (size_t)amt);
3395e9cd1aeSAssar Westerlund 				if (result != amt)
3405e9cd1aeSAssar Westerlund 					haderr = result >= 0 ? EIO : errno;
3415e9cd1aeSAssar Westerlund 			}
3425e9cd1aeSAssar Westerlund 			if (haderr)
343adb0ddaeSAssar Westerlund 				write(remout, bp->buf, amt);
3445e9cd1aeSAssar Westerlund 			else {
345*ae771770SStanislav Sedov 			        result = write(remout, bp->buf, (size_t)amt);
3465e9cd1aeSAssar Westerlund 				if (result != amt)
3475e9cd1aeSAssar Westerlund 					haderr = result >= 0 ? EIO : errno;
3485e9cd1aeSAssar Westerlund 			}
3495e9cd1aeSAssar Westerlund 		}
3505e9cd1aeSAssar Westerlund 		if (close(fd) && !haderr)
3515e9cd1aeSAssar Westerlund 			haderr = errno;
3525e9cd1aeSAssar Westerlund 		if (!haderr)
353adb0ddaeSAssar Westerlund 			write(remout, "", 1);
3545e9cd1aeSAssar Westerlund 		else
3555e9cd1aeSAssar Westerlund 			run_err("%s: %s", name, strerror(haderr));
356adb0ddaeSAssar Westerlund 		response();
3575e9cd1aeSAssar Westerlund 	}
3585e9cd1aeSAssar Westerlund }
3595e9cd1aeSAssar Westerlund 
3605e9cd1aeSAssar Westerlund void
rsource(char * name,struct stat * statp)361adb0ddaeSAssar Westerlund rsource(char *name, struct stat *statp)
3625e9cd1aeSAssar Westerlund {
3635e9cd1aeSAssar Westerlund 	DIR *dirp;
3645e9cd1aeSAssar Westerlund 	struct dirent *dp;
3655e9cd1aeSAssar Westerlund 	char *last, *vect[1], path[MAXPATHLEN];
3665e9cd1aeSAssar Westerlund 
3675e9cd1aeSAssar Westerlund 	if (!(dirp = opendir(name))) {
3685e9cd1aeSAssar Westerlund 		run_err("%s: %s", name, strerror(errno));
3695e9cd1aeSAssar Westerlund 		return;
3705e9cd1aeSAssar Westerlund 	}
3715e9cd1aeSAssar Westerlund 	last = strrchr(name, '/');
3725e9cd1aeSAssar Westerlund 	if (last == 0)
3735e9cd1aeSAssar Westerlund 		last = name;
3745e9cd1aeSAssar Westerlund 	else
3755e9cd1aeSAssar Westerlund 		last++;
3765e9cd1aeSAssar Westerlund 	if (pflag) {
377adb0ddaeSAssar Westerlund 		snprintf(path, sizeof(path), "T%ld 0 %ld 0\n",
3785e9cd1aeSAssar Westerlund 		    (long)statp->st_mtime,
3795e9cd1aeSAssar Westerlund 		    (long)statp->st_atime);
380adb0ddaeSAssar Westerlund 		write(remout, path, strlen(path));
3815e9cd1aeSAssar Westerlund 		if (response() < 0) {
3825e9cd1aeSAssar Westerlund 			closedir(dirp);
3835e9cd1aeSAssar Westerlund 			return;
3845e9cd1aeSAssar Westerlund 		}
3855e9cd1aeSAssar Westerlund 	}
386adb0ddaeSAssar Westerlund 	snprintf(path, sizeof(path),
387*ae771770SStanislav Sedov 		 "D%04o %d %s\n",
388*ae771770SStanislav Sedov 		 (unsigned int)(statp->st_mode & MODEMASK), 0, last);
389adb0ddaeSAssar Westerlund 	write(remout, path, strlen(path));
3905e9cd1aeSAssar Westerlund 	if (response() < 0) {
3915e9cd1aeSAssar Westerlund 		closedir(dirp);
3925e9cd1aeSAssar Westerlund 		return;
3935e9cd1aeSAssar Westerlund 	}
394*ae771770SStanislav Sedov 	while ((dp = readdir(dirp)) != NULL) {
3955e9cd1aeSAssar Westerlund 		if (dp->d_ino == 0)
3965e9cd1aeSAssar Westerlund 			continue;
3975e9cd1aeSAssar Westerlund 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
3985e9cd1aeSAssar Westerlund 			continue;
3995e9cd1aeSAssar Westerlund 		if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
4005e9cd1aeSAssar Westerlund 			run_err("%s/%s: name too long", name, dp->d_name);
4015e9cd1aeSAssar Westerlund 			continue;
4025e9cd1aeSAssar Westerlund 		}
403adb0ddaeSAssar Westerlund 		snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
4045e9cd1aeSAssar Westerlund 		vect[0] = path;
4055e9cd1aeSAssar Westerlund 		source(1, vect);
4065e9cd1aeSAssar Westerlund 	}
407adb0ddaeSAssar Westerlund 	closedir(dirp);
408adb0ddaeSAssar Westerlund 	write(remout, "E\n", 2);
409adb0ddaeSAssar Westerlund 	response();
4105e9cd1aeSAssar Westerlund }
4115e9cd1aeSAssar Westerlund 
4125e9cd1aeSAssar Westerlund void
sink(int argc,char ** argv)413adb0ddaeSAssar Westerlund sink(int argc, char **argv)
4145e9cd1aeSAssar Westerlund {
4155e9cd1aeSAssar Westerlund 	static BUF buffer;
4165e9cd1aeSAssar Westerlund 	struct stat stb;
4175e9cd1aeSAssar Westerlund 	struct timeval tv[2];
4185e9cd1aeSAssar Westerlund 	enum { YES, NO, DISPLAYED } wrerr;
4195e9cd1aeSAssar Westerlund 	BUF *bp;
4205e9cd1aeSAssar Westerlund 	off_t i, j, size;
4215e9cd1aeSAssar Westerlund 	int amt, count, exists, first, mask, mode, ofd, omode;
4225e9cd1aeSAssar Westerlund 	int setimes, targisdir, wrerrno = 0;
4235e9cd1aeSAssar Westerlund 	char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ];
4245e9cd1aeSAssar Westerlund 
4255e9cd1aeSAssar Westerlund #define	atime	tv[0]
4265e9cd1aeSAssar Westerlund #define	mtime	tv[1]
4275e9cd1aeSAssar Westerlund #define	SCREWUP(str)	{ why = str; goto screwup; }
4285e9cd1aeSAssar Westerlund 
4295e9cd1aeSAssar Westerlund 	setimes = targisdir = 0;
4305e9cd1aeSAssar Westerlund 	mask = umask(0);
4315e9cd1aeSAssar Westerlund 	if (!pflag)
432adb0ddaeSAssar Westerlund 		umask(mask);
4335e9cd1aeSAssar Westerlund 	if (argc != 1) {
4345e9cd1aeSAssar Westerlund 		run_err("ambiguous target");
4355e9cd1aeSAssar Westerlund 		exit(1);
4365e9cd1aeSAssar Westerlund 	}
4375e9cd1aeSAssar Westerlund 	targ = *argv;
4385e9cd1aeSAssar Westerlund 	if (targetshouldbedirectory)
4395e9cd1aeSAssar Westerlund 		verifydir(targ);
440adb0ddaeSAssar Westerlund 	write(remout, "", 1);
4415e9cd1aeSAssar Westerlund 	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
4425e9cd1aeSAssar Westerlund 		targisdir = 1;
4435e9cd1aeSAssar Westerlund 	for (first = 1;; first = 0) {
4445e9cd1aeSAssar Westerlund 		cp = buf;
4455e9cd1aeSAssar Westerlund 		if (read(remin, cp, 1) <= 0)
4465e9cd1aeSAssar Westerlund 			return;
4475e9cd1aeSAssar Westerlund 		if (*cp++ == '\n')
4485e9cd1aeSAssar Westerlund 			SCREWUP("unexpected <newline>");
4495e9cd1aeSAssar Westerlund 		do {
4505e9cd1aeSAssar Westerlund 			if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
4515e9cd1aeSAssar Westerlund 				SCREWUP("lost connection");
4525e9cd1aeSAssar Westerlund 			*cp++ = ch;
4535e9cd1aeSAssar Westerlund 		} while (cp < &buf[BUFSIZ - 1] && ch != '\n');
4545e9cd1aeSAssar Westerlund 		*cp = 0;
4555e9cd1aeSAssar Westerlund 
4565e9cd1aeSAssar Westerlund 		if (buf[0] == '\01' || buf[0] == '\02') {
4575e9cd1aeSAssar Westerlund 			if (iamremote == 0)
458adb0ddaeSAssar Westerlund 				write(STDERR_FILENO,
4595e9cd1aeSAssar Westerlund 				    buf + 1, strlen(buf + 1));
4605e9cd1aeSAssar Westerlund 			if (buf[0] == '\02')
4615e9cd1aeSAssar Westerlund 				exit(1);
4625e9cd1aeSAssar Westerlund 			++errs;
4635e9cd1aeSAssar Westerlund 			continue;
4645e9cd1aeSAssar Westerlund 		}
4655e9cd1aeSAssar Westerlund 		if (buf[0] == 'E') {
466adb0ddaeSAssar Westerlund 			write(remout, "", 1);
4675e9cd1aeSAssar Westerlund 			return;
4685e9cd1aeSAssar Westerlund 		}
4695e9cd1aeSAssar Westerlund 
4705e9cd1aeSAssar Westerlund 		if (ch == '\n')
4715e9cd1aeSAssar Westerlund 			*--cp = 0;
4725e9cd1aeSAssar Westerlund 
4735e9cd1aeSAssar Westerlund 		cp = buf;
4745e9cd1aeSAssar Westerlund 		if (*cp == 'T') {
4755e9cd1aeSAssar Westerlund 			setimes++;
4765e9cd1aeSAssar Westerlund 			cp++;
4775e9cd1aeSAssar Westerlund 			mtime.tv_sec = strtol(cp, &cp, 10);
4785e9cd1aeSAssar Westerlund 			if (!cp || *cp++ != ' ')
4795e9cd1aeSAssar Westerlund 				SCREWUP("mtime.sec not delimited");
4805e9cd1aeSAssar Westerlund 			mtime.tv_usec = strtol(cp, &cp, 10);
4815e9cd1aeSAssar Westerlund 			if (!cp || *cp++ != ' ')
4825e9cd1aeSAssar Westerlund 				SCREWUP("mtime.usec not delimited");
4835e9cd1aeSAssar Westerlund 			atime.tv_sec = strtol(cp, &cp, 10);
4845e9cd1aeSAssar Westerlund 			if (!cp || *cp++ != ' ')
4855e9cd1aeSAssar Westerlund 				SCREWUP("atime.sec not delimited");
4865e9cd1aeSAssar Westerlund 			atime.tv_usec = strtol(cp, &cp, 10);
4875e9cd1aeSAssar Westerlund 			if (!cp || *cp++ != '\0')
4885e9cd1aeSAssar Westerlund 				SCREWUP("atime.usec not delimited");
489adb0ddaeSAssar Westerlund 			write(remout, "", 1);
4905e9cd1aeSAssar Westerlund 			continue;
4915e9cd1aeSAssar Westerlund 		}
4925e9cd1aeSAssar Westerlund 		if (*cp != 'C' && *cp != 'D') {
4935e9cd1aeSAssar Westerlund 			/*
4945e9cd1aeSAssar Westerlund 			 * Check for the case "rcp remote:foo\* local:bar".
4955e9cd1aeSAssar Westerlund 			 * In this case, the line "No match." can be returned
4965e9cd1aeSAssar Westerlund 			 * by the shell before the rcp command on the remote is
4975e9cd1aeSAssar Westerlund 			 * executed so the ^Aerror_message convention isn't
4985e9cd1aeSAssar Westerlund 			 * followed.
4995e9cd1aeSAssar Westerlund 			 */
5005e9cd1aeSAssar Westerlund 			if (first) {
5015e9cd1aeSAssar Westerlund 				run_err("%s", cp);
5025e9cd1aeSAssar Westerlund 				exit(1);
5035e9cd1aeSAssar Westerlund 			}
5045e9cd1aeSAssar Westerlund 			SCREWUP("expected control record");
5055e9cd1aeSAssar Westerlund 		}
5065e9cd1aeSAssar Westerlund 		mode = 0;
5075e9cd1aeSAssar Westerlund 		for (++cp; cp < buf + 5; cp++) {
5085e9cd1aeSAssar Westerlund 			if (*cp < '0' || *cp > '7')
5095e9cd1aeSAssar Westerlund 				SCREWUP("bad mode");
5105e9cd1aeSAssar Westerlund 			mode = (mode << 3) | (*cp - '0');
5115e9cd1aeSAssar Westerlund 		}
5125e9cd1aeSAssar Westerlund 		if (*cp++ != ' ')
5135e9cd1aeSAssar Westerlund 			SCREWUP("mode not delimited");
5145e9cd1aeSAssar Westerlund 
5154137ff4cSJacques Vidrine 		for (size = 0; isdigit((unsigned char)*cp);)
5165e9cd1aeSAssar Westerlund 			size = size * 10 + (*cp++ - '0');
5175e9cd1aeSAssar Westerlund 		if (*cp++ != ' ')
5185e9cd1aeSAssar Westerlund 			SCREWUP("size not delimited");
5195e9cd1aeSAssar Westerlund 		if (targisdir) {
5205e9cd1aeSAssar Westerlund 			static char *namebuf;
5215e9cd1aeSAssar Westerlund 			static int cursize;
5225e9cd1aeSAssar Westerlund 			size_t need;
5235e9cd1aeSAssar Westerlund 
5245e9cd1aeSAssar Westerlund 			need = strlen(targ) + strlen(cp) + 250;
5255e9cd1aeSAssar Westerlund 			if (need > cursize) {
5265e9cd1aeSAssar Westerlund 				if (!(namebuf = malloc(need)))
5275e9cd1aeSAssar Westerlund 					run_err("%s", strerror(errno));
5285e9cd1aeSAssar Westerlund 			}
529adb0ddaeSAssar Westerlund 			snprintf(namebuf, need, "%s%s%s", targ,
5305e9cd1aeSAssar Westerlund 			    *targ ? "/" : "", cp);
5315e9cd1aeSAssar Westerlund 			np = namebuf;
5325e9cd1aeSAssar Westerlund 		} else
5335e9cd1aeSAssar Westerlund 			np = targ;
5345e9cd1aeSAssar Westerlund 		exists = stat(np, &stb) == 0;
5355e9cd1aeSAssar Westerlund 		if (buf[0] == 'D') {
5365e9cd1aeSAssar Westerlund 			int mod_flag = pflag;
5375e9cd1aeSAssar Westerlund 			if (exists) {
5385e9cd1aeSAssar Westerlund 				if (!S_ISDIR(stb.st_mode)) {
5395e9cd1aeSAssar Westerlund 					errno = ENOTDIR;
5405e9cd1aeSAssar Westerlund 					goto bad;
5415e9cd1aeSAssar Westerlund 				}
5425e9cd1aeSAssar Westerlund 				if (pflag)
543adb0ddaeSAssar Westerlund 					chmod(np, mode);
5445e9cd1aeSAssar Westerlund 			} else {
5455e9cd1aeSAssar Westerlund 				/* Handle copying from a read-only directory */
5465e9cd1aeSAssar Westerlund 				mod_flag = 1;
5475e9cd1aeSAssar Westerlund 				if (mkdir(np, mode | S_IRWXU) < 0)
5485e9cd1aeSAssar Westerlund 					goto bad;
5495e9cd1aeSAssar Westerlund 			}
5505e9cd1aeSAssar Westerlund 			vect[0] = np;
5515e9cd1aeSAssar Westerlund 			sink(1, vect);
5525e9cd1aeSAssar Westerlund 			if (setimes) {
5535e9cd1aeSAssar Westerlund 				setimes = 0;
5545e9cd1aeSAssar Westerlund 				if (utimes(np, tv) < 0)
5555e9cd1aeSAssar Westerlund 				    run_err("%s: set times: %s",
5565e9cd1aeSAssar Westerlund 					np, strerror(errno));
5575e9cd1aeSAssar Westerlund 			}
5585e9cd1aeSAssar Westerlund 			if (mod_flag)
559adb0ddaeSAssar Westerlund 				chmod(np, mode);
5605e9cd1aeSAssar Westerlund 			continue;
5615e9cd1aeSAssar Westerlund 		}
5625e9cd1aeSAssar Westerlund 		omode = mode;
5635e9cd1aeSAssar Westerlund 		mode |= S_IWRITE;
5645e9cd1aeSAssar Westerlund 		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
5655e9cd1aeSAssar Westerlund bad:			run_err("%s: %s", np, strerror(errno));
5665e9cd1aeSAssar Westerlund 			continue;
5675e9cd1aeSAssar Westerlund 		}
568adb0ddaeSAssar Westerlund 		write(remout, "", 1);
5695e9cd1aeSAssar Westerlund 		if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
570adb0ddaeSAssar Westerlund 			close(ofd);
5715e9cd1aeSAssar Westerlund 			continue;
5725e9cd1aeSAssar Westerlund 		}
5735e9cd1aeSAssar Westerlund 		cp = bp->buf;
5745e9cd1aeSAssar Westerlund 		wrerr = NO;
5755e9cd1aeSAssar Westerlund 		for (count = i = 0; i < size; i += BUFSIZ) {
5765e9cd1aeSAssar Westerlund 			amt = BUFSIZ;
5775e9cd1aeSAssar Westerlund 			if (i + amt > size)
5785e9cd1aeSAssar Westerlund 				amt = size - i;
5795e9cd1aeSAssar Westerlund 			count += amt;
580adb0ddaeSAssar Westerlund 			if((j = net_read(remin, cp, amt)) != amt) {
5815e9cd1aeSAssar Westerlund 			    run_err("%s", j ? strerror(errno) :
5825e9cd1aeSAssar Westerlund 				    "dropped connection");
5835e9cd1aeSAssar Westerlund 			    exit(1);
5845e9cd1aeSAssar Westerlund 			}
5855e9cd1aeSAssar Westerlund 			amt -= j;
5865e9cd1aeSAssar Westerlund 			cp += j;
5875e9cd1aeSAssar Westerlund 			if (count == bp->cnt) {
5885e9cd1aeSAssar Westerlund 				/* Keep reading so we stay sync'd up. */
5895e9cd1aeSAssar Westerlund 				if (wrerr == NO) {
590*ae771770SStanislav Sedov 					j = write(ofd, bp->buf, (size_t)count);
5915e9cd1aeSAssar Westerlund 					if (j != count) {
5925e9cd1aeSAssar Westerlund 						wrerr = YES;
5935e9cd1aeSAssar Westerlund 						wrerrno = j >= 0 ? EIO : errno;
5945e9cd1aeSAssar Westerlund 					}
5955e9cd1aeSAssar Westerlund 				}
5965e9cd1aeSAssar Westerlund 				count = 0;
5975e9cd1aeSAssar Westerlund 				cp = bp->buf;
5985e9cd1aeSAssar Westerlund 			}
5995e9cd1aeSAssar Westerlund 		}
6005e9cd1aeSAssar Westerlund 		if (count != 0 && wrerr == NO &&
601*ae771770SStanislav Sedov 		    (j = write(ofd, bp->buf, (size_t)count)) != count) {
6025e9cd1aeSAssar Westerlund 			wrerr = YES;
6035e9cd1aeSAssar Westerlund 			wrerrno = j >= 0 ? EIO : errno;
6045e9cd1aeSAssar Westerlund 		}
6055e9cd1aeSAssar Westerlund 		if (ftruncate(ofd, size)) {
6065e9cd1aeSAssar Westerlund 			run_err("%s: truncate: %s", np, strerror(errno));
6075e9cd1aeSAssar Westerlund 			wrerr = DISPLAYED;
6085e9cd1aeSAssar Westerlund 		}
6095e9cd1aeSAssar Westerlund 		if (pflag) {
6105e9cd1aeSAssar Westerlund 			if (exists || omode != mode)
6115e9cd1aeSAssar Westerlund 				if (fchmod(ofd, omode))
6125e9cd1aeSAssar Westerlund 					run_err("%s: set mode: %s",
6135e9cd1aeSAssar Westerlund 					    np, strerror(errno));
6145e9cd1aeSAssar Westerlund 		} else {
6155e9cd1aeSAssar Westerlund 			if (!exists && omode != mode)
6165e9cd1aeSAssar Westerlund 				if (fchmod(ofd, omode & ~mask))
6175e9cd1aeSAssar Westerlund 					run_err("%s: set mode: %s",
6185e9cd1aeSAssar Westerlund 					    np, strerror(errno));
6195e9cd1aeSAssar Westerlund 		}
620adb0ddaeSAssar Westerlund 		close(ofd);
621adb0ddaeSAssar Westerlund 		response();
6225e9cd1aeSAssar Westerlund 		if (setimes && wrerr == NO) {
6235e9cd1aeSAssar Westerlund 			setimes = 0;
6245e9cd1aeSAssar Westerlund 			if (utimes(np, tv) < 0) {
6255e9cd1aeSAssar Westerlund 				run_err("%s: set times: %s",
6265e9cd1aeSAssar Westerlund 				    np, strerror(errno));
6275e9cd1aeSAssar Westerlund 				wrerr = DISPLAYED;
6285e9cd1aeSAssar Westerlund 			}
6295e9cd1aeSAssar Westerlund 		}
6305e9cd1aeSAssar Westerlund 		switch(wrerr) {
6315e9cd1aeSAssar Westerlund 		case YES:
6325e9cd1aeSAssar Westerlund 			run_err("%s: %s", np, strerror(wrerrno));
6335e9cd1aeSAssar Westerlund 			break;
6345e9cd1aeSAssar Westerlund 		case NO:
635adb0ddaeSAssar Westerlund 			write(remout, "", 1);
6365e9cd1aeSAssar Westerlund 			break;
6375e9cd1aeSAssar Westerlund 		case DISPLAYED:
6385e9cd1aeSAssar Westerlund 			break;
6395e9cd1aeSAssar Westerlund 		}
6405e9cd1aeSAssar Westerlund 	}
6415e9cd1aeSAssar Westerlund screwup:
6425e9cd1aeSAssar Westerlund 	run_err("protocol error: %s", why);
6435e9cd1aeSAssar Westerlund 	exit(1);
6445e9cd1aeSAssar Westerlund }
6455e9cd1aeSAssar Westerlund 
6465e9cd1aeSAssar Westerlund int
response(void)647adb0ddaeSAssar Westerlund response(void)
6485e9cd1aeSAssar Westerlund {
6495e9cd1aeSAssar Westerlund 	char ch, *cp, resp, rbuf[BUFSIZ];
6505e9cd1aeSAssar Westerlund 
6515e9cd1aeSAssar Westerlund 	if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
6525e9cd1aeSAssar Westerlund 		lostconn(0);
6535e9cd1aeSAssar Westerlund 
6545e9cd1aeSAssar Westerlund 	cp = rbuf;
6555e9cd1aeSAssar Westerlund 	switch(resp) {
6565e9cd1aeSAssar Westerlund 	case 0:				/* ok */
6575e9cd1aeSAssar Westerlund 		return (0);
6585e9cd1aeSAssar Westerlund 	default:
6595e9cd1aeSAssar Westerlund 		*cp++ = resp;
6605e9cd1aeSAssar Westerlund 		/* FALLTHROUGH */
6615e9cd1aeSAssar Westerlund 	case 1:				/* error, followed by error msg */
6625e9cd1aeSAssar Westerlund 	case 2:				/* fatal error, "" */
6635e9cd1aeSAssar Westerlund 		do {
6645e9cd1aeSAssar Westerlund 			if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
6655e9cd1aeSAssar Westerlund 				lostconn(0);
6665e9cd1aeSAssar Westerlund 			*cp++ = ch;
6675e9cd1aeSAssar Westerlund 		} while (cp < &rbuf[BUFSIZ] && ch != '\n');
6685e9cd1aeSAssar Westerlund 
6695e9cd1aeSAssar Westerlund 		if (!iamremote)
670adb0ddaeSAssar Westerlund 			write(STDERR_FILENO, rbuf, cp - rbuf);
6715e9cd1aeSAssar Westerlund 		++errs;
6725e9cd1aeSAssar Westerlund 		if (resp == 1)
6735e9cd1aeSAssar Westerlund 			return (-1);
6745e9cd1aeSAssar Westerlund 		exit(1);
6755e9cd1aeSAssar Westerlund 	}
6765e9cd1aeSAssar Westerlund 	/* NOTREACHED */
6775e9cd1aeSAssar Westerlund }
6785e9cd1aeSAssar Westerlund 
6795e9cd1aeSAssar Westerlund #include <stdarg.h>
6805e9cd1aeSAssar Westerlund 
6815e9cd1aeSAssar Westerlund void
run_err(const char * fmt,...)6825e9cd1aeSAssar Westerlund run_err(const char *fmt, ...)
6835e9cd1aeSAssar Westerlund {
6845e9cd1aeSAssar Westerlund 	static FILE *fp;
6855e9cd1aeSAssar Westerlund 	va_list ap;
6865e9cd1aeSAssar Westerlund 
6875e9cd1aeSAssar Westerlund 	++errs;
6885e9cd1aeSAssar Westerlund 	if (fp == NULL && !(fp = fdopen(remout, "w")))
6895e9cd1aeSAssar Westerlund 		return;
6904137ff4cSJacques Vidrine 	va_start(ap, fmt);
691adb0ddaeSAssar Westerlund 	fprintf(fp, "%c", 0x01);
692adb0ddaeSAssar Westerlund 	fprintf(fp, "rcp: ");
693adb0ddaeSAssar Westerlund 	vfprintf(fp, fmt, ap);
694adb0ddaeSAssar Westerlund 	fprintf(fp, "\n");
695adb0ddaeSAssar Westerlund 	fflush(fp);
6965e9cd1aeSAssar Westerlund 	va_end(ap);
6974137ff4cSJacques Vidrine 
6984137ff4cSJacques Vidrine 	if (!iamremote) {
6994137ff4cSJacques Vidrine 	    va_start(ap, fmt);
7004137ff4cSJacques Vidrine 	    vwarnx(fmt, ap);
7014137ff4cSJacques Vidrine 	    va_end(ap);
7024137ff4cSJacques Vidrine 	}
7035e9cd1aeSAssar Westerlund }
7045e9cd1aeSAssar Westerlund 
7055e9cd1aeSAssar Westerlund /*
7065e9cd1aeSAssar Westerlund  * This function executes the given command as the specified user on the
7075e9cd1aeSAssar Westerlund  * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
7085e9cd1aeSAssar Westerlund  * assigns the input and output file descriptors on success.
7095e9cd1aeSAssar Westerlund  *
7105e9cd1aeSAssar Westerlund  * If it cannot create necessary pipes it exits with error message.
7115e9cd1aeSAssar Westerlund  */
7125e9cd1aeSAssar Westerlund 
7135e9cd1aeSAssar Westerlund int
do_cmd(char * host,char * remuser,char * cmd,int * fdin,int * fdout)7145e9cd1aeSAssar Westerlund do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
7155e9cd1aeSAssar Westerlund {
7165e9cd1aeSAssar Westerlund 	int pin[2], pout[2], reserved[2];
7175e9cd1aeSAssar Westerlund 
7185e9cd1aeSAssar Westerlund 	/*
7195e9cd1aeSAssar Westerlund 	 * Reserve two descriptors so that the real pipes won't get
7205e9cd1aeSAssar Westerlund 	 * descriptors 0 and 1 because that will screw up dup2 below.
7215e9cd1aeSAssar Westerlund 	 */
7225e9cd1aeSAssar Westerlund 	pipe(reserved);
7235e9cd1aeSAssar Westerlund 
7245e9cd1aeSAssar Westerlund 	/* Create a socket pair for communicating with rsh. */
7255e9cd1aeSAssar Westerlund 	if (pipe(pin) < 0) {
7265e9cd1aeSAssar Westerlund 		perror("pipe");
7275e9cd1aeSAssar Westerlund 		exit(255);
7285e9cd1aeSAssar Westerlund 	}
7295e9cd1aeSAssar Westerlund 	if (pipe(pout) < 0) {
7305e9cd1aeSAssar Westerlund 		perror("pipe");
7315e9cd1aeSAssar Westerlund 		exit(255);
7325e9cd1aeSAssar Westerlund 	}
7335e9cd1aeSAssar Westerlund 
7345e9cd1aeSAssar Westerlund 	/* Free the reserved descriptors. */
7355e9cd1aeSAssar Westerlund 	close(reserved[0]);
7365e9cd1aeSAssar Westerlund 	close(reserved[1]);
7375e9cd1aeSAssar Westerlund 
7385e9cd1aeSAssar Westerlund 	/* For a child to execute the command on the remote host using rsh. */
7395e9cd1aeSAssar Westerlund 	if (fork() == 0) {
7405e9cd1aeSAssar Westerlund 		char *args[100];
7415e9cd1aeSAssar Westerlund 		unsigned int i;
7425e9cd1aeSAssar Westerlund 
7435e9cd1aeSAssar Westerlund 		/* Child. */
7445e9cd1aeSAssar Westerlund 		close(pin[1]);
7455e9cd1aeSAssar Westerlund 		close(pout[0]);
7465e9cd1aeSAssar Westerlund 		dup2(pin[0], 0);
7475e9cd1aeSAssar Westerlund 		dup2(pout[1], 1);
7485e9cd1aeSAssar Westerlund 		close(pin[0]);
7495e9cd1aeSAssar Westerlund 		close(pout[1]);
7505e9cd1aeSAssar Westerlund 
7515e9cd1aeSAssar Westerlund 		i = 0;
7525e9cd1aeSAssar Westerlund 		args[i++] = RSH_PROGRAM;
753bbd80c28SJacques Vidrine 		if (usekrb4)
754bbd80c28SJacques Vidrine 			args[i++] = "-4";
7555e9cd1aeSAssar Westerlund 		if (usekrb5)
7565e9cd1aeSAssar Westerlund 			args[i++] = "-5";
7575e9cd1aeSAssar Westerlund 		if (usebroken)
7585e9cd1aeSAssar Westerlund 			args[i++] = "-K";
7595e9cd1aeSAssar Westerlund 		if (doencrypt)
7605e9cd1aeSAssar Westerlund 			args[i++] = "-x";
761adb0ddaeSAssar Westerlund 		if (forwardtkt)
762adb0ddaeSAssar Westerlund 			args[i++] = "-F";
7635e9cd1aeSAssar Westerlund 		if (noencrypt)
7645e9cd1aeSAssar Westerlund 			args[i++] = "-z";
7655e9cd1aeSAssar Westerlund 		if (port != NULL) {
7665e9cd1aeSAssar Westerlund 			args[i++] = "-p";
7675e9cd1aeSAssar Westerlund 			args[i++] = port;
7685e9cd1aeSAssar Westerlund 		}
769c19800e8SDoug Rabson 		if (eflag)
770c19800e8SDoug Rabson 		    args[i++] = "-e";
7715e9cd1aeSAssar Westerlund 		if (remuser != NULL) {
7725e9cd1aeSAssar Westerlund 			args[i++] = "-l";
7735e9cd1aeSAssar Westerlund 			args[i++] = remuser;
7745e9cd1aeSAssar Westerlund 		}
7755e9cd1aeSAssar Westerlund 		args[i++] = host;
7765e9cd1aeSAssar Westerlund 		args[i++] = cmd;
7775e9cd1aeSAssar Westerlund 		args[i++] = NULL;
7785e9cd1aeSAssar Westerlund 
7795e9cd1aeSAssar Westerlund 		execvp(RSH_PROGRAM, args);
7805e9cd1aeSAssar Westerlund 		perror(RSH_PROGRAM);
7815e9cd1aeSAssar Westerlund 		exit(1);
7825e9cd1aeSAssar Westerlund 	}
7835e9cd1aeSAssar Westerlund 	/* Parent.  Close the other side, and return the local side. */
7845e9cd1aeSAssar Westerlund 	close(pin[0]);
7855e9cd1aeSAssar Westerlund 	*fdout = pin[1];
7865e9cd1aeSAssar Westerlund 	close(pout[1]);
7875e9cd1aeSAssar Westerlund 	*fdin = pout[0];
7885e9cd1aeSAssar Westerlund 	return 0;
7895e9cd1aeSAssar Westerlund }
790