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