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