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