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