xref: /openssh-portable/sftp.c (revision 816036f1)
1 /* $OpenBSD: sftp.c,v 1.203 2020/10/18 11:32:02 djm Exp $ */
2 /*
3  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "includes.h"
19 
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #ifdef HAVE_SYS_STAT_H
23 # include <sys/stat.h>
24 #endif
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/wait.h>
28 #ifdef HAVE_SYS_STATVFS_H
29 #include <sys/statvfs.h>
30 #endif
31 
32 #include <ctype.h>
33 #include <errno.h>
34 
35 #ifdef HAVE_PATHS_H
36 # include <paths.h>
37 #endif
38 #ifdef HAVE_LIBGEN_H
39 #include <libgen.h>
40 #endif
41 #ifdef HAVE_LOCALE_H
42 # include <locale.h>
43 #endif
44 #ifdef USE_LIBEDIT
45 #include <histedit.h>
46 #else
47 typedef void EditLine;
48 #endif
49 #include <limits.h>
50 #include <signal.h>
51 #include <stdarg.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <unistd.h>
56 
57 #ifdef HAVE_UTIL_H
58 # include <util.h>
59 #endif
60 
61 #include "xmalloc.h"
62 #include "log.h"
63 #include "pathnames.h"
64 #include "misc.h"
65 #include "utf8.h"
66 
67 #include "sftp.h"
68 #include "ssherr.h"
69 #include "sshbuf.h"
70 #include "sftp-common.h"
71 #include "sftp-client.h"
72 
73 #define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
74 #define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
75 
76 /* File to read commands from */
77 FILE* infile;
78 
79 /* Are we in batchfile mode? */
80 int batchmode = 0;
81 
82 /* PID of ssh transport process */
83 static volatile pid_t sshpid = -1;
84 
85 /* Suppress diagnositic messages */
86 int quiet = 0;
87 
88 /* This is set to 0 if the progressmeter is not desired. */
89 int showprogress = 1;
90 
91 /* When this option is set, we always recursively download/upload directories */
92 int global_rflag = 0;
93 
94 /* When this option is set, we resume download or upload if possible */
95 int global_aflag = 0;
96 
97 /* When this option is set, the file transfers will always preserve times */
98 int global_pflag = 0;
99 
100 /* When this option is set, transfers will have fsync() called on each file */
101 int global_fflag = 0;
102 
103 /* SIGINT received during command processing */
104 volatile sig_atomic_t interrupted = 0;
105 
106 /* I wish qsort() took a separate ctx for the comparison function...*/
107 int sort_flag;
108 glob_t *sort_glob;
109 
110 /* Context used for commandline completion */
111 struct complete_ctx {
112 	struct sftp_conn *conn;
113 	char **remote_pathp;
114 };
115 
116 int remote_glob(struct sftp_conn *, const char *, int,
117     int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
118 
119 extern char *__progname;
120 
121 /* Separators for interactive commands */
122 #define WHITESPACE " \t\r\n"
123 
124 /* ls flags */
125 #define LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
126 #define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
127 #define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
128 #define LS_NAME_SORT	0x0008	/* Sort by name (default) */
129 #define LS_TIME_SORT	0x0010	/* Sort by mtime */
130 #define LS_SIZE_SORT	0x0020	/* Sort by file size */
131 #define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
132 #define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
133 #define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
134 
135 #define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
136 #define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
137 
138 /* Commands for interactive mode */
139 enum sftp_command {
140 	I_CHDIR = 1,
141 	I_CHGRP,
142 	I_CHMOD,
143 	I_CHOWN,
144 	I_DF,
145 	I_GET,
146 	I_HELP,
147 	I_LCHDIR,
148 	I_LINK,
149 	I_LLS,
150 	I_LMKDIR,
151 	I_LPWD,
152 	I_LS,
153 	I_LUMASK,
154 	I_MKDIR,
155 	I_PUT,
156 	I_PWD,
157 	I_QUIT,
158 	I_REGET,
159 	I_RENAME,
160 	I_REPUT,
161 	I_RM,
162 	I_RMDIR,
163 	I_SHELL,
164 	I_SYMLINK,
165 	I_VERSION,
166 	I_PROGRESS,
167 };
168 
169 struct CMD {
170 	const char *c;
171 	const int n;
172 	const int t;
173 };
174 
175 /* Type of completion */
176 #define NOARGS	0
177 #define REMOTE	1
178 #define LOCAL	2
179 
180 static const struct CMD cmds[] = {
181 	{ "bye",	I_QUIT,		NOARGS	},
182 	{ "cd",		I_CHDIR,	REMOTE	},
183 	{ "chdir",	I_CHDIR,	REMOTE	},
184 	{ "chgrp",	I_CHGRP,	REMOTE	},
185 	{ "chmod",	I_CHMOD,	REMOTE	},
186 	{ "chown",	I_CHOWN,	REMOTE	},
187 	{ "df",		I_DF,		REMOTE	},
188 	{ "dir",	I_LS,		REMOTE	},
189 	{ "exit",	I_QUIT,		NOARGS	},
190 	{ "get",	I_GET,		REMOTE	},
191 	{ "help",	I_HELP,		NOARGS	},
192 	{ "lcd",	I_LCHDIR,	LOCAL	},
193 	{ "lchdir",	I_LCHDIR,	LOCAL	},
194 	{ "lls",	I_LLS,		LOCAL	},
195 	{ "lmkdir",	I_LMKDIR,	LOCAL	},
196 	{ "ln",		I_LINK,		REMOTE	},
197 	{ "lpwd",	I_LPWD,		LOCAL	},
198 	{ "ls",		I_LS,		REMOTE	},
199 	{ "lumask",	I_LUMASK,	NOARGS	},
200 	{ "mkdir",	I_MKDIR,	REMOTE	},
201 	{ "mget",	I_GET,		REMOTE	},
202 	{ "mput",	I_PUT,		LOCAL	},
203 	{ "progress",	I_PROGRESS,	NOARGS	},
204 	{ "put",	I_PUT,		LOCAL	},
205 	{ "pwd",	I_PWD,		REMOTE	},
206 	{ "quit",	I_QUIT,		NOARGS	},
207 	{ "reget",	I_REGET,	REMOTE	},
208 	{ "rename",	I_RENAME,	REMOTE	},
209 	{ "reput",	I_REPUT,	LOCAL	},
210 	{ "rm",		I_RM,		REMOTE	},
211 	{ "rmdir",	I_RMDIR,	REMOTE	},
212 	{ "symlink",	I_SYMLINK,	REMOTE	},
213 	{ "version",	I_VERSION,	NOARGS	},
214 	{ "!",		I_SHELL,	NOARGS	},
215 	{ "?",		I_HELP,		NOARGS	},
216 	{ NULL,		-1,		-1	}
217 };
218 
219 /* ARGSUSED */
220 static void
killchild(int signo)221 killchild(int signo)
222 {
223 	pid_t pid;
224 
225 	pid = sshpid;
226 	if (pid > 1) {
227 		kill(pid, SIGTERM);
228 		waitpid(pid, NULL, 0);
229 	}
230 
231 	_exit(1);
232 }
233 
234 /* ARGSUSED */
235 static void
suspchild(int signo)236 suspchild(int signo)
237 {
238 	if (sshpid > 1) {
239 		kill(sshpid, signo);
240 		while (waitpid(sshpid, NULL, WUNTRACED) == -1 && errno == EINTR)
241 			continue;
242 	}
243 	kill(getpid(), SIGSTOP);
244 }
245 
246 /* ARGSUSED */
247 static void
cmd_interrupt(int signo)248 cmd_interrupt(int signo)
249 {
250 	const char msg[] = "\rInterrupt  \n";
251 	int olderrno = errno;
252 
253 	(void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
254 	interrupted = 1;
255 	errno = olderrno;
256 }
257 
258 /*ARGSUSED*/
259 static void
sigchld_handler(int sig)260 sigchld_handler(int sig)
261 {
262 	int save_errno = errno;
263 	pid_t pid;
264 	const char msg[] = "\rConnection closed.  \n";
265 
266 	/* Report if ssh transport process dies. */
267 	while ((pid = waitpid(sshpid, NULL, WNOHANG)) == -1 && errno == EINTR)
268 		continue;
269 	if (pid == sshpid) {
270 		(void)write(STDERR_FILENO, msg, sizeof(msg) - 1);
271 		sshpid = -1;
272 	}
273 
274 	errno = save_errno;
275 }
276 
277 static void
help(void)278 help(void)
279 {
280 	printf("Available commands:\n"
281 	    "bye                                Quit sftp\n"
282 	    "cd path                            Change remote directory to 'path'\n"
283 	    "chgrp [-h] grp path                Change group of file 'path' to 'grp'\n"
284 	    "chmod [-h] mode path               Change permissions of file 'path' to 'mode'\n"
285 	    "chown [-h] own path                Change owner of file 'path' to 'own'\n"
286 	    "df [-hi] [path]                    Display statistics for current directory or\n"
287 	    "                                   filesystem containing 'path'\n"
288 	    "exit                               Quit sftp\n"
289 	    "get [-afpR] remote [local]         Download file\n"
290 	    "help                               Display this help text\n"
291 	    "lcd path                           Change local directory to 'path'\n"
292 	    "lls [ls-options [path]]            Display local directory listing\n"
293 	    "lmkdir path                        Create local directory\n"
294 	    "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
295 	    "lpwd                               Print local working directory\n"
296 	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
297 	    "lumask umask                       Set local umask to 'umask'\n"
298 	    "mkdir path                         Create remote directory\n"
299 	    "progress                           Toggle display of progress meter\n"
300 	    "put [-afpR] local [remote]         Upload file\n"
301 	    "pwd                                Display remote working directory\n"
302 	    "quit                               Quit sftp\n"
303 	    "reget [-fpR] remote [local]        Resume download file\n"
304 	    "rename oldpath newpath             Rename remote file\n"
305 	    "reput [-fpR] local [remote]        Resume upload file\n"
306 	    "rm path                            Delete remote file\n"
307 	    "rmdir path                         Remove remote directory\n"
308 	    "symlink oldpath newpath            Symlink remote file\n"
309 	    "version                            Show SFTP version\n"
310 	    "!command                           Execute 'command' in local shell\n"
311 	    "!                                  Escape to local shell\n"
312 	    "?                                  Synonym for help\n");
313 }
314 
315 static void
local_do_shell(const char * args)316 local_do_shell(const char *args)
317 {
318 	int status;
319 	char *shell;
320 	pid_t pid;
321 
322 	if (!*args)
323 		args = NULL;
324 
325 	if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
326 		shell = _PATH_BSHELL;
327 
328 	if ((pid = fork()) == -1)
329 		fatal("Couldn't fork: %s", strerror(errno));
330 
331 	if (pid == 0) {
332 		/* XXX: child has pipe fds to ssh subproc open - issue? */
333 		if (args) {
334 			debug3("Executing %s -c \"%s\"", shell, args);
335 			execl(shell, shell, "-c", args, (char *)NULL);
336 		} else {
337 			debug3("Executing %s", shell);
338 			execl(shell, shell, (char *)NULL);
339 		}
340 		fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
341 		    strerror(errno));
342 		_exit(1);
343 	}
344 	while (waitpid(pid, &status, 0) == -1)
345 		if (errno != EINTR)
346 			fatal("Couldn't wait for child: %s", strerror(errno));
347 	if (!WIFEXITED(status))
348 		error("Shell exited abnormally");
349 	else if (WEXITSTATUS(status))
350 		error("Shell exited with status %d", WEXITSTATUS(status));
351 }
352 
353 static void
local_do_ls(const char * args)354 local_do_ls(const char *args)
355 {
356 	if (!args || !*args)
357 		local_do_shell(_PATH_LS);
358 	else {
359 		int len = strlen(_PATH_LS " ") + strlen(args) + 1;
360 		char *buf = xmalloc(len);
361 
362 		/* XXX: quoting - rip quoting code from ftp? */
363 		snprintf(buf, len, _PATH_LS " %s", args);
364 		local_do_shell(buf);
365 		free(buf);
366 	}
367 }
368 
369 /* Strip one path (usually the pwd) from the start of another */
370 static char *
path_strip(const char * path,const char * strip)371 path_strip(const char *path, const char *strip)
372 {
373 	size_t len;
374 
375 	if (strip == NULL)
376 		return (xstrdup(path));
377 
378 	len = strlen(strip);
379 	if (strncmp(path, strip, len) == 0) {
380 		if (strip[len - 1] != '/' && path[len] == '/')
381 			len++;
382 		return (xstrdup(path + len));
383 	}
384 
385 	return (xstrdup(path));
386 }
387 
388 static char *
make_absolute(char * p,const char * pwd)389 make_absolute(char *p, const char *pwd)
390 {
391 	char *abs_str;
392 
393 	/* Derelativise */
394 	if (p && !path_absolute(p)) {
395 		abs_str = path_append(pwd, p);
396 		free(p);
397 		return(abs_str);
398 	} else
399 		return(p);
400 }
401 
402 static int
parse_getput_flags(const char * cmd,char ** argv,int argc,int * aflag,int * fflag,int * pflag,int * rflag)403 parse_getput_flags(const char *cmd, char **argv, int argc,
404     int *aflag, int *fflag, int *pflag, int *rflag)
405 {
406 	extern int opterr, optind, optopt, optreset;
407 	int ch;
408 
409 	optind = optreset = 1;
410 	opterr = 0;
411 
412 	*aflag = *fflag = *rflag = *pflag = 0;
413 	while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
414 		switch (ch) {
415 		case 'a':
416 			*aflag = 1;
417 			break;
418 		case 'f':
419 			*fflag = 1;
420 			break;
421 		case 'p':
422 		case 'P':
423 			*pflag = 1;
424 			break;
425 		case 'r':
426 		case 'R':
427 			*rflag = 1;
428 			break;
429 		default:
430 			error("%s: Invalid flag -%c", cmd, optopt);
431 			return -1;
432 		}
433 	}
434 
435 	return optind;
436 }
437 
438 static int
parse_link_flags(const char * cmd,char ** argv,int argc,int * sflag)439 parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
440 {
441 	extern int opterr, optind, optopt, optreset;
442 	int ch;
443 
444 	optind = optreset = 1;
445 	opterr = 0;
446 
447 	*sflag = 0;
448 	while ((ch = getopt(argc, argv, "s")) != -1) {
449 		switch (ch) {
450 		case 's':
451 			*sflag = 1;
452 			break;
453 		default:
454 			error("%s: Invalid flag -%c", cmd, optopt);
455 			return -1;
456 		}
457 	}
458 
459 	return optind;
460 }
461 
462 static int
parse_rename_flags(const char * cmd,char ** argv,int argc,int * lflag)463 parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag)
464 {
465 	extern int opterr, optind, optopt, optreset;
466 	int ch;
467 
468 	optind = optreset = 1;
469 	opterr = 0;
470 
471 	*lflag = 0;
472 	while ((ch = getopt(argc, argv, "l")) != -1) {
473 		switch (ch) {
474 		case 'l':
475 			*lflag = 1;
476 			break;
477 		default:
478 			error("%s: Invalid flag -%c", cmd, optopt);
479 			return -1;
480 		}
481 	}
482 
483 	return optind;
484 }
485 
486 static int
parse_ls_flags(char ** argv,int argc,int * lflag)487 parse_ls_flags(char **argv, int argc, int *lflag)
488 {
489 	extern int opterr, optind, optopt, optreset;
490 	int ch;
491 
492 	optind = optreset = 1;
493 	opterr = 0;
494 
495 	*lflag = LS_NAME_SORT;
496 	while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
497 		switch (ch) {
498 		case '1':
499 			*lflag &= ~VIEW_FLAGS;
500 			*lflag |= LS_SHORT_VIEW;
501 			break;
502 		case 'S':
503 			*lflag &= ~SORT_FLAGS;
504 			*lflag |= LS_SIZE_SORT;
505 			break;
506 		case 'a':
507 			*lflag |= LS_SHOW_ALL;
508 			break;
509 		case 'f':
510 			*lflag &= ~SORT_FLAGS;
511 			break;
512 		case 'h':
513 			*lflag |= LS_SI_UNITS;
514 			break;
515 		case 'l':
516 			*lflag &= ~LS_SHORT_VIEW;
517 			*lflag |= LS_LONG_VIEW;
518 			break;
519 		case 'n':
520 			*lflag &= ~LS_SHORT_VIEW;
521 			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
522 			break;
523 		case 'r':
524 			*lflag |= LS_REVERSE_SORT;
525 			break;
526 		case 't':
527 			*lflag &= ~SORT_FLAGS;
528 			*lflag |= LS_TIME_SORT;
529 			break;
530 		default:
531 			error("ls: Invalid flag -%c", optopt);
532 			return -1;
533 		}
534 	}
535 
536 	return optind;
537 }
538 
539 static int
parse_df_flags(const char * cmd,char ** argv,int argc,int * hflag,int * iflag)540 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
541 {
542 	extern int opterr, optind, optopt, optreset;
543 	int ch;
544 
545 	optind = optreset = 1;
546 	opterr = 0;
547 
548 	*hflag = *iflag = 0;
549 	while ((ch = getopt(argc, argv, "hi")) != -1) {
550 		switch (ch) {
551 		case 'h':
552 			*hflag = 1;
553 			break;
554 		case 'i':
555 			*iflag = 1;
556 			break;
557 		default:
558 			error("%s: Invalid flag -%c", cmd, optopt);
559 			return -1;
560 		}
561 	}
562 
563 	return optind;
564 }
565 
566 static int
parse_ch_flags(const char * cmd,char ** argv,int argc,int * hflag)567 parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag)
568 {
569 	extern int opterr, optind, optopt, optreset;
570 	int ch;
571 
572 	optind = optreset = 1;
573 	opterr = 0;
574 
575 	*hflag = 0;
576 	while ((ch = getopt(argc, argv, "h")) != -1) {
577 		switch (ch) {
578 		case 'h':
579 			*hflag = 1;
580 			break;
581 		default:
582 			error("%s: Invalid flag -%c", cmd, optopt);
583 			return -1;
584 		}
585 	}
586 
587 	return optind;
588 }
589 
590 static int
parse_no_flags(const char * cmd,char ** argv,int argc)591 parse_no_flags(const char *cmd, char **argv, int argc)
592 {
593 	extern int opterr, optind, optopt, optreset;
594 	int ch;
595 
596 	optind = optreset = 1;
597 	opterr = 0;
598 
599 	while ((ch = getopt(argc, argv, "")) != -1) {
600 		switch (ch) {
601 		default:
602 			error("%s: Invalid flag -%c", cmd, optopt);
603 			return -1;
604 		}
605 	}
606 
607 	return optind;
608 }
609 
610 static int
is_dir(const char * path)611 is_dir(const char *path)
612 {
613 	struct stat sb;
614 
615 	/* XXX: report errors? */
616 	if (stat(path, &sb) == -1)
617 		return(0);
618 
619 	return(S_ISDIR(sb.st_mode));
620 }
621 
622 static int
remote_is_dir(struct sftp_conn * conn,const char * path)623 remote_is_dir(struct sftp_conn *conn, const char *path)
624 {
625 	Attrib *a;
626 
627 	/* XXX: report errors? */
628 	if ((a = do_stat(conn, path, 1)) == NULL)
629 		return(0);
630 	if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
631 		return(0);
632 	return(S_ISDIR(a->perm));
633 }
634 
635 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
636 static int
pathname_is_dir(const char * pathname)637 pathname_is_dir(const char *pathname)
638 {
639 	size_t l = strlen(pathname);
640 
641 	return l > 0 && pathname[l - 1] == '/';
642 }
643 
644 static int
process_get(struct sftp_conn * conn,const char * src,const char * dst,const char * pwd,int pflag,int rflag,int resume,int fflag)645 process_get(struct sftp_conn *conn, const char *src, const char *dst,
646     const char *pwd, int pflag, int rflag, int resume, int fflag)
647 {
648 	char *abs_src = NULL;
649 	char *abs_dst = NULL;
650 	glob_t g;
651 	char *filename, *tmp=NULL;
652 	int i, r, err = 0;
653 
654 	abs_src = xstrdup(src);
655 	abs_src = make_absolute(abs_src, pwd);
656 	memset(&g, 0, sizeof(g));
657 
658 	debug3("Looking up %s", abs_src);
659 	if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
660 		if (r == GLOB_NOSPACE) {
661 			error("Too many matches for \"%s\".", abs_src);
662 		} else {
663 			error("File \"%s\" not found.", abs_src);
664 		}
665 		err = -1;
666 		goto out;
667 	}
668 
669 	/*
670 	 * If multiple matches then dst must be a directory or
671 	 * unspecified.
672 	 */
673 	if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
674 		error("Multiple source paths, but destination "
675 		    "\"%s\" is not a directory", dst);
676 		err = -1;
677 		goto out;
678 	}
679 
680 	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
681 		tmp = xstrdup(g.gl_pathv[i]);
682 		if ((filename = basename(tmp)) == NULL) {
683 			error("basename %s: %s", tmp, strerror(errno));
684 			free(tmp);
685 			err = -1;
686 			goto out;
687 		}
688 
689 		if (g.gl_matchc == 1 && dst) {
690 			if (is_dir(dst)) {
691 				abs_dst = path_append(dst, filename);
692 			} else {
693 				abs_dst = xstrdup(dst);
694 			}
695 		} else if (dst) {
696 			abs_dst = path_append(dst, filename);
697 		} else {
698 			abs_dst = xstrdup(filename);
699 		}
700 		free(tmp);
701 
702 		resume |= global_aflag;
703 		if (!quiet && resume)
704 			mprintf("Resuming %s to %s\n",
705 			    g.gl_pathv[i], abs_dst);
706 		else if (!quiet && !resume)
707 			mprintf("Fetching %s to %s\n",
708 			    g.gl_pathv[i], abs_dst);
709 		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
710 			if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
711 			    pflag || global_pflag, 1, resume,
712 			    fflag || global_fflag) == -1)
713 				err = -1;
714 		} else {
715 			if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
716 			    pflag || global_pflag, resume,
717 			    fflag || global_fflag) == -1)
718 				err = -1;
719 		}
720 		free(abs_dst);
721 		abs_dst = NULL;
722 	}
723 
724 out:
725 	free(abs_src);
726 	globfree(&g);
727 	return(err);
728 }
729 
730 static int
process_put(struct sftp_conn * conn,const char * src,const char * dst,const char * pwd,int pflag,int rflag,int resume,int fflag)731 process_put(struct sftp_conn *conn, const char *src, const char *dst,
732     const char *pwd, int pflag, int rflag, int resume, int fflag)
733 {
734 	char *tmp_dst = NULL;
735 	char *abs_dst = NULL;
736 	char *tmp = NULL, *filename = NULL;
737 	glob_t g;
738 	int err = 0;
739 	int i, dst_is_dir = 1;
740 	struct stat sb;
741 
742 	if (dst) {
743 		tmp_dst = xstrdup(dst);
744 		tmp_dst = make_absolute(tmp_dst, pwd);
745 	}
746 
747 	memset(&g, 0, sizeof(g));
748 	debug3("Looking up %s", src);
749 	if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
750 		error("File \"%s\" not found.", src);
751 		err = -1;
752 		goto out;
753 	}
754 
755 	/* If we aren't fetching to pwd then stash this status for later */
756 	if (tmp_dst != NULL)
757 		dst_is_dir = remote_is_dir(conn, tmp_dst);
758 
759 	/* If multiple matches, dst may be directory or unspecified */
760 	if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
761 		error("Multiple paths match, but destination "
762 		    "\"%s\" is not a directory", tmp_dst);
763 		err = -1;
764 		goto out;
765 	}
766 
767 	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
768 		if (stat(g.gl_pathv[i], &sb) == -1) {
769 			err = -1;
770 			error("stat %s: %s", g.gl_pathv[i], strerror(errno));
771 			continue;
772 		}
773 
774 		tmp = xstrdup(g.gl_pathv[i]);
775 		if ((filename = basename(tmp)) == NULL) {
776 			error("basename %s: %s", tmp, strerror(errno));
777 			free(tmp);
778 			err = -1;
779 			goto out;
780 		}
781 
782 		if (g.gl_matchc == 1 && tmp_dst) {
783 			/* If directory specified, append filename */
784 			if (dst_is_dir)
785 				abs_dst = path_append(tmp_dst, filename);
786 			else
787 				abs_dst = xstrdup(tmp_dst);
788 		} else if (tmp_dst) {
789 			abs_dst = path_append(tmp_dst, filename);
790 		} else {
791 			abs_dst = make_absolute(xstrdup(filename), pwd);
792 		}
793 		free(tmp);
794 
795                 resume |= global_aflag;
796 		if (!quiet && resume)
797 			mprintf("Resuming upload of %s to %s\n",
798 			    g.gl_pathv[i], abs_dst);
799 		else if (!quiet && !resume)
800 			mprintf("Uploading %s to %s\n",
801 			    g.gl_pathv[i], abs_dst);
802 		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
803 			if (upload_dir(conn, g.gl_pathv[i], abs_dst,
804 			    pflag || global_pflag, 1, resume,
805 			    fflag || global_fflag) == -1)
806 				err = -1;
807 		} else {
808 			if (do_upload(conn, g.gl_pathv[i], abs_dst,
809 			    pflag || global_pflag, resume,
810 			    fflag || global_fflag) == -1)
811 				err = -1;
812 		}
813 	}
814 
815 out:
816 	free(abs_dst);
817 	free(tmp_dst);
818 	globfree(&g);
819 	return(err);
820 }
821 
822 static int
sdirent_comp(const void * aa,const void * bb)823 sdirent_comp(const void *aa, const void *bb)
824 {
825 	SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
826 	SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
827 	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
828 
829 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
830 	if (sort_flag & LS_NAME_SORT)
831 		return (rmul * strcmp(a->filename, b->filename));
832 	else if (sort_flag & LS_TIME_SORT)
833 		return (rmul * NCMP(a->a.mtime, b->a.mtime));
834 	else if (sort_flag & LS_SIZE_SORT)
835 		return (rmul * NCMP(a->a.size, b->a.size));
836 
837 	fatal("Unknown ls sort type");
838 }
839 
840 /* sftp ls.1 replacement for directories */
841 static int
do_ls_dir(struct sftp_conn * conn,const char * path,const char * strip_path,int lflag)842 do_ls_dir(struct sftp_conn *conn, const char *path,
843     const char *strip_path, int lflag)
844 {
845 	int n;
846 	u_int c = 1, colspace = 0, columns = 1;
847 	SFTP_DIRENT **d;
848 
849 	if ((n = do_readdir(conn, path, &d)) != 0)
850 		return (n);
851 
852 	if (!(lflag & LS_SHORT_VIEW)) {
853 		u_int m = 0, width = 80;
854 		struct winsize ws;
855 		char *tmp;
856 
857 		/* Count entries for sort and find longest filename */
858 		for (n = 0; d[n] != NULL; n++) {
859 			if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
860 				m = MAXIMUM(m, strlen(d[n]->filename));
861 		}
862 
863 		/* Add any subpath that also needs to be counted */
864 		tmp = path_strip(path, strip_path);
865 		m += strlen(tmp);
866 		free(tmp);
867 
868 		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
869 			width = ws.ws_col;
870 
871 		columns = width / (m + 2);
872 		columns = MAXIMUM(columns, 1);
873 		colspace = width / columns;
874 		colspace = MINIMUM(colspace, width);
875 	}
876 
877 	if (lflag & SORT_FLAGS) {
878 		for (n = 0; d[n] != NULL; n++)
879 			;	/* count entries */
880 		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
881 		qsort(d, n, sizeof(*d), sdirent_comp);
882 	}
883 
884 	for (n = 0; d[n] != NULL && !interrupted; n++) {
885 		char *tmp, *fname;
886 
887 		if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
888 			continue;
889 
890 		tmp = path_append(path, d[n]->filename);
891 		fname = path_strip(tmp, strip_path);
892 		free(tmp);
893 
894 		if (lflag & LS_LONG_VIEW) {
895 			if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
896 				char *lname;
897 				struct stat sb;
898 
899 				memset(&sb, 0, sizeof(sb));
900 				attrib_to_stat(&d[n]->a, &sb);
901 				lname = ls_file(fname, &sb, 1,
902 				    (lflag & LS_SI_UNITS));
903 				mprintf("%s\n", lname);
904 				free(lname);
905 			} else
906 				mprintf("%s\n", d[n]->longname);
907 		} else {
908 			mprintf("%-*s", colspace, fname);
909 			if (c >= columns) {
910 				printf("\n");
911 				c = 1;
912 			} else
913 				c++;
914 		}
915 
916 		free(fname);
917 	}
918 
919 	if (!(lflag & LS_LONG_VIEW) && (c != 1))
920 		printf("\n");
921 
922 	free_sftp_dirents(d);
923 	return (0);
924 }
925 
926 static int
sglob_comp(const void * aa,const void * bb)927 sglob_comp(const void *aa, const void *bb)
928 {
929 	u_int a = *(const u_int *)aa;
930 	u_int b = *(const u_int *)bb;
931 	const char *ap = sort_glob->gl_pathv[a];
932 	const char *bp = sort_glob->gl_pathv[b];
933 	const struct stat *as = sort_glob->gl_statv[a];
934 	const struct stat *bs = sort_glob->gl_statv[b];
935 	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
936 
937 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
938 	if (sort_flag & LS_NAME_SORT)
939 		return (rmul * strcmp(ap, bp));
940 	else if (sort_flag & LS_TIME_SORT) {
941 #if defined(HAVE_STRUCT_STAT_ST_MTIM)
942 		return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <));
943 #elif defined(HAVE_STRUCT_STAT_ST_MTIME)
944 		return (rmul * NCMP(as->st_mtime, bs->st_mtime));
945 #else
946 	return rmul * 1;
947 #endif
948 	} else if (sort_flag & LS_SIZE_SORT)
949 		return (rmul * NCMP(as->st_size, bs->st_size));
950 
951 	fatal("Unknown ls sort type");
952 }
953 
954 /* sftp ls.1 replacement which handles path globs */
955 static int
do_globbed_ls(struct sftp_conn * conn,const char * path,const char * strip_path,int lflag)956 do_globbed_ls(struct sftp_conn *conn, const char *path,
957     const char *strip_path, int lflag)
958 {
959 	char *fname, *lname;
960 	glob_t g;
961 	int err, r;
962 	struct winsize ws;
963 	u_int i, j, nentries, *indices = NULL, c = 1;
964 	u_int colspace = 0, columns = 1, m = 0, width = 80;
965 
966 	memset(&g, 0, sizeof(g));
967 
968 	if ((r = remote_glob(conn, path,
969 	    GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
970 	    NULL, &g)) != 0 ||
971 	    (g.gl_pathc && !g.gl_matchc)) {
972 		if (g.gl_pathc)
973 			globfree(&g);
974 		if (r == GLOB_NOSPACE) {
975 			error("Can't ls: Too many matches for \"%s\"", path);
976 		} else {
977 			error("Can't ls: \"%s\" not found", path);
978 		}
979 		return -1;
980 	}
981 
982 	if (interrupted)
983 		goto out;
984 
985 	/*
986 	 * If the glob returns a single match and it is a directory,
987 	 * then just list its contents.
988 	 */
989 	if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
990 	    S_ISDIR(g.gl_statv[0]->st_mode)) {
991 		err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
992 		globfree(&g);
993 		return err;
994 	}
995 
996 	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
997 		width = ws.ws_col;
998 
999 	if (!(lflag & LS_SHORT_VIEW)) {
1000 		/* Count entries for sort and find longest filename */
1001 		for (i = 0; g.gl_pathv[i]; i++)
1002 			m = MAXIMUM(m, strlen(g.gl_pathv[i]));
1003 
1004 		columns = width / (m + 2);
1005 		columns = MAXIMUM(columns, 1);
1006 		colspace = width / columns;
1007 	}
1008 
1009 	/*
1010 	 * Sorting: rather than mess with the contents of glob_t, prepare
1011 	 * an array of indices into it and sort that. For the usual
1012 	 * unsorted case, the indices are just the identity 1=1, 2=2, etc.
1013 	 */
1014 	for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++)
1015 		;	/* count entries */
1016 	indices = calloc(nentries, sizeof(*indices));
1017 	for (i = 0; i < nentries; i++)
1018 		indices[i] = i;
1019 
1020 	if (lflag & SORT_FLAGS) {
1021 		sort_glob = &g;
1022 		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
1023 		qsort(indices, nentries, sizeof(*indices), sglob_comp);
1024 		sort_glob = NULL;
1025 	}
1026 
1027 	for (j = 0; j < nentries && !interrupted; j++) {
1028 		i = indices[j];
1029 		fname = path_strip(g.gl_pathv[i], strip_path);
1030 		if (lflag & LS_LONG_VIEW) {
1031 			if (g.gl_statv[i] == NULL) {
1032 				error("no stat information for %s", fname);
1033 				continue;
1034 			}
1035 			lname = ls_file(fname, g.gl_statv[i], 1,
1036 			    (lflag & LS_SI_UNITS));
1037 			mprintf("%s\n", lname);
1038 			free(lname);
1039 		} else {
1040 			mprintf("%-*s", colspace, fname);
1041 			if (c >= columns) {
1042 				printf("\n");
1043 				c = 1;
1044 			} else
1045 				c++;
1046 		}
1047 		free(fname);
1048 	}
1049 
1050 	if (!(lflag & LS_LONG_VIEW) && (c != 1))
1051 		printf("\n");
1052 
1053  out:
1054 	if (g.gl_pathc)
1055 		globfree(&g);
1056 	free(indices);
1057 
1058 	return 0;
1059 }
1060 
1061 static int
do_df(struct sftp_conn * conn,const char * path,int hflag,int iflag)1062 do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
1063 {
1064 	struct sftp_statvfs st;
1065 	char s_used[FMT_SCALED_STRSIZE], s_avail[FMT_SCALED_STRSIZE];
1066 	char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
1067 	char s_icapacity[16], s_dcapacity[16];
1068 
1069 	if (do_statvfs(conn, path, &st, 1) == -1)
1070 		return -1;
1071 	if (st.f_files == 0)
1072 		strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
1073 	else {
1074 		snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%",
1075 		    (unsigned long long)(100 * (st.f_files - st.f_ffree) /
1076 		    st.f_files));
1077 	}
1078 	if (st.f_blocks == 0)
1079 		strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity));
1080 	else {
1081 		snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%",
1082 		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
1083 		    st.f_blocks));
1084 	}
1085 	if (iflag) {
1086 		printf("     Inodes        Used       Avail      "
1087 		    "(root)    %%Capacity\n");
1088 		printf("%11llu %11llu %11llu %11llu         %s\n",
1089 		    (unsigned long long)st.f_files,
1090 		    (unsigned long long)(st.f_files - st.f_ffree),
1091 		    (unsigned long long)st.f_favail,
1092 		    (unsigned long long)st.f_ffree, s_icapacity);
1093 	} else if (hflag) {
1094 		strlcpy(s_used, "error", sizeof(s_used));
1095 		strlcpy(s_avail, "error", sizeof(s_avail));
1096 		strlcpy(s_root, "error", sizeof(s_root));
1097 		strlcpy(s_total, "error", sizeof(s_total));
1098 		fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
1099 		fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
1100 		fmt_scaled(st.f_bfree * st.f_frsize, s_root);
1101 		fmt_scaled(st.f_blocks * st.f_frsize, s_total);
1102 		printf("    Size     Used    Avail   (root)    %%Capacity\n");
1103 		printf("%7sB %7sB %7sB %7sB         %s\n",
1104 		    s_total, s_used, s_avail, s_root, s_dcapacity);
1105 	} else {
1106 		printf("        Size         Used        Avail       "
1107 		    "(root)    %%Capacity\n");
1108 		printf("%12llu %12llu %12llu %12llu         %s\n",
1109 		    (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
1110 		    (unsigned long long)(st.f_frsize *
1111 		    (st.f_blocks - st.f_bfree) / 1024),
1112 		    (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
1113 		    (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
1114 		    s_dcapacity);
1115 	}
1116 	return 0;
1117 }
1118 
1119 /*
1120  * Undo escaping of glob sequences in place. Used to undo extra escaping
1121  * applied in makeargv() when the string is destined for a function that
1122  * does not glob it.
1123  */
1124 static void
undo_glob_escape(char * s)1125 undo_glob_escape(char *s)
1126 {
1127 	size_t i, j;
1128 
1129 	for (i = j = 0;;) {
1130 		if (s[i] == '\0') {
1131 			s[j] = '\0';
1132 			return;
1133 		}
1134 		if (s[i] != '\\') {
1135 			s[j++] = s[i++];
1136 			continue;
1137 		}
1138 		/* s[i] == '\\' */
1139 		++i;
1140 		switch (s[i]) {
1141 		case '?':
1142 		case '[':
1143 		case '*':
1144 		case '\\':
1145 			s[j++] = s[i++];
1146 			break;
1147 		case '\0':
1148 			s[j++] = '\\';
1149 			s[j] = '\0';
1150 			return;
1151 		default:
1152 			s[j++] = '\\';
1153 			s[j++] = s[i++];
1154 			break;
1155 		}
1156 	}
1157 }
1158 
1159 /*
1160  * Split a string into an argument vector using sh(1)-style quoting,
1161  * comment and escaping rules, but with some tweaks to handle glob(3)
1162  * wildcards.
1163  * The "sloppy" flag allows for recovery from missing terminating quote, for
1164  * use in parsing incomplete commandlines during tab autocompletion.
1165  *
1166  * Returns NULL on error or a NULL-terminated array of arguments.
1167  *
1168  * If "lastquote" is not NULL, the quoting character used for the last
1169  * argument is placed in *lastquote ("\0", "'" or "\"").
1170  *
1171  * If "terminated" is not NULL, *terminated will be set to 1 when the
1172  * last argument's quote has been properly terminated or 0 otherwise.
1173  * This parameter is only of use if "sloppy" is set.
1174  */
1175 #define MAXARGS 	128
1176 #define MAXARGLEN	8192
1177 static char **
makeargv(const char * arg,int * argcp,int sloppy,char * lastquote,u_int * terminated)1178 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1179     u_int *terminated)
1180 {
1181 	int argc, quot;
1182 	size_t i, j;
1183 	static char argvs[MAXARGLEN];
1184 	static char *argv[MAXARGS + 1];
1185 	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
1186 
1187 	*argcp = argc = 0;
1188 	if (strlen(arg) > sizeof(argvs) - 1) {
1189  args_too_longs:
1190 		error("string too long");
1191 		return NULL;
1192 	}
1193 	if (terminated != NULL)
1194 		*terminated = 1;
1195 	if (lastquote != NULL)
1196 		*lastquote = '\0';
1197 	state = MA_START;
1198 	i = j = 0;
1199 	for (;;) {
1200 		if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
1201 			error("Too many arguments.");
1202 			return NULL;
1203 		}
1204 		if (isspace((unsigned char)arg[i])) {
1205 			if (state == MA_UNQUOTED) {
1206 				/* Terminate current argument */
1207 				argvs[j++] = '\0';
1208 				argc++;
1209 				state = MA_START;
1210 			} else if (state != MA_START)
1211 				argvs[j++] = arg[i];
1212 		} else if (arg[i] == '"' || arg[i] == '\'') {
1213 			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
1214 			if (state == MA_START) {
1215 				argv[argc] = argvs + j;
1216 				state = q;
1217 				if (lastquote != NULL)
1218 					*lastquote = arg[i];
1219 			} else if (state == MA_UNQUOTED)
1220 				state = q;
1221 			else if (state == q)
1222 				state = MA_UNQUOTED;
1223 			else
1224 				argvs[j++] = arg[i];
1225 		} else if (arg[i] == '\\') {
1226 			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1227 				quot = state == MA_SQUOTE ? '\'' : '"';
1228 				/* Unescape quote we are in */
1229 				/* XXX support \n and friends? */
1230 				if (arg[i + 1] == quot) {
1231 					i++;
1232 					argvs[j++] = arg[i];
1233 				} else if (arg[i + 1] == '?' ||
1234 				    arg[i + 1] == '[' || arg[i + 1] == '*') {
1235 					/*
1236 					 * Special case for sftp: append
1237 					 * double-escaped glob sequence -
1238 					 * glob will undo one level of
1239 					 * escaping. NB. string can grow here.
1240 					 */
1241 					if (j >= sizeof(argvs) - 5)
1242 						goto args_too_longs;
1243 					argvs[j++] = '\\';
1244 					argvs[j++] = arg[i++];
1245 					argvs[j++] = '\\';
1246 					argvs[j++] = arg[i];
1247 				} else {
1248 					argvs[j++] = arg[i++];
1249 					argvs[j++] = arg[i];
1250 				}
1251 			} else {
1252 				if (state == MA_START) {
1253 					argv[argc] = argvs + j;
1254 					state = MA_UNQUOTED;
1255 					if (lastquote != NULL)
1256 						*lastquote = '\0';
1257 				}
1258 				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1259 				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1260 					/*
1261 					 * Special case for sftp: append
1262 					 * escaped glob sequence -
1263 					 * glob will undo one level of
1264 					 * escaping.
1265 					 */
1266 					argvs[j++] = arg[i++];
1267 					argvs[j++] = arg[i];
1268 				} else {
1269 					/* Unescape everything */
1270 					/* XXX support \n and friends? */
1271 					i++;
1272 					argvs[j++] = arg[i];
1273 				}
1274 			}
1275 		} else if (arg[i] == '#') {
1276 			if (state == MA_SQUOTE || state == MA_DQUOTE)
1277 				argvs[j++] = arg[i];
1278 			else
1279 				goto string_done;
1280 		} else if (arg[i] == '\0') {
1281 			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1282 				if (sloppy) {
1283 					state = MA_UNQUOTED;
1284 					if (terminated != NULL)
1285 						*terminated = 0;
1286 					goto string_done;
1287 				}
1288 				error("Unterminated quoted argument");
1289 				return NULL;
1290 			}
1291  string_done:
1292 			if (state == MA_UNQUOTED) {
1293 				argvs[j++] = '\0';
1294 				argc++;
1295 			}
1296 			break;
1297 		} else {
1298 			if (state == MA_START) {
1299 				argv[argc] = argvs + j;
1300 				state = MA_UNQUOTED;
1301 				if (lastquote != NULL)
1302 					*lastquote = '\0';
1303 			}
1304 			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1305 			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1306 				/*
1307 				 * Special case for sftp: escape quoted
1308 				 * glob(3) wildcards. NB. string can grow
1309 				 * here.
1310 				 */
1311 				if (j >= sizeof(argvs) - 3)
1312 					goto args_too_longs;
1313 				argvs[j++] = '\\';
1314 				argvs[j++] = arg[i];
1315 			} else
1316 				argvs[j++] = arg[i];
1317 		}
1318 		i++;
1319 	}
1320 	*argcp = argc;
1321 	return argv;
1322 }
1323 
1324 static int
parse_args(const char ** cpp,int * ignore_errors,int * disable_echo,int * aflag,int * fflag,int * hflag,int * iflag,int * lflag,int * pflag,int * rflag,int * sflag,unsigned long * n_arg,char ** path1,char ** path2)1325 parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag,
1326 	  int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1327 	  int *rflag, int *sflag,
1328     unsigned long *n_arg, char **path1, char **path2)
1329 {
1330 	const char *cmd, *cp = *cpp;
1331 	char *cp2, **argv;
1332 	int base = 0;
1333 	long long ll;
1334 	int path1_mandatory = 0, i, cmdnum, optidx, argc;
1335 
1336 	/* Skip leading whitespace */
1337 	cp = cp + strspn(cp, WHITESPACE);
1338 
1339 	/*
1340 	 * Check for leading '-' (disable error processing) and '@' (suppress
1341 	 * command echo)
1342 	 */
1343 	*ignore_errors = 0;
1344 	*disable_echo = 0;
1345 	for (;*cp != '\0'; cp++) {
1346 		if (*cp == '-') {
1347 			*ignore_errors = 1;
1348 		} else if (*cp == '@') {
1349 			*disable_echo = 1;
1350 		} else {
1351 			/* all other characters terminate prefix processing */
1352 			break;
1353 		}
1354 	}
1355 	cp = cp + strspn(cp, WHITESPACE);
1356 
1357 	/* Ignore blank lines and lines which begin with comment '#' char */
1358 	if (*cp == '\0' || *cp == '#')
1359 		return (0);
1360 
1361 	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1362 		return -1;
1363 
1364 	/* Figure out which command we have */
1365 	for (i = 0; cmds[i].c != NULL; i++) {
1366 		if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
1367 			break;
1368 	}
1369 	cmdnum = cmds[i].n;
1370 	cmd = cmds[i].c;
1371 
1372 	/* Special case */
1373 	if (*cp == '!') {
1374 		cp++;
1375 		cmdnum = I_SHELL;
1376 	} else if (cmdnum == -1) {
1377 		error("Invalid command.");
1378 		return -1;
1379 	}
1380 
1381 	/* Get arguments and parse flags */
1382 	*aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
1383 	*rflag = *sflag = 0;
1384 	*path1 = *path2 = NULL;
1385 	optidx = 1;
1386 	switch (cmdnum) {
1387 	case I_GET:
1388 	case I_REGET:
1389 	case I_REPUT:
1390 	case I_PUT:
1391 		if ((optidx = parse_getput_flags(cmd, argv, argc,
1392 		    aflag, fflag, pflag, rflag)) == -1)
1393 			return -1;
1394 		/* Get first pathname (mandatory) */
1395 		if (argc - optidx < 1) {
1396 			error("You must specify at least one path after a "
1397 			    "%s command.", cmd);
1398 			return -1;
1399 		}
1400 		*path1 = xstrdup(argv[optidx]);
1401 		/* Get second pathname (optional) */
1402 		if (argc - optidx > 1) {
1403 			*path2 = xstrdup(argv[optidx + 1]);
1404 			/* Destination is not globbed */
1405 			undo_glob_escape(*path2);
1406 		}
1407 		break;
1408 	case I_LINK:
1409 		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1410 			return -1;
1411 		goto parse_two_paths;
1412 	case I_RENAME:
1413 		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1414 			return -1;
1415 		goto parse_two_paths;
1416 	case I_SYMLINK:
1417 		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1418 			return -1;
1419  parse_two_paths:
1420 		if (argc - optidx < 2) {
1421 			error("You must specify two paths after a %s "
1422 			    "command.", cmd);
1423 			return -1;
1424 		}
1425 		*path1 = xstrdup(argv[optidx]);
1426 		*path2 = xstrdup(argv[optidx + 1]);
1427 		/* Paths are not globbed */
1428 		undo_glob_escape(*path1);
1429 		undo_glob_escape(*path2);
1430 		break;
1431 	case I_RM:
1432 	case I_MKDIR:
1433 	case I_RMDIR:
1434 	case I_LMKDIR:
1435 		path1_mandatory = 1;
1436 		/* FALLTHROUGH */
1437 	case I_CHDIR:
1438 	case I_LCHDIR:
1439 		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1440 			return -1;
1441 		/* Get pathname (mandatory) */
1442 		if (argc - optidx < 1) {
1443 			if (!path1_mandatory)
1444 				break; /* return a NULL path1 */
1445 			error("You must specify a path after a %s command.",
1446 			    cmd);
1447 			return -1;
1448 		}
1449 		*path1 = xstrdup(argv[optidx]);
1450 		/* Only "rm" globs */
1451 		if (cmdnum != I_RM)
1452 			undo_glob_escape(*path1);
1453 		break;
1454 	case I_DF:
1455 		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1456 		    iflag)) == -1)
1457 			return -1;
1458 		/* Default to current directory if no path specified */
1459 		if (argc - optidx < 1)
1460 			*path1 = NULL;
1461 		else {
1462 			*path1 = xstrdup(argv[optidx]);
1463 			undo_glob_escape(*path1);
1464 		}
1465 		break;
1466 	case I_LS:
1467 		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1468 			return(-1);
1469 		/* Path is optional */
1470 		if (argc - optidx > 0)
1471 			*path1 = xstrdup(argv[optidx]);
1472 		break;
1473 	case I_LLS:
1474 		/* Skip ls command and following whitespace */
1475 		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1476 	case I_SHELL:
1477 		/* Uses the rest of the line */
1478 		break;
1479 	case I_LUMASK:
1480 	case I_CHMOD:
1481 		base = 8;
1482 		/* FALLTHROUGH */
1483 	case I_CHOWN:
1484 	case I_CHGRP:
1485 		if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1)
1486 			return -1;
1487 		/* Get numeric arg (mandatory) */
1488 		if (argc - optidx < 1)
1489 			goto need_num_arg;
1490 		errno = 0;
1491 		ll = strtoll(argv[optidx], &cp2, base);
1492 		if (cp2 == argv[optidx] || *cp2 != '\0' ||
1493 		    ((ll == LLONG_MIN || ll == LLONG_MAX) && errno == ERANGE) ||
1494 		    ll < 0 || ll > UINT32_MAX) {
1495  need_num_arg:
1496 			error("You must supply a numeric argument "
1497 			    "to the %s command.", cmd);
1498 			return -1;
1499 		}
1500 		*n_arg = ll;
1501 		if (cmdnum == I_LUMASK)
1502 			break;
1503 		/* Get pathname (mandatory) */
1504 		if (argc - optidx < 2) {
1505 			error("You must specify a path after a %s command.",
1506 			    cmd);
1507 			return -1;
1508 		}
1509 		*path1 = xstrdup(argv[optidx + 1]);
1510 		break;
1511 	case I_QUIT:
1512 	case I_PWD:
1513 	case I_LPWD:
1514 	case I_HELP:
1515 	case I_VERSION:
1516 	case I_PROGRESS:
1517 		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1518 			return -1;
1519 		break;
1520 	default:
1521 		fatal("Command not implemented");
1522 	}
1523 
1524 	*cpp = cp;
1525 	return(cmdnum);
1526 }
1527 
1528 static int
parse_dispatch_command(struct sftp_conn * conn,const char * cmd,char ** pwd,const char * startdir,int err_abort,int echo_command)1529 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1530     const char *startdir, int err_abort, int echo_command)
1531 {
1532 	const char *ocmd = cmd;
1533 	char *path1, *path2, *tmp;
1534 	int ignore_errors = 0, disable_echo = 1;
1535 	int aflag = 0, fflag = 0, hflag = 0, iflag = 0;
1536 	int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1537 	int cmdnum, i;
1538 	unsigned long n_arg = 0;
1539 	Attrib a, *aa;
1540 	char path_buf[PATH_MAX];
1541 	int err = 0;
1542 	glob_t g;
1543 
1544 	path1 = path2 = NULL;
1545 	cmdnum = parse_args(&cmd, &ignore_errors, &disable_echo, &aflag, &fflag,
1546 	    &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg,
1547 	    &path1, &path2);
1548 	if (ignore_errors != 0)
1549 		err_abort = 0;
1550 
1551 	if (echo_command && !disable_echo)
1552 		mprintf("sftp> %s\n", ocmd);
1553 
1554 	memset(&g, 0, sizeof(g));
1555 
1556 	/* Perform command */
1557 	switch (cmdnum) {
1558 	case 0:
1559 		/* Blank line */
1560 		break;
1561 	case -1:
1562 		/* Unrecognized command */
1563 		err = -1;
1564 		break;
1565 	case I_REGET:
1566 		aflag = 1;
1567 		/* FALLTHROUGH */
1568 	case I_GET:
1569 		err = process_get(conn, path1, path2, *pwd, pflag,
1570 		    rflag, aflag, fflag);
1571 		break;
1572 	case I_REPUT:
1573 		aflag = 1;
1574 		/* FALLTHROUGH */
1575 	case I_PUT:
1576 		err = process_put(conn, path1, path2, *pwd, pflag,
1577 		    rflag, aflag, fflag);
1578 		break;
1579 	case I_RENAME:
1580 		path1 = make_absolute(path1, *pwd);
1581 		path2 = make_absolute(path2, *pwd);
1582 		err = do_rename(conn, path1, path2, lflag);
1583 		break;
1584 	case I_SYMLINK:
1585 		sflag = 1;
1586 		/* FALLTHROUGH */
1587 	case I_LINK:
1588 		if (!sflag)
1589 			path1 = make_absolute(path1, *pwd);
1590 		path2 = make_absolute(path2, *pwd);
1591 		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1592 		break;
1593 	case I_RM:
1594 		path1 = make_absolute(path1, *pwd);
1595 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1596 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1597 			if (!quiet)
1598 				mprintf("Removing %s\n", g.gl_pathv[i]);
1599 			err = do_rm(conn, g.gl_pathv[i]);
1600 			if (err != 0 && err_abort)
1601 				break;
1602 		}
1603 		break;
1604 	case I_MKDIR:
1605 		path1 = make_absolute(path1, *pwd);
1606 		attrib_clear(&a);
1607 		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1608 		a.perm = 0777;
1609 		err = do_mkdir(conn, path1, &a, 1);
1610 		break;
1611 	case I_RMDIR:
1612 		path1 = make_absolute(path1, *pwd);
1613 		err = do_rmdir(conn, path1);
1614 		break;
1615 	case I_CHDIR:
1616 		if (path1 == NULL || *path1 == '\0')
1617 			path1 = xstrdup(startdir);
1618 		path1 = make_absolute(path1, *pwd);
1619 		if ((tmp = do_realpath(conn, path1)) == NULL) {
1620 			err = 1;
1621 			break;
1622 		}
1623 		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1624 			free(tmp);
1625 			err = 1;
1626 			break;
1627 		}
1628 		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1629 			error("Can't change directory: Can't check target");
1630 			free(tmp);
1631 			err = 1;
1632 			break;
1633 		}
1634 		if (!S_ISDIR(aa->perm)) {
1635 			error("Can't change directory: \"%s\" is not "
1636 			    "a directory", tmp);
1637 			free(tmp);
1638 			err = 1;
1639 			break;
1640 		}
1641 		free(*pwd);
1642 		*pwd = tmp;
1643 		break;
1644 	case I_LS:
1645 		if (!path1) {
1646 			do_ls_dir(conn, *pwd, *pwd, lflag);
1647 			break;
1648 		}
1649 
1650 		/* Strip pwd off beginning of non-absolute paths */
1651 		tmp = NULL;
1652 		if (!path_absolute(path1))
1653 			tmp = *pwd;
1654 
1655 		path1 = make_absolute(path1, *pwd);
1656 		err = do_globbed_ls(conn, path1, tmp, lflag);
1657 		break;
1658 	case I_DF:
1659 		/* Default to current directory if no path specified */
1660 		if (path1 == NULL)
1661 			path1 = xstrdup(*pwd);
1662 		path1 = make_absolute(path1, *pwd);
1663 		err = do_df(conn, path1, hflag, iflag);
1664 		break;
1665 	case I_LCHDIR:
1666 		if (path1 == NULL || *path1 == '\0')
1667 			path1 = xstrdup("~");
1668 		tmp = tilde_expand_filename(path1, getuid());
1669 		free(path1);
1670 		path1 = tmp;
1671 		if (chdir(path1) == -1) {
1672 			error("Couldn't change local directory to "
1673 			    "\"%s\": %s", path1, strerror(errno));
1674 			err = 1;
1675 		}
1676 		break;
1677 	case I_LMKDIR:
1678 		if (mkdir(path1, 0777) == -1) {
1679 			error("Couldn't create local directory "
1680 			    "\"%s\": %s", path1, strerror(errno));
1681 			err = 1;
1682 		}
1683 		break;
1684 	case I_LLS:
1685 		local_do_ls(cmd);
1686 		break;
1687 	case I_SHELL:
1688 		local_do_shell(cmd);
1689 		break;
1690 	case I_LUMASK:
1691 		umask(n_arg);
1692 		printf("Local umask: %03lo\n", n_arg);
1693 		break;
1694 	case I_CHMOD:
1695 		path1 = make_absolute(path1, *pwd);
1696 		attrib_clear(&a);
1697 		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1698 		a.perm = n_arg;
1699 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1700 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1701 			if (!quiet)
1702 				mprintf("Changing mode on %s\n",
1703 				    g.gl_pathv[i]);
1704 			err = (hflag ? do_lsetstat : do_setstat)(conn,
1705 			    g.gl_pathv[i], &a);
1706 			if (err != 0 && err_abort)
1707 				break;
1708 		}
1709 		break;
1710 	case I_CHOWN:
1711 	case I_CHGRP:
1712 		path1 = make_absolute(path1, *pwd);
1713 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1714 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1715 			if (!(aa = (hflag ? do_lstat : do_stat)(conn,
1716 			    g.gl_pathv[i], 0))) {
1717 				if (err_abort) {
1718 					err = -1;
1719 					break;
1720 				} else
1721 					continue;
1722 			}
1723 			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1724 				error("Can't get current ownership of "
1725 				    "remote file \"%s\"", g.gl_pathv[i]);
1726 				if (err_abort) {
1727 					err = -1;
1728 					break;
1729 				} else
1730 					continue;
1731 			}
1732 			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1733 			if (cmdnum == I_CHOWN) {
1734 				if (!quiet)
1735 					mprintf("Changing owner on %s\n",
1736 					    g.gl_pathv[i]);
1737 				aa->uid = n_arg;
1738 			} else {
1739 				if (!quiet)
1740 					mprintf("Changing group on %s\n",
1741 					    g.gl_pathv[i]);
1742 				aa->gid = n_arg;
1743 			}
1744 			err = (hflag ? do_lsetstat : do_setstat)(conn,
1745 			    g.gl_pathv[i], aa);
1746 			if (err != 0 && err_abort)
1747 				break;
1748 		}
1749 		break;
1750 	case I_PWD:
1751 		mprintf("Remote working directory: %s\n", *pwd);
1752 		break;
1753 	case I_LPWD:
1754 		if (!getcwd(path_buf, sizeof(path_buf))) {
1755 			error("Couldn't get local cwd: %s", strerror(errno));
1756 			err = -1;
1757 			break;
1758 		}
1759 		mprintf("Local working directory: %s\n", path_buf);
1760 		break;
1761 	case I_QUIT:
1762 		/* Processed below */
1763 		break;
1764 	case I_HELP:
1765 		help();
1766 		break;
1767 	case I_VERSION:
1768 		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1769 		break;
1770 	case I_PROGRESS:
1771 		showprogress = !showprogress;
1772 		if (showprogress)
1773 			printf("Progress meter enabled\n");
1774 		else
1775 			printf("Progress meter disabled\n");
1776 		break;
1777 	default:
1778 		fatal("%d is not implemented", cmdnum);
1779 	}
1780 
1781 	if (g.gl_pathc)
1782 		globfree(&g);
1783 	free(path1);
1784 	free(path2);
1785 
1786 	/* If an unignored error occurs in batch mode we should abort. */
1787 	if (err_abort && err != 0)
1788 		return (-1);
1789 	else if (cmdnum == I_QUIT)
1790 		return (1);
1791 
1792 	return (0);
1793 }
1794 
1795 #ifdef USE_LIBEDIT
1796 static char *
prompt(EditLine * el)1797 prompt(EditLine *el)
1798 {
1799 	return ("sftp> ");
1800 }
1801 
1802 /* Display entries in 'list' after skipping the first 'len' chars */
1803 static void
complete_display(char ** list,u_int len)1804 complete_display(char **list, u_int len)
1805 {
1806 	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1807 	struct winsize ws;
1808 	char *tmp;
1809 
1810 	/* Count entries for sort and find longest */
1811 	for (y = 0; list[y]; y++)
1812 		m = MAXIMUM(m, strlen(list[y]));
1813 
1814 	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1815 		width = ws.ws_col;
1816 
1817 	m = m > len ? m - len : 0;
1818 	columns = width / (m + 2);
1819 	columns = MAXIMUM(columns, 1);
1820 	colspace = width / columns;
1821 	colspace = MINIMUM(colspace, width);
1822 
1823 	printf("\n");
1824 	m = 1;
1825 	for (y = 0; list[y]; y++) {
1826 		llen = strlen(list[y]);
1827 		tmp = llen > len ? list[y] + len : "";
1828 		mprintf("%-*s", colspace, tmp);
1829 		if (m >= columns) {
1830 			printf("\n");
1831 			m = 1;
1832 		} else
1833 			m++;
1834 	}
1835 	printf("\n");
1836 }
1837 
1838 /*
1839  * Given a "list" of words that begin with a common prefix of "word",
1840  * attempt to find an autocompletion to extends "word" by the next
1841  * characters common to all entries in "list".
1842  */
1843 static char *
complete_ambiguous(const char * word,char ** list,size_t count)1844 complete_ambiguous(const char *word, char **list, size_t count)
1845 {
1846 	if (word == NULL)
1847 		return NULL;
1848 
1849 	if (count > 0) {
1850 		u_int y, matchlen = strlen(list[0]);
1851 
1852 		/* Find length of common stem */
1853 		for (y = 1; list[y]; y++) {
1854 			u_int x;
1855 
1856 			for (x = 0; x < matchlen; x++)
1857 				if (list[0][x] != list[y][x])
1858 					break;
1859 
1860 			matchlen = x;
1861 		}
1862 
1863 		if (matchlen > strlen(word)) {
1864 			char *tmp = xstrdup(list[0]);
1865 
1866 			tmp[matchlen] = '\0';
1867 			return tmp;
1868 		}
1869 	}
1870 
1871 	return xstrdup(word);
1872 }
1873 
1874 /* Autocomplete a sftp command */
1875 static int
complete_cmd_parse(EditLine * el,char * cmd,int lastarg,char quote,int terminated)1876 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1877     int terminated)
1878 {
1879 	u_int y, count = 0, cmdlen, tmplen;
1880 	char *tmp, **list, argterm[3];
1881 	const LineInfo *lf;
1882 
1883 	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1884 
1885 	/* No command specified: display all available commands */
1886 	if (cmd == NULL) {
1887 		for (y = 0; cmds[y].c; y++)
1888 			list[count++] = xstrdup(cmds[y].c);
1889 
1890 		list[count] = NULL;
1891 		complete_display(list, 0);
1892 
1893 		for (y = 0; list[y] != NULL; y++)
1894 			free(list[y]);
1895 		free(list);
1896 		return count;
1897 	}
1898 
1899 	/* Prepare subset of commands that start with "cmd" */
1900 	cmdlen = strlen(cmd);
1901 	for (y = 0; cmds[y].c; y++)  {
1902 		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1903 			list[count++] = xstrdup(cmds[y].c);
1904 	}
1905 	list[count] = NULL;
1906 
1907 	if (count == 0) {
1908 		free(list);
1909 		return 0;
1910 	}
1911 
1912 	/* Complete ambiguous command */
1913 	tmp = complete_ambiguous(cmd, list, count);
1914 	if (count > 1)
1915 		complete_display(list, 0);
1916 
1917 	for (y = 0; list[y]; y++)
1918 		free(list[y]);
1919 	free(list);
1920 
1921 	if (tmp != NULL) {
1922 		tmplen = strlen(tmp);
1923 		cmdlen = strlen(cmd);
1924 		/* If cmd may be extended then do so */
1925 		if (tmplen > cmdlen)
1926 			if (el_insertstr(el, tmp + cmdlen) == -1)
1927 				fatal("el_insertstr failed.");
1928 		lf = el_line(el);
1929 		/* Terminate argument cleanly */
1930 		if (count == 1) {
1931 			y = 0;
1932 			if (!terminated)
1933 				argterm[y++] = quote;
1934 			if (lastarg || *(lf->cursor) != ' ')
1935 				argterm[y++] = ' ';
1936 			argterm[y] = '\0';
1937 			if (y > 0 && el_insertstr(el, argterm) == -1)
1938 				fatal("el_insertstr failed.");
1939 		}
1940 		free(tmp);
1941 	}
1942 
1943 	return count;
1944 }
1945 
1946 /*
1947  * Determine whether a particular sftp command's arguments (if any)
1948  * represent local or remote files.
1949  */
1950 static int
complete_is_remote(char * cmd)1951 complete_is_remote(char *cmd) {
1952 	int i;
1953 
1954 	if (cmd == NULL)
1955 		return -1;
1956 
1957 	for (i = 0; cmds[i].c; i++) {
1958 		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1959 			return cmds[i].t;
1960 	}
1961 
1962 	return -1;
1963 }
1964 
1965 /* Autocomplete a filename "file" */
1966 static int
complete_match(EditLine * el,struct sftp_conn * conn,char * remote_path,char * file,int remote,int lastarg,char quote,int terminated)1967 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1968     char *file, int remote, int lastarg, char quote, int terminated)
1969 {
1970 	glob_t g;
1971 	char *tmp, *tmp2, ins[8];
1972 	u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
1973 	int clen;
1974 	const LineInfo *lf;
1975 
1976 	/* Glob from "file" location */
1977 	if (file == NULL)
1978 		tmp = xstrdup("*");
1979 	else
1980 		xasprintf(&tmp, "%s*", file);
1981 
1982 	/* Check if the path is absolute. */
1983 	isabs = path_absolute(tmp);
1984 
1985 	memset(&g, 0, sizeof(g));
1986 	if (remote != LOCAL) {
1987 		tmp = make_absolute(tmp, remote_path);
1988 		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1989 	} else
1990 		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1991 
1992 	/* Determine length of pwd so we can trim completion display */
1993 	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1994 		/* Terminate counting on first unescaped glob metacharacter */
1995 		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1996 			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1997 				hadglob = 1;
1998 			break;
1999 		}
2000 		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
2001 			tmplen++;
2002 		if (tmp[tmplen] == '/')
2003 			pwdlen = tmplen + 1;	/* track last seen '/' */
2004 	}
2005 	free(tmp);
2006 	tmp = NULL;
2007 
2008 	if (g.gl_matchc == 0)
2009 		goto out;
2010 
2011 	if (g.gl_matchc > 1)
2012 		complete_display(g.gl_pathv, pwdlen);
2013 
2014 	/* Don't try to extend globs */
2015 	if (file == NULL || hadglob)
2016 		goto out;
2017 
2018 	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
2019 	tmp = path_strip(tmp2, isabs ? NULL : remote_path);
2020 	free(tmp2);
2021 
2022 	if (tmp == NULL)
2023 		goto out;
2024 
2025 	tmplen = strlen(tmp);
2026 	filelen = strlen(file);
2027 
2028 	/* Count the number of escaped characters in the input string. */
2029 	cesc = isesc = 0;
2030 	for (i = 0; i < filelen; i++) {
2031 		if (!isesc && file[i] == '\\' && i + 1 < filelen){
2032 			isesc = 1;
2033 			cesc++;
2034 		} else
2035 			isesc = 0;
2036 	}
2037 
2038 	if (tmplen > (filelen - cesc)) {
2039 		tmp2 = tmp + filelen - cesc;
2040 		len = strlen(tmp2);
2041 		/* quote argument on way out */
2042 		for (i = 0; i < len; i += clen) {
2043 			if ((clen = mblen(tmp2 + i, len - i)) < 0 ||
2044 			    (size_t)clen > sizeof(ins) - 2)
2045 				fatal("invalid multibyte character");
2046 			ins[0] = '\\';
2047 			memcpy(ins + 1, tmp2 + i, clen);
2048 			ins[clen + 1] = '\0';
2049 			switch (tmp2[i]) {
2050 			case '\'':
2051 			case '"':
2052 			case '\\':
2053 			case '\t':
2054 			case '[':
2055 			case ' ':
2056 			case '#':
2057 			case '*':
2058 				if (quote == '\0' || tmp2[i] == quote) {
2059 					if (el_insertstr(el, ins) == -1)
2060 						fatal("el_insertstr "
2061 						    "failed.");
2062 					break;
2063 				}
2064 				/* FALLTHROUGH */
2065 			default:
2066 				if (el_insertstr(el, ins + 1) == -1)
2067 					fatal("el_insertstr failed.");
2068 				break;
2069 			}
2070 		}
2071 	}
2072 
2073 	lf = el_line(el);
2074 	if (g.gl_matchc == 1) {
2075 		i = 0;
2076 		if (!terminated && quote != '\0')
2077 			ins[i++] = quote;
2078 		if (*(lf->cursor - 1) != '/' &&
2079 		    (lastarg || *(lf->cursor) != ' '))
2080 			ins[i++] = ' ';
2081 		ins[i] = '\0';
2082 		if (i > 0 && el_insertstr(el, ins) == -1)
2083 			fatal("el_insertstr failed.");
2084 	}
2085 	free(tmp);
2086 
2087  out:
2088 	globfree(&g);
2089 	return g.gl_matchc;
2090 }
2091 
2092 /* tab-completion hook function, called via libedit */
2093 static unsigned char
complete(EditLine * el,int ch)2094 complete(EditLine *el, int ch)
2095 {
2096 	char **argv, *line, quote;
2097 	int argc, carg;
2098 	u_int cursor, len, terminated, ret = CC_ERROR;
2099 	const LineInfo *lf;
2100 	struct complete_ctx *complete_ctx;
2101 
2102 	lf = el_line(el);
2103 	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
2104 		fatal_f("el_get failed");
2105 
2106 	/* Figure out which argument the cursor points to */
2107 	cursor = lf->cursor - lf->buffer;
2108 	line = xmalloc(cursor + 1);
2109 	memcpy(line, lf->buffer, cursor);
2110 	line[cursor] = '\0';
2111 	argv = makeargv(line, &carg, 1, &quote, &terminated);
2112 	free(line);
2113 
2114 	/* Get all the arguments on the line */
2115 	len = lf->lastchar - lf->buffer;
2116 	line = xmalloc(len + 1);
2117 	memcpy(line, lf->buffer, len);
2118 	line[len] = '\0';
2119 	argv = makeargv(line, &argc, 1, NULL, NULL);
2120 
2121 	/* Ensure cursor is at EOL or a argument boundary */
2122 	if (line[cursor] != ' ' && line[cursor] != '\0' &&
2123 	    line[cursor] != '\n') {
2124 		free(line);
2125 		return ret;
2126 	}
2127 
2128 	if (carg == 0) {
2129 		/* Show all available commands */
2130 		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
2131 		ret = CC_REDISPLAY;
2132 	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
2133 		/* Handle the command parsing */
2134 		if (complete_cmd_parse(el, argv[0], argc == carg,
2135 		    quote, terminated) != 0)
2136 			ret = CC_REDISPLAY;
2137 	} else if (carg >= 1) {
2138 		/* Handle file parsing */
2139 		int remote = complete_is_remote(argv[0]);
2140 		char *filematch = NULL;
2141 
2142 		if (carg > 1 && line[cursor-1] != ' ')
2143 			filematch = argv[carg - 1];
2144 
2145 		if (remote != 0 &&
2146 		    complete_match(el, complete_ctx->conn,
2147 		    *complete_ctx->remote_pathp, filematch,
2148 		    remote, carg == argc, quote, terminated) != 0)
2149 			ret = CC_REDISPLAY;
2150 	}
2151 
2152 	free(line);
2153 	return ret;
2154 }
2155 #endif /* USE_LIBEDIT */
2156 
2157 static int
interactive_loop(struct sftp_conn * conn,char * file1,char * file2)2158 interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2159 {
2160 	char *remote_path;
2161 	char *dir = NULL, *startdir = NULL;
2162 	char cmd[2048];
2163 	int err, interactive;
2164 	EditLine *el = NULL;
2165 #ifdef USE_LIBEDIT
2166 	History *hl = NULL;
2167 	HistEvent hev;
2168 	extern char *__progname;
2169 	struct complete_ctx complete_ctx;
2170 
2171 	if (!batchmode && isatty(STDIN_FILENO)) {
2172 		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
2173 			fatal("Couldn't initialise editline");
2174 		if ((hl = history_init()) == NULL)
2175 			fatal("Couldn't initialise editline history");
2176 		history(hl, &hev, H_SETSIZE, 100);
2177 		el_set(el, EL_HIST, history, hl);
2178 
2179 		el_set(el, EL_PROMPT, prompt);
2180 		el_set(el, EL_EDITOR, "emacs");
2181 		el_set(el, EL_TERMINAL, NULL);
2182 		el_set(el, EL_SIGNAL, 1);
2183 		el_source(el, NULL);
2184 
2185 		/* Tab Completion */
2186 		el_set(el, EL_ADDFN, "ftp-complete",
2187 		    "Context sensitive argument completion", complete);
2188 		complete_ctx.conn = conn;
2189 		complete_ctx.remote_pathp = &remote_path;
2190 		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
2191 		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
2192 		/* enable ctrl-left-arrow and ctrl-right-arrow */
2193 		el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
2194 		el_set(el, EL_BIND, "\\e\\e[C", "em-next-word", NULL);
2195 		el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
2196 		el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
2197 		/* make ^w match ksh behaviour */
2198 		el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL);
2199 	}
2200 #endif /* USE_LIBEDIT */
2201 
2202 	remote_path = do_realpath(conn, ".");
2203 	if (remote_path == NULL)
2204 		fatal("Need cwd");
2205 	startdir = xstrdup(remote_path);
2206 
2207 	if (file1 != NULL) {
2208 		dir = xstrdup(file1);
2209 		dir = make_absolute(dir, remote_path);
2210 
2211 		if (remote_is_dir(conn, dir) && file2 == NULL) {
2212 			if (!quiet)
2213 				mprintf("Changing to: %s\n", dir);
2214 			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
2215 			if (parse_dispatch_command(conn, cmd,
2216 			    &remote_path, startdir, 1, 0) != 0) {
2217 				free(dir);
2218 				free(startdir);
2219 				free(remote_path);
2220 				free(conn);
2221 				return (-1);
2222 			}
2223 		} else {
2224 			/* XXX this is wrong wrt quoting */
2225 			snprintf(cmd, sizeof cmd, "get%s %s%s%s",
2226 			    global_aflag ? " -a" : "", dir,
2227 			    file2 == NULL ? "" : " ",
2228 			    file2 == NULL ? "" : file2);
2229 			err = parse_dispatch_command(conn, cmd,
2230 			    &remote_path, startdir, 1, 0);
2231 			free(dir);
2232 			free(startdir);
2233 			free(remote_path);
2234 			free(conn);
2235 			return (err);
2236 		}
2237 		free(dir);
2238 	}
2239 
2240 	setvbuf(stdout, NULL, _IOLBF, 0);
2241 	setvbuf(infile, NULL, _IOLBF, 0);
2242 
2243 	interactive = !batchmode && isatty(STDIN_FILENO);
2244 	err = 0;
2245 	for (;;) {
2246 		ssh_signal(SIGINT, SIG_IGN);
2247 
2248 		if (el == NULL) {
2249 			if (interactive)
2250 				printf("sftp> ");
2251 			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
2252 				if (interactive)
2253 					printf("\n");
2254 				break;
2255 			}
2256 		} else {
2257 #ifdef USE_LIBEDIT
2258 			const char *line;
2259 			int count = 0;
2260 
2261 			if ((line = el_gets(el, &count)) == NULL ||
2262 			    count <= 0) {
2263 				printf("\n");
2264  				break;
2265 			}
2266 			history(hl, &hev, H_ENTER, line);
2267 			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
2268 				fprintf(stderr, "Error: input line too long\n");
2269 				continue;
2270 			}
2271 #endif /* USE_LIBEDIT */
2272 		}
2273 
2274 		cmd[strcspn(cmd, "\n")] = '\0';
2275 
2276 		/* Handle user interrupts gracefully during commands */
2277 		interrupted = 0;
2278 		ssh_signal(SIGINT, cmd_interrupt);
2279 
2280 		err = parse_dispatch_command(conn, cmd, &remote_path,
2281 		    startdir, batchmode, !interactive && el == NULL);
2282 		if (err != 0)
2283 			break;
2284 	}
2285 	ssh_signal(SIGCHLD, SIG_DFL);
2286 	free(remote_path);
2287 	free(startdir);
2288 	free(conn);
2289 
2290 #ifdef USE_LIBEDIT
2291 	if (el != NULL)
2292 		el_end(el);
2293 #endif /* USE_LIBEDIT */
2294 
2295 	/* err == 1 signifies normal "quit" exit */
2296 	return (err >= 0 ? 0 : -1);
2297 }
2298 
2299 static void
connect_to_server(char * path,char ** args,int * in,int * out)2300 connect_to_server(char *path, char **args, int *in, int *out)
2301 {
2302 	int c_in, c_out;
2303 
2304 #ifdef USE_PIPES
2305 	int pin[2], pout[2];
2306 
2307 	if ((pipe(pin) == -1) || (pipe(pout) == -1))
2308 		fatal("pipe: %s", strerror(errno));
2309 	*in = pin[0];
2310 	*out = pout[1];
2311 	c_in = pout[0];
2312 	c_out = pin[1];
2313 #else /* USE_PIPES */
2314 	int inout[2];
2315 
2316 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2317 		fatal("socketpair: %s", strerror(errno));
2318 	*in = *out = inout[0];
2319 	c_in = c_out = inout[1];
2320 #endif /* USE_PIPES */
2321 
2322 	if ((sshpid = fork()) == -1)
2323 		fatal("fork: %s", strerror(errno));
2324 	else if (sshpid == 0) {
2325 		if ((dup2(c_in, STDIN_FILENO) == -1) ||
2326 		    (dup2(c_out, STDOUT_FILENO) == -1)) {
2327 			fprintf(stderr, "dup2: %s\n", strerror(errno));
2328 			_exit(1);
2329 		}
2330 		close(*in);
2331 		close(*out);
2332 		close(c_in);
2333 		close(c_out);
2334 
2335 		/*
2336 		 * The underlying ssh is in the same process group, so we must
2337 		 * ignore SIGINT if we want to gracefully abort commands,
2338 		 * otherwise the signal will make it to the ssh process and
2339 		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2340 		 * underlying ssh, it must *not* ignore that signal.
2341 		 */
2342 		ssh_signal(SIGINT, SIG_IGN);
2343 		ssh_signal(SIGTERM, SIG_DFL);
2344 		execvp(path, args);
2345 		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2346 		_exit(1);
2347 	}
2348 
2349 	ssh_signal(SIGTERM, killchild);
2350 	ssh_signal(SIGINT, killchild);
2351 	ssh_signal(SIGHUP, killchild);
2352 	ssh_signal(SIGTSTP, suspchild);
2353 	ssh_signal(SIGTTIN, suspchild);
2354 	ssh_signal(SIGTTOU, suspchild);
2355 	ssh_signal(SIGCHLD, sigchld_handler);
2356 	close(c_in);
2357 	close(c_out);
2358 }
2359 
2360 static void
usage(void)2361 usage(void)
2362 {
2363 	extern char *__progname;
2364 
2365 	fprintf(stderr,
2366 	    "usage: %s [-46AaCfNpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2367 	    "          [-D sftp_server_path] [-F ssh_config] [-i identity_file]\n"
2368 	    "          [-J destination] [-l limit] [-o ssh_option] [-P port]\n"
2369 	    "          [-R num_requests] [-S program] [-s subsystem | sftp_server]\n"
2370 	    "          destination\n",
2371 	    __progname);
2372 	exit(1);
2373 }
2374 
2375 int
main(int argc,char ** argv)2376 main(int argc, char **argv)
2377 {
2378 	int in, out, ch, err, tmp, port = -1, noisy = 0;
2379 	char *host = NULL, *user, *cp, *file2 = NULL;
2380 	int debug_level = 0;
2381 	char *file1 = NULL, *sftp_server = NULL;
2382 	char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2383 	const char *errstr;
2384 	LogLevel ll = SYSLOG_LEVEL_INFO;
2385 	arglist args;
2386 	extern int optind;
2387 	extern char *optarg;
2388 	struct sftp_conn *conn;
2389 	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2390 	size_t num_requests = DEFAULT_NUM_REQUESTS;
2391 	long long limit_kbps = 0;
2392 
2393 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2394 	sanitise_stdfd();
2395 	msetlocale();
2396 
2397 	seed_rng();
2398 
2399 	__progname = ssh_get_progname(argv[0]);
2400 	memset(&args, '\0', sizeof(args));
2401 	args.list = NULL;
2402 	addargs(&args, "%s", ssh_program);
2403 	addargs(&args, "-oForwardX11 no");
2404 	addargs(&args, "-oPermitLocalCommand no");
2405 	addargs(&args, "-oClearAllForwardings yes");
2406 
2407 	ll = SYSLOG_LEVEL_INFO;
2408 	infile = stdin;
2409 
2410 	while ((ch = getopt(argc, argv,
2411 	    "1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) {
2412 		switch (ch) {
2413 		/* Passed through to ssh(1) */
2414 		case 'A':
2415 		case '4':
2416 		case '6':
2417 		case 'C':
2418 			addargs(&args, "-%c", ch);
2419 			break;
2420 		/* Passed through to ssh(1) with argument */
2421 		case 'F':
2422 		case 'J':
2423 		case 'c':
2424 		case 'i':
2425 		case 'o':
2426 			addargs(&args, "-%c", ch);
2427 			addargs(&args, "%s", optarg);
2428 			break;
2429 		case 'q':
2430 			ll = SYSLOG_LEVEL_ERROR;
2431 			quiet = 1;
2432 			showprogress = 0;
2433 			addargs(&args, "-%c", ch);
2434 			break;
2435 		case 'P':
2436 			port = a2port(optarg);
2437 			if (port <= 0)
2438 				fatal("Bad port \"%s\"\n", optarg);
2439 			break;
2440 		case 'v':
2441 			if (debug_level < 3) {
2442 				addargs(&args, "-v");
2443 				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2444 			}
2445 			debug_level++;
2446 			break;
2447 		case '1':
2448 			fatal("SSH protocol v.1 is no longer supported");
2449 			break;
2450 		case '2':
2451 			/* accept silently */
2452 			break;
2453 		case 'a':
2454 			global_aflag = 1;
2455 			break;
2456 		case 'B':
2457 			copy_buffer_len = strtol(optarg, &cp, 10);
2458 			if (copy_buffer_len == 0 || *cp != '\0')
2459 				fatal("Invalid buffer size \"%s\"", optarg);
2460 			break;
2461 		case 'b':
2462 			if (batchmode)
2463 				fatal("Batch file already specified.");
2464 
2465 			/* Allow "-" as stdin */
2466 			if (strcmp(optarg, "-") != 0 &&
2467 			    (infile = fopen(optarg, "r")) == NULL)
2468 				fatal("%s (%s).", strerror(errno), optarg);
2469 			showprogress = 0;
2470 			quiet = batchmode = 1;
2471 			addargs(&args, "-obatchmode yes");
2472 			break;
2473 		case 'f':
2474 			global_fflag = 1;
2475 			break;
2476 		case 'N':
2477 			noisy = 1; /* Used to clear quiet mode after getopt */
2478 			break;
2479 		case 'p':
2480 			global_pflag = 1;
2481 			break;
2482 		case 'D':
2483 			sftp_direct = optarg;
2484 			break;
2485 		case 'l':
2486 			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2487 			    &errstr);
2488 			if (errstr != NULL)
2489 				usage();
2490 			limit_kbps *= 1024; /* kbps */
2491 			break;
2492 		case 'r':
2493 			global_rflag = 1;
2494 			break;
2495 		case 'R':
2496 			num_requests = strtol(optarg, &cp, 10);
2497 			if (num_requests == 0 || *cp != '\0')
2498 				fatal("Invalid number of requests \"%s\"",
2499 				    optarg);
2500 			break;
2501 		case 's':
2502 			sftp_server = optarg;
2503 			break;
2504 		case 'S':
2505 			ssh_program = optarg;
2506 			replacearg(&args, 0, "%s", ssh_program);
2507 			break;
2508 		case 'h':
2509 		default:
2510 			usage();
2511 		}
2512 	}
2513 
2514 	/* Do this last because we want the user to be able to override it */
2515 	addargs(&args, "-oForwardAgent no");
2516 
2517 	if (!isatty(STDERR_FILENO))
2518 		showprogress = 0;
2519 
2520 	if (noisy)
2521 		quiet = 0;
2522 
2523 	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2524 
2525 	if (sftp_direct == NULL) {
2526 		if (optind == argc || argc > (optind + 2))
2527 			usage();
2528 		argv += optind;
2529 
2530 		switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) {
2531 		case -1:
2532 			usage();
2533 			break;
2534 		case 0:
2535 			if (tmp != -1)
2536 				port = tmp;
2537 			break;
2538 		default:
2539 			/* Try with user, host and path. */
2540 			if (parse_user_host_path(*argv, &user, &host,
2541 			    &file1) == 0)
2542 				break;
2543 			/* Try with user and host. */
2544 			if (parse_user_host_port(*argv, &user, &host, NULL)
2545 			    == 0)
2546 				break;
2547 			/* Treat as a plain hostname. */
2548 			host = xstrdup(*argv);
2549 			host = cleanhostname(host);
2550 			break;
2551 		}
2552 		file2 = *(argv + 1);
2553 
2554 		if (!*host) {
2555 			fprintf(stderr, "Missing hostname\n");
2556 			usage();
2557 		}
2558 
2559 		if (port != -1)
2560 			addargs(&args, "-oPort %d", port);
2561 		if (user != NULL) {
2562 			addargs(&args, "-l");
2563 			addargs(&args, "%s", user);
2564 		}
2565 
2566 		/* no subsystem if the server-spec contains a '/' */
2567 		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2568 			addargs(&args, "-s");
2569 
2570 		addargs(&args, "--");
2571 		addargs(&args, "%s", host);
2572 		addargs(&args, "%s", (sftp_server != NULL ?
2573 		    sftp_server : "sftp"));
2574 
2575 		connect_to_server(ssh_program, args.list, &in, &out);
2576 	} else {
2577 		args.list = NULL;
2578 		addargs(&args, "sftp-server");
2579 
2580 		connect_to_server(sftp_direct, args.list, &in, &out);
2581 	}
2582 	freeargs(&args);
2583 
2584 	conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2585 	if (conn == NULL)
2586 		fatal("Couldn't initialise connection to server");
2587 
2588 	if (!quiet) {
2589 		if (sftp_direct == NULL)
2590 			fprintf(stderr, "Connected to %s.\n", host);
2591 		else
2592 			fprintf(stderr, "Attached to %s.\n", sftp_direct);
2593 	}
2594 
2595 	err = interactive_loop(conn, file1, file2);
2596 
2597 #if !defined(USE_PIPES)
2598 	shutdown(in, SHUT_RDWR);
2599 	shutdown(out, SHUT_RDWR);
2600 #endif
2601 
2602 	close(in);
2603 	close(out);
2604 	if (batchmode)
2605 		fclose(infile);
2606 
2607 	while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1)
2608 		if (errno != EINTR)
2609 			fatal("Couldn't wait for ssh process: %s",
2610 			    strerror(errno));
2611 
2612 	exit(err == 0 ? 0 : 1);
2613 }
2614