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