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