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