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