1 /* 2 * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 #include "includes.h" 25 RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm Exp $"); 26 27 #include "buffer.h" 28 #include "bufaux.h" 29 #include "getput.h" 30 #include "log.h" 31 #include "xmalloc.h" 32 33 #include "sftp.h" 34 #include "sftp-common.h" 35 36 /* helper */ 37 #define get_int64() buffer_get_int64(&iqueue); 38 #define get_int() buffer_get_int(&iqueue); 39 #define get_string(lenp) buffer_get_string(&iqueue, lenp); 40 #define TRACE debug 41 42 #ifdef HAVE___PROGNAME 43 extern char *__progname; 44 #else 45 char *__progname; 46 #endif 47 48 /* input and output queue */ 49 Buffer iqueue; 50 Buffer oqueue; 51 52 /* Version of client */ 53 int version; 54 55 /* portable attibutes, etc. */ 56 57 typedef struct Stat Stat; 58 59 struct Stat { 60 char *name; 61 char *long_name; 62 Attrib attrib; 63 }; 64 65 static int 66 errno_to_portable(int unixerrno) 67 { 68 int ret = 0; 69 70 switch (unixerrno) { 71 case 0: 72 ret = SSH2_FX_OK; 73 break; 74 case ENOENT: 75 case ENOTDIR: 76 case EBADF: 77 case ELOOP: 78 ret = SSH2_FX_NO_SUCH_FILE; 79 break; 80 case EPERM: 81 case EACCES: 82 case EFAULT: 83 ret = SSH2_FX_PERMISSION_DENIED; 84 break; 85 case ENAMETOOLONG: 86 case EINVAL: 87 ret = SSH2_FX_BAD_MESSAGE; 88 break; 89 default: 90 ret = SSH2_FX_FAILURE; 91 break; 92 } 93 return ret; 94 } 95 96 static int 97 flags_from_portable(int pflags) 98 { 99 int flags = 0; 100 101 if ((pflags & SSH2_FXF_READ) && 102 (pflags & SSH2_FXF_WRITE)) { 103 flags = O_RDWR; 104 } else if (pflags & SSH2_FXF_READ) { 105 flags = O_RDONLY; 106 } else if (pflags & SSH2_FXF_WRITE) { 107 flags = O_WRONLY; 108 } 109 if (pflags & SSH2_FXF_CREAT) 110 flags |= O_CREAT; 111 if (pflags & SSH2_FXF_TRUNC) 112 flags |= O_TRUNC; 113 if (pflags & SSH2_FXF_EXCL) 114 flags |= O_EXCL; 115 return flags; 116 } 117 118 static Attrib * 119 get_attrib(void) 120 { 121 return decode_attrib(&iqueue); 122 } 123 124 /* handle handles */ 125 126 typedef struct Handle Handle; 127 struct Handle { 128 int use; 129 DIR *dirp; 130 int fd; 131 char *name; 132 }; 133 134 enum { 135 HANDLE_UNUSED, 136 HANDLE_DIR, 137 HANDLE_FILE 138 }; 139 140 Handle handles[100]; 141 142 static void 143 handle_init(void) 144 { 145 int i; 146 147 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) 148 handles[i].use = HANDLE_UNUSED; 149 } 150 151 static int 152 handle_new(int use, char *name, int fd, DIR *dirp) 153 { 154 int i; 155 156 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) { 157 if (handles[i].use == HANDLE_UNUSED) { 158 handles[i].use = use; 159 handles[i].dirp = dirp; 160 handles[i].fd = fd; 161 handles[i].name = name; 162 return i; 163 } 164 } 165 return -1; 166 } 167 168 static int 169 handle_is_ok(int i, int type) 170 { 171 return i >= 0 && i < sizeof(handles)/sizeof(Handle) && 172 handles[i].use == type; 173 } 174 175 static int 176 handle_to_string(int handle, char **stringp, int *hlenp) 177 { 178 if (stringp == NULL || hlenp == NULL) 179 return -1; 180 *stringp = xmalloc(sizeof(int32_t)); 181 PUT_32BIT(*stringp, handle); 182 *hlenp = sizeof(int32_t); 183 return 0; 184 } 185 186 static int 187 handle_from_string(char *handle, u_int hlen) 188 { 189 int val; 190 191 if (hlen != sizeof(int32_t)) 192 return -1; 193 val = GET_32BIT(handle); 194 if (handle_is_ok(val, HANDLE_FILE) || 195 handle_is_ok(val, HANDLE_DIR)) 196 return val; 197 return -1; 198 } 199 200 static char * 201 handle_to_name(int handle) 202 { 203 if (handle_is_ok(handle, HANDLE_DIR)|| 204 handle_is_ok(handle, HANDLE_FILE)) 205 return handles[handle].name; 206 return NULL; 207 } 208 209 static DIR * 210 handle_to_dir(int handle) 211 { 212 if (handle_is_ok(handle, HANDLE_DIR)) 213 return handles[handle].dirp; 214 return NULL; 215 } 216 217 static int 218 handle_to_fd(int handle) 219 { 220 if (handle_is_ok(handle, HANDLE_FILE)) 221 return handles[handle].fd; 222 return -1; 223 } 224 225 static int 226 handle_close(int handle) 227 { 228 int ret = -1; 229 230 if (handle_is_ok(handle, HANDLE_FILE)) { 231 ret = close(handles[handle].fd); 232 handles[handle].use = HANDLE_UNUSED; 233 } else if (handle_is_ok(handle, HANDLE_DIR)) { 234 ret = closedir(handles[handle].dirp); 235 handles[handle].use = HANDLE_UNUSED; 236 } else { 237 errno = ENOENT; 238 } 239 return ret; 240 } 241 242 static int 243 get_handle(void) 244 { 245 char *handle; 246 int val = -1; 247 u_int hlen; 248 249 handle = get_string(&hlen); 250 if (hlen < 256) 251 val = handle_from_string(handle, hlen); 252 xfree(handle); 253 return val; 254 } 255 256 /* send replies */ 257 258 static void 259 send_msg(Buffer *m) 260 { 261 int mlen = buffer_len(m); 262 263 buffer_put_int(&oqueue, mlen); 264 buffer_append(&oqueue, buffer_ptr(m), mlen); 265 buffer_consume(m, mlen); 266 } 267 268 static void 269 send_status(u_int32_t id, u_int32_t error) 270 { 271 Buffer msg; 272 const char *status_messages[] = { 273 "Success", /* SSH_FX_OK */ 274 "End of file", /* SSH_FX_EOF */ 275 "No such file", /* SSH_FX_NO_SUCH_FILE */ 276 "Permission denied", /* SSH_FX_PERMISSION_DENIED */ 277 "Failure", /* SSH_FX_FAILURE */ 278 "Bad message", /* SSH_FX_BAD_MESSAGE */ 279 "No connection", /* SSH_FX_NO_CONNECTION */ 280 "Connection lost", /* SSH_FX_CONNECTION_LOST */ 281 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ 282 "Unknown error" /* Others */ 283 }; 284 285 TRACE("sent status id %u error %u", id, error); 286 buffer_init(&msg); 287 buffer_put_char(&msg, SSH2_FXP_STATUS); 288 buffer_put_int(&msg, id); 289 buffer_put_int(&msg, error); 290 if (version >= 3) { 291 buffer_put_cstring(&msg, 292 status_messages[MIN(error,SSH2_FX_MAX)]); 293 buffer_put_cstring(&msg, ""); 294 } 295 send_msg(&msg); 296 buffer_free(&msg); 297 } 298 static void 299 send_data_or_handle(char type, u_int32_t id, char *data, int dlen) 300 { 301 Buffer msg; 302 303 buffer_init(&msg); 304 buffer_put_char(&msg, type); 305 buffer_put_int(&msg, id); 306 buffer_put_string(&msg, data, dlen); 307 send_msg(&msg); 308 buffer_free(&msg); 309 } 310 311 static void 312 send_data(u_int32_t id, char *data, int dlen) 313 { 314 TRACE("sent data id %u len %d", id, dlen); 315 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); 316 } 317 318 static void 319 send_handle(u_int32_t id, int handle) 320 { 321 char *string; 322 int hlen; 323 324 handle_to_string(handle, &string, &hlen); 325 TRACE("sent handle id %u handle %d", id, handle); 326 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); 327 xfree(string); 328 } 329 330 static void 331 send_names(u_int32_t id, int count, Stat *stats) 332 { 333 Buffer msg; 334 int i; 335 336 buffer_init(&msg); 337 buffer_put_char(&msg, SSH2_FXP_NAME); 338 buffer_put_int(&msg, id); 339 buffer_put_int(&msg, count); 340 TRACE("sent names id %u count %d", id, count); 341 for (i = 0; i < count; i++) { 342 buffer_put_cstring(&msg, stats[i].name); 343 buffer_put_cstring(&msg, stats[i].long_name); 344 encode_attrib(&msg, &stats[i].attrib); 345 } 346 send_msg(&msg); 347 buffer_free(&msg); 348 } 349 350 static void 351 send_attrib(u_int32_t id, Attrib *a) 352 { 353 Buffer msg; 354 355 TRACE("sent attrib id %u have 0x%x", id, a->flags); 356 buffer_init(&msg); 357 buffer_put_char(&msg, SSH2_FXP_ATTRS); 358 buffer_put_int(&msg, id); 359 encode_attrib(&msg, a); 360 send_msg(&msg); 361 buffer_free(&msg); 362 } 363 364 /* parse incoming */ 365 366 static void 367 process_init(void) 368 { 369 Buffer msg; 370 371 version = get_int(); 372 TRACE("client version %d", version); 373 buffer_init(&msg); 374 buffer_put_char(&msg, SSH2_FXP_VERSION); 375 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 376 send_msg(&msg); 377 buffer_free(&msg); 378 } 379 380 static void 381 process_open(void) 382 { 383 u_int32_t id, pflags; 384 Attrib *a; 385 char *name; 386 int handle, fd, flags, mode, status = SSH2_FX_FAILURE; 387 388 id = get_int(); 389 name = get_string(NULL); 390 pflags = get_int(); /* portable flags */ 391 a = get_attrib(); 392 flags = flags_from_portable(pflags); 393 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; 394 TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); 395 fd = open(name, flags, mode); 396 if (fd < 0) { 397 status = errno_to_portable(errno); 398 } else { 399 handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL); 400 if (handle < 0) { 401 close(fd); 402 } else { 403 send_handle(id, handle); 404 status = SSH2_FX_OK; 405 } 406 } 407 if (status != SSH2_FX_OK) 408 send_status(id, status); 409 xfree(name); 410 } 411 412 static void 413 process_close(void) 414 { 415 u_int32_t id; 416 int handle, ret, status = SSH2_FX_FAILURE; 417 418 id = get_int(); 419 handle = get_handle(); 420 TRACE("close id %u handle %d", id, handle); 421 ret = handle_close(handle); 422 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 423 send_status(id, status); 424 } 425 426 static void 427 process_read(void) 428 { 429 char buf[64*1024]; 430 u_int32_t id, len; 431 int handle, fd, ret, status = SSH2_FX_FAILURE; 432 u_int64_t off; 433 434 id = get_int(); 435 handle = get_handle(); 436 off = get_int64(); 437 len = get_int(); 438 439 TRACE("read id %u handle %d off %llu len %d", id, handle, 440 (u_int64_t)off, len); 441 if (len > sizeof buf) { 442 len = sizeof buf; 443 log("read change len %d", len); 444 } 445 fd = handle_to_fd(handle); 446 if (fd >= 0) { 447 if (lseek(fd, off, SEEK_SET) < 0) { 448 error("process_read: seek failed"); 449 status = errno_to_portable(errno); 450 } else { 451 ret = read(fd, buf, len); 452 if (ret < 0) { 453 status = errno_to_portable(errno); 454 } else if (ret == 0) { 455 status = SSH2_FX_EOF; 456 } else { 457 send_data(id, buf, ret); 458 status = SSH2_FX_OK; 459 } 460 } 461 } 462 if (status != SSH2_FX_OK) 463 send_status(id, status); 464 } 465 466 static void 467 process_write(void) 468 { 469 u_int32_t id; 470 u_int64_t off; 471 u_int len; 472 int handle, fd, ret, status = SSH2_FX_FAILURE; 473 char *data; 474 475 id = get_int(); 476 handle = get_handle(); 477 off = get_int64(); 478 data = get_string(&len); 479 480 TRACE("write id %u handle %d off %llu len %d", id, handle, 481 (u_int64_t)off, len); 482 fd = handle_to_fd(handle); 483 if (fd >= 0) { 484 if (lseek(fd, off, SEEK_SET) < 0) { 485 status = errno_to_portable(errno); 486 error("process_write: seek failed"); 487 } else { 488 /* XXX ATOMICIO ? */ 489 ret = write(fd, data, len); 490 if (ret == -1) { 491 error("process_write: write failed"); 492 status = errno_to_portable(errno); 493 } else if (ret == len) { 494 status = SSH2_FX_OK; 495 } else { 496 log("nothing at all written"); 497 } 498 } 499 } 500 send_status(id, status); 501 xfree(data); 502 } 503 504 static void 505 process_do_stat(int do_lstat) 506 { 507 Attrib a; 508 struct stat st; 509 u_int32_t id; 510 char *name; 511 int ret, status = SSH2_FX_FAILURE; 512 513 id = get_int(); 514 name = get_string(NULL); 515 TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); 516 ret = do_lstat ? lstat(name, &st) : stat(name, &st); 517 if (ret < 0) { 518 status = errno_to_portable(errno); 519 } else { 520 stat_to_attrib(&st, &a); 521 send_attrib(id, &a); 522 status = SSH2_FX_OK; 523 } 524 if (status != SSH2_FX_OK) 525 send_status(id, status); 526 xfree(name); 527 } 528 529 static void 530 process_stat(void) 531 { 532 process_do_stat(0); 533 } 534 535 static void 536 process_lstat(void) 537 { 538 process_do_stat(1); 539 } 540 541 static void 542 process_fstat(void) 543 { 544 Attrib a; 545 struct stat st; 546 u_int32_t id; 547 int fd, ret, handle, status = SSH2_FX_FAILURE; 548 549 id = get_int(); 550 handle = get_handle(); 551 TRACE("fstat id %u handle %d", id, handle); 552 fd = handle_to_fd(handle); 553 if (fd >= 0) { 554 ret = fstat(fd, &st); 555 if (ret < 0) { 556 status = errno_to_portable(errno); 557 } else { 558 stat_to_attrib(&st, &a); 559 send_attrib(id, &a); 560 status = SSH2_FX_OK; 561 } 562 } 563 if (status != SSH2_FX_OK) 564 send_status(id, status); 565 } 566 567 static struct timeval * 568 attrib_to_tv(Attrib *a) 569 { 570 static struct timeval tv[2]; 571 572 tv[0].tv_sec = a->atime; 573 tv[0].tv_usec = 0; 574 tv[1].tv_sec = a->mtime; 575 tv[1].tv_usec = 0; 576 return tv; 577 } 578 579 static void 580 process_setstat(void) 581 { 582 Attrib *a; 583 u_int32_t id; 584 char *name; 585 int status = SSH2_FX_OK, ret; 586 587 id = get_int(); 588 name = get_string(NULL); 589 a = get_attrib(); 590 TRACE("setstat id %u name %s", id, name); 591 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 592 ret = truncate(name, a->size); 593 if (ret == -1) 594 status = errno_to_portable(errno); 595 } 596 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 597 ret = chmod(name, a->perm & 0777); 598 if (ret == -1) 599 status = errno_to_portable(errno); 600 } 601 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 602 ret = utimes(name, attrib_to_tv(a)); 603 if (ret == -1) 604 status = errno_to_portable(errno); 605 } 606 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 607 ret = chown(name, a->uid, a->gid); 608 if (ret == -1) 609 status = errno_to_portable(errno); 610 } 611 send_status(id, status); 612 xfree(name); 613 } 614 615 static void 616 process_fsetstat(void) 617 { 618 Attrib *a; 619 u_int32_t id; 620 int handle, fd, ret; 621 int status = SSH2_FX_OK; 622 char *name; 623 624 id = get_int(); 625 handle = get_handle(); 626 a = get_attrib(); 627 TRACE("fsetstat id %u handle %d", id, handle); 628 fd = handle_to_fd(handle); 629 name = handle_to_name(handle); 630 if (fd < 0 || name == NULL) { 631 status = SSH2_FX_FAILURE; 632 } else { 633 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 634 ret = ftruncate(fd, a->size); 635 if (ret == -1) 636 status = errno_to_portable(errno); 637 } 638 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 639 #ifdef HAVE_FCHMOD 640 ret = fchmod(fd, a->perm & 0777); 641 #else 642 ret = chmod(name, a->perm & 0777); 643 #endif 644 if (ret == -1) 645 status = errno_to_portable(errno); 646 } 647 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 648 #ifdef HAVE_FUTIMES 649 ret = futimes(fd, attrib_to_tv(a)); 650 #else 651 ret = utimes(name, attrib_to_tv(a)); 652 #endif 653 if (ret == -1) 654 status = errno_to_portable(errno); 655 } 656 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 657 #ifdef HAVE_FCHOWN 658 ret = fchown(fd, a->uid, a->gid); 659 #else 660 ret = chown(name, a->uid, a->gid); 661 #endif 662 if (ret == -1) 663 status = errno_to_portable(errno); 664 } 665 } 666 send_status(id, status); 667 } 668 669 static void 670 process_opendir(void) 671 { 672 DIR *dirp = NULL; 673 char *path; 674 int handle, status = SSH2_FX_FAILURE; 675 u_int32_t id; 676 677 id = get_int(); 678 path = get_string(NULL); 679 TRACE("opendir id %u path %s", id, path); 680 dirp = opendir(path); 681 if (dirp == NULL) { 682 status = errno_to_portable(errno); 683 } else { 684 handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); 685 if (handle < 0) { 686 closedir(dirp); 687 } else { 688 send_handle(id, handle); 689 status = SSH2_FX_OK; 690 } 691 692 } 693 if (status != SSH2_FX_OK) 694 send_status(id, status); 695 xfree(path); 696 } 697 698 static void 699 process_readdir(void) 700 { 701 DIR *dirp; 702 struct dirent *dp; 703 char *path; 704 int handle; 705 u_int32_t id; 706 707 id = get_int(); 708 handle = get_handle(); 709 TRACE("readdir id %u handle %d", id, handle); 710 dirp = handle_to_dir(handle); 711 path = handle_to_name(handle); 712 if (dirp == NULL || path == NULL) { 713 send_status(id, SSH2_FX_FAILURE); 714 } else { 715 struct stat st; 716 char pathname[1024]; 717 Stat *stats; 718 int nstats = 10, count = 0, i; 719 720 stats = xmalloc(nstats * sizeof(Stat)); 721 while ((dp = readdir(dirp)) != NULL) { 722 if (count >= nstats) { 723 nstats *= 2; 724 stats = xrealloc(stats, nstats * sizeof(Stat)); 725 } 726 /* XXX OVERFLOW ? */ 727 snprintf(pathname, sizeof pathname, "%s%s%s", path, 728 strcmp(path, "/") ? "/" : "", dp->d_name); 729 if (lstat(pathname, &st) < 0) 730 continue; 731 stat_to_attrib(&st, &(stats[count].attrib)); 732 stats[count].name = xstrdup(dp->d_name); 733 stats[count].long_name = ls_file(dp->d_name, &st, 0); 734 count++; 735 /* send up to 100 entries in one message */ 736 /* XXX check packet size instead */ 737 if (count == 100) 738 break; 739 } 740 if (count > 0) { 741 send_names(id, count, stats); 742 for (i = 0; i < count; i++) { 743 xfree(stats[i].name); 744 xfree(stats[i].long_name); 745 } 746 } else { 747 send_status(id, SSH2_FX_EOF); 748 } 749 xfree(stats); 750 } 751 } 752 753 static void 754 process_remove(void) 755 { 756 char *name; 757 u_int32_t id; 758 int status = SSH2_FX_FAILURE; 759 int ret; 760 761 id = get_int(); 762 name = get_string(NULL); 763 TRACE("remove id %u name %s", id, name); 764 ret = unlink(name); 765 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 766 send_status(id, status); 767 xfree(name); 768 } 769 770 static void 771 process_mkdir(void) 772 { 773 Attrib *a; 774 u_int32_t id; 775 char *name; 776 int ret, mode, status = SSH2_FX_FAILURE; 777 778 id = get_int(); 779 name = get_string(NULL); 780 a = get_attrib(); 781 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 782 a->perm & 0777 : 0777; 783 TRACE("mkdir id %u name %s mode 0%o", id, name, mode); 784 ret = mkdir(name, mode); 785 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 786 send_status(id, status); 787 xfree(name); 788 } 789 790 static void 791 process_rmdir(void) 792 { 793 u_int32_t id; 794 char *name; 795 int ret, status; 796 797 id = get_int(); 798 name = get_string(NULL); 799 TRACE("rmdir id %u name %s", id, name); 800 ret = rmdir(name); 801 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 802 send_status(id, status); 803 xfree(name); 804 } 805 806 static void 807 process_realpath(void) 808 { 809 char resolvedname[MAXPATHLEN]; 810 u_int32_t id; 811 char *path; 812 813 id = get_int(); 814 path = get_string(NULL); 815 if (path[0] == '\0') { 816 xfree(path); 817 path = xstrdup("."); 818 } 819 TRACE("realpath id %u path %s", id, path); 820 if (realpath(path, resolvedname) == NULL) { 821 send_status(id, errno_to_portable(errno)); 822 } else { 823 Stat s; 824 attrib_clear(&s.attrib); 825 s.name = s.long_name = resolvedname; 826 send_names(id, 1, &s); 827 } 828 xfree(path); 829 } 830 831 static void 832 process_rename(void) 833 { 834 u_int32_t id; 835 struct stat st; 836 char *oldpath, *newpath; 837 int ret, status = SSH2_FX_FAILURE; 838 839 id = get_int(); 840 oldpath = get_string(NULL); 841 newpath = get_string(NULL); 842 TRACE("rename id %u old %s new %s", id, oldpath, newpath); 843 /* fail if 'newpath' exists */ 844 if (stat(newpath, &st) == -1) { 845 ret = rename(oldpath, newpath); 846 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 847 } 848 send_status(id, status); 849 xfree(oldpath); 850 xfree(newpath); 851 } 852 853 static void 854 process_readlink(void) 855 { 856 u_int32_t id; 857 int len; 858 char link[MAXPATHLEN]; 859 char *path; 860 861 id = get_int(); 862 path = get_string(NULL); 863 TRACE("readlink id %u path %s", id, path); 864 if ((len = readlink(path, link, sizeof(link) - 1)) == -1) 865 send_status(id, errno_to_portable(errno)); 866 else { 867 Stat s; 868 869 link[len] = '\0'; 870 attrib_clear(&s.attrib); 871 s.name = s.long_name = link; 872 send_names(id, 1, &s); 873 } 874 xfree(path); 875 } 876 877 static void 878 process_symlink(void) 879 { 880 u_int32_t id; 881 struct stat st; 882 char *oldpath, *newpath; 883 int ret, status = SSH2_FX_FAILURE; 884 885 id = get_int(); 886 oldpath = get_string(NULL); 887 newpath = get_string(NULL); 888 TRACE("symlink id %u old %s new %s", id, oldpath, newpath); 889 /* fail if 'newpath' exists */ 890 if (stat(newpath, &st) == -1) { 891 ret = symlink(oldpath, newpath); 892 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 893 } 894 send_status(id, status); 895 xfree(oldpath); 896 xfree(newpath); 897 } 898 899 static void 900 process_extended(void) 901 { 902 u_int32_t id; 903 char *request; 904 905 id = get_int(); 906 request = get_string(NULL); 907 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 908 xfree(request); 909 } 910 911 /* stolen from ssh-agent */ 912 913 static void 914 process(void) 915 { 916 u_int msg_len; 917 u_int buf_len; 918 u_int consumed; 919 u_int type; 920 u_char *cp; 921 922 buf_len = buffer_len(&iqueue); 923 if (buf_len < 5) 924 return; /* Incomplete message. */ 925 cp = buffer_ptr(&iqueue); 926 msg_len = GET_32BIT(cp); 927 if (msg_len > 256 * 1024) { 928 error("bad message "); 929 exit(11); 930 } 931 if (buf_len < msg_len + 4) 932 return; 933 buffer_consume(&iqueue, 4); 934 buf_len -= 4; 935 type = buffer_get_char(&iqueue); 936 switch (type) { 937 case SSH2_FXP_INIT: 938 process_init(); 939 break; 940 case SSH2_FXP_OPEN: 941 process_open(); 942 break; 943 case SSH2_FXP_CLOSE: 944 process_close(); 945 break; 946 case SSH2_FXP_READ: 947 process_read(); 948 break; 949 case SSH2_FXP_WRITE: 950 process_write(); 951 break; 952 case SSH2_FXP_LSTAT: 953 process_lstat(); 954 break; 955 case SSH2_FXP_FSTAT: 956 process_fstat(); 957 break; 958 case SSH2_FXP_SETSTAT: 959 process_setstat(); 960 break; 961 case SSH2_FXP_FSETSTAT: 962 process_fsetstat(); 963 break; 964 case SSH2_FXP_OPENDIR: 965 process_opendir(); 966 break; 967 case SSH2_FXP_READDIR: 968 process_readdir(); 969 break; 970 case SSH2_FXP_REMOVE: 971 process_remove(); 972 break; 973 case SSH2_FXP_MKDIR: 974 process_mkdir(); 975 break; 976 case SSH2_FXP_RMDIR: 977 process_rmdir(); 978 break; 979 case SSH2_FXP_REALPATH: 980 process_realpath(); 981 break; 982 case SSH2_FXP_STAT: 983 process_stat(); 984 break; 985 case SSH2_FXP_RENAME: 986 process_rename(); 987 break; 988 case SSH2_FXP_READLINK: 989 process_readlink(); 990 break; 991 case SSH2_FXP_SYMLINK: 992 process_symlink(); 993 break; 994 case SSH2_FXP_EXTENDED: 995 process_extended(); 996 break; 997 default: 998 error("Unknown message %d", type); 999 break; 1000 } 1001 /* discard the remaining bytes from the current packet */ 1002 if (buf_len < buffer_len(&iqueue)) 1003 fatal("iqueue grows"); 1004 consumed = buf_len - buffer_len(&iqueue); 1005 if (msg_len < consumed) 1006 fatal("msg_len %d < consumed %d", msg_len, consumed); 1007 if (msg_len > consumed) 1008 buffer_consume(&iqueue, msg_len - consumed); 1009 } 1010 1011 int 1012 main(int ac, char **av) 1013 { 1014 fd_set *rset, *wset; 1015 int in, out, max; 1016 ssize_t len, olen, set_size; 1017 1018 /* XXX should use getopt */ 1019 1020 __progname = get_progname(av[0]); 1021 handle_init(); 1022 1023 #ifdef DEBUG_SFTP_SERVER 1024 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1025 #endif 1026 1027 in = dup(STDIN_FILENO); 1028 out = dup(STDOUT_FILENO); 1029 1030 #ifdef HAVE_CYGWIN 1031 setmode(in, O_BINARY); 1032 setmode(out, O_BINARY); 1033 #endif 1034 1035 max = 0; 1036 if (in > max) 1037 max = in; 1038 if (out > max) 1039 max = out; 1040 1041 buffer_init(&iqueue); 1042 buffer_init(&oqueue); 1043 1044 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); 1045 rset = (fd_set *)xmalloc(set_size); 1046 wset = (fd_set *)xmalloc(set_size); 1047 1048 for (;;) { 1049 memset(rset, 0, set_size); 1050 memset(wset, 0, set_size); 1051 1052 FD_SET(in, rset); 1053 olen = buffer_len(&oqueue); 1054 if (olen > 0) 1055 FD_SET(out, wset); 1056 1057 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1058 if (errno == EINTR) 1059 continue; 1060 exit(2); 1061 } 1062 1063 /* copy stdin to iqueue */ 1064 if (FD_ISSET(in, rset)) { 1065 char buf[4*4096]; 1066 len = read(in, buf, sizeof buf); 1067 if (len == 0) { 1068 debug("read eof"); 1069 exit(0); 1070 } else if (len < 0) { 1071 error("read error"); 1072 exit(1); 1073 } else { 1074 buffer_append(&iqueue, buf, len); 1075 } 1076 } 1077 /* send oqueue to stdout */ 1078 if (FD_ISSET(out, wset)) { 1079 len = write(out, buffer_ptr(&oqueue), olen); 1080 if (len < 0) { 1081 error("write error"); 1082 exit(1); 1083 } else { 1084 buffer_consume(&oqueue, len); 1085 } 1086 } 1087 /* process requests from client */ 1088 process(); 1089 } 1090 } 1091