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