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