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