1 /* $OpenBSD: sftp.c,v 1.190 2019/01/21 22:50:42 tb 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 [-h] grp path Change group of file 'path' to 'grp'\n" 282 "chmod [-h] mode path Change permissions of file 'path' to 'mode'\n" 283 "chown [-h] 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_ch_flags(const char *cmd, char **argv, int argc, int *hflag) 566 { 567 extern int opterr, optind, optopt, optreset; 568 int ch; 569 570 optind = optreset = 1; 571 opterr = 0; 572 573 *hflag = 0; 574 while ((ch = getopt(argc, argv, "h")) != -1) { 575 switch (ch) { 576 case 'h': 577 *hflag = 1; 578 break; 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 parse_no_flags(const char *cmd, char **argv, int argc) 590 { 591 extern int opterr, optind, optopt, optreset; 592 int ch; 593 594 optind = optreset = 1; 595 opterr = 0; 596 597 while ((ch = getopt(argc, argv, "")) != -1) { 598 switch (ch) { 599 default: 600 error("%s: Invalid flag -%c", cmd, optopt); 601 return -1; 602 } 603 } 604 605 return optind; 606 } 607 608 static int 609 is_dir(const char *path) 610 { 611 struct stat sb; 612 613 /* XXX: report errors? */ 614 if (stat(path, &sb) == -1) 615 return(0); 616 617 return(S_ISDIR(sb.st_mode)); 618 } 619 620 static int 621 remote_is_dir(struct sftp_conn *conn, const char *path) 622 { 623 Attrib *a; 624 625 /* XXX: report errors? */ 626 if ((a = do_stat(conn, path, 1)) == NULL) 627 return(0); 628 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) 629 return(0); 630 return(S_ISDIR(a->perm)); 631 } 632 633 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ 634 static int 635 pathname_is_dir(const char *pathname) 636 { 637 size_t l = strlen(pathname); 638 639 return l > 0 && pathname[l - 1] == '/'; 640 } 641 642 static int 643 process_get(struct sftp_conn *conn, const char *src, const char *dst, 644 const char *pwd, int pflag, int rflag, int resume, int fflag) 645 { 646 char *abs_src = NULL; 647 char *abs_dst = NULL; 648 glob_t g; 649 char *filename, *tmp=NULL; 650 int i, r, err = 0; 651 652 abs_src = xstrdup(src); 653 abs_src = make_absolute(abs_src, pwd); 654 memset(&g, 0, sizeof(g)); 655 656 debug3("Looking up %s", abs_src); 657 if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) { 658 if (r == GLOB_NOSPACE) { 659 error("Too many matches for \"%s\".", abs_src); 660 } else { 661 error("File \"%s\" not found.", abs_src); 662 } 663 err = -1; 664 goto out; 665 } 666 667 /* 668 * If multiple matches then dst must be a directory or 669 * unspecified. 670 */ 671 if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { 672 error("Multiple source paths, but destination " 673 "\"%s\" is not a directory", dst); 674 err = -1; 675 goto out; 676 } 677 678 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 679 tmp = xstrdup(g.gl_pathv[i]); 680 if ((filename = basename(tmp)) == NULL) { 681 error("basename %s: %s", tmp, strerror(errno)); 682 free(tmp); 683 err = -1; 684 goto out; 685 } 686 687 if (g.gl_matchc == 1 && dst) { 688 if (is_dir(dst)) { 689 abs_dst = path_append(dst, filename); 690 } else { 691 abs_dst = xstrdup(dst); 692 } 693 } else if (dst) { 694 abs_dst = path_append(dst, filename); 695 } else { 696 abs_dst = xstrdup(filename); 697 } 698 free(tmp); 699 700 resume |= global_aflag; 701 if (!quiet && resume) 702 mprintf("Resuming %s to %s\n", 703 g.gl_pathv[i], abs_dst); 704 else if (!quiet && !resume) 705 mprintf("Fetching %s to %s\n", 706 g.gl_pathv[i], abs_dst); 707 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 708 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 709 pflag || global_pflag, 1, resume, 710 fflag || global_fflag) == -1) 711 err = -1; 712 } else { 713 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, 714 pflag || global_pflag, resume, 715 fflag || global_fflag) == -1) 716 err = -1; 717 } 718 free(abs_dst); 719 abs_dst = NULL; 720 } 721 722 out: 723 free(abs_src); 724 globfree(&g); 725 return(err); 726 } 727 728 static int 729 process_put(struct sftp_conn *conn, const char *src, const char *dst, 730 const char *pwd, int pflag, int rflag, int resume, int fflag) 731 { 732 char *tmp_dst = NULL; 733 char *abs_dst = NULL; 734 char *tmp = NULL, *filename = NULL; 735 glob_t g; 736 int err = 0; 737 int i, dst_is_dir = 1; 738 struct stat sb; 739 740 if (dst) { 741 tmp_dst = xstrdup(dst); 742 tmp_dst = make_absolute(tmp_dst, pwd); 743 } 744 745 memset(&g, 0, sizeof(g)); 746 debug3("Looking up %s", src); 747 if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { 748 error("File \"%s\" not found.", src); 749 err = -1; 750 goto out; 751 } 752 753 /* If we aren't fetching to pwd then stash this status for later */ 754 if (tmp_dst != NULL) 755 dst_is_dir = remote_is_dir(conn, tmp_dst); 756 757 /* If multiple matches, dst may be directory or unspecified */ 758 if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { 759 error("Multiple paths match, but destination " 760 "\"%s\" is not a directory", tmp_dst); 761 err = -1; 762 goto out; 763 } 764 765 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 766 if (stat(g.gl_pathv[i], &sb) == -1) { 767 err = -1; 768 error("stat %s: %s", g.gl_pathv[i], strerror(errno)); 769 continue; 770 } 771 772 tmp = xstrdup(g.gl_pathv[i]); 773 if ((filename = basename(tmp)) == NULL) { 774 error("basename %s: %s", tmp, strerror(errno)); 775 free(tmp); 776 err = -1; 777 goto out; 778 } 779 780 if (g.gl_matchc == 1 && tmp_dst) { 781 /* If directory specified, append filename */ 782 if (dst_is_dir) 783 abs_dst = path_append(tmp_dst, filename); 784 else 785 abs_dst = xstrdup(tmp_dst); 786 } else if (tmp_dst) { 787 abs_dst = path_append(tmp_dst, filename); 788 } else { 789 abs_dst = make_absolute(xstrdup(filename), pwd); 790 } 791 free(tmp); 792 793 resume |= global_aflag; 794 if (!quiet && resume) 795 mprintf("Resuming upload of %s to %s\n", 796 g.gl_pathv[i], abs_dst); 797 else if (!quiet && !resume) 798 mprintf("Uploading %s to %s\n", 799 g.gl_pathv[i], abs_dst); 800 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 801 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 802 pflag || global_pflag, 1, resume, 803 fflag || global_fflag) == -1) 804 err = -1; 805 } else { 806 if (do_upload(conn, g.gl_pathv[i], abs_dst, 807 pflag || global_pflag, resume, 808 fflag || global_fflag) == -1) 809 err = -1; 810 } 811 } 812 813 out: 814 free(abs_dst); 815 free(tmp_dst); 816 globfree(&g); 817 return(err); 818 } 819 820 static int 821 sdirent_comp(const void *aa, const void *bb) 822 { 823 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; 824 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; 825 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 826 827 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 828 if (sort_flag & LS_NAME_SORT) 829 return (rmul * strcmp(a->filename, b->filename)); 830 else if (sort_flag & LS_TIME_SORT) 831 return (rmul * NCMP(a->a.mtime, b->a.mtime)); 832 else if (sort_flag & LS_SIZE_SORT) 833 return (rmul * NCMP(a->a.size, b->a.size)); 834 835 fatal("Unknown ls sort type"); 836 } 837 838 /* sftp ls.1 replacement for directories */ 839 static int 840 do_ls_dir(struct sftp_conn *conn, const char *path, 841 const char *strip_path, int lflag) 842 { 843 int n; 844 u_int c = 1, colspace = 0, columns = 1; 845 SFTP_DIRENT **d; 846 847 if ((n = do_readdir(conn, path, &d)) != 0) 848 return (n); 849 850 if (!(lflag & LS_SHORT_VIEW)) { 851 u_int m = 0, width = 80; 852 struct winsize ws; 853 char *tmp; 854 855 /* Count entries for sort and find longest filename */ 856 for (n = 0; d[n] != NULL; n++) { 857 if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) 858 m = MAXIMUM(m, strlen(d[n]->filename)); 859 } 860 861 /* Add any subpath that also needs to be counted */ 862 tmp = path_strip(path, strip_path); 863 m += strlen(tmp); 864 free(tmp); 865 866 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 867 width = ws.ws_col; 868 869 columns = width / (m + 2); 870 columns = MAXIMUM(columns, 1); 871 colspace = width / columns; 872 colspace = MINIMUM(colspace, width); 873 } 874 875 if (lflag & SORT_FLAGS) { 876 for (n = 0; d[n] != NULL; n++) 877 ; /* count entries */ 878 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 879 qsort(d, n, sizeof(*d), sdirent_comp); 880 } 881 882 for (n = 0; d[n] != NULL && !interrupted; n++) { 883 char *tmp, *fname; 884 885 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) 886 continue; 887 888 tmp = path_append(path, d[n]->filename); 889 fname = path_strip(tmp, strip_path); 890 free(tmp); 891 892 if (lflag & LS_LONG_VIEW) { 893 if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { 894 char *lname; 895 struct stat sb; 896 897 memset(&sb, 0, sizeof(sb)); 898 attrib_to_stat(&d[n]->a, &sb); 899 lname = ls_file(fname, &sb, 1, 900 (lflag & LS_SI_UNITS)); 901 mprintf("%s\n", lname); 902 free(lname); 903 } else 904 mprintf("%s\n", d[n]->longname); 905 } else { 906 mprintf("%-*s", colspace, fname); 907 if (c >= columns) { 908 printf("\n"); 909 c = 1; 910 } else 911 c++; 912 } 913 914 free(fname); 915 } 916 917 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 918 printf("\n"); 919 920 free_sftp_dirents(d); 921 return (0); 922 } 923 924 static int 925 sglob_comp(const void *aa, const void *bb) 926 { 927 u_int a = *(const u_int *)aa; 928 u_int b = *(const u_int *)bb; 929 const char *ap = sort_glob->gl_pathv[a]; 930 const char *bp = sort_glob->gl_pathv[b]; 931 const struct stat *as = sort_glob->gl_statv[a]; 932 const struct stat *bs = sort_glob->gl_statv[b]; 933 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 934 935 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 936 if (sort_flag & LS_NAME_SORT) 937 return (rmul * strcmp(ap, bp)); 938 else if (sort_flag & LS_TIME_SORT) { 939 #if defined(HAVE_STRUCT_STAT_ST_MTIM) 940 return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <)); 941 #elif defined(HAVE_STRUCT_STAT_ST_MTIME) 942 return (rmul * NCMP(as->st_mtime, bs->st_mtime)); 943 #else 944 return rmul * 1; 945 #endif 946 } else if (sort_flag & LS_SIZE_SORT) 947 return (rmul * NCMP(as->st_size, bs->st_size)); 948 949 fatal("Unknown ls sort type"); 950 } 951 952 /* sftp ls.1 replacement which handles path globs */ 953 static int 954 do_globbed_ls(struct sftp_conn *conn, const char *path, 955 const char *strip_path, int lflag) 956 { 957 char *fname, *lname; 958 glob_t g; 959 int err, r; 960 struct winsize ws; 961 u_int i, j, nentries, *indices = NULL, c = 1; 962 u_int colspace = 0, columns = 1, m = 0, width = 80; 963 964 memset(&g, 0, sizeof(g)); 965 966 if ((r = remote_glob(conn, path, 967 GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, 968 NULL, &g)) != 0 || 969 (g.gl_pathc && !g.gl_matchc)) { 970 if (g.gl_pathc) 971 globfree(&g); 972 if (r == GLOB_NOSPACE) { 973 error("Can't ls: Too many matches for \"%s\"", path); 974 } else { 975 error("Can't ls: \"%s\" not found", path); 976 } 977 return -1; 978 } 979 980 if (interrupted) 981 goto out; 982 983 /* 984 * If the glob returns a single match and it is a directory, 985 * then just list its contents. 986 */ 987 if (g.gl_matchc == 1 && g.gl_statv[0] != NULL && 988 S_ISDIR(g.gl_statv[0]->st_mode)) { 989 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); 990 globfree(&g); 991 return err; 992 } 993 994 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 995 width = ws.ws_col; 996 997 if (!(lflag & LS_SHORT_VIEW)) { 998 /* Count entries for sort and find longest filename */ 999 for (i = 0; g.gl_pathv[i]; i++) 1000 m = MAXIMUM(m, strlen(g.gl_pathv[i])); 1001 1002 columns = width / (m + 2); 1003 columns = MAXIMUM(columns, 1); 1004 colspace = width / columns; 1005 } 1006 1007 /* 1008 * Sorting: rather than mess with the contents of glob_t, prepare 1009 * an array of indices into it and sort that. For the usual 1010 * unsorted case, the indices are just the identity 1=1, 2=2, etc. 1011 */ 1012 for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++) 1013 ; /* count entries */ 1014 indices = calloc(nentries, sizeof(*indices)); 1015 for (i = 0; i < nentries; i++) 1016 indices[i] = i; 1017 1018 if (lflag & SORT_FLAGS) { 1019 sort_glob = &g; 1020 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 1021 qsort(indices, nentries, sizeof(*indices), sglob_comp); 1022 sort_glob = NULL; 1023 } 1024 1025 for (j = 0; j < nentries && !interrupted; j++) { 1026 i = indices[j]; 1027 fname = path_strip(g.gl_pathv[i], strip_path); 1028 if (lflag & LS_LONG_VIEW) { 1029 if (g.gl_statv[i] == NULL) { 1030 error("no stat information for %s", fname); 1031 continue; 1032 } 1033 lname = ls_file(fname, g.gl_statv[i], 1, 1034 (lflag & LS_SI_UNITS)); 1035 mprintf("%s\n", lname); 1036 free(lname); 1037 } else { 1038 mprintf("%-*s", colspace, fname); 1039 if (c >= columns) { 1040 printf("\n"); 1041 c = 1; 1042 } else 1043 c++; 1044 } 1045 free(fname); 1046 } 1047 1048 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 1049 printf("\n"); 1050 1051 out: 1052 if (g.gl_pathc) 1053 globfree(&g); 1054 free(indices); 1055 1056 return 0; 1057 } 1058 1059 static int 1060 do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag) 1061 { 1062 struct sftp_statvfs st; 1063 char s_used[FMT_SCALED_STRSIZE], s_avail[FMT_SCALED_STRSIZE]; 1064 char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE]; 1065 char s_icapacity[16], s_dcapacity[16]; 1066 1067 if (do_statvfs(conn, path, &st, 1) == -1) 1068 return -1; 1069 if (st.f_files == 0) 1070 strlcpy(s_icapacity, "ERR", sizeof(s_icapacity)); 1071 else { 1072 snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%", 1073 (unsigned long long)(100 * (st.f_files - st.f_ffree) / 1074 st.f_files)); 1075 } 1076 if (st.f_blocks == 0) 1077 strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity)); 1078 else { 1079 snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%", 1080 (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / 1081 st.f_blocks)); 1082 } 1083 if (iflag) { 1084 printf(" Inodes Used Avail " 1085 "(root) %%Capacity\n"); 1086 printf("%11llu %11llu %11llu %11llu %s\n", 1087 (unsigned long long)st.f_files, 1088 (unsigned long long)(st.f_files - st.f_ffree), 1089 (unsigned long long)st.f_favail, 1090 (unsigned long long)st.f_ffree, s_icapacity); 1091 } else if (hflag) { 1092 strlcpy(s_used, "error", sizeof(s_used)); 1093 strlcpy(s_avail, "error", sizeof(s_avail)); 1094 strlcpy(s_root, "error", sizeof(s_root)); 1095 strlcpy(s_total, "error", sizeof(s_total)); 1096 fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); 1097 fmt_scaled(st.f_bavail * st.f_frsize, s_avail); 1098 fmt_scaled(st.f_bfree * st.f_frsize, s_root); 1099 fmt_scaled(st.f_blocks * st.f_frsize, s_total); 1100 printf(" Size Used Avail (root) %%Capacity\n"); 1101 printf("%7sB %7sB %7sB %7sB %s\n", 1102 s_total, s_used, s_avail, s_root, s_dcapacity); 1103 } else { 1104 printf(" Size Used Avail " 1105 "(root) %%Capacity\n"); 1106 printf("%12llu %12llu %12llu %12llu %s\n", 1107 (unsigned long long)(st.f_frsize * st.f_blocks / 1024), 1108 (unsigned long long)(st.f_frsize * 1109 (st.f_blocks - st.f_bfree) / 1024), 1110 (unsigned long long)(st.f_frsize * st.f_bavail / 1024), 1111 (unsigned long long)(st.f_frsize * st.f_bfree / 1024), 1112 s_dcapacity); 1113 } 1114 return 0; 1115 } 1116 1117 /* 1118 * Undo escaping of glob sequences in place. Used to undo extra escaping 1119 * applied in makeargv() when the string is destined for a function that 1120 * does not glob it. 1121 */ 1122 static void 1123 undo_glob_escape(char *s) 1124 { 1125 size_t i, j; 1126 1127 for (i = j = 0;;) { 1128 if (s[i] == '\0') { 1129 s[j] = '\0'; 1130 return; 1131 } 1132 if (s[i] != '\\') { 1133 s[j++] = s[i++]; 1134 continue; 1135 } 1136 /* s[i] == '\\' */ 1137 ++i; 1138 switch (s[i]) { 1139 case '?': 1140 case '[': 1141 case '*': 1142 case '\\': 1143 s[j++] = s[i++]; 1144 break; 1145 case '\0': 1146 s[j++] = '\\'; 1147 s[j] = '\0'; 1148 return; 1149 default: 1150 s[j++] = '\\'; 1151 s[j++] = s[i++]; 1152 break; 1153 } 1154 } 1155 } 1156 1157 /* 1158 * Split a string into an argument vector using sh(1)-style quoting, 1159 * comment and escaping rules, but with some tweaks to handle glob(3) 1160 * wildcards. 1161 * The "sloppy" flag allows for recovery from missing terminating quote, for 1162 * use in parsing incomplete commandlines during tab autocompletion. 1163 * 1164 * Returns NULL on error or a NULL-terminated array of arguments. 1165 * 1166 * If "lastquote" is not NULL, the quoting character used for the last 1167 * argument is placed in *lastquote ("\0", "'" or "\""). 1168 * 1169 * If "terminated" is not NULL, *terminated will be set to 1 when the 1170 * last argument's quote has been properly terminated or 0 otherwise. 1171 * This parameter is only of use if "sloppy" is set. 1172 */ 1173 #define MAXARGS 128 1174 #define MAXARGLEN 8192 1175 static char ** 1176 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, 1177 u_int *terminated) 1178 { 1179 int argc, quot; 1180 size_t i, j; 1181 static char argvs[MAXARGLEN]; 1182 static char *argv[MAXARGS + 1]; 1183 enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q; 1184 1185 *argcp = argc = 0; 1186 if (strlen(arg) > sizeof(argvs) - 1) { 1187 args_too_longs: 1188 error("string too long"); 1189 return NULL; 1190 } 1191 if (terminated != NULL) 1192 *terminated = 1; 1193 if (lastquote != NULL) 1194 *lastquote = '\0'; 1195 state = MA_START; 1196 i = j = 0; 1197 for (;;) { 1198 if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){ 1199 error("Too many arguments."); 1200 return NULL; 1201 } 1202 if (isspace((unsigned char)arg[i])) { 1203 if (state == MA_UNQUOTED) { 1204 /* Terminate current argument */ 1205 argvs[j++] = '\0'; 1206 argc++; 1207 state = MA_START; 1208 } else if (state != MA_START) 1209 argvs[j++] = arg[i]; 1210 } else if (arg[i] == '"' || arg[i] == '\'') { 1211 q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE; 1212 if (state == MA_START) { 1213 argv[argc] = argvs + j; 1214 state = q; 1215 if (lastquote != NULL) 1216 *lastquote = arg[i]; 1217 } else if (state == MA_UNQUOTED) 1218 state = q; 1219 else if (state == q) 1220 state = MA_UNQUOTED; 1221 else 1222 argvs[j++] = arg[i]; 1223 } else if (arg[i] == '\\') { 1224 if (state == MA_SQUOTE || state == MA_DQUOTE) { 1225 quot = state == MA_SQUOTE ? '\'' : '"'; 1226 /* Unescape quote we are in */ 1227 /* XXX support \n and friends? */ 1228 if (arg[i + 1] == quot) { 1229 i++; 1230 argvs[j++] = arg[i]; 1231 } else if (arg[i + 1] == '?' || 1232 arg[i + 1] == '[' || arg[i + 1] == '*') { 1233 /* 1234 * Special case for sftp: append 1235 * double-escaped glob sequence - 1236 * glob will undo one level of 1237 * escaping. NB. string can grow here. 1238 */ 1239 if (j >= sizeof(argvs) - 5) 1240 goto args_too_longs; 1241 argvs[j++] = '\\'; 1242 argvs[j++] = arg[i++]; 1243 argvs[j++] = '\\'; 1244 argvs[j++] = arg[i]; 1245 } else { 1246 argvs[j++] = arg[i++]; 1247 argvs[j++] = arg[i]; 1248 } 1249 } else { 1250 if (state == MA_START) { 1251 argv[argc] = argvs + j; 1252 state = MA_UNQUOTED; 1253 if (lastquote != NULL) 1254 *lastquote = '\0'; 1255 } 1256 if (arg[i + 1] == '?' || arg[i + 1] == '[' || 1257 arg[i + 1] == '*' || arg[i + 1] == '\\') { 1258 /* 1259 * Special case for sftp: append 1260 * escaped glob sequence - 1261 * glob will undo one level of 1262 * escaping. 1263 */ 1264 argvs[j++] = arg[i++]; 1265 argvs[j++] = arg[i]; 1266 } else { 1267 /* Unescape everything */ 1268 /* XXX support \n and friends? */ 1269 i++; 1270 argvs[j++] = arg[i]; 1271 } 1272 } 1273 } else if (arg[i] == '#') { 1274 if (state == MA_SQUOTE || state == MA_DQUOTE) 1275 argvs[j++] = arg[i]; 1276 else 1277 goto string_done; 1278 } else if (arg[i] == '\0') { 1279 if (state == MA_SQUOTE || state == MA_DQUOTE) { 1280 if (sloppy) { 1281 state = MA_UNQUOTED; 1282 if (terminated != NULL) 1283 *terminated = 0; 1284 goto string_done; 1285 } 1286 error("Unterminated quoted argument"); 1287 return NULL; 1288 } 1289 string_done: 1290 if (state == MA_UNQUOTED) { 1291 argvs[j++] = '\0'; 1292 argc++; 1293 } 1294 break; 1295 } else { 1296 if (state == MA_START) { 1297 argv[argc] = argvs + j; 1298 state = MA_UNQUOTED; 1299 if (lastquote != NULL) 1300 *lastquote = '\0'; 1301 } 1302 if ((state == MA_SQUOTE || state == MA_DQUOTE) && 1303 (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) { 1304 /* 1305 * Special case for sftp: escape quoted 1306 * glob(3) wildcards. NB. string can grow 1307 * here. 1308 */ 1309 if (j >= sizeof(argvs) - 3) 1310 goto args_too_longs; 1311 argvs[j++] = '\\'; 1312 argvs[j++] = arg[i]; 1313 } else 1314 argvs[j++] = arg[i]; 1315 } 1316 i++; 1317 } 1318 *argcp = argc; 1319 return argv; 1320 } 1321 1322 static int 1323 parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag, 1324 int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, 1325 int *rflag, int *sflag, 1326 unsigned long *n_arg, char **path1, char **path2) 1327 { 1328 const char *cmd, *cp = *cpp; 1329 char *cp2, **argv; 1330 int base = 0; 1331 long l; 1332 int path1_mandatory = 0, i, cmdnum, optidx, argc; 1333 1334 /* Skip leading whitespace */ 1335 cp = cp + strspn(cp, WHITESPACE); 1336 1337 /* 1338 * Check for leading '-' (disable error processing) and '@' (suppress 1339 * command echo) 1340 */ 1341 *ignore_errors = 0; 1342 *disable_echo = 0; 1343 for (;*cp != '\0'; cp++) { 1344 if (*cp == '-') { 1345 *ignore_errors = 1; 1346 } else if (*cp == '@') { 1347 *disable_echo = 1; 1348 } else { 1349 /* all other characters terminate prefix processing */ 1350 break; 1351 } 1352 } 1353 cp = cp + strspn(cp, WHITESPACE); 1354 1355 /* Ignore blank lines and lines which begin with comment '#' char */ 1356 if (*cp == '\0' || *cp == '#') 1357 return (0); 1358 1359 if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL) 1360 return -1; 1361 1362 /* Figure out which command we have */ 1363 for (i = 0; cmds[i].c != NULL; i++) { 1364 if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0) 1365 break; 1366 } 1367 cmdnum = cmds[i].n; 1368 cmd = cmds[i].c; 1369 1370 /* Special case */ 1371 if (*cp == '!') { 1372 cp++; 1373 cmdnum = I_SHELL; 1374 } else if (cmdnum == -1) { 1375 error("Invalid command."); 1376 return -1; 1377 } 1378 1379 /* Get arguments and parse flags */ 1380 *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0; 1381 *rflag = *sflag = 0; 1382 *path1 = *path2 = NULL; 1383 optidx = 1; 1384 switch (cmdnum) { 1385 case I_GET: 1386 case I_REGET: 1387 case I_REPUT: 1388 case I_PUT: 1389 if ((optidx = parse_getput_flags(cmd, argv, argc, 1390 aflag, fflag, pflag, rflag)) == -1) 1391 return -1; 1392 /* Get first pathname (mandatory) */ 1393 if (argc - optidx < 1) { 1394 error("You must specify at least one path after a " 1395 "%s command.", cmd); 1396 return -1; 1397 } 1398 *path1 = xstrdup(argv[optidx]); 1399 /* Get second pathname (optional) */ 1400 if (argc - optidx > 1) { 1401 *path2 = xstrdup(argv[optidx + 1]); 1402 /* Destination is not globbed */ 1403 undo_glob_escape(*path2); 1404 } 1405 break; 1406 case I_LINK: 1407 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) 1408 return -1; 1409 goto parse_two_paths; 1410 case I_RENAME: 1411 if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1) 1412 return -1; 1413 goto parse_two_paths; 1414 case I_SYMLINK: 1415 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1416 return -1; 1417 parse_two_paths: 1418 if (argc - optidx < 2) { 1419 error("You must specify two paths after a %s " 1420 "command.", cmd); 1421 return -1; 1422 } 1423 *path1 = xstrdup(argv[optidx]); 1424 *path2 = xstrdup(argv[optidx + 1]); 1425 /* Paths are not globbed */ 1426 undo_glob_escape(*path1); 1427 undo_glob_escape(*path2); 1428 break; 1429 case I_RM: 1430 case I_MKDIR: 1431 case I_RMDIR: 1432 case I_LMKDIR: 1433 path1_mandatory = 1; 1434 /* FALLTHROUGH */ 1435 case I_CHDIR: 1436 case I_LCHDIR: 1437 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1438 return -1; 1439 /* Get pathname (mandatory) */ 1440 if (argc - optidx < 1) { 1441 if (!path1_mandatory) 1442 break; /* return a NULL path1 */ 1443 error("You must specify a path after a %s command.", 1444 cmd); 1445 return -1; 1446 } 1447 *path1 = xstrdup(argv[optidx]); 1448 /* Only "rm" globs */ 1449 if (cmdnum != I_RM) 1450 undo_glob_escape(*path1); 1451 break; 1452 case I_DF: 1453 if ((optidx = parse_df_flags(cmd, argv, argc, hflag, 1454 iflag)) == -1) 1455 return -1; 1456 /* Default to current directory if no path specified */ 1457 if (argc - optidx < 1) 1458 *path1 = NULL; 1459 else { 1460 *path1 = xstrdup(argv[optidx]); 1461 undo_glob_escape(*path1); 1462 } 1463 break; 1464 case I_LS: 1465 if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) 1466 return(-1); 1467 /* Path is optional */ 1468 if (argc - optidx > 0) 1469 *path1 = xstrdup(argv[optidx]); 1470 break; 1471 case I_LLS: 1472 /* Skip ls command and following whitespace */ 1473 cp = cp + strlen(cmd) + strspn(cp, WHITESPACE); 1474 case I_SHELL: 1475 /* Uses the rest of the line */ 1476 break; 1477 case I_LUMASK: 1478 case I_CHMOD: 1479 base = 8; 1480 /* FALLTHROUGH */ 1481 case I_CHOWN: 1482 case I_CHGRP: 1483 if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1) 1484 return -1; 1485 /* Get numeric arg (mandatory) */ 1486 if (argc - optidx < 1) 1487 goto need_num_arg; 1488 errno = 0; 1489 l = strtol(argv[optidx], &cp2, base); 1490 if (cp2 == argv[optidx] || *cp2 != '\0' || 1491 ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) || 1492 l < 0) { 1493 need_num_arg: 1494 error("You must supply a numeric argument " 1495 "to the %s command.", cmd); 1496 return -1; 1497 } 1498 *n_arg = l; 1499 if (cmdnum == I_LUMASK) 1500 break; 1501 /* Get pathname (mandatory) */ 1502 if (argc - optidx < 2) { 1503 error("You must specify a path after a %s command.", 1504 cmd); 1505 return -1; 1506 } 1507 *path1 = xstrdup(argv[optidx + 1]); 1508 break; 1509 case I_QUIT: 1510 case I_PWD: 1511 case I_LPWD: 1512 case I_HELP: 1513 case I_VERSION: 1514 case I_PROGRESS: 1515 if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) 1516 return -1; 1517 break; 1518 default: 1519 fatal("Command not implemented"); 1520 } 1521 1522 *cpp = cp; 1523 return(cmdnum); 1524 } 1525 1526 static int 1527 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, 1528 const char *startdir, int err_abort, int echo_command) 1529 { 1530 const char *ocmd = cmd; 1531 char *path1, *path2, *tmp; 1532 int ignore_errors = 0, disable_echo = 1; 1533 int aflag = 0, fflag = 0, hflag = 0, iflag = 0; 1534 int lflag = 0, pflag = 0, rflag = 0, sflag = 0; 1535 int cmdnum, i; 1536 unsigned long n_arg = 0; 1537 Attrib a, *aa; 1538 char path_buf[PATH_MAX]; 1539 int err = 0; 1540 glob_t g; 1541 1542 path1 = path2 = NULL; 1543 cmdnum = parse_args(&cmd, &ignore_errors, &disable_echo, &aflag, &fflag, 1544 &hflag, &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, 1545 &path1, &path2); 1546 if (ignore_errors != 0) 1547 err_abort = 0; 1548 1549 if (echo_command && !disable_echo) 1550 mprintf("sftp> %s\n", ocmd); 1551 1552 memset(&g, 0, sizeof(g)); 1553 1554 /* Perform command */ 1555 switch (cmdnum) { 1556 case 0: 1557 /* Blank line */ 1558 break; 1559 case -1: 1560 /* Unrecognized command */ 1561 err = -1; 1562 break; 1563 case I_REGET: 1564 aflag = 1; 1565 /* FALLTHROUGH */ 1566 case I_GET: 1567 err = process_get(conn, path1, path2, *pwd, pflag, 1568 rflag, aflag, fflag); 1569 break; 1570 case I_REPUT: 1571 aflag = 1; 1572 /* FALLTHROUGH */ 1573 case I_PUT: 1574 err = process_put(conn, path1, path2, *pwd, pflag, 1575 rflag, aflag, fflag); 1576 break; 1577 case I_RENAME: 1578 path1 = make_absolute(path1, *pwd); 1579 path2 = make_absolute(path2, *pwd); 1580 err = do_rename(conn, path1, path2, lflag); 1581 break; 1582 case I_SYMLINK: 1583 sflag = 1; 1584 /* FALLTHROUGH */ 1585 case I_LINK: 1586 if (!sflag) 1587 path1 = make_absolute(path1, *pwd); 1588 path2 = make_absolute(path2, *pwd); 1589 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); 1590 break; 1591 case I_RM: 1592 path1 = make_absolute(path1, *pwd); 1593 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1594 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1595 if (!quiet) 1596 mprintf("Removing %s\n", g.gl_pathv[i]); 1597 err = do_rm(conn, g.gl_pathv[i]); 1598 if (err != 0 && err_abort) 1599 break; 1600 } 1601 break; 1602 case I_MKDIR: 1603 path1 = make_absolute(path1, *pwd); 1604 attrib_clear(&a); 1605 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1606 a.perm = 0777; 1607 err = do_mkdir(conn, path1, &a, 1); 1608 break; 1609 case I_RMDIR: 1610 path1 = make_absolute(path1, *pwd); 1611 err = do_rmdir(conn, path1); 1612 break; 1613 case I_CHDIR: 1614 if (path1 == NULL || *path1 == '\0') 1615 path1 = xstrdup(startdir); 1616 path1 = make_absolute(path1, *pwd); 1617 if ((tmp = do_realpath(conn, path1)) == NULL) { 1618 err = 1; 1619 break; 1620 } 1621 if ((aa = do_stat(conn, tmp, 0)) == NULL) { 1622 free(tmp); 1623 err = 1; 1624 break; 1625 } 1626 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { 1627 error("Can't change directory: Can't check target"); 1628 free(tmp); 1629 err = 1; 1630 break; 1631 } 1632 if (!S_ISDIR(aa->perm)) { 1633 error("Can't change directory: \"%s\" is not " 1634 "a directory", tmp); 1635 free(tmp); 1636 err = 1; 1637 break; 1638 } 1639 free(*pwd); 1640 *pwd = tmp; 1641 break; 1642 case I_LS: 1643 if (!path1) { 1644 do_ls_dir(conn, *pwd, *pwd, lflag); 1645 break; 1646 } 1647 1648 /* Strip pwd off beginning of non-absolute paths */ 1649 tmp = NULL; 1650 if (!path_absolute(path1)) 1651 tmp = *pwd; 1652 1653 path1 = make_absolute(path1, *pwd); 1654 err = do_globbed_ls(conn, path1, tmp, lflag); 1655 break; 1656 case I_DF: 1657 /* Default to current directory if no path specified */ 1658 if (path1 == NULL) 1659 path1 = xstrdup(*pwd); 1660 path1 = make_absolute(path1, *pwd); 1661 err = do_df(conn, path1, hflag, iflag); 1662 break; 1663 case I_LCHDIR: 1664 if (path1 == NULL || *path1 == '\0') 1665 path1 = xstrdup("~"); 1666 tmp = tilde_expand_filename(path1, getuid()); 1667 free(path1); 1668 path1 = tmp; 1669 if (chdir(path1) == -1) { 1670 error("Couldn't change local directory to " 1671 "\"%s\": %s", path1, strerror(errno)); 1672 err = 1; 1673 } 1674 break; 1675 case I_LMKDIR: 1676 if (mkdir(path1, 0777) == -1) { 1677 error("Couldn't create local directory " 1678 "\"%s\": %s", path1, strerror(errno)); 1679 err = 1; 1680 } 1681 break; 1682 case I_LLS: 1683 local_do_ls(cmd); 1684 break; 1685 case I_SHELL: 1686 local_do_shell(cmd); 1687 break; 1688 case I_LUMASK: 1689 umask(n_arg); 1690 printf("Local umask: %03lo\n", n_arg); 1691 break; 1692 case I_CHMOD: 1693 path1 = make_absolute(path1, *pwd); 1694 attrib_clear(&a); 1695 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 1696 a.perm = n_arg; 1697 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1698 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1699 if (!quiet) 1700 mprintf("Changing mode on %s\n", 1701 g.gl_pathv[i]); 1702 err = (hflag ? do_lsetstat : do_setstat)(conn, 1703 g.gl_pathv[i], &a); 1704 if (err != 0 && err_abort) 1705 break; 1706 } 1707 break; 1708 case I_CHOWN: 1709 case I_CHGRP: 1710 path1 = make_absolute(path1, *pwd); 1711 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); 1712 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 1713 if (!(aa = (hflag ? do_lstat : do_stat)(conn, 1714 g.gl_pathv[i], 0))) { 1715 if (err_abort) { 1716 err = -1; 1717 break; 1718 } else 1719 continue; 1720 } 1721 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 1722 error("Can't get current ownership of " 1723 "remote file \"%s\"", g.gl_pathv[i]); 1724 if (err_abort) { 1725 err = -1; 1726 break; 1727 } else 1728 continue; 1729 } 1730 aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; 1731 if (cmdnum == I_CHOWN) { 1732 if (!quiet) 1733 mprintf("Changing owner on %s\n", 1734 g.gl_pathv[i]); 1735 aa->uid = n_arg; 1736 } else { 1737 if (!quiet) 1738 mprintf("Changing group on %s\n", 1739 g.gl_pathv[i]); 1740 aa->gid = n_arg; 1741 } 1742 err = (hflag ? do_lsetstat : do_setstat)(conn, 1743 g.gl_pathv[i], aa); 1744 if (err != 0 && err_abort) 1745 break; 1746 } 1747 break; 1748 case I_PWD: 1749 mprintf("Remote working directory: %s\n", *pwd); 1750 break; 1751 case I_LPWD: 1752 if (!getcwd(path_buf, sizeof(path_buf))) { 1753 error("Couldn't get local cwd: %s", strerror(errno)); 1754 err = -1; 1755 break; 1756 } 1757 mprintf("Local working directory: %s\n", path_buf); 1758 break; 1759 case I_QUIT: 1760 /* Processed below */ 1761 break; 1762 case I_HELP: 1763 help(); 1764 break; 1765 case I_VERSION: 1766 printf("SFTP protocol version %u\n", sftp_proto_version(conn)); 1767 break; 1768 case I_PROGRESS: 1769 showprogress = !showprogress; 1770 if (showprogress) 1771 printf("Progress meter enabled\n"); 1772 else 1773 printf("Progress meter disabled\n"); 1774 break; 1775 default: 1776 fatal("%d is not implemented", cmdnum); 1777 } 1778 1779 if (g.gl_pathc) 1780 globfree(&g); 1781 free(path1); 1782 free(path2); 1783 1784 /* If an unignored error occurs in batch mode we should abort. */ 1785 if (err_abort && err != 0) 1786 return (-1); 1787 else if (cmdnum == I_QUIT) 1788 return (1); 1789 1790 return (0); 1791 } 1792 1793 #ifdef USE_LIBEDIT 1794 static char * 1795 prompt(EditLine *el) 1796 { 1797 return ("sftp> "); 1798 } 1799 1800 /* Display entries in 'list' after skipping the first 'len' chars */ 1801 static void 1802 complete_display(char **list, u_int len) 1803 { 1804 u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; 1805 struct winsize ws; 1806 char *tmp; 1807 1808 /* Count entries for sort and find longest */ 1809 for (y = 0; list[y]; y++) 1810 m = MAXIMUM(m, strlen(list[y])); 1811 1812 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 1813 width = ws.ws_col; 1814 1815 m = m > len ? m - len : 0; 1816 columns = width / (m + 2); 1817 columns = MAXIMUM(columns, 1); 1818 colspace = width / columns; 1819 colspace = MINIMUM(colspace, width); 1820 1821 printf("\n"); 1822 m = 1; 1823 for (y = 0; list[y]; y++) { 1824 llen = strlen(list[y]); 1825 tmp = llen > len ? list[y] + len : ""; 1826 mprintf("%-*s", colspace, tmp); 1827 if (m >= columns) { 1828 printf("\n"); 1829 m = 1; 1830 } else 1831 m++; 1832 } 1833 printf("\n"); 1834 } 1835 1836 /* 1837 * Given a "list" of words that begin with a common prefix of "word", 1838 * attempt to find an autocompletion to extends "word" by the next 1839 * characters common to all entries in "list". 1840 */ 1841 static char * 1842 complete_ambiguous(const char *word, char **list, size_t count) 1843 { 1844 if (word == NULL) 1845 return NULL; 1846 1847 if (count > 0) { 1848 u_int y, matchlen = strlen(list[0]); 1849 1850 /* Find length of common stem */ 1851 for (y = 1; list[y]; y++) { 1852 u_int x; 1853 1854 for (x = 0; x < matchlen; x++) 1855 if (list[0][x] != list[y][x]) 1856 break; 1857 1858 matchlen = x; 1859 } 1860 1861 if (matchlen > strlen(word)) { 1862 char *tmp = xstrdup(list[0]); 1863 1864 tmp[matchlen] = '\0'; 1865 return tmp; 1866 } 1867 } 1868 1869 return xstrdup(word); 1870 } 1871 1872 /* Autocomplete a sftp command */ 1873 static int 1874 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, 1875 int terminated) 1876 { 1877 u_int y, count = 0, cmdlen, tmplen; 1878 char *tmp, **list, argterm[3]; 1879 const LineInfo *lf; 1880 1881 list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); 1882 1883 /* No command specified: display all available commands */ 1884 if (cmd == NULL) { 1885 for (y = 0; cmds[y].c; y++) 1886 list[count++] = xstrdup(cmds[y].c); 1887 1888 list[count] = NULL; 1889 complete_display(list, 0); 1890 1891 for (y = 0; list[y] != NULL; y++) 1892 free(list[y]); 1893 free(list); 1894 return count; 1895 } 1896 1897 /* Prepare subset of commands that start with "cmd" */ 1898 cmdlen = strlen(cmd); 1899 for (y = 0; cmds[y].c; y++) { 1900 if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 1901 list[count++] = xstrdup(cmds[y].c); 1902 } 1903 list[count] = NULL; 1904 1905 if (count == 0) { 1906 free(list); 1907 return 0; 1908 } 1909 1910 /* Complete ambiguous command */ 1911 tmp = complete_ambiguous(cmd, list, count); 1912 if (count > 1) 1913 complete_display(list, 0); 1914 1915 for (y = 0; list[y]; y++) 1916 free(list[y]); 1917 free(list); 1918 1919 if (tmp != NULL) { 1920 tmplen = strlen(tmp); 1921 cmdlen = strlen(cmd); 1922 /* If cmd may be extended then do so */ 1923 if (tmplen > cmdlen) 1924 if (el_insertstr(el, tmp + cmdlen) == -1) 1925 fatal("el_insertstr failed."); 1926 lf = el_line(el); 1927 /* Terminate argument cleanly */ 1928 if (count == 1) { 1929 y = 0; 1930 if (!terminated) 1931 argterm[y++] = quote; 1932 if (lastarg || *(lf->cursor) != ' ') 1933 argterm[y++] = ' '; 1934 argterm[y] = '\0'; 1935 if (y > 0 && el_insertstr(el, argterm) == -1) 1936 fatal("el_insertstr failed."); 1937 } 1938 free(tmp); 1939 } 1940 1941 return count; 1942 } 1943 1944 /* 1945 * Determine whether a particular sftp command's arguments (if any) 1946 * represent local or remote files. 1947 */ 1948 static int 1949 complete_is_remote(char *cmd) { 1950 int i; 1951 1952 if (cmd == NULL) 1953 return -1; 1954 1955 for (i = 0; cmds[i].c; i++) { 1956 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 1957 return cmds[i].t; 1958 } 1959 1960 return -1; 1961 } 1962 1963 /* Autocomplete a filename "file" */ 1964 static int 1965 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, 1966 char *file, int remote, int lastarg, char quote, int terminated) 1967 { 1968 glob_t g; 1969 char *tmp, *tmp2, ins[8]; 1970 u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; 1971 int clen; 1972 const LineInfo *lf; 1973 1974 /* Glob from "file" location */ 1975 if (file == NULL) 1976 tmp = xstrdup("*"); 1977 else 1978 xasprintf(&tmp, "%s*", file); 1979 1980 /* Check if the path is absolute. */ 1981 isabs = path_absolute(tmp); 1982 1983 memset(&g, 0, sizeof(g)); 1984 if (remote != LOCAL) { 1985 tmp = make_absolute(tmp, remote_path); 1986 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1987 } else 1988 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1989 1990 /* Determine length of pwd so we can trim completion display */ 1991 for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { 1992 /* Terminate counting on first unescaped glob metacharacter */ 1993 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { 1994 if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') 1995 hadglob = 1; 1996 break; 1997 } 1998 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') 1999 tmplen++; 2000 if (tmp[tmplen] == '/') 2001 pwdlen = tmplen + 1; /* track last seen '/' */ 2002 } 2003 free(tmp); 2004 tmp = NULL; 2005 2006 if (g.gl_matchc == 0) 2007 goto out; 2008 2009 if (g.gl_matchc > 1) 2010 complete_display(g.gl_pathv, pwdlen); 2011 2012 /* Don't try to extend globs */ 2013 if (file == NULL || hadglob) 2014 goto out; 2015 2016 tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); 2017 tmp = path_strip(tmp2, isabs ? NULL : remote_path); 2018 free(tmp2); 2019 2020 if (tmp == NULL) 2021 goto out; 2022 2023 tmplen = strlen(tmp); 2024 filelen = strlen(file); 2025 2026 /* Count the number of escaped characters in the input string. */ 2027 cesc = isesc = 0; 2028 for (i = 0; i < filelen; i++) { 2029 if (!isesc && file[i] == '\\' && i + 1 < filelen){ 2030 isesc = 1; 2031 cesc++; 2032 } else 2033 isesc = 0; 2034 } 2035 2036 if (tmplen > (filelen - cesc)) { 2037 tmp2 = tmp + filelen - cesc; 2038 len = strlen(tmp2); 2039 /* quote argument on way out */ 2040 for (i = 0; i < len; i += clen) { 2041 if ((clen = mblen(tmp2 + i, len - i)) < 0 || 2042 (size_t)clen > sizeof(ins) - 2) 2043 fatal("invalid multibyte character"); 2044 ins[0] = '\\'; 2045 memcpy(ins + 1, tmp2 + i, clen); 2046 ins[clen + 1] = '\0'; 2047 switch (tmp2[i]) { 2048 case '\'': 2049 case '"': 2050 case '\\': 2051 case '\t': 2052 case '[': 2053 case ' ': 2054 case '#': 2055 case '*': 2056 if (quote == '\0' || tmp2[i] == quote) { 2057 if (el_insertstr(el, ins) == -1) 2058 fatal("el_insertstr " 2059 "failed."); 2060 break; 2061 } 2062 /* FALLTHROUGH */ 2063 default: 2064 if (el_insertstr(el, ins + 1) == -1) 2065 fatal("el_insertstr failed."); 2066 break; 2067 } 2068 } 2069 } 2070 2071 lf = el_line(el); 2072 if (g.gl_matchc == 1) { 2073 i = 0; 2074 if (!terminated && quote != '\0') 2075 ins[i++] = quote; 2076 if (*(lf->cursor - 1) != '/' && 2077 (lastarg || *(lf->cursor) != ' ')) 2078 ins[i++] = ' '; 2079 ins[i] = '\0'; 2080 if (i > 0 && el_insertstr(el, ins) == -1) 2081 fatal("el_insertstr failed."); 2082 } 2083 free(tmp); 2084 2085 out: 2086 globfree(&g); 2087 return g.gl_matchc; 2088 } 2089 2090 /* tab-completion hook function, called via libedit */ 2091 static unsigned char 2092 complete(EditLine *el, int ch) 2093 { 2094 char **argv, *line, quote; 2095 int argc, carg; 2096 u_int cursor, len, terminated, ret = CC_ERROR; 2097 const LineInfo *lf; 2098 struct complete_ctx *complete_ctx; 2099 2100 lf = el_line(el); 2101 if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) 2102 fatal("%s: el_get failed", __func__); 2103 2104 /* Figure out which argument the cursor points to */ 2105 cursor = lf->cursor - lf->buffer; 2106 line = xmalloc(cursor + 1); 2107 memcpy(line, lf->buffer, cursor); 2108 line[cursor] = '\0'; 2109 argv = makeargv(line, &carg, 1, "e, &terminated); 2110 free(line); 2111 2112 /* Get all the arguments on the line */ 2113 len = lf->lastchar - lf->buffer; 2114 line = xmalloc(len + 1); 2115 memcpy(line, lf->buffer, len); 2116 line[len] = '\0'; 2117 argv = makeargv(line, &argc, 1, NULL, NULL); 2118 2119 /* Ensure cursor is at EOL or a argument boundary */ 2120 if (line[cursor] != ' ' && line[cursor] != '\0' && 2121 line[cursor] != '\n') { 2122 free(line); 2123 return ret; 2124 } 2125 2126 if (carg == 0) { 2127 /* Show all available commands */ 2128 complete_cmd_parse(el, NULL, argc == carg, '\0', 1); 2129 ret = CC_REDISPLAY; 2130 } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { 2131 /* Handle the command parsing */ 2132 if (complete_cmd_parse(el, argv[0], argc == carg, 2133 quote, terminated) != 0) 2134 ret = CC_REDISPLAY; 2135 } else if (carg >= 1) { 2136 /* Handle file parsing */ 2137 int remote = complete_is_remote(argv[0]); 2138 char *filematch = NULL; 2139 2140 if (carg > 1 && line[cursor-1] != ' ') 2141 filematch = argv[carg - 1]; 2142 2143 if (remote != 0 && 2144 complete_match(el, complete_ctx->conn, 2145 *complete_ctx->remote_pathp, filematch, 2146 remote, carg == argc, quote, terminated) != 0) 2147 ret = CC_REDISPLAY; 2148 } 2149 2150 free(line); 2151 return ret; 2152 } 2153 #endif /* USE_LIBEDIT */ 2154 2155 static int 2156 interactive_loop(struct sftp_conn *conn, char *file1, char *file2) 2157 { 2158 char *remote_path; 2159 char *dir = NULL, *startdir = NULL; 2160 char cmd[2048]; 2161 int err, interactive; 2162 EditLine *el = NULL; 2163 #ifdef USE_LIBEDIT 2164 History *hl = NULL; 2165 HistEvent hev; 2166 extern char *__progname; 2167 struct complete_ctx complete_ctx; 2168 2169 if (!batchmode && isatty(STDIN_FILENO)) { 2170 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 2171 fatal("Couldn't initialise editline"); 2172 if ((hl = history_init()) == NULL) 2173 fatal("Couldn't initialise editline history"); 2174 history(hl, &hev, H_SETSIZE, 100); 2175 el_set(el, EL_HIST, history, hl); 2176 2177 el_set(el, EL_PROMPT, prompt); 2178 el_set(el, EL_EDITOR, "emacs"); 2179 el_set(el, EL_TERMINAL, NULL); 2180 el_set(el, EL_SIGNAL, 1); 2181 el_source(el, NULL); 2182 2183 /* Tab Completion */ 2184 el_set(el, EL_ADDFN, "ftp-complete", 2185 "Context sensitive argument completion", complete); 2186 complete_ctx.conn = conn; 2187 complete_ctx.remote_pathp = &remote_path; 2188 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 2189 el_set(el, EL_BIND, "^I", "ftp-complete", NULL); 2190 /* enable ctrl-left-arrow and ctrl-right-arrow */ 2191 el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); 2192 el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL); 2193 el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); 2194 el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); 2195 /* make ^w match ksh behaviour */ 2196 el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); 2197 } 2198 #endif /* USE_LIBEDIT */ 2199 2200 remote_path = do_realpath(conn, "."); 2201 if (remote_path == NULL) 2202 fatal("Need cwd"); 2203 startdir = xstrdup(remote_path); 2204 2205 if (file1 != NULL) { 2206 dir = xstrdup(file1); 2207 dir = make_absolute(dir, remote_path); 2208 2209 if (remote_is_dir(conn, dir) && file2 == NULL) { 2210 if (!quiet) 2211 mprintf("Changing to: %s\n", dir); 2212 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 2213 if (parse_dispatch_command(conn, cmd, 2214 &remote_path, startdir, 1, 0) != 0) { 2215 free(dir); 2216 free(startdir); 2217 free(remote_path); 2218 free(conn); 2219 return (-1); 2220 } 2221 } else { 2222 /* XXX this is wrong wrt quoting */ 2223 snprintf(cmd, sizeof cmd, "get%s %s%s%s", 2224 global_aflag ? " -a" : "", dir, 2225 file2 == NULL ? "" : " ", 2226 file2 == NULL ? "" : file2); 2227 err = parse_dispatch_command(conn, cmd, 2228 &remote_path, startdir, 1, 0); 2229 free(dir); 2230 free(startdir); 2231 free(remote_path); 2232 free(conn); 2233 return (err); 2234 } 2235 free(dir); 2236 } 2237 2238 setvbuf(stdout, NULL, _IOLBF, 0); 2239 setvbuf(infile, NULL, _IOLBF, 0); 2240 2241 interactive = !batchmode && isatty(STDIN_FILENO); 2242 err = 0; 2243 for (;;) { 2244 signal(SIGINT, SIG_IGN); 2245 2246 if (el == NULL) { 2247 if (interactive) 2248 printf("sftp> "); 2249 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 2250 if (interactive) 2251 printf("\n"); 2252 break; 2253 } 2254 } else { 2255 #ifdef USE_LIBEDIT 2256 const char *line; 2257 int count = 0; 2258 2259 if ((line = el_gets(el, &count)) == NULL || 2260 count <= 0) { 2261 printf("\n"); 2262 break; 2263 } 2264 history(hl, &hev, H_ENTER, line); 2265 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 2266 fprintf(stderr, "Error: input line too long\n"); 2267 continue; 2268 } 2269 #endif /* USE_LIBEDIT */ 2270 } 2271 2272 cmd[strcspn(cmd, "\n")] = '\0'; 2273 2274 /* Handle user interrupts gracefully during commands */ 2275 interrupted = 0; 2276 signal(SIGINT, cmd_interrupt); 2277 2278 err = parse_dispatch_command(conn, cmd, &remote_path, 2279 startdir, batchmode, !interactive && el == NULL); 2280 if (err != 0) 2281 break; 2282 } 2283 signal(SIGCHLD, SIG_DFL); 2284 free(remote_path); 2285 free(startdir); 2286 free(conn); 2287 2288 #ifdef USE_LIBEDIT 2289 if (el != NULL) 2290 el_end(el); 2291 #endif /* USE_LIBEDIT */ 2292 2293 /* err == 1 signifies normal "quit" exit */ 2294 return (err >= 0 ? 0 : -1); 2295 } 2296 2297 static void 2298 connect_to_server(char *path, char **args, int *in, int *out) 2299 { 2300 int c_in, c_out; 2301 2302 #ifdef USE_PIPES 2303 int pin[2], pout[2]; 2304 2305 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 2306 fatal("pipe: %s", strerror(errno)); 2307 *in = pin[0]; 2308 *out = pout[1]; 2309 c_in = pout[0]; 2310 c_out = pin[1]; 2311 #else /* USE_PIPES */ 2312 int inout[2]; 2313 2314 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 2315 fatal("socketpair: %s", strerror(errno)); 2316 *in = *out = inout[0]; 2317 c_in = c_out = inout[1]; 2318 #endif /* USE_PIPES */ 2319 2320 if ((sshpid = fork()) == -1) 2321 fatal("fork: %s", strerror(errno)); 2322 else if (sshpid == 0) { 2323 if ((dup2(c_in, STDIN_FILENO) == -1) || 2324 (dup2(c_out, STDOUT_FILENO) == -1)) { 2325 fprintf(stderr, "dup2: %s\n", strerror(errno)); 2326 _exit(1); 2327 } 2328 close(*in); 2329 close(*out); 2330 close(c_in); 2331 close(c_out); 2332 2333 /* 2334 * The underlying ssh is in the same process group, so we must 2335 * ignore SIGINT if we want to gracefully abort commands, 2336 * otherwise the signal will make it to the ssh process and 2337 * kill it too. Contrawise, since sftp sends SIGTERMs to the 2338 * underlying ssh, it must *not* ignore that signal. 2339 */ 2340 signal(SIGINT, SIG_IGN); 2341 signal(SIGTERM, SIG_DFL); 2342 execvp(path, args); 2343 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 2344 _exit(1); 2345 } 2346 2347 signal(SIGTERM, killchild); 2348 signal(SIGINT, killchild); 2349 signal(SIGHUP, killchild); 2350 signal(SIGTSTP, suspchild); 2351 signal(SIGTTIN, suspchild); 2352 signal(SIGTTOU, suspchild); 2353 signal(SIGCHLD, sigchld_handler); 2354 close(c_in); 2355 close(c_out); 2356 } 2357 2358 static void 2359 usage(void) 2360 { 2361 extern char *__progname; 2362 2363 fprintf(stderr, 2364 "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2365 " [-D sftp_server_path] [-F ssh_config] [-i identity_file]\n" 2366 " [-J destination] [-l limit] [-o ssh_option] [-P port]\n" 2367 " [-R num_requests] [-S program] [-s subsystem | sftp_server]\n" 2368 " destination\n", 2369 __progname); 2370 exit(1); 2371 } 2372 2373 int 2374 main(int argc, char **argv) 2375 { 2376 int in, out, ch, err, tmp, port = -1; 2377 char *host = NULL, *user, *cp, *file2 = NULL; 2378 int debug_level = 0, sshver = 2; 2379 char *file1 = NULL, *sftp_server = NULL; 2380 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2381 const char *errstr; 2382 LogLevel ll = SYSLOG_LEVEL_INFO; 2383 arglist args; 2384 extern int optind; 2385 extern char *optarg; 2386 struct sftp_conn *conn; 2387 size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; 2388 size_t num_requests = DEFAULT_NUM_REQUESTS; 2389 long long limit_kbps = 0; 2390 2391 ssh_malloc_init(); /* must be called before any mallocs */ 2392 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2393 sanitise_stdfd(); 2394 msetlocale(); 2395 2396 seed_rng(); 2397 2398 __progname = ssh_get_progname(argv[0]); 2399 memset(&args, '\0', sizeof(args)); 2400 args.list = NULL; 2401 addargs(&args, "%s", ssh_program); 2402 addargs(&args, "-oForwardX11 no"); 2403 addargs(&args, "-oForwardAgent no"); 2404 addargs(&args, "-oPermitLocalCommand no"); 2405 addargs(&args, "-oClearAllForwardings yes"); 2406 2407 ll = SYSLOG_LEVEL_INFO; 2408 infile = stdin; 2409 2410 while ((ch = getopt(argc, argv, 2411 "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { 2412 switch (ch) { 2413 /* Passed through to ssh(1) */ 2414 case '4': 2415 case '6': 2416 case 'C': 2417 addargs(&args, "-%c", ch); 2418 break; 2419 /* Passed through to ssh(1) with argument */ 2420 case 'F': 2421 case 'J': 2422 case 'c': 2423 case 'i': 2424 case 'o': 2425 addargs(&args, "-%c", ch); 2426 addargs(&args, "%s", optarg); 2427 break; 2428 case 'q': 2429 ll = SYSLOG_LEVEL_ERROR; 2430 quiet = 1; 2431 showprogress = 0; 2432 addargs(&args, "-%c", ch); 2433 break; 2434 case 'P': 2435 port = a2port(optarg); 2436 if (port <= 0) 2437 fatal("Bad port \"%s\"\n", optarg); 2438 break; 2439 case 'v': 2440 if (debug_level < 3) { 2441 addargs(&args, "-v"); 2442 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 2443 } 2444 debug_level++; 2445 break; 2446 case '1': 2447 sshver = 1; 2448 if (sftp_server == NULL) 2449 sftp_server = _PATH_SFTP_SERVER; 2450 break; 2451 case '2': 2452 sshver = 2; 2453 break; 2454 case 'a': 2455 global_aflag = 1; 2456 break; 2457 case 'B': 2458 copy_buffer_len = strtol(optarg, &cp, 10); 2459 if (copy_buffer_len == 0 || *cp != '\0') 2460 fatal("Invalid buffer size \"%s\"", optarg); 2461 break; 2462 case 'b': 2463 if (batchmode) 2464 fatal("Batch file already specified."); 2465 2466 /* Allow "-" as stdin */ 2467 if (strcmp(optarg, "-") != 0 && 2468 (infile = fopen(optarg, "r")) == NULL) 2469 fatal("%s (%s).", strerror(errno), optarg); 2470 showprogress = 0; 2471 quiet = batchmode = 1; 2472 addargs(&args, "-obatchmode yes"); 2473 break; 2474 case 'f': 2475 global_fflag = 1; 2476 break; 2477 case 'p': 2478 global_pflag = 1; 2479 break; 2480 case 'D': 2481 sftp_direct = optarg; 2482 break; 2483 case 'l': 2484 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 2485 &errstr); 2486 if (errstr != NULL) 2487 usage(); 2488 limit_kbps *= 1024; /* kbps */ 2489 break; 2490 case 'r': 2491 global_rflag = 1; 2492 break; 2493 case 'R': 2494 num_requests = strtol(optarg, &cp, 10); 2495 if (num_requests == 0 || *cp != '\0') 2496 fatal("Invalid number of requests \"%s\"", 2497 optarg); 2498 break; 2499 case 's': 2500 sftp_server = optarg; 2501 break; 2502 case 'S': 2503 ssh_program = optarg; 2504 replacearg(&args, 0, "%s", ssh_program); 2505 break; 2506 case 'h': 2507 default: 2508 usage(); 2509 } 2510 } 2511 2512 if (!isatty(STDERR_FILENO)) 2513 showprogress = 0; 2514 2515 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 2516 2517 if (sftp_direct == NULL) { 2518 if (optind == argc || argc > (optind + 2)) 2519 usage(); 2520 argv += optind; 2521 2522 switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) { 2523 case -1: 2524 usage(); 2525 break; 2526 case 0: 2527 if (tmp != -1) 2528 port = tmp; 2529 break; 2530 default: 2531 if (parse_user_host_path(*argv, &user, &host, 2532 &file1) == -1) { 2533 /* Treat as a plain hostname. */ 2534 host = xstrdup(*argv); 2535 host = cleanhostname(host); 2536 } 2537 break; 2538 } 2539 file2 = *(argv + 1); 2540 2541 if (!*host) { 2542 fprintf(stderr, "Missing hostname\n"); 2543 usage(); 2544 } 2545 2546 if (port != -1) 2547 addargs(&args, "-oPort %d", port); 2548 if (user != NULL) { 2549 addargs(&args, "-l"); 2550 addargs(&args, "%s", user); 2551 } 2552 addargs(&args, "-oProtocol %d", sshver); 2553 2554 /* no subsystem if the server-spec contains a '/' */ 2555 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 2556 addargs(&args, "-s"); 2557 2558 addargs(&args, "--"); 2559 addargs(&args, "%s", host); 2560 addargs(&args, "%s", (sftp_server != NULL ? 2561 sftp_server : "sftp")); 2562 2563 connect_to_server(ssh_program, args.list, &in, &out); 2564 } else { 2565 args.list = NULL; 2566 addargs(&args, "sftp-server"); 2567 2568 connect_to_server(sftp_direct, args.list, &in, &out); 2569 } 2570 freeargs(&args); 2571 2572 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); 2573 if (conn == NULL) 2574 fatal("Couldn't initialise connection to server"); 2575 2576 if (!quiet) { 2577 if (sftp_direct == NULL) 2578 fprintf(stderr, "Connected to %s.\n", host); 2579 else 2580 fprintf(stderr, "Attached to %s.\n", sftp_direct); 2581 } 2582 2583 err = interactive_loop(conn, file1, file2); 2584 2585 #if !defined(USE_PIPES) 2586 shutdown(in, SHUT_RDWR); 2587 shutdown(out, SHUT_RDWR); 2588 #endif 2589 2590 close(in); 2591 close(out); 2592 if (batchmode) 2593 fclose(infile); 2594 2595 while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1) 2596 if (errno != EINTR) 2597 fatal("Couldn't wait for ssh process: %s", 2598 strerror(errno)); 2599 2600 exit(err == 0 ? 0 : 1); 2601 } 2602