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