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