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