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