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