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