1/* $OpenBSD: scp.c,v 1.171 2011/09/09 22:37:01 djm Exp $ */
2/*
3 * scp - secure remote copy.  This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd).
5 *
6 * NOTE: This version should NOT be suid root.  (This uses ssh to
7 * do the transfer and ssh has the necessary privileges.)
8 *
9 * 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
10 *
11 * As far as I am concerned, the code I have written for this software
12 * can be used freely for any purpose.  Any derived versions of this
13 * software must be clearly marked as such, and if the derived work is
14 * incompatible with the protocol description in the RFC file, it must be
15 * called by a name other than "ssh" or "Secure Shell".
16 */
17/*
18 * Copyright (c) 1999 Theo de Raadt.  All rights reserved.
19 * Copyright (c) 1999 Aaron Campbell.  All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 *    notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 *    notice, this list of conditions and the following disclaimer in the
28 *    documentation and/or other materials provided with the distribution.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
31 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
33 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
39 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41
42/*
43 * Parts from:
44 *
45 * Copyright (c) 1983, 1990, 1992, 1993, 1995
46 *	The Regents of the University of California.  All rights reserved.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 *    notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 *    notice, this list of conditions and the following disclaimer in the
55 *    documentation and/or other materials provided with the distribution.
56 * 3. Neither the name of the University nor the names of its contributors
57 *    may be used to endorse or promote products derived from this software
58 *    without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 *
72 */
73
74#include "includes.h"
75
76#include <sys/types.h>
77#include <sys/param.h>
78#ifdef HAVE_SYS_STAT_H
79# include <sys/stat.h>
80#endif
81#ifdef __APPLE_XSAN__
82#include <sys/mount.h>
83#endif
84#ifdef HAVE_POLL_H
85#include <poll.h>
86#else
87# ifdef HAVE_SYS_POLL_H
88#  include <sys/poll.h>
89# endif
90#endif
91#ifdef HAVE_SYS_TIME_H
92# include <sys/time.h>
93#endif
94#include <sys/wait.h>
95#include <sys/uio.h>
96
97#include <ctype.h>
98#include <dirent.h>
99#include <errno.h>
100#include <fcntl.h>
101#include <pwd.h>
102#include <signal.h>
103#include <stdarg.h>
104#include <stdio.h>
105#include <stdlib.h>
106#include <string.h>
107#include <time.h>
108#include <unistd.h>
109#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS)
110#include <vis.h>
111#endif
112
113#include "xmalloc.h"
114#include "atomicio.h"
115#include "pathnames.h"
116#include "log.h"
117#include "misc.h"
118#include "progressmeter.h"
119
120#ifdef HAVE_COPYFILE_H
121#include <libgen.h>
122#include <copyfile.h>
123#endif
124
125extern char *__progname;
126
127#define COPY_BUFLEN	16384
128
129int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
130int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
131
132/* Struct for addargs */
133arglist args;
134arglist remote_remote_args;
135
136/* Bandwidth limit */
137long long limit_kbps = 0;
138struct bwlimit bwlimit;
139
140/* Name of current file being transferred. */
141char *curfile;
142
143/* This is set to non-zero to enable verbose mode. */
144int verbose_mode = 0;
145
146/* This is set to zero if the progressmeter is not desired. */
147int showprogress = 1;
148
149/*
150 * This is set to non-zero if remote-remote copy should be piped
151 * through this process.
152 */
153int throughlocal = 0;
154
155/* This is the program to execute for the secured connection. ("ssh" or -S) */
156char *ssh_program = _PATH_SSH_PROGRAM;
157
158/* This is used to store the pid of ssh_program */
159pid_t do_cmd_pid = -1;
160
161#ifdef HAVE_COPYFILE
162int copy_xattr = 0;
163int md_flag = 0;
164#endif
165
166
167static void
168killchild(int signo)
169{
170	if (do_cmd_pid > 1) {
171		kill(do_cmd_pid, signo ? signo : SIGTERM);
172		waitpid(do_cmd_pid, NULL, 0);
173	}
174
175	if (signo)
176		_exit(1);
177	exit(1);
178}
179
180static void
181suspchild(int signo)
182{
183	int status;
184
185	if (do_cmd_pid > 1) {
186		kill(do_cmd_pid, signo);
187		while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
188		    errno == EINTR)
189			;
190		kill(getpid(), SIGSTOP);
191	}
192}
193
194static int
195do_local_cmd(arglist *a)
196{
197	u_int i;
198	int status;
199	pid_t pid;
200
201	if (a->num == 0)
202		fatal("do_local_cmd: no arguments");
203
204	if (verbose_mode) {
205		fprintf(stderr, "Executing:");
206		for (i = 0; i < a->num; i++)
207			fprintf(stderr, " %s", a->list[i]);
208		fprintf(stderr, "\n");
209	}
210	if ((pid = fork()) == -1)
211		fatal("do_local_cmd: fork: %s", strerror(errno));
212
213	if (pid == 0) {
214		execvp(a->list[0], a->list);
215		perror(a->list[0]);
216		exit(1);
217	}
218
219	do_cmd_pid = pid;
220	signal(SIGTERM, killchild);
221	signal(SIGINT, killchild);
222	signal(SIGHUP, killchild);
223
224	while (waitpid(pid, &status, 0) == -1)
225		if (errno != EINTR)
226			fatal("do_local_cmd: waitpid: %s", strerror(errno));
227
228	do_cmd_pid = -1;
229
230	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
231		return (-1);
232
233	return (0);
234}
235
236/*
237 * This function executes the given command as the specified user on the
238 * given host.  This returns < 0 if execution fails, and >= 0 otherwise. This
239 * assigns the input and output file descriptors on success.
240 */
241
242int
243do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
244{
245	int pin[2], pout[2], reserved[2];
246
247	if (verbose_mode)
248		fprintf(stderr,
249		    "Executing: program %s host %s, user %s, command %s\n",
250		    ssh_program, host,
251		    remuser ? remuser : "(unspecified)", cmd);
252
253	/*
254	 * Reserve two descriptors so that the real pipes won't get
255	 * descriptors 0 and 1 because that will screw up dup2 below.
256	 */
257	if (pipe(reserved) < 0)
258		fatal("pipe: %s", strerror(errno));
259
260	/* Create a socket pair for communicating with ssh. */
261	if (pipe(pin) < 0)
262		fatal("pipe: %s", strerror(errno));
263	if (pipe(pout) < 0)
264		fatal("pipe: %s", strerror(errno));
265
266	/* Free the reserved descriptors. */
267	close(reserved[0]);
268	close(reserved[1]);
269
270	signal(SIGTSTP, suspchild);
271	signal(SIGTTIN, suspchild);
272	signal(SIGTTOU, suspchild);
273
274	/* Fork a child to execute the command on the remote host using ssh. */
275	do_cmd_pid = fork();
276	if (do_cmd_pid == 0) {
277		/* Child. */
278		close(pin[1]);
279		close(pout[0]);
280		dup2(pin[0], 0);
281		dup2(pout[1], 1);
282		close(pin[0]);
283		close(pout[1]);
284
285		replacearg(&args, 0, "%s", ssh_program);
286		if (remuser != NULL) {
287			addargs(&args, "-l");
288			addargs(&args, "%s", remuser);
289		}
290		addargs(&args, "--");
291		addargs(&args, "%s", host);
292		addargs(&args, "%s", cmd);
293
294		execvp(ssh_program, args.list);
295		perror(ssh_program);
296		exit(1);
297	} else if (do_cmd_pid == -1) {
298		fatal("fork: %s", strerror(errno));
299	}
300	/* Parent.  Close the other side, and return the local side. */
301	close(pin[0]);
302	*fdout = pin[1];
303	close(pout[1]);
304	*fdin = pout[0];
305	signal(SIGTERM, killchild);
306	signal(SIGINT, killchild);
307	signal(SIGHUP, killchild);
308	return 0;
309}
310
311/*
312 * This functions executes a command simlar to do_cmd(), but expects the
313 * input and output descriptors to be setup by a previous call to do_cmd().
314 * This way the input and output of two commands can be connected.
315 */
316int
317do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
318{
319	pid_t pid;
320	int status;
321
322	if (verbose_mode)
323		fprintf(stderr,
324		    "Executing: 2nd program %s host %s, user %s, command %s\n",
325		    ssh_program, host,
326		    remuser ? remuser : "(unspecified)", cmd);
327
328	/* Fork a child to execute the command on the remote host using ssh. */
329	pid = fork();
330	if (pid == 0) {
331		dup2(fdin, 0);
332		dup2(fdout, 1);
333
334		replacearg(&args, 0, "%s", ssh_program);
335		if (remuser != NULL) {
336			addargs(&args, "-l");
337			addargs(&args, "%s", remuser);
338		}
339		addargs(&args, "--");
340		addargs(&args, "%s", host);
341		addargs(&args, "%s", cmd);
342
343		execvp(ssh_program, args.list);
344		perror(ssh_program);
345		exit(1);
346	} else if (pid == -1) {
347		fatal("fork: %s", strerror(errno));
348	}
349	while (waitpid(pid, &status, 0) == -1)
350		if (errno != EINTR)
351			fatal("do_cmd2: waitpid: %s", strerror(errno));
352	return 0;
353}
354
355typedef struct {
356	size_t cnt;
357	char *buf;
358} BUF;
359
360BUF *allocbuf(BUF *, int, int);
361void lostconn(int);
362int okname(char *);
363void run_err(const char *,...);
364void verifydir(char *);
365
366struct passwd *pwd;
367uid_t userid;
368int errs, remin, remout;
369int pflag, iamremote, iamrecursive, targetshouldbedirectory;
370
371#define	CMDNEEDS	64
372char cmd[CMDNEEDS];		/* must hold "rcp -r -p -d\0" */
373
374int response(void);
375void rsource(char *, struct stat *);
376void sink(int, char *[]);
377void source(int, char *[]);
378void tolocal(int, char *[]);
379void toremote(char *, int, char *[]);
380void usage(void);
381
382int
383main(int argc, char **argv)
384{
385	int ch, fflag, tflag, status, n;
386	char *targ, **newargv;
387	const char *errstr;
388	extern char *optarg;
389	extern int optind;
390
391	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
392	sanitise_stdfd();
393
394	/* Copy argv, because we modify it */
395	newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv));
396	for (n = 0; n < argc; n++)
397		newargv[n] = xstrdup(argv[n]);
398	argv = newargv;
399
400	__progname = ssh_get_progname(argv[0]);
401
402	memset(&args, '\0', sizeof(args));
403	memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
404	args.list = remote_remote_args.list = NULL;
405	addargs(&args, "%s", ssh_program);
406	addargs(&args, "-x");
407	addargs(&args, "-oForwardAgent=no");
408	addargs(&args, "-oPermitLocalCommand=no");
409	addargs(&args, "-oClearAllForwardings=yes");
410
411	fflag = tflag = 0;
412#if HAVE_COPYFILE
413	while ((ch = getopt(argc, argv, "dfl:prtvBCEc:i:P:q12346S:o:F:")) != -1)
414#else
415	while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
416#endif
417		switch (ch) {
418		/* User-visible flags. */
419		case '1':
420		case '2':
421		case '4':
422		case '6':
423		case 'C':
424			addargs(&args, "-%c", ch);
425			addargs(&remote_remote_args, "-%c", ch);
426			break;
427		case '3':
428			throughlocal = 1;
429			break;
430		case 'o':
431		case 'c':
432		case 'i':
433		case 'F':
434			addargs(&remote_remote_args, "-%c", ch);
435			addargs(&remote_remote_args, "%s", optarg);
436			addargs(&args, "-%c", ch);
437			addargs(&args, "%s", optarg);
438			break;
439		case 'P':
440			addargs(&remote_remote_args, "-p");
441			addargs(&remote_remote_args, "%s", optarg);
442			addargs(&args, "-p");
443			addargs(&args, "%s", optarg);
444			break;
445		case 'B':
446			addargs(&remote_remote_args, "-oBatchmode=yes");
447			addargs(&args, "-oBatchmode=yes");
448			break;
449		case 'l':
450			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
451			    &errstr);
452			if (errstr != NULL)
453				usage();
454			limit_kbps *= 1024; /* kbps */
455			bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
456			break;
457		case 'p':
458			pflag = 1;
459			break;
460		case 'r':
461			iamrecursive = 1;
462			break;
463		case 'S':
464			ssh_program = xstrdup(optarg);
465			break;
466		case 'v':
467			addargs(&args, "-v");
468			addargs(&remote_remote_args, "-v");
469			verbose_mode = 1;
470			break;
471		case 'q':
472			addargs(&args, "-q");
473			addargs(&remote_remote_args, "-q");
474			showprogress = 0;
475			break;
476
477#ifdef HAVE_COPYFILE
478		case 'E':
479			copy_xattr = 1;
480			break;
481#endif
482		/* Server options. */
483		case 'd':
484			targetshouldbedirectory = 1;
485			break;
486		case 'f':	/* "from" */
487			iamremote = 1;
488			fflag = 1;
489			break;
490		case 't':	/* "to" */
491			iamremote = 1;
492			tflag = 1;
493#ifdef HAVE_CYGWIN
494			setmode(0, O_BINARY);
495#endif
496			break;
497		default:
498			usage();
499		}
500	argc -= optind;
501	argv += optind;
502
503	if ((pwd = getpwuid(userid = getuid())) == NULL)
504		fatal("unknown user %u", (u_int) userid);
505
506	if (!isatty(STDOUT_FILENO))
507		showprogress = 0;
508
509	remin = STDIN_FILENO;
510	remout = STDOUT_FILENO;
511
512	if (fflag) {
513		/* Follow "protocol", send data. */
514		(void) response();
515		source(argc, argv);
516		exit(errs != 0);
517	}
518	if (tflag) {
519		/* Receive data. */
520		sink(argc, argv);
521		exit(errs != 0);
522	}
523	if (argc < 2)
524		usage();
525	if (argc > 2)
526		targetshouldbedirectory = 1;
527
528	remin = remout = -1;
529	do_cmd_pid = -1;
530	/* Command to be executed on remote system using "ssh". */
531#if HAVE_COPYFILE
532	(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s%s",
533	    copy_xattr ? " -E" : "",
534#else
535	(void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
536#endif
537	    verbose_mode ? " -v" : "",
538	    iamrecursive ? " -r" : "", pflag ? " -p" : "",
539	    targetshouldbedirectory ? " -d" : "");
540
541	(void) signal(SIGPIPE, lostconn);
542
543	if ((targ = colon(argv[argc - 1])))	/* Dest is remote host. */
544		toremote(targ, argc, argv);
545	else {
546		if (targetshouldbedirectory)
547			verifydir(argv[argc - 1]);
548		tolocal(argc, argv);	/* Dest is local host. */
549	}
550	/*
551	 * Finally check the exit status of the ssh process, if one was forked
552	 * and no error has occurred yet
553	 */
554	if (do_cmd_pid != -1 && errs == 0) {
555		if (remin != -1)
556		    (void) close(remin);
557		if (remout != -1)
558		    (void) close(remout);
559		if (waitpid(do_cmd_pid, &status, 0) == -1)
560			errs = 1;
561		else {
562			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
563				errs = 1;
564		}
565	}
566	exit(errs != 0);
567}
568
569/* Callback from atomicio6 to update progress meter and limit bandwidth */
570static int
571scpio(void *_cnt, size_t s)
572{
573	off_t *cnt = (off_t *)_cnt;
574
575	*cnt += s;
576	if (limit_kbps > 0)
577		bandwidth_limit(&bwlimit, s);
578	return 0;
579}
580
581void
582toremote(char *targ, int argc, char **argv)
583{
584	char *bp, *host, *src, *suser, *thost, *tuser, *arg;
585	arglist alist;
586	int i;
587	u_int j;
588
589	memset(&alist, '\0', sizeof(alist));
590	alist.list = NULL;
591
592	*targ++ = 0;
593	if (*targ == 0)
594		targ = ".";
595
596	arg = xstrdup(argv[argc - 1]);
597	if ((thost = strrchr(arg, '@'))) {
598		/* user@host */
599		*thost++ = 0;
600		tuser = arg;
601		if (*tuser == '\0')
602			tuser = NULL;
603	} else {
604		thost = arg;
605		tuser = NULL;
606	}
607
608	if (tuser != NULL && !okname(tuser)) {
609		xfree(arg);
610		return;
611	}
612
613	for (i = 0; i < argc - 1; i++) {
614		src = colon(argv[i]);
615		if (src && throughlocal) {	/* extended remote to remote */
616			*src++ = 0;
617			if (*src == 0)
618				src = ".";
619			host = strrchr(argv[i], '@');
620			if (host) {
621				*host++ = 0;
622				host = cleanhostname(host);
623				suser = argv[i];
624				if (*suser == '\0')
625					suser = pwd->pw_name;
626				else if (!okname(suser))
627					continue;
628			} else {
629				host = cleanhostname(argv[i]);
630				suser = NULL;
631			}
632			xasprintf(&bp, "%s -f %s%s", cmd,
633			    *src == '-' ? "-- " : "", src);
634			if (do_cmd(host, suser, bp, &remin, &remout) < 0)
635				exit(1);
636			(void) xfree(bp);
637			host = cleanhostname(thost);
638			xasprintf(&bp, "%s -t %s%s", cmd,
639			    *targ == '-' ? "-- " : "", targ);
640			if (do_cmd2(host, tuser, bp, remin, remout) < 0)
641				exit(1);
642			(void) xfree(bp);
643			(void) close(remin);
644			(void) close(remout);
645			remin = remout = -1;
646		} else if (src) {	/* standard remote to remote */
647			freeargs(&alist);
648			addargs(&alist, "%s", ssh_program);
649			addargs(&alist, "-x");
650			addargs(&alist, "-oClearAllForwardings=yes");
651			addargs(&alist, "-n");
652			for (j = 0; j < remote_remote_args.num; j++) {
653				addargs(&alist, "%s",
654				    remote_remote_args.list[j]);
655			}
656			*src++ = 0;
657			if (*src == 0)
658				src = ".";
659			host = strrchr(argv[i], '@');
660
661			if (host) {
662				*host++ = 0;
663				host = cleanhostname(host);
664				suser = argv[i];
665				if (*suser == '\0')
666					suser = pwd->pw_name;
667				else if (!okname(suser))
668					continue;
669				addargs(&alist, "-l");
670				addargs(&alist, "%s", suser);
671			} else {
672				host = cleanhostname(argv[i]);
673			}
674			addargs(&alist, "--");
675			addargs(&alist, "%s", host);
676			addargs(&alist, "%s", cmd);
677			addargs(&alist, "%s", src);
678			addargs(&alist, "%s%s%s:%s",
679			    tuser ? tuser : "", tuser ? "@" : "",
680			    thost, targ);
681			if (do_local_cmd(&alist) != 0)
682				errs = 1;
683		} else {	/* local to remote */
684			if (remin == -1) {
685				xasprintf(&bp, "%s -t %s%s", cmd,
686				    *targ == '-' ? "-- " : "", targ);
687				host = cleanhostname(thost);
688				if (do_cmd(host, tuser, bp, &remin,
689				    &remout) < 0)
690					exit(1);
691				if (response() < 0)
692					exit(1);
693				(void) xfree(bp);
694			}
695			source(1, argv + i);
696		}
697	}
698	xfree(arg);
699}
700
701void
702tolocal(int argc, char **argv)
703{
704	char *bp, *host, *src, *suser;
705	arglist alist;
706	int i;
707
708	memset(&alist, '\0', sizeof(alist));
709	alist.list = NULL;
710
711	for (i = 0; i < argc - 1; i++) {
712		if (!(src = colon(argv[i]))) {	/* Local to local. */
713			freeargs(&alist);
714			addargs(&alist, "%s", _PATH_CP);
715			if (iamrecursive)
716				addargs(&alist, "-r");
717			if (pflag)
718				addargs(&alist, "-p");
719			addargs(&alist, "--");
720			addargs(&alist, "%s", argv[i]);
721			addargs(&alist, "%s", argv[argc-1]);
722			if (do_local_cmd(&alist))
723				++errs;
724			continue;
725		}
726		*src++ = 0;
727		if (*src == 0)
728			src = ".";
729		if ((host = strrchr(argv[i], '@')) == NULL) {
730			host = argv[i];
731			suser = NULL;
732		} else {
733			*host++ = 0;
734			suser = argv[i];
735			if (*suser == '\0')
736				suser = pwd->pw_name;
737		}
738		host = cleanhostname(host);
739		xasprintf(&bp, "%s -f %s%s",
740		    cmd, *src == '-' ? "-- " : "", src);
741		if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
742			(void) xfree(bp);
743			++errs;
744			continue;
745		}
746		xfree(bp);
747		sink(1, argv + argc - 1);
748		(void) close(remin);
749		remin = remout = -1;
750	}
751}
752
753void
754source(int argc, char **argv)
755{
756	struct stat stb;
757	static BUF buffer;
758	BUF *bp;
759	off_t i, statbytes;
760	size_t amt;
761	int fd = -1, haderr, indx;
762	char *last, *name, buf[2048], encname[MAXPATHLEN];
763	int len;
764#if HAVE_COPYFILE
765	char md_name[MAXPATHLEN];
766	char *md_tmp;
767#endif
768
769	for (indx = 0; indx < argc; ++indx) {
770		name = argv[indx];
771		statbytes = 0;
772		len = strlen(name);
773		while (len > 1 && name[len-1] == '/')
774			name[--len] = '\0';
775#if HAVE_COPYFILE
776md_next:
777		statbytes = 0;
778		if (md_flag) {
779		    fd = open(md_tmp, O_RDONLY, 0);
780		    unlink(md_tmp);
781		    free(md_tmp);
782		    if (fd < 0)
783			goto syserr;
784		} else {
785#endif
786		if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0)
787			goto syserr;
788		if (strchr(name, '\n') != NULL) {
789			strnvis(encname, name, sizeof(encname), VIS_NL);
790			name = encname;
791		}
792#if HAVE_COPYFILE
793		}
794#endif
795		if (fstat(fd, &stb) < 0) {
796syserr:			run_err("%s: %s", name, strerror(errno));
797			goto next;
798		}
799		if (stb.st_size < 0) {
800			run_err("%s: %s", name, "Negative file size");
801			goto next;
802		}
803		unset_nonblock(fd);
804		switch (stb.st_mode & S_IFMT) {
805		case S_IFREG:
806			break;
807		case S_IFDIR:
808			if (iamrecursive) {
809				rsource(name, &stb);
810				goto next;
811			}
812			/* FALLTHROUGH */
813		default:
814			run_err("%s: not a regular file", name);
815			goto next;
816		}
817		if ((last = strrchr(name, '/')) == NULL)
818			last = name;
819		else
820			++last;
821		curfile = last;
822		if (pflag) {
823			/*
824			 * Make it compatible with possible future
825			 * versions expecting microseconds.
826			 */
827			(void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
828			    (u_long) (stb.st_mtime < 0 ? 0 : stb.st_mtime),
829			    (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime));
830			if (verbose_mode) {
831				fprintf(stderr, "File mtime %ld atime %ld\n",
832				    (long)stb.st_mtime, (long)stb.st_atime);
833				fprintf(stderr, "Sending file timestamps: %s",
834				    buf);
835			}
836			(void) atomicio(vwrite, remout, buf, strlen(buf));
837			if (response() < 0)
838				goto next;
839		}
840#define	FILEMODEMASK	(S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
841		snprintf(buf, sizeof buf, "C%04o %lld %s\n",
842		    (u_int) (stb.st_mode & FILEMODEMASK),
843		    (long long)stb.st_size, last);
844		if (verbose_mode) {
845			fprintf(stderr, "Sending file modes: %s", buf);
846		}
847		(void) atomicio(vwrite, remout, buf, strlen(buf));
848		if (response() < 0)
849			goto next;
850		if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
851next:			if (fd != -1) {
852				(void) close(fd);
853				fd = -1;
854			}
855			continue;
856		}
857		if (showprogress)
858			start_progress_meter(curfile, stb.st_size, &statbytes);
859		set_nonblock(remout);
860		for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
861			amt = bp->cnt;
862			if (i + (off_t)amt > stb.st_size)
863				amt = stb.st_size - i;
864			if (!haderr) {
865				if (atomicio(read, fd, bp->buf, amt) != amt)
866					haderr = errno;
867			}
868			/* Keep writing after error to retain sync */
869			if (haderr) {
870				(void)atomicio(vwrite, remout, bp->buf, amt);
871				continue;
872			}
873			if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
874			    &statbytes) != amt)
875				haderr = errno;
876		}
877		unset_nonblock(remout);
878		if (showprogress)
879			stop_progress_meter();
880
881		if (fd != -1) {
882			if (close(fd) < 0 && !haderr)
883				haderr = errno;
884			fd = -1;
885		}
886		if (!haderr)
887			(void) atomicio(vwrite, remout, "", 1);
888		else
889			run_err("%s: %s", name, strerror(haderr));
890		(void) response();
891#ifdef HAVE_COPYFILE
892		if (copy_xattr && md_flag == 0)
893		{
894		    if (!copyfile(name, NULL, 0,
895			    COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_CHECK))
896			continue;
897
898		    /*
899		     * this file will hold the actual metadata
900		     * to be transferred
901		     */
902		    md_tmp = strdup("/tmp/scp.md.XXXXXX");
903		    md_tmp = mktemp(md_tmp);
904
905		    if(copyfile(name, md_tmp, 0,
906				COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_PACK) == 0)
907		    {
908			/*
909			 * this is the fake name to display
910			 */
911			snprintf(md_name, sizeof md_name, "%s/._%s", dirname(name), basename(name));
912			name = md_name;
913			md_flag = 1;
914			if (verbose_mode)
915			    fprintf(stderr, "copyfile(%s, %s, PACK)\n", name, md_tmp);
916			goto md_next;
917		    }
918		} else
919		    md_flag = 0;
920#endif
921	}
922}
923
924void
925rsource(char *name, struct stat *statp)
926{
927	DIR *dirp;
928	struct dirent *dp;
929	char *last, *vect[1], path[1100];
930
931	if (!(dirp = opendir(name))) {
932		run_err("%s: %s", name, strerror(errno));
933		return;
934	}
935	last = strrchr(name, '/');
936	if (last == 0)
937		last = name;
938	else
939		last++;
940	if (pflag) {
941		(void) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n",
942		    (u_long) statp->st_mtime,
943		    (u_long) statp->st_atime);
944		(void) atomicio(vwrite, remout, path, strlen(path));
945		if (response() < 0) {
946			closedir(dirp);
947			return;
948		}
949	}
950	(void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
951	    (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
952	if (verbose_mode)
953		fprintf(stderr, "Entering directory: %s", path);
954	(void) atomicio(vwrite, remout, path, strlen(path));
955	if (response() < 0) {
956		closedir(dirp);
957		return;
958	}
959	while ((dp = readdir(dirp)) != NULL) {
960		if (dp->d_ino == 0)
961			continue;
962		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
963			continue;
964		if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
965			run_err("%s/%s: name too long", name, dp->d_name);
966			continue;
967		}
968		(void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
969		vect[0] = path;
970		source(1, vect);
971	}
972	(void) closedir(dirp);
973	(void) atomicio(vwrite, remout, "E\n", 2);
974	(void) response();
975}
976
977void
978sink(int argc, char **argv)
979{
980	static BUF buffer;
981	struct stat stb;
982	enum {
983		YES, NO, DISPLAYED
984	} wrerr;
985	BUF *bp;
986	off_t i;
987	size_t j, count;
988	int amt, exists, first, ofd;
989	mode_t mode, omode, mask;
990	off_t size, statbytes;
991	int setimes, targisdir, wrerrno = 0;
992	char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
993	struct timeval tv[2];
994
995#define	atime	tv[0]
996#define	mtime	tv[1]
997#define	SCREWUP(str)	{ why = str; goto screwup; }
998
999	setimes = targisdir = 0;
1000	mask = umask(0);
1001	if (!pflag)
1002		(void) umask(mask);
1003	if (argc != 1) {
1004		run_err("ambiguous target");
1005		exit(1);
1006	}
1007	targ = *argv;
1008	if (targetshouldbedirectory)
1009		verifydir(targ);
1010
1011	(void) atomicio(vwrite, remout, "", 1);
1012	if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
1013		targisdir = 1;
1014	for (first = 1;; first = 0) {
1015#if HAVE_COPYFILE
1016		char md_src[MAXPATHLEN];
1017		char md_dst[MAXPATHLEN];
1018#endif
1019		cp = buf;
1020		if (atomicio(read, remin, cp, 1) != 1)
1021			return;
1022		if (*cp++ == '\n')
1023			SCREWUP("unexpected <newline>");
1024		do {
1025			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
1026				SCREWUP("lost connection");
1027			*cp++ = ch;
1028		} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
1029		*cp = 0;
1030		if (verbose_mode)
1031			fprintf(stderr, "Sink: %s", buf);
1032
1033		if (buf[0] == '\01' || buf[0] == '\02') {
1034			if (iamremote == 0)
1035				(void) atomicio(vwrite, STDERR_FILENO,
1036				    buf + 1, strlen(buf + 1));
1037			if (buf[0] == '\02')
1038				exit(1);
1039			++errs;
1040			continue;
1041		}
1042		if (buf[0] == 'E') {
1043			(void) atomicio(vwrite, remout, "", 1);
1044			return;
1045		}
1046		if (ch == '\n')
1047			*--cp = 0;
1048
1049		cp = buf;
1050		if (*cp == 'T') {
1051			setimes++;
1052			cp++;
1053			mtime.tv_sec = strtol(cp, &cp, 10);
1054			if (!cp || *cp++ != ' ')
1055				SCREWUP("mtime.sec not delimited");
1056			mtime.tv_usec = strtol(cp, &cp, 10);
1057			if (!cp || *cp++ != ' ')
1058				SCREWUP("mtime.usec not delimited");
1059			atime.tv_sec = strtol(cp, &cp, 10);
1060			if (!cp || *cp++ != ' ')
1061				SCREWUP("atime.sec not delimited");
1062			atime.tv_usec = strtol(cp, &cp, 10);
1063			if (!cp || *cp++ != '\0')
1064				SCREWUP("atime.usec not delimited");
1065			(void) atomicio(vwrite, remout, "", 1);
1066			continue;
1067		}
1068		if (*cp != 'C' && *cp != 'D') {
1069			/*
1070			 * Check for the case "rcp remote:foo\* local:bar".
1071			 * In this case, the line "No match." can be returned
1072			 * by the shell before the rcp command on the remote is
1073			 * executed so the ^Aerror_message convention isn't
1074			 * followed.
1075			 */
1076			if (first) {
1077				run_err("%s", cp);
1078				exit(1);
1079			}
1080			SCREWUP("expected control record");
1081		}
1082		mode = 0;
1083		for (++cp; cp < buf + 5; cp++) {
1084			if (*cp < '0' || *cp > '7')
1085				SCREWUP("bad mode");
1086			mode = (mode << 3) | (*cp - '0');
1087		}
1088		if (*cp++ != ' ')
1089			SCREWUP("mode not delimited");
1090
1091		for (size = 0; isdigit(*cp);)
1092			size = size * 10 + (*cp++ - '0');
1093		if (*cp++ != ' ')
1094			SCREWUP("size not delimited");
1095		if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
1096			run_err("error: unexpected filename: %s", cp);
1097			exit(1);
1098		}
1099		if (targisdir) {
1100			static char *namebuf;
1101			static size_t cursize;
1102			size_t need;
1103
1104			need = strlen(targ) + strlen(cp) + 250;
1105			if (need > cursize) {
1106				if (namebuf)
1107					xfree(namebuf);
1108				namebuf = xmalloc(need);
1109				cursize = need;
1110			}
1111			(void) snprintf(namebuf, need, "%s%s%s", targ,
1112			    strcmp(targ, "/") ? "/" : "", cp);
1113			np = namebuf;
1114		} else
1115			np = targ;
1116		curfile = cp;
1117		exists = stat(np, &stb) == 0;
1118		if (buf[0] == 'D') {
1119			int mod_flag = pflag;
1120			if (!iamrecursive)
1121				SCREWUP("received directory without -r");
1122			if (exists) {
1123				if (!S_ISDIR(stb.st_mode)) {
1124					errno = ENOTDIR;
1125					goto bad;
1126				}
1127				if (pflag)
1128					(void) chmod(np, mode);
1129			} else {
1130				/* Handle copying from a read-only
1131				   directory */
1132				mod_flag = 1;
1133				if (mkdir(np, mode | S_IRWXU) < 0)
1134					goto bad;
1135			}
1136			vect[0] = xstrdup(np);
1137			sink(1, vect);
1138			if (setimes) {
1139				setimes = 0;
1140				if (utimes(vect[0], tv) < 0)
1141					run_err("%s: set times: %s",
1142					    vect[0], strerror(errno));
1143			}
1144			if (mod_flag)
1145				(void) chmod(vect[0], mode);
1146			if (vect[0])
1147				xfree(vect[0]);
1148			continue;
1149		}
1150		omode = mode;
1151		mode |= S_IWRITE;
1152
1153#if HAVE_COPYFILE
1154		if (copy_xattr && !strncmp(basename(curfile), "._", 2))
1155		{
1156			int mdfd;
1157			if (targisdir)
1158			{
1159			    snprintf(md_src, sizeof md_src, "%s.XXXXXX", np);
1160			    snprintf(md_dst, sizeof md_dst, "%s/%s",
1161				    dirname(np), basename(np) + 2);
1162			    if((mdfd = mkstemp(md_src)) < 0)
1163				continue;
1164			}
1165			else
1166			{
1167			    snprintf(md_src, sizeof md_src, "%s/._%s.XXXXXX",
1168				    dirname(np), basename(np));
1169			    snprintf(md_dst, sizeof md_dst, "%s", np);
1170			    if((mdfd = mkstemp(md_src)) < 0)
1171				continue;
1172			}
1173			if (mdfd >= 0)
1174				close(mdfd);
1175			np = md_src;
1176		}
1177#endif
1178		if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
1179bad:			run_err("%s: %s", np, strerror(errno));
1180			continue;
1181		}
1182#ifdef __APPLE_XSAN__
1183		{
1184			/*
1185			 * Pre-allocate blocks for the destination file.
1186			 */
1187			fstore_t fst;
1188
1189			fst.fst_flags = 0;
1190			fst.fst_posmode = F_PEOFPOSMODE;
1191			fst.fst_offset = 0;
1192			fst.fst_length = size;
1193
1194			(void) fcntl(ofd, F_PREALLOCATE, &fst);
1195		}
1196#endif /* __APPLE_XSAN__ */
1197		(void) atomicio(vwrite, remout, "", 1);
1198		if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
1199			(void) close(ofd);
1200			continue;
1201		}
1202		cp = bp->buf;
1203		wrerr = NO;
1204
1205		statbytes = 0;
1206		if (showprogress)
1207			start_progress_meter(curfile, size, &statbytes);
1208		set_nonblock(remin);
1209		for (count = i = 0; i < size; i += bp->cnt) {
1210			amt = bp->cnt;
1211			if (i + amt > size)
1212				amt = size - i;
1213			count += amt;
1214			do {
1215				j = atomicio6(read, remin, cp, amt,
1216				    scpio, &statbytes);
1217				if (j == 0) {
1218					run_err("%s", j != EPIPE ?
1219					    strerror(errno) :
1220					    "dropped connection");
1221					exit(1);
1222				}
1223				amt -= j;
1224				cp += j;
1225			} while (amt > 0);
1226
1227			if (count == bp->cnt) {
1228				/* Keep reading so we stay sync'd up. */
1229				if (wrerr == NO) {
1230					if (atomicio(vwrite, ofd, bp->buf,
1231					    count) != count) {
1232						wrerr = YES;
1233						wrerrno = errno;
1234					}
1235				}
1236				count = 0;
1237				cp = bp->buf;
1238			}
1239		}
1240		unset_nonblock(remin);
1241		if (showprogress)
1242			stop_progress_meter();
1243		if (count != 0 && wrerr == NO &&
1244		    atomicio(vwrite, ofd, bp->buf, count) != count) {
1245			wrerr = YES;
1246			wrerrno = errno;
1247		}
1248		if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
1249		    ftruncate(ofd, size) != 0) {
1250			run_err("%s: truncate: %s", np, strerror(errno));
1251			wrerr = DISPLAYED;
1252		}
1253		if (pflag) {
1254			if (exists || omode != mode)
1255#ifdef HAVE_FCHMOD
1256				if (fchmod(ofd, omode)) {
1257#else /* HAVE_FCHMOD */
1258				if (chmod(np, omode)) {
1259#endif /* HAVE_FCHMOD */
1260					run_err("%s: set mode: %s",
1261					    np, strerror(errno));
1262					wrerr = DISPLAYED;
1263				}
1264		} else {
1265			if (!exists && omode != mode)
1266#ifdef HAVE_FCHMOD
1267				if (fchmod(ofd, omode & ~mask)) {
1268#else /* HAVE_FCHMOD */
1269				if (chmod(np, omode & ~mask)) {
1270#endif /* HAVE_FCHMOD */
1271					run_err("%s: set mode: %s",
1272					    np, strerror(errno));
1273					wrerr = DISPLAYED;
1274				}
1275		}
1276		if (close(ofd) == -1) {
1277			wrerr = YES;
1278			wrerrno = errno;
1279		}
1280		(void) response();
1281#ifdef HAVE_COPYFILE
1282		if (copy_xattr && strncmp(basename(np), "._", 2) == 0)
1283		{
1284			if (verbose_mode)
1285			    fprintf(stderr, "copyfile(%s, %s, UNPACK)\n", md_src, md_dst);
1286			if(!copyfile(md_src, md_dst, 0,
1287			    COPYFILE_ACL | COPYFILE_XATTR | COPYFILE_UNPACK) < 0)
1288			{
1289			    snprintf(md_dst, sizeof md_dst, "%s/._%s",
1290				    dirname(md_dst), basename(md_dst));
1291			    rename(md_src, md_dst);
1292			} else
1293			    unlink(md_src);
1294			if (setimes && wrerr == NO) {
1295				setimes = 0;
1296				if (utimes(md_dst, tv) < 0) {
1297					run_err("%s: set times: %s",
1298					np, strerror(errno));
1299					wrerr = DISPLAYED;
1300				}
1301			}
1302		} else
1303#endif
1304		if (setimes && wrerr == NO) {
1305			setimes = 0;
1306			if (utimes(np, tv) < 0) {
1307				run_err("%s: set times: %s",
1308				    np, strerror(errno));
1309				wrerr = DISPLAYED;
1310			}
1311		}
1312		switch (wrerr) {
1313		case YES:
1314			run_err("%s: %s", np, strerror(wrerrno));
1315			break;
1316		case NO:
1317			(void) atomicio(vwrite, remout, "", 1);
1318			break;
1319		case DISPLAYED:
1320			break;
1321		}
1322	}
1323screwup:
1324	run_err("protocol error: %s", why);
1325	exit(1);
1326}
1327
1328int
1329response(void)
1330{
1331	char ch, *cp, resp, rbuf[2048];
1332
1333	if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
1334		lostconn(0);
1335
1336	cp = rbuf;
1337	switch (resp) {
1338	case 0:		/* ok */
1339		return (0);
1340	default:
1341		*cp++ = resp;
1342		/* FALLTHROUGH */
1343	case 1:		/* error, followed by error msg */
1344	case 2:		/* fatal error, "" */
1345		do {
1346			if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
1347				lostconn(0);
1348			*cp++ = ch;
1349		} while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
1350
1351		if (!iamremote)
1352			(void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf);
1353		++errs;
1354		if (resp == 1)
1355			return (-1);
1356		exit(1);
1357	}
1358	/* NOTREACHED */
1359}
1360
1361void
1362usage(void)
1363{
1364	(void) fprintf(stderr,
1365#if HAVE_COPYFILE
1366	    "usage: scp [-12346BCEpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1367#else
1368	    "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1369#endif
1370	    "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
1371	    "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
1372	exit(1);
1373}
1374
1375void
1376run_err(const char *fmt,...)
1377{
1378	static FILE *fp;
1379	va_list ap;
1380
1381	++errs;
1382	if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
1383		(void) fprintf(fp, "%c", 0x01);
1384		(void) fprintf(fp, "scp: ");
1385		va_start(ap, fmt);
1386		(void) vfprintf(fp, fmt, ap);
1387		va_end(ap);
1388		(void) fprintf(fp, "\n");
1389		(void) fflush(fp);
1390	}
1391
1392	if (!iamremote) {
1393		va_start(ap, fmt);
1394		vfprintf(stderr, fmt, ap);
1395		va_end(ap);
1396		fprintf(stderr, "\n");
1397	}
1398}
1399
1400void
1401verifydir(char *cp)
1402{
1403	struct stat stb;
1404
1405	if (!stat(cp, &stb)) {
1406		if (S_ISDIR(stb.st_mode))
1407			return;
1408		errno = ENOTDIR;
1409	}
1410	run_err("%s: %s", cp, strerror(errno));
1411	killchild(0);
1412}
1413
1414int
1415okname(char *cp0)
1416{
1417	int c;
1418	char *cp;
1419
1420	cp = cp0;
1421	do {
1422		c = (int)*cp;
1423		if (c & 0200)
1424			goto bad;
1425		if (!isalpha(c) && !isdigit(c)) {
1426			switch (c) {
1427			case '\'':
1428			case '"':
1429			case '`':
1430			case ' ':
1431			case '#':
1432				goto bad;
1433			default:
1434				break;
1435			}
1436		}
1437	} while (*++cp);
1438	return (1);
1439
1440bad:	fprintf(stderr, "%s: invalid user name\n", cp0);
1441	return (0);
1442}
1443
1444BUF *
1445allocbuf(BUF *bp, int fd, int blksize)
1446{
1447	size_t size;
1448#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
1449	struct stat stb;
1450
1451	if (fstat(fd, &stb) < 0) {
1452		run_err("fstat: %s", strerror(errno));
1453		return (0);
1454	}
1455	size = roundup(stb.st_blksize, blksize);
1456	if (size == 0)
1457		size = blksize;
1458#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1459	size = blksize;
1460#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
1461	if (bp->cnt >= size)
1462		return (bp);
1463	if (bp->buf == NULL)
1464		bp->buf = xmalloc(size);
1465	else
1466		bp->buf = xrealloc(bp->buf, 1, size);
1467	memset(bp->buf, 0, size);
1468	bp->cnt = size;
1469	return (bp);
1470}
1471
1472void
1473lostconn(int signo)
1474{
1475	if (!iamremote)
1476		write(STDERR_FILENO, "lost connection\n", 16);
1477	if (signo)
1478		_exit(1);
1479	else
1480		exit(1);
1481}
1482