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