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