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