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