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