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