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