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