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