1 /* $OpenBSD: sftp.c,v 1.218 2022/06/28 06:09:14 jmc Exp $ */ 2 /* 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/ioctl.h> 20 #include <sys/wait.h> 21 #include <sys/stat.h> 22 #include <sys/socket.h> 23 #include <sys/statvfs.h> 24 25 #include <ctype.h> 26 #include <errno.h> 27 #include <glob.h> 28 #include <histedit.h> 29 #include <paths.h> 30 #include <libgen.h> 31 #include <locale.h> 32 #include <signal.h> 33 #include <stdarg.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <limits.h> 39 #include <util.h> 40 41 #include "xmalloc.h" 42 #include "log.h" 43 #include "pathnames.h" 44 #include "misc.h" 45 #include "utf8.h" 46 47 #include "sftp.h" 48 #include "ssherr.h" 49 #include "sshbuf.h" 50 #include "sftp-common.h" 51 #include "sftp-client.h" 52 53 /* File to read commands from */ 54 FILE* infile; 55 56 /* Are we in batchfile mode? */ 57 int batchmode = 0; 58 59 /* PID of ssh transport process */ 60 static volatile pid_t sshpid = -1; 61 62 /* Suppress diagnostic messages */ 63 int quiet = 0; 64 65 /* This is set to 0 if the progressmeter is not desired. */ 66 int showprogress = 1; 67 68 /* When this option is set, we always recursively download/upload directories */ 69 int global_rflag = 0; 70 71 /* When this option is set, we resume download or upload if possible */ 72 int global_aflag = 0; 73 74 /* When this option is set, the file transfers will always preserve times */ 75 int global_pflag = 0; 76 77 /* When this option is set, transfers will have fsync() called on each file */ 78 int global_fflag = 0; 79 80 /* SIGINT received during command processing */ 81 volatile sig_atomic_t interrupted = 0; 82 83 /* I wish qsort() took a separate ctx for the comparison function...*/ 84 int sort_flag; 85 glob_t *sort_glob; 86 87 /* Context used for commandline completion */ 88 struct complete_ctx { 89 struct sftp_conn *conn; 90 char **remote_pathp; 91 }; 92 93 int remote_glob(struct sftp_conn *, const char *, int, 94 int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ 95 96 /* Separators for interactive commands */ 97 #define WHITESPACE " \t\r\n" 98 99 /* ls flags */ 100 #define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ 101 #define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ 102 #define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ 103 #define LS_NAME_SORT 0x0008 /* Sort by name (default) */ 104 #define LS_TIME_SORT 0x0010 /* Sort by mtime */ 105 #define LS_SIZE_SORT 0x0020 /* Sort by file size */ 106 #define LS_REVERSE_SORT 0x0040 /* Reverse sort order */ 107 #define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */ 108 #define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */ 109 110 #define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS) 111 #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) 112 113 /* Commands for interactive mode */ 114 enum sftp_command { 115 I_CHDIR = 1, 116 I_CHGRP, 117 I_CHMOD, 118 I_CHOWN, 119 I_COPY, 120 I_DF, 121 I_GET, 122 I_HELP, 123 I_LCHDIR, 124 I_LINK, 125 I_LLS, 126 I_LMKDIR, 127 I_LPWD, 128 I_LS, 129 I_LUMASK, 130 I_MKDIR, 131 I_PUT, 132 I_PWD, 133 I_QUIT, 134 I_REGET, 135 I_RENAME, 136 I_REPUT, 137 I_RM, 138 I_RMDIR, 139 I_SHELL, 140 I_SYMLINK, 141 I_VERSION, 142 I_PROGRESS, 143 }; 144 145 struct CMD { 146 const char *c; 147 const int n; 148 const int t; 149 }; 150 151 /* Type of completion */ 152 #define NOARGS 0 153 #define REMOTE 1 154 #define LOCAL 2 155 156 static const struct CMD cmds[] = { 157 { "bye", I_QUIT, NOARGS }, 158 { "cd", I_CHDIR, REMOTE }, 159 { "chdir", I_CHDIR, REMOTE }, 160 { "chgrp", I_CHGRP, REMOTE }, 161 { "chmod", I_CHMOD, REMOTE }, 162 { "chown", I_CHOWN, REMOTE }, 163 { "copy", I_COPY, REMOTE }, 164 { "cp", I_COPY, REMOTE }, 165 { "df", I_DF, REMOTE }, 166 { "dir", I_LS, REMOTE }, 167 { "exit", I_QUIT, NOARGS }, 168 { "get", I_GET, REMOTE }, 169 { "help", I_HELP, NOARGS }, 170 { "lcd", I_LCHDIR, LOCAL }, 171 { "lchdir", I_LCHDIR, LOCAL }, 172 { "lls", I_LLS, LOCAL }, 173 { "lmkdir", I_LMKDIR, LOCAL }, 174 { "ln", I_LINK, REMOTE }, 175 { "lpwd", I_LPWD, LOCAL }, 176 { "ls", I_LS, REMOTE }, 177 { "lumask", I_LUMASK, NOARGS }, 178 { "mkdir", I_MKDIR, REMOTE }, 179 { "mget", I_GET, REMOTE }, 180 { "mput", I_PUT, LOCAL }, 181 { "progress", I_PROGRESS, NOARGS }, 182 { "put", I_PUT, LOCAL }, 183 { "pwd", I_PWD, REMOTE }, 184 { "quit", I_QUIT, NOARGS }, 185 { "reget", I_REGET, REMOTE }, 186 { "rename", I_RENAME, REMOTE }, 187 { "reput", I_REPUT, LOCAL }, 188 { "rm", I_RM, REMOTE }, 189 { "rmdir", I_RMDIR, REMOTE }, 190 { "symlink", I_SYMLINK, REMOTE }, 191 { "version", I_VERSION, NOARGS }, 192 { "!", I_SHELL, NOARGS }, 193 { "?", I_HELP, NOARGS }, 194 { NULL, -1, -1 } 195 }; 196 197 /* ARGSUSED */ 198 static void 199 killchild(int signo) 200 { 201 pid_t pid; 202 203 pid = sshpid; 204 if (pid > 1) { 205 kill(pid, SIGTERM); 206 waitpid(pid, NULL, 0); 207 } 208 209 _exit(1); 210 } 211 212 /* ARGSUSED */ 213 static void 214 suspchild(int signo) 215 { 216 if (sshpid > 1) { 217 kill(sshpid, signo); 218 while (waitpid(sshpid, NULL, WUNTRACED) == -1 && errno == EINTR) 219 continue; 220 } 221 kill(getpid(), SIGSTOP); 222 } 223 224 /* ARGSUSED */ 225 static void 226 cmd_interrupt(int signo) 227 { 228 const char msg[] = "\rInterrupt \n"; 229 int olderrno = errno; 230 231 (void)write(STDERR_FILENO, msg, sizeof(msg) - 1); 232 interrupted = 1; 233 errno = olderrno; 234 } 235 236 /* ARGSUSED */ 237 static void 238 read_interrupt(int signo) 239 { 240 interrupted = 1; 241 } 242 243 /*ARGSUSED*/ 244 static void 245 sigchld_handler(int sig) 246 { 247 int save_errno = errno; 248 pid_t pid; 249 const char msg[] = "\rConnection closed. \n"; 250 251 /* Report if ssh transport process dies. */ 252 while ((pid = waitpid(sshpid, NULL, WNOHANG)) == -1 && errno == EINTR) 253 continue; 254 if (pid == sshpid) { 255 (void)write(STDERR_FILENO, msg, sizeof(msg) - 1); 256 sshpid = -1; 257 } 258 259 errno = save_errno; 260 } 261 262 static void 263 help(void) 264 { 265 printf("Available commands:\n" 266 "bye Quit sftp\n" 267 "cd path Change remote directory to 'path'\n" 268 "chgrp [-h] grp path Change group of file 'path' to 'grp'\n" 269 "chmod [-h] mode path Change permissions of file 'path' to 'mode'\n" 270 "chown [-h] own path Change owner of file 'path' to 'own'\n" 271 "copy oldpath newpath Copy remote file\n" 272 "cp oldpath newpath Copy remote file\n" 273 "df [-hi] [path] Display statistics for current directory or\n" 274 " filesystem containing 'path'\n" 275 "exit Quit sftp\n" 276 "get [-afpR] remote [local] Download file\n" 277 "help Display this help text\n" 278 "lcd path Change local directory to 'path'\n" 279 "lls [ls-options [path]] Display local directory listing\n" 280 "lmkdir path Create local directory\n" 281 "ln [-s] oldpath newpath Link remote file (-s for symlink)\n" 282 "lpwd Print local working directory\n" 283 "ls [-1afhlnrSt] [path] Display remote directory listing\n" 284 "lumask umask Set local umask to 'umask'\n" 285 "mkdir path Create remote directory\n" 286 "progress Toggle display of progress meter\n" 287 "put [-afpR] local [remote] Upload file\n" 288 "pwd Display remote working directory\n" 289 "quit Quit sftp\n" 290 "reget [-fpR] remote [local] Resume download file\n" 291 "rename oldpath newpath Rename remote file\n" 292 "reput [-fpR] local [remote] Resume upload file\n" 293 "rm path Delete remote file\n" 294 "rmdir path Remove remote directory\n" 295 "symlink oldpath newpath Symlink remote file\n" 296 "version Show SFTP version\n" 297 "!command Execute 'command' in local shell\n" 298 "! Escape to local shell\n" 299 "? Synonym for help\n"); 300 } 301 302 static void 303 local_do_shell(const char *args) 304 { 305 int status; 306 char *shell; 307 pid_t pid; 308 309 if (!*args) 310 args = NULL; 311 312 if ((shell = getenv("SHELL")) == NULL || *shell == '\0') 313 shell = _PATH_BSHELL; 314 315 if ((pid = fork()) == -1) 316 fatal("Couldn't fork: %s", strerror(errno)); 317 318 if (pid == 0) { 319 /* XXX: child has pipe fds to ssh subproc open - issue? */ 320 if (args) { 321 debug3("Executing %s -c \"%s\"", shell, args); 322 execl(shell, shell, "-c", args, (char *)NULL); 323 } else { 324 debug3("Executing %s", shell); 325 execl(shell, shell, (char *)NULL); 326 } 327 fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, 328 strerror(errno)); 329 _exit(1); 330 } 331 while (waitpid(pid, &status, 0) == -1) 332 if (errno != EINTR) 333 fatal("Couldn't wait for child: %s", strerror(errno)); 334 if (!WIFEXITED(status)) 335 error("Shell exited abnormally"); 336 else if (WEXITSTATUS(status)) 337 error("Shell exited with status %d", WEXITSTATUS(status)); 338 } 339 340 static void 341 local_do_ls(const char *args) 342 { 343 if (!args || !*args) 344 local_do_shell(_PATH_LS); 345 else { 346 int len = strlen(_PATH_LS " ") + strlen(args) + 1; 347 char *buf = xmalloc(len); 348 349 /* XXX: quoting - rip quoting code from ftp? */ 350 snprintf(buf, len, _PATH_LS " %s", args); 351 local_do_shell(buf); 352 free(buf); 353 } 354 } 355 356 /* Strip one path (usually the pwd) from the start of another */ 357 static char * 358 path_strip(const char *path, const char *strip) 359 { 360 size_t len; 361 362 if (strip == NULL) 363 return (xstrdup(path)); 364 365 len = strlen(strip); 366 if (strncmp(path, strip, len) == 0) { 367 if (strip[len - 1] != '/' && path[len] == '/') 368 len++; 369 return (xstrdup(path + len)); 370 } 371 372 return (xstrdup(path)); 373 } 374 375 static int 376 parse_getput_flags(const char *cmd, char **argv, int argc, 377 int *aflag, int *fflag, int *pflag, int *rflag) 378 { 379 extern int opterr, optind, optopt, optreset; 380 int ch; 381 382 optind = optreset = 1; 383 opterr = 0; 384 385 *aflag = *fflag = *rflag = *pflag = 0; 386 while ((ch = getopt(argc, argv, "afPpRr")) != -1) { 387 switch (ch) { 388 case 'a': 389 *aflag = 1; 390 break; 391 case 'f': 392 *fflag = 1; 393 break; 394 case 'p': 395 case 'P': 396 *pflag = 1; 397 break; 398 case 'r': 399 case 'R': 400 *rflag = 1; 401 break; 402 default: 403 error("%s: Invalid flag -%c", cmd, optopt); 404 return -1; 405 } 406 } 407 408 return optind; 409 } 410 411 static int 412 parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) 413 { 414 extern int opterr, optind, optopt, optreset; 415 int ch; 416 417 optind = optreset = 1; 418 opterr = 0; 419 420 *sflag = 0; 421 while ((ch = getopt(argc, argv, "s")) != -1) { 422 switch (ch) { 423 case 's': 424 *sflag = 1; 425 break; 426 default: 427 error("%s: Invalid flag -%c", cmd, optopt); 428 return -1; 429 } 430 } 431 432 return optind; 433 } 434 435 static int 436 parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag) 437 { 438 extern int opterr, optind, optopt, optreset; 439 int ch; 440 441 optind = optreset = 1; 442 opterr = 0; 443 444 *lflag = 0; 445 while ((ch = getopt(argc, argv, "l")) != -1) { 446 switch (ch) { 447 case 'l': 448 *lflag = 1; 449 break; 450 default: 451 error("%s: Invalid flag -%c", cmd, optopt); 452 return -1; 453 } 454 } 455 456 return optind; 457 } 458 459 static int 460 parse_ls_flags(char **argv, int argc, int *lflag) 461 { 462 extern int opterr, optind, optopt, optreset; 463 int ch; 464 465 optind = optreset = 1; 466 opterr = 0; 467 468 *lflag = LS_NAME_SORT; 469 while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) { 470 switch (ch) { 471 case '1': 472 *lflag &= ~VIEW_FLAGS; 473 *lflag |= LS_SHORT_VIEW; 474 break; 475 case 'S': 476 *lflag &= ~SORT_FLAGS; 477 *lflag |= LS_SIZE_SORT; 478 break; 479 case 'a': 480 *lflag |= LS_SHOW_ALL; 481 break; 482 case 'f': 483 *lflag &= ~SORT_FLAGS; 484 break; 485 case 'h': 486 *lflag |= LS_SI_UNITS; 487 break; 488 case 'l': 489 *lflag &= ~LS_SHORT_VIEW; 490 *lflag |= LS_LONG_VIEW; 491 break; 492 case 'n': 493 *lflag &= ~LS_SHORT_VIEW; 494 *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; 495 break; 496 case 'r': 497 *lflag |= LS_REVERSE_SORT; 498 break; 499 case 't': 500 *lflag &= ~SORT_FLAGS; 501 *lflag |= LS_TIME_SORT; 502 break; 503 default: 504 error("ls: Invalid flag -%c", optopt); 505 return -1; 506 } 507 } 508 509 return optind; 510 } 511 512 static int 513 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) 514 { 515 extern int opterr, optind, optopt, optreset; 516 int ch; 517 518 optind = optreset = 1; 519 opterr = 0; 520 521 *hflag = *iflag = 0; 522 while ((ch = getopt(argc, argv, "hi")) != -1) { 523 switch (ch) { 524 case 'h': 525 *hflag = 1; 526 break; 527 case 'i': 528 *iflag = 1; 529 break; 530 default: 531 error("%s: Invalid flag -%c", cmd, optopt); 532 return -1; 533 } 534 } 535 536 return optind; 537 } 538 539 static int 540 parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag) 541 { 542 extern int opterr, optind, optopt, optreset; 543 int ch; 544 545 optind = optreset = 1; 546 opterr = 0; 547 548 *hflag = 0; 549 while ((ch = getopt(argc, argv, "h")) != -1) { 550 switch (ch) { 551 case 'h': 552 *hflag = 1; 553 break; 554 default: 555 error("%s: Invalid flag -%c", cmd, optopt); 556 return -1; 557 } 558 } 559 560 return optind; 561 } 562 563 static int 564 parse_no_flags(const char *cmd, char **argv, int argc) 565 { 566 extern int opterr, optind, optopt, optreset; 567 int ch; 568 569 optind = optreset = 1; 570 opterr = 0; 571 572 while ((ch = getopt(argc, argv, "")) != -1) { 573 switch (ch) { 574 default: 575 error("%s: Invalid flag -%c", cmd, optopt); 576 return -1; 577 } 578 } 579 580 return optind; 581 } 582 583 static char * 584 escape_glob(const char *s) 585 { 586 size_t i, o, len; 587 char *ret; 588 589 len = strlen(s); 590 ret = xcalloc(2, len + 1); 591 for (i = o = 0; i < len; i++) { 592 if (strchr("[]?*\\", s[i]) != NULL) 593 ret[o++] = '\\'; 594 ret[o++] = s[i]; 595 } 596 ret[o++] = '\0'; 597 return ret; 598 } 599 600 static char * 601 make_absolute_pwd_glob(const char *p, const char *pwd) 602 { 603 char *ret, *escpwd; 604 605 escpwd = escape_glob(pwd); 606 if (p == NULL) 607 return escpwd; 608 ret = make_absolute(xstrdup(p), escpwd); 609 free(escpwd); 610 return ret; 611 } 612 613 static int 614 process_get(struct sftp_conn *conn, const char *src, const char *dst, 615 const char *pwd, int pflag, int rflag, int resume, int fflag) 616 { 617 char *filename, *abs_src = NULL, *abs_dst = NULL, *tmp = NULL; 618 glob_t g; 619 int i, r, err = 0; 620 621 abs_src = make_absolute_pwd_glob(src, pwd); 622 memset(&g, 0, sizeof(g)); 623 624 debug3("Looking up %s", abs_src); 625 if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) { 626 if (r == GLOB_NOSPACE) { 627 error("Too many matches for \"%s\".", abs_src); 628 } else { 629 error("File \"%s\" not found.", abs_src); 630 } 631 err = -1; 632 goto out; 633 } 634 635 /* 636 * If multiple matches then dst must be a directory or 637 * unspecified. 638 */ 639 if (g.gl_matchc > 1 && dst != NULL && !local_is_dir(dst)) { 640 error("Multiple source paths, but destination " 641 "\"%s\" is not a directory", dst); 642 err = -1; 643 goto out; 644 } 645 646 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 647 tmp = xstrdup(g.gl_pathv[i]); 648 if ((filename = basename(tmp)) == NULL) { 649 error("basename %s: %s", tmp, strerror(errno)); 650 free(tmp); 651 err = -1; 652 goto out; 653 } 654 655 if (g.gl_matchc == 1 && dst) { 656 if (local_is_dir(dst)) { 657 abs_dst = path_append(dst, filename); 658 } else { 659 abs_dst = xstrdup(dst); 660 } 661 } else if (dst) { 662 abs_dst = path_append(dst, filename); 663 } else { 664 abs_dst = xstrdup(filename); 665 } 666 free(tmp); 667 668 resume |= global_aflag; 669 if (!quiet && resume) 670 mprintf("Resuming %s to %s\n", 671 g.gl_pathv[i], abs_dst); 672 else if (!quiet && !resume) 673 mprintf("Fetching %s to %s\n", 674 g.gl_pathv[i], abs_dst); 675 /* XXX follow link flag */ 676 if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 677 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 678 pflag || global_pflag, 1, resume, 679 fflag || global_fflag, 0, 0) == -1) 680 err = -1; 681 } else { 682 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, 683 pflag || global_pflag, resume, 684 fflag || global_fflag, 0) == -1) 685 err = -1; 686 } 687 free(abs_dst); 688 abs_dst = NULL; 689 } 690 691 out: 692 free(abs_src); 693 globfree(&g); 694 return(err); 695 } 696 697 static int 698 process_put(struct sftp_conn *conn, const char *src, const char *dst, 699 const char *pwd, int pflag, int rflag, int resume, int fflag) 700 { 701 char *tmp_dst = NULL; 702 char *abs_dst = NULL; 703 char *tmp = NULL, *filename = NULL; 704 glob_t g; 705 int err = 0; 706 int i, dst_is_dir = 1; 707 struct stat sb; 708 709 if (dst) { 710 tmp_dst = xstrdup(dst); 711 tmp_dst = make_absolute(tmp_dst, pwd); 712 } 713 714 memset(&g, 0, sizeof(g)); 715 debug3("Looking up %s", src); 716 if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { 717 error("File \"%s\" not found.", src); 718 err = -1; 719 goto out; 720 } 721 722 /* If we aren't fetching to pwd then stash this status for later */ 723 if (tmp_dst != NULL) 724 dst_is_dir = remote_is_dir(conn, tmp_dst); 725 726 /* If multiple matches, dst may be directory or unspecified */ 727 if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { 728 error("Multiple paths match, but destination " 729 "\"%s\" is not a directory", tmp_dst); 730 err = -1; 731 goto out; 732 } 733 734 for (i = 0; g.gl_pathv[i] && !interrupted; i++) { 735 if (stat(g.gl_pathv[i], &sb) == -1) { 736 err = -1; 737 error("stat %s: %s", g.gl_pathv[i], strerror(errno)); 738 continue; 739 } 740 741 tmp = xstrdup(g.gl_pathv[i]); 742 if ((filename = basename(tmp)) == NULL) { 743 error("basename %s: %s", tmp, strerror(errno)); 744 free(tmp); 745 err = -1; 746 goto out; 747 } 748 749 if (g.gl_matchc == 1 && tmp_dst) { 750 /* If directory specified, append filename */ 751 if (dst_is_dir) 752 abs_dst = path_append(tmp_dst, filename); 753 else 754 abs_dst = xstrdup(tmp_dst); 755 } else if (tmp_dst) { 756 abs_dst = path_append(tmp_dst, filename); 757 } else { 758 abs_dst = make_absolute(xstrdup(filename), pwd); 759 } 760 free(tmp); 761 762 resume |= global_aflag; 763 if (!quiet && resume) 764 mprintf("Resuming upload of %s to %s\n", 765 g.gl_pathv[i], abs_dst); 766 else if (!quiet && !resume) 767 mprintf("Uploading %s to %s\n", 768 g.gl_pathv[i], abs_dst); 769 /* XXX follow_link_flag */ 770 if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 771 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 772 pflag || global_pflag, 1, resume, 773 fflag || global_fflag, 0, 0) == -1) 774 err = -1; 775 } else { 776 if (do_upload(conn, g.gl_pathv[i], abs_dst, 777 pflag || global_pflag, resume, 778 fflag || global_fflag, 0) == -1) 779 err = -1; 780 } 781 } 782 783 out: 784 free(abs_dst); 785 free(tmp_dst); 786 globfree(&g); 787 return(err); 788 } 789 790 static int 791 sdirent_comp(const void *aa, const void *bb) 792 { 793 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; 794 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; 795 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 796 797 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 798 if (sort_flag & LS_NAME_SORT) 799 return (rmul * strcmp(a->filename, b->filename)); 800 else if (sort_flag & LS_TIME_SORT) 801 return (rmul * NCMP(a->a.mtime, b->a.mtime)); 802 else if (sort_flag & LS_SIZE_SORT) 803 return (rmul * NCMP(a->a.size, b->a.size)); 804 805 fatal("Unknown ls sort type"); 806 } 807 808 /* sftp ls.1 replacement for directories */ 809 static int 810 do_ls_dir(struct sftp_conn *conn, const char *path, 811 const char *strip_path, int lflag) 812 { 813 int n; 814 u_int c = 1, colspace = 0, columns = 1; 815 SFTP_DIRENT **d; 816 817 if ((n = do_readdir(conn, path, &d)) != 0) 818 return (n); 819 820 if (!(lflag & LS_SHORT_VIEW)) { 821 u_int m = 0, width = 80; 822 struct winsize ws; 823 char *tmp; 824 825 /* Count entries for sort and find longest filename */ 826 for (n = 0; d[n] != NULL; n++) { 827 if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) 828 m = MAXIMUM(m, strlen(d[n]->filename)); 829 } 830 831 /* Add any subpath that also needs to be counted */ 832 tmp = path_strip(path, strip_path); 833 m += strlen(tmp); 834 free(tmp); 835 836 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 837 width = ws.ws_col; 838 839 columns = width / (m + 2); 840 columns = MAXIMUM(columns, 1); 841 colspace = width / columns; 842 colspace = MINIMUM(colspace, width); 843 } 844 845 if (lflag & SORT_FLAGS) { 846 for (n = 0; d[n] != NULL; n++) 847 ; /* count entries */ 848 sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); 849 qsort(d, n, sizeof(*d), sdirent_comp); 850 } 851 852 for (n = 0; d[n] != NULL && !interrupted; n++) { 853 char *tmp, *fname; 854 855 if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) 856 continue; 857 858 tmp = path_append(path, d[n]->filename); 859 fname = path_strip(tmp, strip_path); 860 free(tmp); 861 862 if (lflag & LS_LONG_VIEW) { 863 if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { 864 char *lname; 865 struct stat sb; 866 867 memset(&sb, 0, sizeof(sb)); 868 attrib_to_stat(&d[n]->a, &sb); 869 lname = ls_file(fname, &sb, 1, 870 (lflag & LS_SI_UNITS)); 871 mprintf("%s\n", lname); 872 free(lname); 873 } else 874 mprintf("%s\n", d[n]->longname); 875 } else { 876 mprintf("%-*s", colspace, fname); 877 if (c >= columns) { 878 printf("\n"); 879 c = 1; 880 } else 881 c++; 882 } 883 884 free(fname); 885 } 886 887 if (!(lflag & LS_LONG_VIEW) && (c != 1)) 888 printf("\n"); 889 890 free_sftp_dirents(d); 891 return (0); 892 } 893 894 static int 895 sglob_comp(const void *aa, const void *bb) 896 { 897 u_int a = *(const u_int *)aa; 898 u_int b = *(const u_int *)bb; 899 const char *ap = sort_glob->gl_pathv[a]; 900 const char *bp = sort_glob->gl_pathv[b]; 901 const struct stat *as = sort_glob->gl_statv[a]; 902 const struct stat *bs = sort_glob->gl_statv[b]; 903 int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; 904 905 #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) 906 if (sort_flag & LS_NAME_SORT) 907 return (rmul * strcmp(ap, bp)); 908 else if (sort_flag & LS_TIME_SORT) { 909 if (timespeccmp(&as->st_mtim, &bs->st_mtim, ==)) 910 return 0; 911 return timespeccmp(&as->st_mtim, &bs->st_mtim, <) ? 912 rmul : -rmul; 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_pwd_glob(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_pwd_glob(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_pwd_glob(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_pwd_glob(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 static char * 1770 prompt(EditLine *el) 1771 { 1772 return ("sftp> "); 1773 } 1774 1775 /* Display entries in 'list' after skipping the first 'len' chars */ 1776 static void 1777 complete_display(char **list, u_int len) 1778 { 1779 u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; 1780 struct winsize ws; 1781 char *tmp; 1782 1783 /* Count entries for sort and find longest */ 1784 for (y = 0; list[y]; y++) 1785 m = MAXIMUM(m, strlen(list[y])); 1786 1787 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) 1788 width = ws.ws_col; 1789 1790 m = m > len ? m - len : 0; 1791 columns = width / (m + 2); 1792 columns = MAXIMUM(columns, 1); 1793 colspace = width / columns; 1794 colspace = MINIMUM(colspace, width); 1795 1796 printf("\n"); 1797 m = 1; 1798 for (y = 0; list[y]; y++) { 1799 llen = strlen(list[y]); 1800 tmp = llen > len ? list[y] + len : ""; 1801 mprintf("%-*s", colspace, tmp); 1802 if (m >= columns) { 1803 printf("\n"); 1804 m = 1; 1805 } else 1806 m++; 1807 } 1808 printf("\n"); 1809 } 1810 1811 /* 1812 * Given a "list" of words that begin with a common prefix of "word", 1813 * attempt to find an autocompletion to extends "word" by the next 1814 * characters common to all entries in "list". 1815 */ 1816 static char * 1817 complete_ambiguous(const char *word, char **list, size_t count) 1818 { 1819 if (word == NULL) 1820 return NULL; 1821 1822 if (count > 0) { 1823 u_int y, matchlen = strlen(list[0]); 1824 1825 /* Find length of common stem */ 1826 for (y = 1; list[y]; y++) { 1827 u_int x; 1828 1829 for (x = 0; x < matchlen; x++) 1830 if (list[0][x] != list[y][x]) 1831 break; 1832 1833 matchlen = x; 1834 } 1835 1836 if (matchlen > strlen(word)) { 1837 char *tmp = xstrdup(list[0]); 1838 1839 tmp[matchlen] = '\0'; 1840 return tmp; 1841 } 1842 } 1843 1844 return xstrdup(word); 1845 } 1846 1847 /* Autocomplete a sftp command */ 1848 static int 1849 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, 1850 int terminated) 1851 { 1852 u_int y, count = 0, cmdlen, tmplen; 1853 char *tmp, **list, argterm[3]; 1854 const LineInfo *lf; 1855 1856 list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); 1857 1858 /* No command specified: display all available commands */ 1859 if (cmd == NULL) { 1860 for (y = 0; cmds[y].c; y++) 1861 list[count++] = xstrdup(cmds[y].c); 1862 1863 list[count] = NULL; 1864 complete_display(list, 0); 1865 1866 for (y = 0; list[y] != NULL; y++) 1867 free(list[y]); 1868 free(list); 1869 return count; 1870 } 1871 1872 /* Prepare subset of commands that start with "cmd" */ 1873 cmdlen = strlen(cmd); 1874 for (y = 0; cmds[y].c; y++) { 1875 if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 1876 list[count++] = xstrdup(cmds[y].c); 1877 } 1878 list[count] = NULL; 1879 1880 if (count == 0) { 1881 free(list); 1882 return 0; 1883 } 1884 1885 /* Complete ambiguous command */ 1886 tmp = complete_ambiguous(cmd, list, count); 1887 if (count > 1) 1888 complete_display(list, 0); 1889 1890 for (y = 0; list[y]; y++) 1891 free(list[y]); 1892 free(list); 1893 1894 if (tmp != NULL) { 1895 tmplen = strlen(tmp); 1896 cmdlen = strlen(cmd); 1897 /* If cmd may be extended then do so */ 1898 if (tmplen > cmdlen) 1899 if (el_insertstr(el, tmp + cmdlen) == -1) 1900 fatal("el_insertstr failed."); 1901 lf = el_line(el); 1902 /* Terminate argument cleanly */ 1903 if (count == 1) { 1904 y = 0; 1905 if (!terminated) 1906 argterm[y++] = quote; 1907 if (lastarg || *(lf->cursor) != ' ') 1908 argterm[y++] = ' '; 1909 argterm[y] = '\0'; 1910 if (y > 0 && el_insertstr(el, argterm) == -1) 1911 fatal("el_insertstr failed."); 1912 } 1913 free(tmp); 1914 } 1915 1916 return count; 1917 } 1918 1919 /* 1920 * Determine whether a particular sftp command's arguments (if any) 1921 * represent local or remote files. 1922 */ 1923 static int 1924 complete_is_remote(char *cmd) { 1925 int i; 1926 1927 if (cmd == NULL) 1928 return -1; 1929 1930 for (i = 0; cmds[i].c; i++) { 1931 if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 1932 return cmds[i].t; 1933 } 1934 1935 return -1; 1936 } 1937 1938 /* Autocomplete a filename "file" */ 1939 static int 1940 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, 1941 char *file, int remote, int lastarg, char quote, int terminated) 1942 { 1943 glob_t g; 1944 char *tmp, *tmp2, ins[8]; 1945 u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; 1946 int clen; 1947 const LineInfo *lf; 1948 1949 /* Glob from "file" location */ 1950 if (file == NULL) 1951 tmp = xstrdup("*"); 1952 else 1953 xasprintf(&tmp, "%s*", file); 1954 1955 /* Check if the path is absolute. */ 1956 isabs = path_absolute(tmp); 1957 1958 memset(&g, 0, sizeof(g)); 1959 if (remote != LOCAL) { 1960 tmp = make_absolute_pwd_glob(tmp, remote_path); 1961 remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1962 } else 1963 glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); 1964 1965 /* Determine length of pwd so we can trim completion display */ 1966 for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { 1967 /* Terminate counting on first unescaped glob metacharacter */ 1968 if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { 1969 if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') 1970 hadglob = 1; 1971 break; 1972 } 1973 if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') 1974 tmplen++; 1975 if (tmp[tmplen] == '/') 1976 pwdlen = tmplen + 1; /* track last seen '/' */ 1977 } 1978 free(tmp); 1979 tmp = NULL; 1980 1981 if (g.gl_matchc == 0) 1982 goto out; 1983 1984 if (g.gl_matchc > 1) 1985 complete_display(g.gl_pathv, pwdlen); 1986 1987 /* Don't try to extend globs */ 1988 if (file == NULL || hadglob) 1989 goto out; 1990 1991 tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); 1992 tmp = path_strip(tmp2, isabs ? NULL : remote_path); 1993 free(tmp2); 1994 1995 if (tmp == NULL) 1996 goto out; 1997 1998 tmplen = strlen(tmp); 1999 filelen = strlen(file); 2000 2001 /* Count the number of escaped characters in the input string. */ 2002 cesc = isesc = 0; 2003 for (i = 0; i < filelen; i++) { 2004 if (!isesc && file[i] == '\\' && i + 1 < filelen){ 2005 isesc = 1; 2006 cesc++; 2007 } else 2008 isesc = 0; 2009 } 2010 2011 if (tmplen > (filelen - cesc)) { 2012 tmp2 = tmp + filelen - cesc; 2013 len = strlen(tmp2); 2014 /* quote argument on way out */ 2015 for (i = 0; i < len; i += clen) { 2016 if ((clen = mblen(tmp2 + i, len - i)) < 0 || 2017 (size_t)clen > sizeof(ins) - 2) 2018 fatal("invalid multibyte character"); 2019 ins[0] = '\\'; 2020 memcpy(ins + 1, tmp2 + i, clen); 2021 ins[clen + 1] = '\0'; 2022 switch (tmp2[i]) { 2023 case '\'': 2024 case '"': 2025 case '\\': 2026 case '\t': 2027 case '[': 2028 case ' ': 2029 case '#': 2030 case '*': 2031 if (quote == '\0' || tmp2[i] == quote) { 2032 if (el_insertstr(el, ins) == -1) 2033 fatal("el_insertstr " 2034 "failed."); 2035 break; 2036 } 2037 /* FALLTHROUGH */ 2038 default: 2039 if (el_insertstr(el, ins + 1) == -1) 2040 fatal("el_insertstr failed."); 2041 break; 2042 } 2043 } 2044 } 2045 2046 lf = el_line(el); 2047 if (g.gl_matchc == 1) { 2048 i = 0; 2049 if (!terminated && quote != '\0') 2050 ins[i++] = quote; 2051 if (*(lf->cursor - 1) != '/' && 2052 (lastarg || *(lf->cursor) != ' ')) 2053 ins[i++] = ' '; 2054 ins[i] = '\0'; 2055 if (i > 0 && el_insertstr(el, ins) == -1) 2056 fatal("el_insertstr failed."); 2057 } 2058 free(tmp); 2059 2060 out: 2061 globfree(&g); 2062 return g.gl_matchc; 2063 } 2064 2065 /* tab-completion hook function, called via libedit */ 2066 static unsigned char 2067 complete(EditLine *el, int ch) 2068 { 2069 char **argv, *line, quote; 2070 int argc, carg; 2071 u_int cursor, len, terminated, ret = CC_ERROR; 2072 const LineInfo *lf; 2073 struct complete_ctx *complete_ctx; 2074 2075 lf = el_line(el); 2076 if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) 2077 fatal_f("el_get failed"); 2078 2079 /* Figure out which argument the cursor points to */ 2080 cursor = lf->cursor - lf->buffer; 2081 line = xmalloc(cursor + 1); 2082 memcpy(line, lf->buffer, cursor); 2083 line[cursor] = '\0'; 2084 argv = makeargv(line, &carg, 1, "e, &terminated); 2085 free(line); 2086 2087 /* Get all the arguments on the line */ 2088 len = lf->lastchar - lf->buffer; 2089 line = xmalloc(len + 1); 2090 memcpy(line, lf->buffer, len); 2091 line[len] = '\0'; 2092 argv = makeargv(line, &argc, 1, NULL, NULL); 2093 2094 /* Ensure cursor is at EOL or a argument boundary */ 2095 if (line[cursor] != ' ' && line[cursor] != '\0' && 2096 line[cursor] != '\n') { 2097 free(line); 2098 return ret; 2099 } 2100 2101 if (carg == 0) { 2102 /* Show all available commands */ 2103 complete_cmd_parse(el, NULL, argc == carg, '\0', 1); 2104 ret = CC_REDISPLAY; 2105 } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { 2106 /* Handle the command parsing */ 2107 if (complete_cmd_parse(el, argv[0], argc == carg, 2108 quote, terminated) != 0) 2109 ret = CC_REDISPLAY; 2110 } else if (carg >= 1) { 2111 /* Handle file parsing */ 2112 int remote = complete_is_remote(argv[0]); 2113 char *filematch = NULL; 2114 2115 if (carg > 1 && line[cursor-1] != ' ') 2116 filematch = argv[carg - 1]; 2117 2118 if (remote != 0 && 2119 complete_match(el, complete_ctx->conn, 2120 *complete_ctx->remote_pathp, filematch, 2121 remote, carg == argc, quote, terminated) != 0) 2122 ret = CC_REDISPLAY; 2123 } 2124 2125 free(line); 2126 return ret; 2127 } 2128 2129 static int 2130 interactive_loop(struct sftp_conn *conn, char *file1, char *file2) 2131 { 2132 char *remote_path; 2133 char *dir = NULL, *startdir = NULL; 2134 char cmd[2048]; 2135 int err, interactive; 2136 EditLine *el = NULL; 2137 History *hl = NULL; 2138 HistEvent hev; 2139 extern char *__progname; 2140 struct complete_ctx complete_ctx; 2141 2142 if (!batchmode && isatty(STDIN_FILENO)) { 2143 if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) 2144 fatal("Couldn't initialise editline"); 2145 if ((hl = history_init()) == NULL) 2146 fatal("Couldn't initialise editline history"); 2147 history(hl, &hev, H_SETSIZE, 100); 2148 el_set(el, EL_HIST, history, hl); 2149 2150 el_set(el, EL_PROMPT, prompt); 2151 el_set(el, EL_EDITOR, "emacs"); 2152 el_set(el, EL_TERMINAL, NULL); 2153 el_set(el, EL_SIGNAL, 1); 2154 el_source(el, NULL); 2155 2156 /* Tab Completion */ 2157 el_set(el, EL_ADDFN, "ftp-complete", 2158 "Context sensitive argument completion", complete); 2159 complete_ctx.conn = conn; 2160 complete_ctx.remote_pathp = &remote_path; 2161 el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); 2162 el_set(el, EL_BIND, "^I", "ftp-complete", NULL); 2163 /* enable ctrl-left-arrow and ctrl-right-arrow */ 2164 el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); 2165 el_set(el, EL_BIND, "\\e\\e[C", "em-next-word", NULL); 2166 el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); 2167 el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); 2168 /* make ^w match ksh behaviour */ 2169 el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); 2170 } 2171 2172 remote_path = do_realpath(conn, "."); 2173 if (remote_path == NULL) 2174 fatal("Need cwd"); 2175 startdir = xstrdup(remote_path); 2176 2177 if (file1 != NULL) { 2178 dir = xstrdup(file1); 2179 dir = make_absolute(dir, remote_path); 2180 2181 if (remote_is_dir(conn, dir) && file2 == NULL) { 2182 if (!quiet) 2183 mprintf("Changing to: %s\n", dir); 2184 snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); 2185 if (parse_dispatch_command(conn, cmd, 2186 &remote_path, startdir, 1, 0) != 0) { 2187 free(dir); 2188 free(startdir); 2189 free(remote_path); 2190 free(conn); 2191 return (-1); 2192 } 2193 } else { 2194 /* XXX this is wrong wrt quoting */ 2195 snprintf(cmd, sizeof cmd, "get%s %s%s%s", 2196 global_aflag ? " -a" : "", dir, 2197 file2 == NULL ? "" : " ", 2198 file2 == NULL ? "" : file2); 2199 err = parse_dispatch_command(conn, cmd, 2200 &remote_path, startdir, 1, 0); 2201 free(dir); 2202 free(startdir); 2203 free(remote_path); 2204 free(conn); 2205 return (err); 2206 } 2207 free(dir); 2208 } 2209 2210 setvbuf(stdout, NULL, _IOLBF, 0); 2211 setvbuf(infile, NULL, _IOLBF, 0); 2212 2213 interactive = !batchmode && isatty(STDIN_FILENO); 2214 err = 0; 2215 for (;;) { 2216 struct sigaction sa; 2217 const char *line; 2218 int count = 0; 2219 2220 interrupted = 0; 2221 memset(&sa, 0, sizeof(sa)); 2222 sa.sa_handler = interactive ? read_interrupt : killchild; 2223 if (sigaction(SIGINT, &sa, NULL) == -1) { 2224 debug3("sigaction(%s): %s", strsignal(SIGINT), 2225 strerror(errno)); 2226 break; 2227 } 2228 if (el == NULL) { 2229 if (interactive) 2230 printf("sftp> "); 2231 if (fgets(cmd, sizeof(cmd), infile) == NULL) { 2232 if (interactive) 2233 printf("\n"); 2234 if (interrupted) 2235 continue; 2236 break; 2237 } 2238 } else { 2239 if ((line = el_gets(el, &count)) == NULL || 2240 count <= 0) { 2241 printf("\n"); 2242 if (interrupted) 2243 continue; 2244 break; 2245 } 2246 history(hl, &hev, H_ENTER, line); 2247 if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) { 2248 fprintf(stderr, "Error: input line too long\n"); 2249 continue; 2250 } 2251 } 2252 2253 cmd[strcspn(cmd, "\n")] = '\0'; 2254 2255 /* Handle user interrupts gracefully during commands */ 2256 interrupted = 0; 2257 ssh_signal(SIGINT, cmd_interrupt); 2258 2259 err = parse_dispatch_command(conn, cmd, &remote_path, 2260 startdir, batchmode, !interactive && el == NULL); 2261 if (err != 0) 2262 break; 2263 } 2264 ssh_signal(SIGCHLD, SIG_DFL); 2265 free(remote_path); 2266 free(startdir); 2267 free(conn); 2268 2269 if (el != NULL) 2270 el_end(el); 2271 2272 /* err == 1 signifies normal "quit" exit */ 2273 return (err >= 0 ? 0 : -1); 2274 } 2275 2276 static void 2277 connect_to_server(char *path, char **args, int *in, int *out) 2278 { 2279 int c_in, c_out, inout[2]; 2280 2281 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 2282 fatal("socketpair: %s", strerror(errno)); 2283 *in = *out = inout[0]; 2284 c_in = c_out = inout[1]; 2285 2286 if ((sshpid = fork()) == -1) 2287 fatal("fork: %s", strerror(errno)); 2288 else if (sshpid == 0) { 2289 if ((dup2(c_in, STDIN_FILENO) == -1) || 2290 (dup2(c_out, STDOUT_FILENO) == -1)) { 2291 fprintf(stderr, "dup2: %s\n", strerror(errno)); 2292 _exit(1); 2293 } 2294 close(*in); 2295 close(*out); 2296 close(c_in); 2297 close(c_out); 2298 2299 /* 2300 * The underlying ssh is in the same process group, so we must 2301 * ignore SIGINT if we want to gracefully abort commands, 2302 * otherwise the signal will make it to the ssh process and 2303 * kill it too. Contrawise, since sftp sends SIGTERMs to the 2304 * underlying ssh, it must *not* ignore that signal. 2305 */ 2306 ssh_signal(SIGINT, SIG_IGN); 2307 ssh_signal(SIGTERM, SIG_DFL); 2308 execvp(path, args); 2309 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 2310 _exit(1); 2311 } 2312 2313 ssh_signal(SIGTERM, killchild); 2314 ssh_signal(SIGINT, killchild); 2315 ssh_signal(SIGHUP, killchild); 2316 ssh_signal(SIGTSTP, suspchild); 2317 ssh_signal(SIGTTIN, suspchild); 2318 ssh_signal(SIGTTOU, suspchild); 2319 ssh_signal(SIGCHLD, sigchld_handler); 2320 close(c_in); 2321 close(c_out); 2322 } 2323 2324 static void 2325 usage(void) 2326 { 2327 extern char *__progname; 2328 2329 fprintf(stderr, 2330 "usage: %s [-46AaCfNpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" 2331 " [-D sftp_server_command] [-F ssh_config] [-i identity_file]\n" 2332 " [-J destination] [-l limit] [-o ssh_option] [-P port]\n" 2333 " [-R num_requests] [-S program] [-s subsystem | sftp_server]\n" 2334 " destination\n", 2335 __progname); 2336 exit(1); 2337 } 2338 2339 int 2340 main(int argc, char **argv) 2341 { 2342 int r, in, out, ch, err, tmp, port = -1, noisy = 0; 2343 char *host = NULL, *user, *cp, **cpp, *file2 = NULL; 2344 int debug_level = 0; 2345 char *file1 = NULL, *sftp_server = NULL; 2346 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 2347 const char *errstr; 2348 LogLevel ll = SYSLOG_LEVEL_INFO; 2349 arglist args; 2350 extern int optind; 2351 extern char *optarg; 2352 struct sftp_conn *conn; 2353 size_t copy_buffer_len = 0; 2354 size_t num_requests = 0; 2355 long long limit_kbps = 0; 2356 2357 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 2358 sanitise_stdfd(); 2359 setlocale(LC_CTYPE, ""); 2360 2361 memset(&args, '\0', sizeof(args)); 2362 args.list = NULL; 2363 addargs(&args, "%s", ssh_program); 2364 addargs(&args, "-oForwardX11 no"); 2365 addargs(&args, "-oPermitLocalCommand no"); 2366 addargs(&args, "-oClearAllForwardings yes"); 2367 2368 ll = SYSLOG_LEVEL_INFO; 2369 infile = stdin; 2370 2371 while ((ch = getopt(argc, argv, 2372 "1246AafhNpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { 2373 switch (ch) { 2374 /* Passed through to ssh(1) */ 2375 case 'A': 2376 case '4': 2377 case '6': 2378 case 'C': 2379 addargs(&args, "-%c", ch); 2380 break; 2381 /* Passed through to ssh(1) with argument */ 2382 case 'F': 2383 case 'J': 2384 case 'c': 2385 case 'i': 2386 case 'o': 2387 addargs(&args, "-%c", ch); 2388 addargs(&args, "%s", optarg); 2389 break; 2390 case 'q': 2391 ll = SYSLOG_LEVEL_ERROR; 2392 quiet = 1; 2393 showprogress = 0; 2394 addargs(&args, "-%c", ch); 2395 break; 2396 case 'P': 2397 port = a2port(optarg); 2398 if (port <= 0) 2399 fatal("Bad port \"%s\"\n", optarg); 2400 break; 2401 case 'v': 2402 if (debug_level < 3) { 2403 addargs(&args, "-v"); 2404 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 2405 } 2406 debug_level++; 2407 break; 2408 case '1': 2409 fatal("SSH protocol v.1 is no longer supported"); 2410 break; 2411 case '2': 2412 /* accept silently */ 2413 break; 2414 case 'a': 2415 global_aflag = 1; 2416 break; 2417 case 'B': 2418 copy_buffer_len = strtol(optarg, &cp, 10); 2419 if (copy_buffer_len == 0 || *cp != '\0') 2420 fatal("Invalid buffer size \"%s\"", optarg); 2421 break; 2422 case 'b': 2423 if (batchmode) 2424 fatal("Batch file already specified."); 2425 2426 /* Allow "-" as stdin */ 2427 if (strcmp(optarg, "-") != 0 && 2428 (infile = fopen(optarg, "r")) == NULL) 2429 fatal("%s (%s).", strerror(errno), optarg); 2430 showprogress = 0; 2431 quiet = batchmode = 1; 2432 addargs(&args, "-obatchmode yes"); 2433 break; 2434 case 'f': 2435 global_fflag = 1; 2436 break; 2437 case 'N': 2438 noisy = 1; /* Used to clear quiet mode after getopt */ 2439 break; 2440 case 'p': 2441 global_pflag = 1; 2442 break; 2443 case 'D': 2444 sftp_direct = optarg; 2445 break; 2446 case 'l': 2447 limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024, 2448 &errstr); 2449 if (errstr != NULL) 2450 usage(); 2451 limit_kbps *= 1024; /* kbps */ 2452 break; 2453 case 'r': 2454 global_rflag = 1; 2455 break; 2456 case 'R': 2457 num_requests = strtol(optarg, &cp, 10); 2458 if (num_requests == 0 || *cp != '\0') 2459 fatal("Invalid number of requests \"%s\"", 2460 optarg); 2461 break; 2462 case 's': 2463 sftp_server = optarg; 2464 break; 2465 case 'S': 2466 ssh_program = optarg; 2467 replacearg(&args, 0, "%s", ssh_program); 2468 break; 2469 case 'h': 2470 default: 2471 usage(); 2472 } 2473 } 2474 2475 /* Do this last because we want the user to be able to override it */ 2476 addargs(&args, "-oForwardAgent no"); 2477 2478 if (!isatty(STDERR_FILENO)) 2479 showprogress = 0; 2480 2481 if (noisy) 2482 quiet = 0; 2483 2484 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 2485 2486 if (sftp_direct == NULL) { 2487 if (optind == argc || argc > (optind + 2)) 2488 usage(); 2489 argv += optind; 2490 2491 switch (parse_uri("sftp", *argv, &user, &host, &tmp, &file1)) { 2492 case -1: 2493 usage(); 2494 break; 2495 case 0: 2496 if (tmp != -1) 2497 port = tmp; 2498 break; 2499 default: 2500 /* Try with user, host and path. */ 2501 if (parse_user_host_path(*argv, &user, &host, 2502 &file1) == 0) 2503 break; 2504 /* Try with user and host. */ 2505 if (parse_user_host_port(*argv, &user, &host, NULL) 2506 == 0) 2507 break; 2508 /* Treat as a plain hostname. */ 2509 host = xstrdup(*argv); 2510 host = cleanhostname(host); 2511 break; 2512 } 2513 file2 = *(argv + 1); 2514 2515 if (!*host) { 2516 fprintf(stderr, "Missing hostname\n"); 2517 usage(); 2518 } 2519 2520 if (port != -1) 2521 addargs(&args, "-oPort %d", port); 2522 if (user != NULL) { 2523 addargs(&args, "-l"); 2524 addargs(&args, "%s", user); 2525 } 2526 2527 /* no subsystem if the server-spec contains a '/' */ 2528 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 2529 addargs(&args, "-s"); 2530 2531 addargs(&args, "--"); 2532 addargs(&args, "%s", host); 2533 addargs(&args, "%s", (sftp_server != NULL ? 2534 sftp_server : "sftp")); 2535 2536 connect_to_server(ssh_program, args.list, &in, &out); 2537 } else { 2538 if ((r = argv_split(sftp_direct, &tmp, &cpp, 1)) != 0) 2539 fatal_r(r, "Parse -D arguments"); 2540 if (cpp[0] == 0) 2541 fatal("No sftp server specified via -D"); 2542 connect_to_server(cpp[0], cpp, &in, &out); 2543 argv_free(cpp, tmp); 2544 } 2545 freeargs(&args); 2546 2547 conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); 2548 if (conn == NULL) 2549 fatal("Couldn't initialise connection to server"); 2550 2551 if (!quiet) { 2552 if (sftp_direct == NULL) 2553 fprintf(stderr, "Connected to %s.\n", host); 2554 else 2555 fprintf(stderr, "Attached to %s.\n", sftp_direct); 2556 } 2557 2558 err = interactive_loop(conn, file1, file2); 2559 2560 close(in); 2561 close(out); 2562 if (batchmode) 2563 fclose(infile); 2564 2565 while (waitpid(sshpid, NULL, 0) == -1 && sshpid > 1) 2566 if (errno != EINTR) 2567 fatal("Couldn't wait for ssh process: %s", 2568 strerror(errno)); 2569 2570 exit(err == 0 ? 0 : 1); 2571 } 2572