Deleted Added
sdiff udiff text old ( 1.254 ) new ( 1.255 )
full compact
1/* $OpenBSD: scp.c,v 1.254 2023/03/27 03:25:08 djm 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 <sys/types.h>
75#include <sys/poll.h>
76#include <sys/wait.h>
77#include <sys/stat.h>
78#include <sys/time.h>
79#include <sys/uio.h>
80
81#include <ctype.h>
82#include <dirent.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <fnmatch.h>
86#include <glob.h>
87#include <libgen.h>
88#include <locale.h>
89#include <pwd.h>
90#include <signal.h>
91#include <stdarg.h>
92#include <stdint.h>
93#include <stdio.h>
94#include <stdlib.h>
95#include <string.h>
96#include <time.h>
97#include <unistd.h>
98#include <limits.h>
99#include <util.h>
100#include <vis.h>
101
102#include "xmalloc.h"
103#include "ssh.h"
104#include "atomicio.h"
105#include "pathnames.h"
106#include "log.h"
107#include "misc.h"
108#include "progressmeter.h"
109#include "utf8.h"
110#include "sftp.h"
111
112#include "sftp-common.h"
113#include "sftp-client.h"
114
115#define COPY_BUFLEN 16384
116
117int do_cmd(char *, char *, char *, int, int, char *, int *, int *, pid_t *);
118int do_cmd2(char *, char *, int, char *, int, int);
119
120/* Struct for addargs */
121arglist args;
122arglist remote_remote_args;
123
124/* Bandwidth limit */
125long long limit_kbps = 0;
126struct bwlimit bwlimit;
127
128/* Name of current file being transferred. */
129char *curfile;
130
131/* This is set to non-zero to enable verbose mode. */
132int verbose_mode = 0;
133LogLevel log_level = SYSLOG_LEVEL_INFO;
134
135/* This is set to zero if the progressmeter is not desired. */
136int showprogress = 1;
137
138/*
139 * This is set to non-zero if remote-remote copy should be piped
140 * through this process.
141 */
142int throughlocal = 1;
143
144/* Non-standard port to use for the ssh connection or -1. */
145int sshport = -1;
146
147/* This is the program to execute for the secured connection. ("ssh" or -S) */
148char *ssh_program = _PATH_SSH_PROGRAM;
149
150/* This is used to store the pid of ssh_program */
151pid_t do_cmd_pid = -1;
152pid_t do_cmd_pid2 = -1;
153
154/* SFTP copy parameters */
155size_t sftp_copy_buflen;
156size_t sftp_nrequests;
157
158/* Needed for sftp */
159volatile sig_atomic_t interrupted = 0;
160
161int remote_glob(struct sftp_conn *, const char *, int,
162 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
163
164static void
165killchild(int signo)
166{
167 if (do_cmd_pid > 1) {
168 kill(do_cmd_pid, signo ? signo : SIGTERM);
169 waitpid(do_cmd_pid, NULL, 0);
170 }
171 if (do_cmd_pid2 > 1) {
172 kill(do_cmd_pid2, signo ? signo : SIGTERM);
173 waitpid(do_cmd_pid2, NULL, 0);
174 }
175
176 if (signo)
177 _exit(1);
178 exit(1);
179}
180
181static void
182suspone(int pid, int signo)
183{
184 int status;
185
186 if (pid > 1) {
187 kill(pid, signo);
188 while (waitpid(pid, &status, WUNTRACED) == -1 &&
189 errno == EINTR)
190 ;
191 }
192}
193
194static void
195suspchild(int signo)
196{
197 suspone(do_cmd_pid, signo);
198 suspone(do_cmd_pid2, signo);
199 kill(getpid(), SIGSTOP);
200}
201
202static int
203do_local_cmd(arglist *a)
204{
205 u_int i;
206 int status;
207 pid_t pid;
208
209 if (a->num == 0)
210 fatal("do_local_cmd: no arguments");
211
212 if (verbose_mode) {
213 fprintf(stderr, "Executing:");
214 for (i = 0; i < a->num; i++)
215 fmprintf(stderr, " %s", a->list[i]);
216 fprintf(stderr, "\n");
217 }
218 if ((pid = fork()) == -1)
219 fatal("do_local_cmd: fork: %s", strerror(errno));
220
221 if (pid == 0) {
222 execvp(a->list[0], a->list);
223 perror(a->list[0]);
224 exit(1);
225 }
226
227 do_cmd_pid = pid;
228 ssh_signal(SIGTERM, killchild);
229 ssh_signal(SIGINT, killchild);
230 ssh_signal(SIGHUP, killchild);
231
232 while (waitpid(pid, &status, 0) == -1)
233 if (errno != EINTR)
234 fatal("do_local_cmd: waitpid: %s", strerror(errno));
235
236 do_cmd_pid = -1;
237
238 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
239 return (-1);
240
241 return (0);
242}
243
244/*
245 * This function executes the given command as the specified user on the
246 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This
247 * assigns the input and output file descriptors on success.
248 */
249
250int
251do_cmd(char *program, char *host, char *remuser, int port, int subsystem,
252 char *cmd, int *fdin, int *fdout, pid_t *pid)
253{
254 int sv[2];
255
256 if (verbose_mode)
257 fmprintf(stderr,
258 "Executing: program %s host %s, user %s, command %s\n",
259 program, host,
260 remuser ? remuser : "(unspecified)", cmd);
261
262 if (port == -1)
263 port = sshport;
264
265 /* Create a socket pair for communicating with ssh. */
266 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1)
267 fatal("socketpair: %s", strerror(errno));
268
269 ssh_signal(SIGTSTP, suspchild);
270 ssh_signal(SIGTTIN, suspchild);
271 ssh_signal(SIGTTOU, suspchild);
272
273 /* Fork a child to execute the command on the remote host using ssh. */
274 *pid = fork();
275 switch (*pid) {
276 case -1:
277 fatal("fork: %s", strerror(errno));
278 case 0:
279 /* Child. */
280 if (dup2(sv[0], STDIN_FILENO) == -1 ||
281 dup2(sv[0], STDOUT_FILENO) == -1) {
282 perror("dup2");
283 _exit(1);
284 }
285 close(sv[0]);
286 close(sv[1]);
287 replacearg(&args, 0, "%s", program);
288 if (port != -1) {
289 addargs(&args, "-p");
290 addargs(&args, "%d", port);
291 }
292 if (remuser != NULL) {
293 addargs(&args, "-l");
294 addargs(&args, "%s", remuser);
295 }
296 if (subsystem)
297 addargs(&args, "-s");
298 addargs(&args, "--");
299 addargs(&args, "%s", host);
300 addargs(&args, "%s", cmd);
301
302 execvp(program, args.list);
303 perror(program);
304 _exit(1);
305 default:
306 /* Parent. Close the other side, and return the local side. */
307 close(sv[0]);
308 *fdin = sv[1];
309 *fdout = sv[1];
310 ssh_signal(SIGTERM, killchild);
311 ssh_signal(SIGINT, killchild);
312 ssh_signal(SIGHUP, killchild);
313 return 0;
314 }
315}
316
317/*
318 * This function executes a command similar to do_cmd(), but expects the
319 * input and output descriptors to be setup by a previous call to do_cmd().
320 * This way the input and output of two commands can be connected.
321 */
322int
323do_cmd2(char *host, char *remuser, int port, char *cmd,
324 int fdin, int fdout)
325{
326 int status;
327 pid_t pid;
328
329 if (verbose_mode)
330 fmprintf(stderr,
331 "Executing: 2nd program %s host %s, user %s, command %s\n",
332 ssh_program, host,
333 remuser ? remuser : "(unspecified)", cmd);
334
335 if (port == -1)
336 port = sshport;
337
338 /* Fork a child to execute the command on the remote host using ssh. */
339 pid = fork();
340 if (pid == 0) {
341 if (dup2(fdin, 0) == -1)
342 perror("dup2");
343 if (dup2(fdout, 1) == -1)
344 perror("dup2");
345
346 replacearg(&args, 0, "%s", ssh_program);
347 if (port != -1) {
348 addargs(&args, "-p");
349 addargs(&args, "%d", port);
350 }
351 if (remuser != NULL) {
352 addargs(&args, "-l");
353 addargs(&args, "%s", remuser);
354 }
355 addargs(&args, "-oBatchMode=yes");
356 addargs(&args, "--");
357 addargs(&args, "%s", host);
358 addargs(&args, "%s", cmd);
359
360 execvp(ssh_program, args.list);
361 perror(ssh_program);
362 exit(1);
363 } else if (pid == -1) {
364 fatal("fork: %s", strerror(errno));
365 }
366 while (waitpid(pid, &status, 0) == -1)
367 if (errno != EINTR)
368 fatal("do_cmd2: waitpid: %s", strerror(errno));
369 return 0;
370}
371
372typedef struct {
373 size_t cnt;
374 char *buf;
375} BUF;
376
377BUF *allocbuf(BUF *, int, int);
378void lostconn(int);
379int okname(char *);
380void run_err(const char *,...)
381 __attribute__((__format__ (printf, 1, 2)))
382 __attribute__((__nonnull__ (1)));
383int note_err(const char *,...)
384 __attribute__((__format__ (printf, 1, 2)));
385void verifydir(char *);
386
387struct passwd *pwd;
388uid_t userid;
389int errs, remin, remout, remin2, remout2;
390int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
391
392#define CMDNEEDS 64
393char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
394
395enum scp_mode_e {
396 MODE_SCP,
397 MODE_SFTP
398};
399
400int response(void);
401void rsource(char *, struct stat *);
402void sink(int, char *[], const char *);
403void source(int, char *[]);
404void tolocal(int, char *[], enum scp_mode_e, char *sftp_direct);
405void toremote(int, char *[], enum scp_mode_e, char *sftp_direct);
406void usage(void);
407
408void source_sftp(int, char *, char *, struct sftp_conn *);
409void sink_sftp(int, char *, const char *, struct sftp_conn *);
410void throughlocal_sftp(struct sftp_conn *, struct sftp_conn *,
411 char *, char *);
412
413int
414main(int argc, char **argv)
415{
416 int ch, fflag, tflag, status, r, n;
417 char **newargv, *argv0;
418 const char *errstr;
419 extern char *optarg;
420 extern int optind;
421 enum scp_mode_e mode = MODE_SFTP;
422 char *sftp_direct = NULL;
423 long long llv;
424
425 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
426 sanitise_stdfd();
427
428 setlocale(LC_CTYPE, "");
429
430 /* Copy argv, because we modify it */
431 argv0 = argv[0];
432 newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv));
433 for (n = 0; n < argc; n++)
434 newargv[n] = xstrdup(argv[n]);
435 argv = newargv;
436
437 log_init(argv0, log_level, SYSLOG_FACILITY_USER, 2);
438
439 memset(&args, '\0', sizeof(args));
440 memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
441 args.list = remote_remote_args.list = NULL;
442 addargs(&args, "%s", ssh_program);
443 addargs(&args, "-x");
444 addargs(&args, "-oPermitLocalCommand=no");
445 addargs(&args, "-oClearAllForwardings=yes");
446 addargs(&args, "-oRemoteCommand=none");
447 addargs(&args, "-oRequestTTY=no");
448
449 fflag = Tflag = tflag = 0;
450 while ((ch = getopt(argc, argv,
451 "12346ABCTdfOpqRrstvD:F:J:M:P:S:c:i:l:o:X:")) != -1) {
452 switch (ch) {
453 /* User-visible flags. */
454 case '1':
455 fatal("SSH protocol v.1 is no longer supported");
456 break;
457 case '2':
458 /* Ignored */
459 break;
460 case 'A':
461 case '4':
462 case '6':
463 case 'C':
464 addargs(&args, "-%c", ch);
465 addargs(&remote_remote_args, "-%c", ch);
466 break;
467 case 'D':
468 sftp_direct = optarg;
469 break;
470 case '3':
471 throughlocal = 1;
472 break;
473 case 'R':
474 throughlocal = 0;
475 break;
476 case 'o':
477 case 'c':
478 case 'i':
479 case 'F':
480 case 'J':
481 addargs(&remote_remote_args, "-%c", ch);
482 addargs(&remote_remote_args, "%s", optarg);
483 addargs(&args, "-%c", ch);
484 addargs(&args, "%s", optarg);
485 break;
486 case 'O':
487 mode = MODE_SCP;
488 break;
489 case 's':
490 mode = MODE_SFTP;
491 break;
492 case 'P':
493 sshport = a2port(optarg);
494 if (sshport <= 0)
495 fatal("bad port \"%s\"\n", optarg);
496 break;
497 case 'B':
498 addargs(&remote_remote_args, "-oBatchmode=yes");
499 addargs(&args, "-oBatchmode=yes");
500 break;
501 case 'l':
502 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
503 &errstr);
504 if (errstr != NULL)
505 usage();
506 limit_kbps *= 1024; /* kbps */
507 bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
508 break;
509 case 'p':
510 pflag = 1;
511 break;
512 case 'r':
513 iamrecursive = 1;
514 break;
515 case 'S':
516 ssh_program = xstrdup(optarg);
517 break;
518 case 'v':
519 addargs(&args, "-v");
520 addargs(&remote_remote_args, "-v");
521 if (verbose_mode == 0)
522 log_level = SYSLOG_LEVEL_DEBUG1;
523 else if (log_level < SYSLOG_LEVEL_DEBUG3)
524 log_level++;
525 verbose_mode = 1;
526 break;
527 case 'q':
528 addargs(&args, "-q");
529 addargs(&remote_remote_args, "-q");
530 showprogress = 0;
531 break;
532 case 'X':
533 /* Please keep in sync with sftp.c -X */
534 if (strncmp(optarg, "buffer=", 7) == 0) {
535 r = scan_scaled(optarg + 7, &llv);
536 if (r == 0 && (llv <= 0 || llv > 256 * 1024)) {
537 r = -1;
538 errno = EINVAL;
539 }
540 if (r == -1) {
541 fatal("Invalid buffer size \"%s\": %s",
542 optarg + 7, strerror(errno));
543 }
544 sftp_copy_buflen = (size_t)llv;
545 } else if (strncmp(optarg, "nrequests=", 10) == 0) {
546 llv = strtonum(optarg + 10, 1, 256 * 1024,
547 &errstr);
548 if (errstr != NULL) {
549 fatal("Invalid number of requests "
550 "\"%s\": %s", optarg + 10, errstr);
551 }
552 sftp_nrequests = (size_t)llv;
553 } else {
554 fatal("Invalid -X option");
555 }
556 break;
557
558 /* Server options. */
559 case 'd':
560 targetshouldbedirectory = 1;
561 break;
562 case 'f': /* "from" */
563 iamremote = 1;
564 fflag = 1;
565 break;
566 case 't': /* "to" */
567 iamremote = 1;
568 tflag = 1;
569 break;
570 case 'T':
571 Tflag = 1;
572 break;
573 default:
574 usage();
575 }
576 }
577 argc -= optind;
578 argv += optind;
579
580 log_init(argv0, log_level, SYSLOG_FACILITY_USER, 2);
581
582 /* Do this last because we want the user to be able to override it */
583 addargs(&args, "-oForwardAgent=no");
584
585 if (iamremote)
586 mode = MODE_SCP;
587
588 if ((pwd = getpwuid(userid = getuid())) == NULL)
589 fatal("unknown user %u", (u_int) userid);
590
591 if (!isatty(STDOUT_FILENO))
592 showprogress = 0;
593
594 if (pflag) {
595 /* Cannot pledge: -p allows setuid/setgid files... */
596 } else {
597 if (pledge("stdio rpath wpath cpath fattr tty proc exec",
598 NULL) == -1) {
599 perror("pledge");
600 exit(1);
601 }
602 }
603
604 remin = STDIN_FILENO;
605 remout = STDOUT_FILENO;
606
607 if (fflag) {
608 /* Follow "protocol", send data. */
609 (void) response();
610 source(argc, argv);
611 exit(errs != 0);
612 }
613 if (tflag) {
614 /* Receive data. */
615 sink(argc, argv, NULL);
616 exit(errs != 0);
617 }
618 if (argc < 2)
619 usage();
620 if (argc > 2)
621 targetshouldbedirectory = 1;
622
623 remin = remout = -1;
624 do_cmd_pid = -1;
625 /* Command to be executed on remote system using "ssh". */
626 (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s",
627 verbose_mode ? " -v" : "",
628 iamrecursive ? " -r" : "", pflag ? " -p" : "",
629 targetshouldbedirectory ? " -d" : "");
630
631 (void) ssh_signal(SIGPIPE, lostconn);
632
633 if (colon(argv[argc - 1])) /* Dest is remote host. */
634 toremote(argc, argv, mode, sftp_direct);
635 else {
636 if (targetshouldbedirectory)
637 verifydir(argv[argc - 1]);
638 tolocal(argc, argv, mode, sftp_direct); /* Dest is local host. */
639 }
640 /*
641 * Finally check the exit status of the ssh process, if one was forked
642 * and no error has occurred yet
643 */
644 if (do_cmd_pid != -1 && (mode == MODE_SFTP || errs == 0)) {
645 if (remin != -1)
646 (void) close(remin);
647 if (remout != -1)
648 (void) close(remout);
649 if (waitpid(do_cmd_pid, &status, 0) == -1)
650 errs = 1;
651 else {
652 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
653 errs = 1;
654 }
655 }
656 exit(errs != 0);
657}
658
659/* Callback from atomicio6 to update progress meter and limit bandwidth */
660static int
661scpio(void *_cnt, size_t s)
662{
663 off_t *cnt = (off_t *)_cnt;
664
665 *cnt += s;
666 refresh_progress_meter(0);
667 if (limit_kbps > 0)
668 bandwidth_limit(&bwlimit, s);
669 return 0;
670}
671
672static int
673do_times(int fd, int verb, const struct stat *sb)
674{
675 /* strlen(2^64) == 20; strlen(10^6) == 7 */
676 char buf[(20 + 7 + 2) * 2 + 2];
677
678 (void)snprintf(buf, sizeof(buf), "T%llu 0 %llu 0\n",
679 (unsigned long long) (sb->st_mtime < 0 ? 0 : sb->st_mtime),
680 (unsigned long long) (sb->st_atime < 0 ? 0 : sb->st_atime));
681 if (verb) {
682 fprintf(stderr, "File mtime %lld atime %lld\n",
683 (long long)sb->st_mtime, (long long)sb->st_atime);
684 fprintf(stderr, "Sending file timestamps: %s", buf);
685 }
686 (void) atomicio(vwrite, fd, buf, strlen(buf));
687 return (response());
688}
689
690static int
691parse_scp_uri(const char *uri, char **userp, char **hostp, int *portp,
692 char **pathp)
693{
694 int r;
695
696 r = parse_uri("scp", uri, userp, hostp, portp, pathp);
697 if (r == 0 && *pathp == NULL)
698 *pathp = xstrdup(".");
699 return r;
700}
701
702/* Appends a string to an array; returns 0 on success, -1 on alloc failure */
703static int
704append(char *cp, char ***ap, size_t *np)
705{
706 char **tmp;
707
708 if ((tmp = reallocarray(*ap, *np + 1, sizeof(*tmp))) == NULL)
709 return -1;
710 tmp[(*np)] = cp;
711 (*np)++;
712 *ap = tmp;
713 return 0;
714}
715
716/*
717 * Finds the start and end of the first brace pair in the pattern.
718 * returns 0 on success or -1 for invalid patterns.
719 */
720static int
721find_brace(const char *pattern, int *startp, int *endp)
722{
723 int i;
724 int in_bracket, brace_level;
725
726 *startp = *endp = -1;
727 in_bracket = brace_level = 0;
728 for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) {
729 switch (pattern[i]) {
730 case '\\':
731 /* skip next character */
732 if (pattern[i + 1] != '\0')
733 i++;
734 break;
735 case '[':
736 in_bracket = 1;
737 break;
738 case ']':
739 in_bracket = 0;
740 break;
741 case '{':
742 if (in_bracket)
743 break;
744 if (pattern[i + 1] == '}') {
745 /* Protect a single {}, for find(1), like csh */
746 i++; /* skip */
747 break;
748 }
749 if (*startp == -1)
750 *startp = i;
751 brace_level++;
752 break;
753 case '}':
754 if (in_bracket)
755 break;
756 if (*startp < 0) {
757 /* Unbalanced brace */
758 return -1;
759 }
760 if (--brace_level <= 0)
761 *endp = i;
762 break;
763 }
764 }
765 /* unbalanced brackets/braces */
766 if (*endp < 0 && (*startp >= 0 || in_bracket))
767 return -1;
768 return 0;
769}
770
771/*
772 * Assembles and records a successfully-expanded pattern, returns -1 on
773 * alloc failure.
774 */
775static int
776emit_expansion(const char *pattern, int brace_start, int brace_end,
777 int sel_start, int sel_end, char ***patternsp, size_t *npatternsp)
778{
779 char *cp;
780 int o = 0, tail_len = strlen(pattern + brace_end + 1);
781
782 if ((cp = malloc(brace_start + (sel_end - sel_start) +
783 tail_len + 1)) == NULL)
784 return -1;
785
786 /* Pattern before initial brace */
787 if (brace_start > 0) {
788 memcpy(cp, pattern, brace_start);
789 o = brace_start;
790 }
791 /* Current braced selection */
792 if (sel_end - sel_start > 0) {
793 memcpy(cp + o, pattern + sel_start,
794 sel_end - sel_start);
795 o += sel_end - sel_start;
796 }
797 /* Remainder of pattern after closing brace */
798 if (tail_len > 0) {
799 memcpy(cp + o, pattern + brace_end + 1, tail_len);
800 o += tail_len;
801 }
802 cp[o] = '\0';
803 if (append(cp, patternsp, npatternsp) != 0) {
804 free(cp);
805 return -1;
806 }
807 return 0;
808}
809
810/*
811 * Expand the first encountered brace in pattern, appending the expanded
812 * patterns it yielded to the *patternsp array.
813 *
814 * Returns 0 on success or -1 on allocation failure.
815 *
816 * Signals whether expansion was performed via *expanded and whether
817 * pattern was invalid via *invalid.
818 */
819static int
820brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp,
821 int *expanded, int *invalid)
822{
823 int i;
824 int in_bracket, brace_start, brace_end, brace_level;
825 int sel_start, sel_end;
826
827 *invalid = *expanded = 0;
828
829 if (find_brace(pattern, &brace_start, &brace_end) != 0) {
830 *invalid = 1;
831 return 0;
832 } else if (brace_start == -1)
833 return 0;
834
835 in_bracket = brace_level = 0;
836 for (i = sel_start = brace_start + 1; i < brace_end; i++) {
837 switch (pattern[i]) {
838 case '{':
839 if (in_bracket)
840 break;
841 brace_level++;
842 break;
843 case '}':
844 if (in_bracket)
845 break;
846 brace_level--;
847 break;
848 case '[':
849 in_bracket = 1;
850 break;
851 case ']':
852 in_bracket = 0;
853 break;
854 case '\\':
855 if (i < brace_end - 1)
856 i++; /* skip */
857 break;
858 }
859 if (pattern[i] == ',' || i == brace_end - 1) {
860 if (in_bracket || brace_level > 0)
861 continue;
862 /* End of a selection, emit an expanded pattern */
863
864 /* Adjust end index for last selection */
865 sel_end = (i == brace_end - 1) ? brace_end : i;
866 if (emit_expansion(pattern, brace_start, brace_end,
867 sel_start, sel_end, patternsp, npatternsp) != 0)
868 return -1;
869 /* move on to the next selection */
870 sel_start = i + 1;
871 continue;
872 }
873 }
874 if (in_bracket || brace_level > 0) {
875 *invalid = 1;
876 return 0;
877 }
878 /* success */
879 *expanded = 1;
880 return 0;
881}
882
883/* Expand braces from pattern. Returns 0 on success, -1 on failure */
884static int
885brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp)
886{
887 char *cp, *cp2, **active = NULL, **done = NULL;
888 size_t i, nactive = 0, ndone = 0;
889 int ret = -1, invalid = 0, expanded = 0;
890
891 *patternsp = NULL;
892 *npatternsp = 0;
893
894 /* Start the worklist with the original pattern */
895 if ((cp = strdup(pattern)) == NULL)
896 return -1;
897 if (append(cp, &active, &nactive) != 0) {
898 free(cp);
899 return -1;
900 }
901 while (nactive > 0) {
902 cp = active[nactive - 1];
903 nactive--;
904 if (brace_expand_one(cp, &active, &nactive,
905 &expanded, &invalid) == -1) {
906 free(cp);
907 goto fail;
908 }
909 if (invalid)
910 fatal_f("invalid brace pattern \"%s\"", cp);
911 if (expanded) {
912 /*
913 * Current entry expanded to new entries on the
914 * active list; discard the progenitor pattern.
915 */
916 free(cp);
917 continue;
918 }
919 /*
920 * Pattern did not expand; append the finename component to
921 * the completed list
922 */
923 if ((cp2 = strrchr(cp, '/')) != NULL)
924 *cp2++ = '\0';
925 else
926 cp2 = cp;
927 if (append(xstrdup(cp2), &done, &ndone) != 0) {
928 free(cp);
929 goto fail;
930 }
931 free(cp);
932 }
933 /* success */
934 *patternsp = done;
935 *npatternsp = ndone;
936 done = NULL;
937 ndone = 0;
938 ret = 0;
939 fail:
940 for (i = 0; i < nactive; i++)
941 free(active[i]);
942 free(active);
943 for (i = 0; i < ndone; i++)
944 free(done[i]);
945 free(done);
946 return ret;
947}
948
949static struct sftp_conn *
950do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
951 int *reminp, int *remoutp, int *pidp)
952{
953 if (sftp_direct == NULL) {
954 if (do_cmd(ssh_program, host, user, port, 1, "sftp",
955 reminp, remoutp, pidp) < 0)
956 return NULL;
957
958 } else {
959 freeargs(&args);
960 addargs(&args, "sftp-server");
961 if (do_cmd(sftp_direct, host, NULL, -1, 0, "sftp",
962 reminp, remoutp, pidp) < 0)
963 return NULL;
964 }
965 return do_init(*reminp, *remoutp,
966 sftp_copy_buflen, sftp_nrequests, limit_kbps);
967}
968
969void
970toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
971{
972 char *suser = NULL, *host = NULL, *src = NULL;
973 char *bp, *tuser, *thost, *targ;
974 int sport = -1, tport = -1;
975 struct sftp_conn *conn = NULL, *conn2 = NULL;
976 arglist alist;
977 int i, r, status;
978 struct stat sb;
979 u_int j;
980
981 memset(&alist, '\0', sizeof(alist));
982 alist.list = NULL;
983
984 /* Parse target */
985 r = parse_scp_uri(argv[argc - 1], &tuser, &thost, &tport, &targ);
986 if (r == -1) {
987 fmprintf(stderr, "%s: invalid uri\n", argv[argc - 1]);
988 ++errs;
989 goto out;
990 }
991 if (r != 0) {
992 if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
993 &targ) == -1) {
994 fmprintf(stderr, "%s: invalid target\n", argv[argc - 1]);
995 ++errs;
996 goto out;
997 }
998 }
999
1000 /* Parse source files */
1001 for (i = 0; i < argc - 1; i++) {
1002 free(suser);
1003 free(host);
1004 free(src);
1005 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
1006 if (r == -1) {
1007 fmprintf(stderr, "%s: invalid uri\n", argv[i]);
1008 ++errs;
1009 continue;
1010 }
1011 if (r != 0) {
1012 parse_user_host_path(argv[i], &suser, &host, &src);
1013 }
1014 if (suser != NULL && !okname(suser)) {
1015 ++errs;
1016 continue;
1017 }
1018 if (host && throughlocal) { /* extended remote to remote */
1019 if (mode == MODE_SFTP) {
1020 if (remin == -1) {
1021 /* Connect to dest now */
1022 conn = do_sftp_connect(thost, tuser,
1023 tport, sftp_direct,
1024 &remin, &remout, &do_cmd_pid);
1025 if (conn == NULL) {
1026 fatal("Unable to open "
1027 "destination connection");
1028 }
1029 debug3_f("origin in %d out %d pid %ld",
1030 remin, remout, (long)do_cmd_pid);
1031 }
1032 /*
1033 * XXX remember suser/host/sport and only
1034 * reconnect if they change between arguments.
1035 * would save reconnections for cases like
1036 * scp -3 hosta:/foo hosta:/bar hostb:
1037 */
1038 /* Connect to origin now */
1039 conn2 = do_sftp_connect(host, suser,
1040 sport, sftp_direct,
1041 &remin2, &remout2, &do_cmd_pid2);
1042 if (conn2 == NULL) {
1043 fatal("Unable to open "
1044 "source connection");
1045 }
1046 debug3_f("destination in %d out %d pid %ld",
1047 remin2, remout2, (long)do_cmd_pid2);
1048 throughlocal_sftp(conn2, conn, src, targ);
1049 (void) close(remin2);
1050 (void) close(remout2);
1051 remin2 = remout2 = -1;
1052 if (waitpid(do_cmd_pid2, &status, 0) == -1)
1053 ++errs;
1054 else if (!WIFEXITED(status) ||
1055 WEXITSTATUS(status) != 0)
1056 ++errs;
1057 do_cmd_pid2 = -1;
1058 continue;
1059 } else {
1060 xasprintf(&bp, "%s -f %s%s", cmd,
1061 *src == '-' ? "-- " : "", src);
1062 if (do_cmd(ssh_program, host, suser, sport, 0,
1063 bp, &remin, &remout, &do_cmd_pid) < 0)
1064 exit(1);
1065 free(bp);
1066 xasprintf(&bp, "%s -t %s%s", cmd,
1067 *targ == '-' ? "-- " : "", targ);
1068 if (do_cmd2(thost, tuser, tport, bp,
1069 remin, remout) < 0)
1070 exit(1);
1071 free(bp);
1072 (void) close(remin);
1073 (void) close(remout);
1074 remin = remout = -1;
1075 }
1076 } else if (host) { /* standard remote to remote */
1077 /*
1078 * Second remote user is passed to first remote side
1079 * via scp command-line. Ensure it contains no obvious
1080 * shell characters.
1081 */
1082 if (tuser != NULL && !okname(tuser)) {
1083 ++errs;
1084 continue;
1085 }
1086 if (tport != -1 && tport != SSH_DEFAULT_PORT) {
1087 /* This would require the remote support URIs */
1088 fatal("target port not supported with two "
1089 "remote hosts and the -R option");
1090 }
1091
1092 freeargs(&alist);
1093 addargs(&alist, "%s", ssh_program);
1094 addargs(&alist, "-x");
1095 addargs(&alist, "-oClearAllForwardings=yes");
1096 addargs(&alist, "-n");
1097 for (j = 0; j < remote_remote_args.num; j++) {
1098 addargs(&alist, "%s",
1099 remote_remote_args.list[j]);
1100 }
1101
1102 if (sport != -1) {
1103 addargs(&alist, "-p");
1104 addargs(&alist, "%d", sport);
1105 }
1106 if (suser) {
1107 addargs(&alist, "-l");
1108 addargs(&alist, "%s", suser);
1109 }
1110 addargs(&alist, "--");
1111 addargs(&alist, "%s", host);
1112 addargs(&alist, "%s", cmd);
1113 addargs(&alist, "%s", src);
1114 addargs(&alist, "%s%s%s:%s",
1115 tuser ? tuser : "", tuser ? "@" : "",
1116 thost, targ);
1117 if (do_local_cmd(&alist) != 0)
1118 errs = 1;
1119 } else { /* local to remote */
1120 if (mode == MODE_SFTP) {
1121 /* no need to glob: already done by shell */
1122 if (stat(argv[i], &sb) != 0) {
1123 fatal("stat local \"%s\": %s", argv[i],
1124 strerror(errno));
1125 }
1126 if (remin == -1) {
1127 /* Connect to remote now */
1128 conn = do_sftp_connect(thost, tuser,
1129 tport, sftp_direct,
1130 &remin, &remout, &do_cmd_pid);
1131 if (conn == NULL) {
1132 fatal("Unable to open sftp "
1133 "connection");
1134 }
1135 }
1136
1137 /* The protocol */
1138 source_sftp(1, argv[i], targ, conn);
1139 continue;
1140 }
1141 /* SCP */
1142 if (remin == -1) {
1143 xasprintf(&bp, "%s -t %s%s", cmd,
1144 *targ == '-' ? "-- " : "", targ);
1145 if (do_cmd(ssh_program, thost, tuser, tport, 0,
1146 bp, &remin, &remout, &do_cmd_pid) < 0)
1147 exit(1);
1148 if (response() < 0)
1149 exit(1);
1150 free(bp);
1151 }
1152 source(1, argv + i);
1153 }
1154 }
1155out:
1156 if (mode == MODE_SFTP)
1157 free(conn);
1158 free(tuser);
1159 free(thost);
1160 free(targ);
1161 free(suser);
1162 free(host);
1163 free(src);
1164}
1165
1166void
1167tolocal(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct)
1168{
1169 char *bp, *host = NULL, *src = NULL, *suser = NULL;
1170 arglist alist;
1171 struct sftp_conn *conn = NULL;
1172 int i, r, sport = -1;
1173
1174 memset(&alist, '\0', sizeof(alist));
1175 alist.list = NULL;
1176
1177 for (i = 0; i < argc - 1; i++) {
1178 free(suser);
1179 free(host);
1180 free(src);
1181 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
1182 if (r == -1) {
1183 fmprintf(stderr, "%s: invalid uri\n", argv[i]);
1184 ++errs;
1185 continue;
1186 }
1187 if (r != 0)
1188 parse_user_host_path(argv[i], &suser, &host, &src);
1189 if (suser != NULL && !okname(suser)) {
1190 ++errs;
1191 continue;
1192 }
1193 if (!host) { /* Local to local. */
1194 freeargs(&alist);
1195 addargs(&alist, "%s", _PATH_CP);
1196 if (iamrecursive)
1197 addargs(&alist, "-r");
1198 if (pflag)
1199 addargs(&alist, "-p");
1200 addargs(&alist, "--");
1201 addargs(&alist, "%s", argv[i]);
1202 addargs(&alist, "%s", argv[argc-1]);
1203 if (do_local_cmd(&alist))
1204 ++errs;
1205 continue;
1206 }
1207 /* Remote to local. */
1208 if (mode == MODE_SFTP) {
1209 conn = do_sftp_connect(host, suser, sport,
1210 sftp_direct, &remin, &remout, &do_cmd_pid);
1211 if (conn == NULL) {
1212 error("sftp connection failed");
1213 ++errs;
1214 continue;
1215 }
1216
1217 /* The protocol */
1218 sink_sftp(1, argv[argc - 1], src, conn);
1219
1220 free(conn);
1221 (void) close(remin);
1222 (void) close(remout);
1223 remin = remout = -1;
1224 continue;
1225 }
1226 /* SCP */
1227 xasprintf(&bp, "%s -f %s%s",
1228 cmd, *src == '-' ? "-- " : "", src);
1229 if (do_cmd(ssh_program, host, suser, sport, 0, bp,
1230 &remin, &remout, &do_cmd_pid) < 0) {
1231 free(bp);
1232 ++errs;
1233 continue;
1234 }
1235 free(bp);
1236 sink(1, argv + argc - 1, src);
1237 (void) close(remin);
1238 remin = remout = -1;
1239 }
1240 free(suser);
1241 free(host);
1242 free(src);
1243}
1244
1245/* Prepare remote path, handling ~ by assuming cwd is the homedir */
1246static char *
1247prepare_remote_path(struct sftp_conn *conn, const char *path)
1248{
1249 size_t nslash;
1250
1251 /* Handle ~ prefixed paths */
1252 if (*path == '\0' || strcmp(path, "~") == 0)
1253 return xstrdup(".");
1254 if (*path != '~')
1255 return xstrdup(path);
1256 if (strncmp(path, "~/", 2) == 0) {
1257 if ((nslash = strspn(path + 2, "/")) == strlen(path + 2))
1258 return xstrdup(".");
1259 return xstrdup(path + 2 + nslash);
1260 }
1261 if (can_expand_path(conn))
1262 return do_expand_path(conn, path);
1263 /* No protocol extension */
1264 error("server expand-path extension is required "
1265 "for ~user paths in SFTP mode");
1266 return NULL;
1267}
1268
1269void
1270source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
1271{
1272 char *target = NULL, *filename = NULL, *abs_dst = NULL;
1273 int src_is_dir, target_is_dir;
1274 Attrib a;
1275 struct stat st;
1276
1277 memset(&a, '\0', sizeof(a));
1278 if (stat(src, &st) != 0)
1279 fatal("stat local \"%s\": %s", src, strerror(errno));
1280 src_is_dir = S_ISDIR(st.st_mode);
1281 if ((filename = basename(src)) == NULL)
1282 fatal("basename \"%s\": %s", src, strerror(errno));
1283
1284 /*
1285 * No need to glob here - the local shell already took care of
1286 * the expansions
1287 */
1288 if ((target = prepare_remote_path(conn, targ)) == NULL)
1289 cleanup_exit(255);
1290 target_is_dir = remote_is_dir(conn, target);
1291 if (targetshouldbedirectory && !target_is_dir) {
1292 debug("target directory \"%s\" does not exist", target);
1293 a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
1294 a.perm = st.st_mode | 0700; /* ensure writable */
1295 if (do_mkdir(conn, target, &a, 1) != 0)
1296 cleanup_exit(255); /* error already logged */
1297 target_is_dir = 1;
1298 }
1299 if (target_is_dir)
1300 abs_dst = path_append(target, filename);
1301 else {
1302 abs_dst = target;
1303 target = NULL;
1304 }
1305 debug3_f("copying local %s to remote %s", src, abs_dst);
1306
1307 if (src_is_dir && iamrecursive) {
1308 if (upload_dir(conn, src, abs_dst, pflag,
1309 SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
1310 error("failed to upload directory %s to %s", src, targ);
1311 errs = 1;
1312 }
1313 } else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
1314 error("failed to upload file %s to %s", src, targ);
1315 errs = 1;
1316 }
1317
1318 free(abs_dst);
1319 free(target);
1320}
1321
1322void
1323source(int argc, char **argv)
1324{
1325 struct stat stb;
1326 static BUF buffer;
1327 BUF *bp;
1328 off_t i, statbytes;
1329 size_t amt, nr;
1330 int fd = -1, haderr, indx;
1331 char *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX];
1332 int len;
1333
1334 for (indx = 0; indx < argc; ++indx) {
1335 name = argv[indx];
1336 statbytes = 0;
1337 len = strlen(name);
1338 while (len > 1 && name[len-1] == '/')
1339 name[--len] = '\0';
1340 if ((fd = open(name, O_RDONLY|O_NONBLOCK)) == -1)
1341 goto syserr;
1342 if (strchr(name, '\n') != NULL) {
1343 strnvis(encname, name, sizeof(encname), VIS_NL);
1344 name = encname;
1345 }
1346 if (fstat(fd, &stb) == -1) {
1347syserr: run_err("%s: %s", name, strerror(errno));
1348 goto next;
1349 }
1350 if (stb.st_size < 0) {
1351 run_err("%s: %s", name, "Negative file size");
1352 goto next;
1353 }
1354 unset_nonblock(fd);
1355 switch (stb.st_mode & S_IFMT) {
1356 case S_IFREG:
1357 break;
1358 case S_IFDIR:
1359 if (iamrecursive) {
1360 rsource(name, &stb);
1361 goto next;
1362 }
1363 /* FALLTHROUGH */
1364 default:
1365 run_err("%s: not a regular file", name);
1366 goto next;
1367 }
1368 if ((last = strrchr(name, '/')) == NULL)
1369 last = name;
1370 else
1371 ++last;
1372 curfile = last;
1373 if (pflag) {
1374 if (do_times(remout, verbose_mode, &stb) < 0)
1375 goto next;
1376 }
1377#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
1378 snprintf(buf, sizeof buf, "C%04o %lld %s\n",
1379 (u_int) (stb.st_mode & FILEMODEMASK),
1380 (long long)stb.st_size, last);
1381 if (verbose_mode)
1382 fmprintf(stderr, "Sending file modes: %s", buf);
1383 (void) atomicio(vwrite, remout, buf, strlen(buf));
1384 if (response() < 0)
1385 goto next;
1386 if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
1387next: if (fd != -1) {
1388 (void) close(fd);
1389 fd = -1;
1390 }
1391 continue;
1392 }
1393 if (showprogress)
1394 start_progress_meter(curfile, stb.st_size, &statbytes);
1395 set_nonblock(remout);
1396 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
1397 amt = bp->cnt;
1398 if (i + (off_t)amt > stb.st_size)
1399 amt = stb.st_size - i;
1400 if (!haderr) {
1401 if ((nr = atomicio(read, fd,
1402 bp->buf, amt)) != amt) {
1403 haderr = errno;
1404 memset(bp->buf + nr, 0, amt - nr);
1405 }
1406 }
1407 /* Keep writing after error to retain sync */
1408 if (haderr) {
1409 (void)atomicio(vwrite, remout, bp->buf, amt);
1410 memset(bp->buf, 0, amt);
1411 continue;
1412 }
1413 if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
1414 &statbytes) != amt)
1415 haderr = errno;
1416 }
1417 unset_nonblock(remout);
1418
1419 if (fd != -1) {
1420 if (close(fd) == -1 && !haderr)
1421 haderr = errno;
1422 fd = -1;
1423 }
1424 if (!haderr)
1425 (void) atomicio(vwrite, remout, "", 1);
1426 else
1427 run_err("%s: %s", name, strerror(haderr));
1428 (void) response();
1429 if (showprogress)
1430 stop_progress_meter();
1431 }
1432}
1433
1434void
1435rsource(char *name, struct stat *statp)
1436{
1437 DIR *dirp;
1438 struct dirent *dp;
1439 char *last, *vect[1], path[PATH_MAX];
1440
1441 if (!(dirp = opendir(name))) {
1442 run_err("%s: %s", name, strerror(errno));
1443 return;
1444 }
1445 last = strrchr(name, '/');
1446 if (last == NULL)
1447 last = name;
1448 else
1449 last++;
1450 if (pflag) {
1451 if (do_times(remout, verbose_mode, statp) < 0) {
1452 closedir(dirp);
1453 return;
1454 }
1455 }
1456 (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n",
1457 (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
1458 if (verbose_mode)
1459 fmprintf(stderr, "Entering directory: %s", path);
1460 (void) atomicio(vwrite, remout, path, strlen(path));
1461 if (response() < 0) {
1462 closedir(dirp);
1463 return;
1464 }
1465 while ((dp = readdir(dirp)) != NULL) {
1466 if (dp->d_ino == 0)
1467 continue;
1468 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1469 continue;
1470 if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
1471 run_err("%s/%s: name too long", name, dp->d_name);
1472 continue;
1473 }
1474 (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name);
1475 vect[0] = path;
1476 source(1, vect);
1477 }
1478 (void) closedir(dirp);
1479 (void) atomicio(vwrite, remout, "E\n", 2);
1480 (void) response();
1481}
1482
1483void
1484sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
1485{
1486 char *abs_src = NULL;
1487 char *abs_dst = NULL;
1488 glob_t g;
1489 char *filename, *tmp = NULL;
1490 int i, r, err = 0, dst_is_dir;
1491 struct stat st;
1492
1493 memset(&g, 0, sizeof(g));
1494
1495 /*
1496 * Here, we need remote glob as SFTP can not depend on remote shell
1497 * expansions
1498 */
1499 if ((abs_src = prepare_remote_path(conn, src)) == NULL) {
1500 err = -1;
1501 goto out;
1502 }
1503
1504 debug3_f("copying remote %s to local %s", abs_src, dst);
1505 if ((r = remote_glob(conn, abs_src, GLOB_NOCHECK|GLOB_MARK,
1506 NULL, &g)) != 0) {
1507 if (r == GLOB_NOSPACE)
1508 error("%s: too many glob matches", src);
1509 else
1510 error("%s: %s", src, strerror(ENOENT));
1511 err = -1;
1512 goto out;
1513 }
1514
1515 /* Did we actually get any matches back from the glob? */
1516 if (g.gl_matchc == 0 && g.gl_pathc == 1 && g.gl_pathv[0] != 0) {
1517 /*
1518 * If nothing matched but a path returned, then it's probably
1519 * a GLOB_NOCHECK result. Check whether the unglobbed path
1520 * exists so we can give a nice error message early.
1521 */
1522 if (do_stat(conn, g.gl_pathv[0], 1) == NULL) {
1523 error("%s: %s", src, strerror(ENOENT));
1524 err = -1;
1525 goto out;
1526 }
1527 }
1528
1529 if ((r = stat(dst, &st)) != 0)
1530 debug2_f("stat local \"%s\": %s", dst, strerror(errno));
1531 dst_is_dir = r == 0 && S_ISDIR(st.st_mode);
1532
1533 if (g.gl_matchc > 1 && !dst_is_dir) {
1534 if (r == 0) {
1535 error("Multiple files match pattern, but destination "
1536 "\"%s\" is not a directory", dst);
1537 err = -1;
1538 goto out;
1539 }
1540 debug2_f("creating destination \"%s\"", dst);
1541 if (mkdir(dst, 0777) != 0) {
1542 error("local mkdir \"%s\": %s", dst, strerror(errno));
1543 err = -1;
1544 goto out;
1545 }
1546 dst_is_dir = 1;
1547 }
1548
1549 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1550 tmp = xstrdup(g.gl_pathv[i]);
1551 if ((filename = basename(tmp)) == NULL) {
1552 error("basename %s: %s", tmp, strerror(errno));
1553 err = -1;
1554 goto out;
1555 }
1556
1557 if (dst_is_dir)
1558 abs_dst = path_append(dst, filename);
1559 else
1560 abs_dst = xstrdup(dst);
1561
1562 debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
1563 if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
1564 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
1565 pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
1566 err = -1;
1567 } else {
1568 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
1569 pflag, 0, 0, 1) == -1)
1570 err = -1;
1571 }
1572 free(abs_dst);
1573 abs_dst = NULL;
1574 free(tmp);
1575 tmp = NULL;
1576 }
1577
1578out:
1579 free(abs_src);
1580 free(tmp);
1581 globfree(&g);
1582 if (err == -1)
1583 errs = 1;
1584}
1585
1586
1587#define TYPE_OVERFLOW(type, val) \
1588 ((sizeof(type) == 4 && (val) > INT32_MAX) || \
1589 (sizeof(type) == 8 && (val) > INT64_MAX) || \
1590 (sizeof(type) != 4 && sizeof(type) != 8))
1591
1592void
1593sink(int argc, char **argv, const char *src)
1594{
1595 static BUF buffer;
1596 struct stat stb;
1597 BUF *bp;
1598 off_t i;
1599 size_t j, count;
1600 int amt, exists, first, ofd;
1601 mode_t mode, omode, mask;
1602 off_t size, statbytes;
1603 unsigned long long ull;
1604 int setimes, targisdir, wrerr;
1605 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
1606 char **patterns = NULL;
1607 size_t n, npatterns = 0;
1608 struct timeval tv[2];
1609
1610#define atime tv[0]
1611#define mtime tv[1]
1612#define SCREWUP(str) { why = str; goto screwup; }
1613
1614 if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0))
1615 SCREWUP("Unexpected off_t/time_t size");
1616
1617 setimes = targisdir = 0;
1618 mask = umask(0);
1619 if (!pflag)
1620 (void) umask(mask);
1621 if (argc != 1) {
1622 run_err("ambiguous target");
1623 exit(1);
1624 }
1625 targ = *argv;
1626 if (targetshouldbedirectory)
1627 verifydir(targ);
1628
1629 (void) atomicio(vwrite, remout, "", 1);
1630 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
1631 targisdir = 1;
1632 if (src != NULL && !iamrecursive && !Tflag) {
1633 /*
1634 * Prepare to try to restrict incoming filenames to match
1635 * the requested destination file glob.
1636 */
1637 if (brace_expand(src, &patterns, &npatterns) != 0)
1638 fatal_f("could not expand pattern");
1639 }
1640 for (first = 1;; first = 0) {
1641 cp = buf;
1642 if (atomicio(read, remin, cp, 1) != 1)
1643 goto done;
1644 if (*cp++ == '\n')
1645 SCREWUP("unexpected <newline>");
1646 do {
1647 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
1648 SCREWUP("lost connection");
1649 *cp++ = ch;
1650 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
1651 *cp = 0;
1652 if (verbose_mode)
1653 fmprintf(stderr, "Sink: %s", buf);
1654
1655 if (buf[0] == '\01' || buf[0] == '\02') {
1656 if (iamremote == 0) {
1657 (void) snmprintf(visbuf, sizeof(visbuf),
1658 NULL, "%s", buf + 1);
1659 (void) atomicio(vwrite, STDERR_FILENO,
1660 visbuf, strlen(visbuf));
1661 }
1662 if (buf[0] == '\02')
1663 exit(1);
1664 ++errs;
1665 continue;
1666 }
1667 if (buf[0] == 'E') {
1668 (void) atomicio(vwrite, remout, "", 1);
1669 goto done;
1670 }
1671 if (ch == '\n')
1672 *--cp = 0;
1673
1674 cp = buf;
1675 if (*cp == 'T') {
1676 setimes++;
1677 cp++;
1678 if (!isdigit((unsigned char)*cp))
1679 SCREWUP("mtime.sec not present");
1680 ull = strtoull(cp, &cp, 10);
1681 if (!cp || *cp++ != ' ')
1682 SCREWUP("mtime.sec not delimited");
1683 if (TYPE_OVERFLOW(time_t, ull))
1684 setimes = 0; /* out of range */
1685 mtime.tv_sec = ull;
1686 mtime.tv_usec = strtol(cp, &cp, 10);
1687 if (!cp || *cp++ != ' ' || mtime.tv_usec < 0 ||
1688 mtime.tv_usec > 999999)
1689 SCREWUP("mtime.usec not delimited");
1690 if (!isdigit((unsigned char)*cp))
1691 SCREWUP("atime.sec not present");
1692 ull = strtoull(cp, &cp, 10);
1693 if (!cp || *cp++ != ' ')
1694 SCREWUP("atime.sec not delimited");
1695 if (TYPE_OVERFLOW(time_t, ull))
1696 setimes = 0; /* out of range */
1697 atime.tv_sec = ull;
1698 atime.tv_usec = strtol(cp, &cp, 10);
1699 if (!cp || *cp++ != '\0' || atime.tv_usec < 0 ||
1700 atime.tv_usec > 999999)
1701 SCREWUP("atime.usec not delimited");
1702 (void) atomicio(vwrite, remout, "", 1);
1703 continue;
1704 }
1705 if (*cp != 'C' && *cp != 'D') {
1706 /*
1707 * Check for the case "rcp remote:foo\* local:bar".
1708 * In this case, the line "No match." can be returned
1709 * by the shell before the rcp command on the remote is
1710 * executed so the ^Aerror_message convention isn't
1711 * followed.
1712 */
1713 if (first) {
1714 run_err("%s", cp);
1715 exit(1);
1716 }
1717 SCREWUP("expected control record");
1718 }
1719 mode = 0;
1720 for (++cp; cp < buf + 5; cp++) {
1721 if (*cp < '0' || *cp > '7')
1722 SCREWUP("bad mode");
1723 mode = (mode << 3) | (*cp - '0');
1724 }
1725 if (!pflag)
1726 mode &= ~mask;
1727 if (*cp++ != ' ')
1728 SCREWUP("mode not delimited");
1729
1730 if (!isdigit((unsigned char)*cp))
1731 SCREWUP("size not present");
1732 ull = strtoull(cp, &cp, 10);
1733 if (!cp || *cp++ != ' ')
1734 SCREWUP("size not delimited");
1735 if (TYPE_OVERFLOW(off_t, ull))
1736 SCREWUP("size out of range");
1737 size = (off_t)ull;
1738
1739 if (*cp == '\0' || strchr(cp, '/') != NULL ||
1740 strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) {
1741 run_err("error: unexpected filename: %s", cp);
1742 exit(1);
1743 }
1744 if (npatterns > 0) {
1745 for (n = 0; n < npatterns; n++) {
1746 if (strcmp(patterns[n], cp) == 0 ||
1747 fnmatch(patterns[n], cp, 0) == 0)
1748 break;
1749 }
1750 if (n >= npatterns)
1751 SCREWUP("filename does not match request");
1752 }
1753 if (targisdir) {
1754 static char *namebuf;
1755 static size_t cursize;
1756 size_t need;
1757
1758 need = strlen(targ) + strlen(cp) + 250;
1759 if (need > cursize) {
1760 free(namebuf);
1761 namebuf = xmalloc(need);
1762 cursize = need;
1763 }
1764 (void) snprintf(namebuf, need, "%s%s%s", targ,
1765 strcmp(targ, "/") ? "/" : "", cp);
1766 np = namebuf;
1767 } else
1768 np = targ;
1769 curfile = cp;
1770 exists = stat(np, &stb) == 0;
1771 if (buf[0] == 'D') {
1772 int mod_flag = pflag;
1773 if (!iamrecursive)
1774 SCREWUP("received directory without -r");
1775 if (exists) {
1776 if (!S_ISDIR(stb.st_mode)) {
1777 errno = ENOTDIR;
1778 goto bad;
1779 }
1780 if (pflag)
1781 (void) chmod(np, mode);
1782 } else {
1783 /* Handle copying from a read-only directory */
1784 mod_flag = 1;
1785 if (mkdir(np, mode | S_IRWXU) == -1)
1786 goto bad;
1787 }
1788 vect[0] = xstrdup(np);
1789 sink(1, vect, src);
1790 if (setimes) {
1791 setimes = 0;
1792 (void) utimes(vect[0], tv);
1793 }
1794 if (mod_flag)
1795 (void) chmod(vect[0], mode);
1796 free(vect[0]);
1797 continue;
1798 }
1799 omode = mode;
1800 mode |= S_IWUSR;
1801 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) {
1802bad: run_err("%s: %s", np, strerror(errno));
1803 continue;
1804 }
1805 (void) atomicio(vwrite, remout, "", 1);
1806 if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
1807 (void) close(ofd);
1808 continue;
1809 }
1810 cp = bp->buf;
1811 wrerr = 0;
1812
1813 /*
1814 * NB. do not use run_err() unless immediately followed by
1815 * exit() below as it may send a spurious reply that might
1816 * desyncronise us from the peer. Use note_err() instead.
1817 */
1818 statbytes = 0;
1819 if (showprogress)
1820 start_progress_meter(curfile, size, &statbytes);
1821 set_nonblock(remin);
1822 for (count = i = 0; i < size; i += bp->cnt) {
1823 amt = bp->cnt;
1824 if (i + amt > size)
1825 amt = size - i;
1826 count += amt;
1827 do {
1828 j = atomicio6(read, remin, cp, amt,
1829 scpio, &statbytes);
1830 if (j == 0) {
1831 run_err("%s", j != EPIPE ?
1832 strerror(errno) :
1833 "dropped connection");
1834 exit(1);
1835 }
1836 amt -= j;
1837 cp += j;
1838 } while (amt > 0);
1839
1840 if (count == bp->cnt) {
1841 /* Keep reading so we stay sync'd up. */
1842 if (!wrerr) {
1843 if (atomicio(vwrite, ofd, bp->buf,
1844 count) != count) {
1845 note_err("%s: %s", np,
1846 strerror(errno));
1847 wrerr = 1;
1848 }
1849 }
1850 count = 0;
1851 cp = bp->buf;
1852 }
1853 }
1854 unset_nonblock(remin);
1855 if (count != 0 && !wrerr &&
1856 atomicio(vwrite, ofd, bp->buf, count) != count) {
1857 note_err("%s: %s", np, strerror(errno));
1858 wrerr = 1;
1859 }
1860 if (!wrerr && (!exists || S_ISREG(stb.st_mode)) &&
1861 ftruncate(ofd, size) != 0)
1862 note_err("%s: truncate: %s", np, strerror(errno));
1863 if (pflag) {
1864 if (exists || omode != mode)
1865 if (fchmod(ofd, omode)) {
1866 note_err("%s: set mode: %s",
1867 np, strerror(errno));
1868 }
1869 } else {
1870 if (!exists && omode != mode)
1871 if (fchmod(ofd, omode & ~mask)) {
1872 note_err("%s: set mode: %s",
1873 np, strerror(errno));
1874 }
1875 }
1876 if (close(ofd) == -1)
1877 note_err("%s: close: %s", np, strerror(errno));
1878 (void) response();
1879 if (showprogress)
1880 stop_progress_meter();
1881 if (setimes && !wrerr) {
1882 setimes = 0;
1883 if (utimes(np, tv) == -1) {
1884 note_err("%s: set times: %s",
1885 np, strerror(errno));
1886 }
1887 }
1888 /* If no error was noted then signal success for this file */
1889 if (note_err(NULL) == 0)
1890 (void) atomicio(vwrite, remout, "", 1);
1891 }
1892done:
1893 for (n = 0; n < npatterns; n++)
1894 free(patterns[n]);
1895 free(patterns);
1896 return;
1897screwup:
1898 for (n = 0; n < npatterns; n++)
1899 free(patterns[n]);
1900 free(patterns);
1901 run_err("protocol error: %s", why);
1902 exit(1);
1903}
1904
1905void
1906throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
1907 char *src, char *targ)
1908{
1909 char *target = NULL, *filename = NULL, *abs_dst = NULL;
1910 char *abs_src = NULL, *tmp = NULL;
1911 glob_t g;
1912 int i, r, targetisdir, err = 0;
1913
1914 if ((filename = basename(src)) == NULL)
1915 fatal("basename %s: %s", src, strerror(errno));
1916
1917 if ((abs_src = prepare_remote_path(from, src)) == NULL ||
1918 (target = prepare_remote_path(to, targ)) == NULL)
1919 cleanup_exit(255);
1920 memset(&g, 0, sizeof(g));
1921
1922 targetisdir = remote_is_dir(to, target);
1923 if (!targetisdir && targetshouldbedirectory) {
1924 error("%s: destination is not a directory", targ);
1925 err = -1;
1926 goto out;
1927 }
1928
1929 debug3_f("copying remote %s to remote %s", abs_src, target);
1930 if ((r = remote_glob(from, abs_src, GLOB_NOCHECK|GLOB_MARK,
1931 NULL, &g)) != 0) {
1932 if (r == GLOB_NOSPACE)
1933 error("%s: too many glob matches", src);
1934 else
1935 error("%s: %s", src, strerror(ENOENT));
1936 err = -1;
1937 goto out;
1938 }
1939
1940 /* Did we actually get any matches back from the glob? */
1941 if (g.gl_matchc == 0 && g.gl_pathc == 1 && g.gl_pathv[0] != 0) {
1942 /*
1943 * If nothing matched but a path returned, then it's probably
1944 * a GLOB_NOCHECK result. Check whether the unglobbed path
1945 * exists so we can give a nice error message early.
1946 */
1947 if (do_stat(from, g.gl_pathv[0], 1) == NULL) {
1948 error("%s: %s", src, strerror(ENOENT));
1949 err = -1;
1950 goto out;
1951 }
1952 }
1953
1954 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1955 tmp = xstrdup(g.gl_pathv[i]);
1956 if ((filename = basename(tmp)) == NULL) {
1957 error("basename %s: %s", tmp, strerror(errno));
1958 err = -1;
1959 goto out;
1960 }
1961
1962 if (targetisdir)
1963 abs_dst = path_append(target, filename);
1964 else
1965 abs_dst = xstrdup(target);
1966
1967 debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
1968 if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
1969 if (crossload_dir(from, to, g.gl_pathv[i], abs_dst,
1970 NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
1971 err = -1;
1972 } else {
1973 if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL,
1974 pflag) == -1)
1975 err = -1;
1976 }
1977 free(abs_dst);
1978 abs_dst = NULL;
1979 free(tmp);
1980 tmp = NULL;
1981 }
1982
1983out:
1984 free(abs_src);
1985 free(abs_dst);
1986 free(target);
1987 free(tmp);
1988 globfree(&g);
1989 if (err == -1)
1990 errs = 1;
1991}
1992
1993int
1994response(void)
1995{
1996 char ch, *cp, resp, rbuf[2048], visbuf[2048];
1997
1998 if (atomicio(read, remin, &resp, sizeof(resp)) != sizeof(resp))
1999 lostconn(0);
2000
2001 cp = rbuf;
2002 switch (resp) {
2003 case 0: /* ok */
2004 return (0);
2005 default:
2006 *cp++ = resp;
2007 /* FALLTHROUGH */
2008 case 1: /* error, followed by error msg */
2009 case 2: /* fatal error, "" */
2010 do {
2011 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
2012 lostconn(0);
2013 *cp++ = ch;
2014 } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
2015
2016 if (!iamremote) {
2017 cp[-1] = '\0';
2018 (void) snmprintf(visbuf, sizeof(visbuf),
2019 NULL, "%s\n", rbuf);
2020 (void) atomicio(vwrite, STDERR_FILENO,
2021 visbuf, strlen(visbuf));
2022 }
2023 ++errs;
2024 if (resp == 1)
2025 return (-1);
2026 exit(1);
2027 }
2028 /* NOTREACHED */
2029}
2030
2031void
2032usage(void)
2033{
2034 (void) fprintf(stderr,
2035 "usage: scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n"
2036 " [-i identity_file] [-J destination] [-l limit] [-o ssh_option]\n"
2037 " [-P port] [-S program] [-X sftp_option] source ... target\n");
2038 exit(1);
2039}
2040
2041void
2042run_err(const char *fmt,...)
2043{
2044 static FILE *fp;
2045 va_list ap;
2046
2047 ++errs;
2048 if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
2049 (void) fprintf(fp, "%c", 0x01);
2050 (void) fprintf(fp, "scp: ");
2051 va_start(ap, fmt);
2052 (void) vfprintf(fp, fmt, ap);
2053 va_end(ap);
2054 (void) fprintf(fp, "\n");
2055 (void) fflush(fp);
2056 }
2057
2058 if (!iamremote) {
2059 va_start(ap, fmt);
2060 vfmprintf(stderr, fmt, ap);
2061 va_end(ap);
2062 fprintf(stderr, "\n");
2063 }
2064}
2065
2066/*
2067 * Notes a sink error for sending at the end of a file transfer. Returns 0 if
2068 * no error has been noted or -1 otherwise. Use note_err(NULL) to flush
2069 * any active error at the end of the transfer.
2070 */
2071int
2072note_err(const char *fmt, ...)
2073{
2074 static char *emsg;
2075 va_list ap;
2076
2077 /* Replay any previously-noted error */
2078 if (fmt == NULL) {
2079 if (emsg == NULL)
2080 return 0;
2081 run_err("%s", emsg);
2082 free(emsg);
2083 emsg = NULL;
2084 return -1;
2085 }
2086
2087 errs++;
2088 /* Prefer first-noted error */
2089 if (emsg != NULL)
2090 return -1;
2091
2092 va_start(ap, fmt);
2093 vasnmprintf(&emsg, INT_MAX, NULL, fmt, ap);
2094 va_end(ap);
2095 return -1;
2096}
2097
2098void
2099verifydir(char *cp)
2100{
2101 struct stat stb;
2102
2103 if (!stat(cp, &stb)) {
2104 if (S_ISDIR(stb.st_mode))
2105 return;
2106 errno = ENOTDIR;
2107 }
2108 run_err("%s: %s", cp, strerror(errno));
2109 killchild(0);
2110}
2111
2112int
2113okname(char *cp0)
2114{
2115 int c;
2116 char *cp;
2117
2118 cp = cp0;
2119 do {
2120 c = (int)*cp;
2121 if (c & 0200)
2122 goto bad;
2123 if (!isalpha(c) && !isdigit((unsigned char)c)) {
2124 switch (c) {
2125 case '\'':
2126 case '"':
2127 case '`':
2128 case ' ':
2129 case '#':
2130 goto bad;
2131 default:
2132 break;
2133 }
2134 }
2135 } while (*++cp);
2136 return (1);
2137
2138bad: fmprintf(stderr, "%s: invalid user name\n", cp0);
2139 return (0);
2140}
2141
2142BUF *
2143allocbuf(BUF *bp, int fd, int blksize)
2144{
2145 size_t size;
2146 struct stat stb;
2147
2148 if (fstat(fd, &stb) == -1) {
2149 run_err("fstat: %s", strerror(errno));
2150 return (0);
2151 }
2152 size = ROUNDUP(stb.st_blksize, blksize);
2153 if (size == 0)
2154 size = blksize;
2155 if (bp->cnt >= size)
2156 return (bp);
2157 bp->buf = xrecallocarray(bp->buf, bp->cnt, size, 1);
2158 bp->cnt = size;
2159 return (bp);
2160}
2161
2162void
2163lostconn(int signo)
2164{
2165 if (!iamremote)
2166 (void)write(STDERR_FILENO, "lost connection\n", 16);
2167 if (signo)
2168 _exit(1);
2169 else
2170 exit(1);
2171}
2172
2173void
2174cleanup_exit(int i)
2175{
2176 if (remin > 0)
2177 close(remin);
2178 if (remout > 0)
2179 close(remout);
2180 if (remin2 > 0)
2181 close(remin2);
2182 if (remout2 > 0)
2183 close(remout2);
2184 if (do_cmd_pid > 0)
2185 waitpid(do_cmd_pid, NULL, 0);
2186 if (do_cmd_pid2 > 0)
2187 waitpid(do_cmd_pid2, NULL, 0);
2188 exit(i);
2189}