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