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