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