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