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