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