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