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