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