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