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