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