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