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