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