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.41 2003/03/26 04:02:51 deraadt 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 = xstrdup(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 xfree(handles[handle].name); 234 } else if (handle_is_ok(handle, HANDLE_DIR)) { 235 ret = closedir(handles[handle].dirp); 236 handles[handle].use = HANDLE_UNUSED; 237 xfree(handles[handle].name); 238 } else { 239 errno = ENOENT; 240 } 241 return ret; 242 } 243 244 static int 245 get_handle(void) 246 { 247 char *handle; 248 int val = -1; 249 u_int hlen; 250 251 handle = get_string(&hlen); 252 if (hlen < 256) 253 val = handle_from_string(handle, hlen); 254 xfree(handle); 255 return val; 256 } 257 258 /* send replies */ 259 260 static void 261 send_msg(Buffer *m) 262 { 263 int mlen = buffer_len(m); 264 265 buffer_put_int(&oqueue, mlen); 266 buffer_append(&oqueue, buffer_ptr(m), mlen); 267 buffer_consume(m, mlen); 268 } 269 270 static void 271 send_status(u_int32_t id, u_int32_t error) 272 { 273 Buffer msg; 274 const char *status_messages[] = { 275 "Success", /* SSH_FX_OK */ 276 "End of file", /* SSH_FX_EOF */ 277 "No such file", /* SSH_FX_NO_SUCH_FILE */ 278 "Permission denied", /* SSH_FX_PERMISSION_DENIED */ 279 "Failure", /* SSH_FX_FAILURE */ 280 "Bad message", /* SSH_FX_BAD_MESSAGE */ 281 "No connection", /* SSH_FX_NO_CONNECTION */ 282 "Connection lost", /* SSH_FX_CONNECTION_LOST */ 283 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ 284 "Unknown error" /* Others */ 285 }; 286 287 TRACE("sent status id %u error %u", id, error); 288 buffer_init(&msg); 289 buffer_put_char(&msg, SSH2_FXP_STATUS); 290 buffer_put_int(&msg, id); 291 buffer_put_int(&msg, error); 292 if (version >= 3) { 293 buffer_put_cstring(&msg, 294 status_messages[MIN(error,SSH2_FX_MAX)]); 295 buffer_put_cstring(&msg, ""); 296 } 297 send_msg(&msg); 298 buffer_free(&msg); 299 } 300 static void 301 send_data_or_handle(char type, u_int32_t id, char *data, int dlen) 302 { 303 Buffer msg; 304 305 buffer_init(&msg); 306 buffer_put_char(&msg, type); 307 buffer_put_int(&msg, id); 308 buffer_put_string(&msg, data, dlen); 309 send_msg(&msg); 310 buffer_free(&msg); 311 } 312 313 static void 314 send_data(u_int32_t id, char *data, int dlen) 315 { 316 TRACE("sent data id %u len %d", id, dlen); 317 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); 318 } 319 320 static void 321 send_handle(u_int32_t id, int handle) 322 { 323 char *string; 324 int hlen; 325 326 handle_to_string(handle, &string, &hlen); 327 TRACE("sent handle id %u handle %d", id, handle); 328 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); 329 xfree(string); 330 } 331 332 static void 333 send_names(u_int32_t id, int count, Stat *stats) 334 { 335 Buffer msg; 336 int i; 337 338 buffer_init(&msg); 339 buffer_put_char(&msg, SSH2_FXP_NAME); 340 buffer_put_int(&msg, id); 341 buffer_put_int(&msg, count); 342 TRACE("sent names id %u count %d", id, count); 343 for (i = 0; i < count; i++) { 344 buffer_put_cstring(&msg, stats[i].name); 345 buffer_put_cstring(&msg, stats[i].long_name); 346 encode_attrib(&msg, &stats[i].attrib); 347 } 348 send_msg(&msg); 349 buffer_free(&msg); 350 } 351 352 static void 353 send_attrib(u_int32_t id, Attrib *a) 354 { 355 Buffer msg; 356 357 TRACE("sent attrib id %u have 0x%x", id, a->flags); 358 buffer_init(&msg); 359 buffer_put_char(&msg, SSH2_FXP_ATTRS); 360 buffer_put_int(&msg, id); 361 encode_attrib(&msg, a); 362 send_msg(&msg); 363 buffer_free(&msg); 364 } 365 366 /* parse incoming */ 367 368 static void 369 process_init(void) 370 { 371 Buffer msg; 372 373 version = get_int(); 374 TRACE("client version %d", version); 375 buffer_init(&msg); 376 buffer_put_char(&msg, SSH2_FXP_VERSION); 377 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 378 send_msg(&msg); 379 buffer_free(&msg); 380 } 381 382 static void 383 process_open(void) 384 { 385 u_int32_t id, pflags; 386 Attrib *a; 387 char *name; 388 int handle, fd, flags, mode, status = SSH2_FX_FAILURE; 389 390 id = get_int(); 391 name = get_string(NULL); 392 pflags = get_int(); /* portable flags */ 393 a = get_attrib(); 394 flags = flags_from_portable(pflags); 395 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; 396 TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); 397 fd = open(name, flags, mode); 398 if (fd < 0) { 399 status = errno_to_portable(errno); 400 } else { 401 handle = handle_new(HANDLE_FILE, name, fd, NULL); 402 if (handle < 0) { 403 close(fd); 404 } else { 405 send_handle(id, handle); 406 status = SSH2_FX_OK; 407 } 408 } 409 if (status != SSH2_FX_OK) 410 send_status(id, status); 411 xfree(name); 412 } 413 414 static void 415 process_close(void) 416 { 417 u_int32_t id; 418 int handle, ret, status = SSH2_FX_FAILURE; 419 420 id = get_int(); 421 handle = get_handle(); 422 TRACE("close id %u handle %d", id, handle); 423 ret = handle_close(handle); 424 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 425 send_status(id, status); 426 } 427 428 static void 429 process_read(void) 430 { 431 char buf[64*1024]; 432 u_int32_t id, len; 433 int handle, fd, ret, status = SSH2_FX_FAILURE; 434 u_int64_t off; 435 436 id = get_int(); 437 handle = get_handle(); 438 off = get_int64(); 439 len = get_int(); 440 441 TRACE("read id %u handle %d off %llu len %d", id, handle, 442 (u_int64_t)off, len); 443 if (len > sizeof buf) { 444 len = sizeof buf; 445 log("read change len %d", len); 446 } 447 fd = handle_to_fd(handle); 448 if (fd >= 0) { 449 if (lseek(fd, off, SEEK_SET) < 0) { 450 error("process_read: seek failed"); 451 status = errno_to_portable(errno); 452 } else { 453 ret = read(fd, buf, len); 454 if (ret < 0) { 455 status = errno_to_portable(errno); 456 } else if (ret == 0) { 457 status = SSH2_FX_EOF; 458 } else { 459 send_data(id, buf, ret); 460 status = SSH2_FX_OK; 461 } 462 } 463 } 464 if (status != SSH2_FX_OK) 465 send_status(id, status); 466 } 467 468 static void 469 process_write(void) 470 { 471 u_int32_t id; 472 u_int64_t off; 473 u_int len; 474 int handle, fd, ret, status = SSH2_FX_FAILURE; 475 char *data; 476 477 id = get_int(); 478 handle = get_handle(); 479 off = get_int64(); 480 data = get_string(&len); 481 482 TRACE("write id %u handle %d off %llu len %d", id, handle, 483 (u_int64_t)off, len); 484 fd = handle_to_fd(handle); 485 if (fd >= 0) { 486 if (lseek(fd, off, SEEK_SET) < 0) { 487 status = errno_to_portable(errno); 488 error("process_write: seek failed"); 489 } else { 490 /* XXX ATOMICIO ? */ 491 ret = write(fd, data, len); 492 if (ret == -1) { 493 error("process_write: write failed"); 494 status = errno_to_portable(errno); 495 } else if (ret == len) { 496 status = SSH2_FX_OK; 497 } else { 498 log("nothing at all written"); 499 } 500 } 501 } 502 send_status(id, status); 503 xfree(data); 504 } 505 506 static void 507 process_do_stat(int do_lstat) 508 { 509 Attrib a; 510 struct stat st; 511 u_int32_t id; 512 char *name; 513 int ret, status = SSH2_FX_FAILURE; 514 515 id = get_int(); 516 name = get_string(NULL); 517 TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); 518 ret = do_lstat ? lstat(name, &st) : stat(name, &st); 519 if (ret < 0) { 520 status = errno_to_portable(errno); 521 } else { 522 stat_to_attrib(&st, &a); 523 send_attrib(id, &a); 524 status = SSH2_FX_OK; 525 } 526 if (status != SSH2_FX_OK) 527 send_status(id, status); 528 xfree(name); 529 } 530 531 static void 532 process_stat(void) 533 { 534 process_do_stat(0); 535 } 536 537 static void 538 process_lstat(void) 539 { 540 process_do_stat(1); 541 } 542 543 static void 544 process_fstat(void) 545 { 546 Attrib a; 547 struct stat st; 548 u_int32_t id; 549 int fd, ret, handle, status = SSH2_FX_FAILURE; 550 551 id = get_int(); 552 handle = get_handle(); 553 TRACE("fstat id %u handle %d", id, handle); 554 fd = handle_to_fd(handle); 555 if (fd >= 0) { 556 ret = fstat(fd, &st); 557 if (ret < 0) { 558 status = errno_to_portable(errno); 559 } else { 560 stat_to_attrib(&st, &a); 561 send_attrib(id, &a); 562 status = SSH2_FX_OK; 563 } 564 } 565 if (status != SSH2_FX_OK) 566 send_status(id, status); 567 } 568 569 static struct timeval * 570 attrib_to_tv(Attrib *a) 571 { 572 static struct timeval tv[2]; 573 574 tv[0].tv_sec = a->atime; 575 tv[0].tv_usec = 0; 576 tv[1].tv_sec = a->mtime; 577 tv[1].tv_usec = 0; 578 return tv; 579 } 580 581 static void 582 process_setstat(void) 583 { 584 Attrib *a; 585 u_int32_t id; 586 char *name; 587 int status = SSH2_FX_OK, ret; 588 589 id = get_int(); 590 name = get_string(NULL); 591 a = get_attrib(); 592 TRACE("setstat id %u name %s", id, name); 593 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 594 ret = truncate(name, a->size); 595 if (ret == -1) 596 status = errno_to_portable(errno); 597 } 598 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 599 ret = chmod(name, a->perm & 0777); 600 if (ret == -1) 601 status = errno_to_portable(errno); 602 } 603 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 604 ret = utimes(name, attrib_to_tv(a)); 605 if (ret == -1) 606 status = errno_to_portable(errno); 607 } 608 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 609 ret = chown(name, a->uid, a->gid); 610 if (ret == -1) 611 status = errno_to_portable(errno); 612 } 613 send_status(id, status); 614 xfree(name); 615 } 616 617 static void 618 process_fsetstat(void) 619 { 620 Attrib *a; 621 u_int32_t id; 622 int handle, fd, ret; 623 int status = SSH2_FX_OK; 624 char *name; 625 626 id = get_int(); 627 handle = get_handle(); 628 a = get_attrib(); 629 TRACE("fsetstat id %u handle %d", id, handle); 630 fd = handle_to_fd(handle); 631 name = handle_to_name(handle); 632 if (fd < 0 || name == NULL) { 633 status = SSH2_FX_FAILURE; 634 } else { 635 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 636 ret = ftruncate(fd, a->size); 637 if (ret == -1) 638 status = errno_to_portable(errno); 639 } 640 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 641 #ifdef HAVE_FCHMOD 642 ret = fchmod(fd, a->perm & 0777); 643 #else 644 ret = chmod(name, a->perm & 0777); 645 #endif 646 if (ret == -1) 647 status = errno_to_portable(errno); 648 } 649 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 650 #ifdef HAVE_FUTIMES 651 ret = futimes(fd, attrib_to_tv(a)); 652 #else 653 ret = utimes(name, attrib_to_tv(a)); 654 #endif 655 if (ret == -1) 656 status = errno_to_portable(errno); 657 } 658 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 659 #ifdef HAVE_FCHOWN 660 ret = fchown(fd, a->uid, a->gid); 661 #else 662 ret = chown(name, a->uid, a->gid); 663 #endif 664 if (ret == -1) 665 status = errno_to_portable(errno); 666 } 667 } 668 send_status(id, status); 669 } 670 671 static void 672 process_opendir(void) 673 { 674 DIR *dirp = NULL; 675 char *path; 676 int handle, status = SSH2_FX_FAILURE; 677 u_int32_t id; 678 679 id = get_int(); 680 path = get_string(NULL); 681 TRACE("opendir id %u path %s", id, path); 682 dirp = opendir(path); 683 if (dirp == NULL) { 684 status = errno_to_portable(errno); 685 } else { 686 handle = handle_new(HANDLE_DIR, path, 0, dirp); 687 if (handle < 0) { 688 closedir(dirp); 689 } else { 690 send_handle(id, handle); 691 status = SSH2_FX_OK; 692 } 693 694 } 695 if (status != SSH2_FX_OK) 696 send_status(id, status); 697 xfree(path); 698 } 699 700 static void 701 process_readdir(void) 702 { 703 DIR *dirp; 704 struct dirent *dp; 705 char *path; 706 int handle; 707 u_int32_t id; 708 709 id = get_int(); 710 handle = get_handle(); 711 TRACE("readdir id %u handle %d", id, handle); 712 dirp = handle_to_dir(handle); 713 path = handle_to_name(handle); 714 if (dirp == NULL || path == NULL) { 715 send_status(id, SSH2_FX_FAILURE); 716 } else { 717 struct stat st; 718 char pathname[1024]; 719 Stat *stats; 720 int nstats = 10, count = 0, i; 721 722 stats = xmalloc(nstats * sizeof(Stat)); 723 while ((dp = readdir(dirp)) != NULL) { 724 if (count >= nstats) { 725 nstats *= 2; 726 stats = xrealloc(stats, nstats * sizeof(Stat)); 727 } 728 /* XXX OVERFLOW ? */ 729 snprintf(pathname, sizeof pathname, "%s%s%s", path, 730 strcmp(path, "/") ? "/" : "", dp->d_name); 731 if (lstat(pathname, &st) < 0) 732 continue; 733 stat_to_attrib(&st, &(stats[count].attrib)); 734 stats[count].name = xstrdup(dp->d_name); 735 stats[count].long_name = ls_file(dp->d_name, &st, 0); 736 count++; 737 /* send up to 100 entries in one message */ 738 /* XXX check packet size instead */ 739 if (count == 100) 740 break; 741 } 742 if (count > 0) { 743 send_names(id, count, stats); 744 for (i = 0; i < count; i++) { 745 xfree(stats[i].name); 746 xfree(stats[i].long_name); 747 } 748 } else { 749 send_status(id, SSH2_FX_EOF); 750 } 751 xfree(stats); 752 } 753 } 754 755 static void 756 process_remove(void) 757 { 758 char *name; 759 u_int32_t id; 760 int status = SSH2_FX_FAILURE; 761 int ret; 762 763 id = get_int(); 764 name = get_string(NULL); 765 TRACE("remove id %u name %s", id, name); 766 ret = unlink(name); 767 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 768 send_status(id, status); 769 xfree(name); 770 } 771 772 static void 773 process_mkdir(void) 774 { 775 Attrib *a; 776 u_int32_t id; 777 char *name; 778 int ret, mode, status = SSH2_FX_FAILURE; 779 780 id = get_int(); 781 name = get_string(NULL); 782 a = get_attrib(); 783 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 784 a->perm & 0777 : 0777; 785 TRACE("mkdir id %u name %s mode 0%o", id, name, mode); 786 ret = mkdir(name, mode); 787 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 788 send_status(id, status); 789 xfree(name); 790 } 791 792 static void 793 process_rmdir(void) 794 { 795 u_int32_t id; 796 char *name; 797 int ret, status; 798 799 id = get_int(); 800 name = get_string(NULL); 801 TRACE("rmdir id %u name %s", id, name); 802 ret = rmdir(name); 803 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 804 send_status(id, status); 805 xfree(name); 806 } 807 808 static void 809 process_realpath(void) 810 { 811 char resolvedname[MAXPATHLEN]; 812 u_int32_t id; 813 char *path; 814 815 id = get_int(); 816 path = get_string(NULL); 817 if (path[0] == '\0') { 818 xfree(path); 819 path = xstrdup("."); 820 } 821 TRACE("realpath id %u path %s", id, path); 822 if (realpath(path, resolvedname) == NULL) { 823 send_status(id, errno_to_portable(errno)); 824 } else { 825 Stat s; 826 attrib_clear(&s.attrib); 827 s.name = s.long_name = resolvedname; 828 send_names(id, 1, &s); 829 } 830 xfree(path); 831 } 832 833 static void 834 process_rename(void) 835 { 836 u_int32_t id; 837 char *oldpath, *newpath; 838 int status; 839 struct stat sb; 840 841 id = get_int(); 842 oldpath = get_string(NULL); 843 newpath = get_string(NULL); 844 TRACE("rename id %u old %s new %s", id, oldpath, newpath); 845 status = SSH2_FX_FAILURE; 846 if (lstat(oldpath, &sb) == -1) 847 status = errno_to_portable(errno); 848 else if (S_ISREG(sb.st_mode)) { 849 /* Race-free rename of regular files */ 850 if (link(oldpath, newpath) == -1) 851 status = errno_to_portable(errno); 852 else if (unlink(oldpath) == -1) { 853 status = errno_to_portable(errno); 854 /* clean spare link */ 855 unlink(newpath); 856 } else 857 status = SSH2_FX_OK; 858 } else if (stat(newpath, &sb) == -1) { 859 if (rename(oldpath, newpath) == -1) 860 status = errno_to_portable(errno); 861 else 862 status = SSH2_FX_OK; 863 } 864 send_status(id, status); 865 xfree(oldpath); 866 xfree(newpath); 867 } 868 869 static void 870 process_readlink(void) 871 { 872 u_int32_t id; 873 int len; 874 char link[MAXPATHLEN]; 875 char *path; 876 877 id = get_int(); 878 path = get_string(NULL); 879 TRACE("readlink id %u path %s", id, path); 880 if ((len = readlink(path, link, sizeof(link) - 1)) == -1) 881 send_status(id, errno_to_portable(errno)); 882 else { 883 Stat s; 884 885 link[len] = '\0'; 886 attrib_clear(&s.attrib); 887 s.name = s.long_name = link; 888 send_names(id, 1, &s); 889 } 890 xfree(path); 891 } 892 893 static void 894 process_symlink(void) 895 { 896 u_int32_t id; 897 char *oldpath, *newpath; 898 int ret, status; 899 900 id = get_int(); 901 oldpath = get_string(NULL); 902 newpath = get_string(NULL); 903 TRACE("symlink id %u old %s new %s", id, oldpath, newpath); 904 /* this will fail if 'newpath' exists */ 905 ret = symlink(oldpath, newpath); 906 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 907 send_status(id, status); 908 xfree(oldpath); 909 xfree(newpath); 910 } 911 912 static void 913 process_extended(void) 914 { 915 u_int32_t id; 916 char *request; 917 918 id = get_int(); 919 request = get_string(NULL); 920 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 921 xfree(request); 922 } 923 924 /* stolen from ssh-agent */ 925 926 static void 927 process(void) 928 { 929 u_int msg_len; 930 u_int buf_len; 931 u_int consumed; 932 u_int type; 933 u_char *cp; 934 935 buf_len = buffer_len(&iqueue); 936 if (buf_len < 5) 937 return; /* Incomplete message. */ 938 cp = buffer_ptr(&iqueue); 939 msg_len = GET_32BIT(cp); 940 if (msg_len > 256 * 1024) { 941 error("bad message "); 942 exit(11); 943 } 944 if (buf_len < msg_len + 4) 945 return; 946 buffer_consume(&iqueue, 4); 947 buf_len -= 4; 948 type = buffer_get_char(&iqueue); 949 switch (type) { 950 case SSH2_FXP_INIT: 951 process_init(); 952 break; 953 case SSH2_FXP_OPEN: 954 process_open(); 955 break; 956 case SSH2_FXP_CLOSE: 957 process_close(); 958 break; 959 case SSH2_FXP_READ: 960 process_read(); 961 break; 962 case SSH2_FXP_WRITE: 963 process_write(); 964 break; 965 case SSH2_FXP_LSTAT: 966 process_lstat(); 967 break; 968 case SSH2_FXP_FSTAT: 969 process_fstat(); 970 break; 971 case SSH2_FXP_SETSTAT: 972 process_setstat(); 973 break; 974 case SSH2_FXP_FSETSTAT: 975 process_fsetstat(); 976 break; 977 case SSH2_FXP_OPENDIR: 978 process_opendir(); 979 break; 980 case SSH2_FXP_READDIR: 981 process_readdir(); 982 break; 983 case SSH2_FXP_REMOVE: 984 process_remove(); 985 break; 986 case SSH2_FXP_MKDIR: 987 process_mkdir(); 988 break; 989 case SSH2_FXP_RMDIR: 990 process_rmdir(); 991 break; 992 case SSH2_FXP_REALPATH: 993 process_realpath(); 994 break; 995 case SSH2_FXP_STAT: 996 process_stat(); 997 break; 998 case SSH2_FXP_RENAME: 999 process_rename(); 1000 break; 1001 case SSH2_FXP_READLINK: 1002 process_readlink(); 1003 break; 1004 case SSH2_FXP_SYMLINK: 1005 process_symlink(); 1006 break; 1007 case SSH2_FXP_EXTENDED: 1008 process_extended(); 1009 break; 1010 default: 1011 error("Unknown message %d", type); 1012 break; 1013 } 1014 /* discard the remaining bytes from the current packet */ 1015 if (buf_len < buffer_len(&iqueue)) 1016 fatal("iqueue grows"); 1017 consumed = buf_len - buffer_len(&iqueue); 1018 if (msg_len < consumed) 1019 fatal("msg_len %d < consumed %d", msg_len, consumed); 1020 if (msg_len > consumed) 1021 buffer_consume(&iqueue, msg_len - consumed); 1022 } 1023 1024 int 1025 main(int ac, char **av) 1026 { 1027 fd_set *rset, *wset; 1028 int in, out, max; 1029 ssize_t len, olen, set_size; 1030 1031 /* XXX should use getopt */ 1032 1033 __progname = get_progname(av[0]); 1034 handle_init(); 1035 1036 #ifdef DEBUG_SFTP_SERVER 1037 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1038 #endif 1039 1040 in = dup(STDIN_FILENO); 1041 out = dup(STDOUT_FILENO); 1042 1043 #ifdef HAVE_CYGWIN 1044 setmode(in, O_BINARY); 1045 setmode(out, O_BINARY); 1046 #endif 1047 1048 max = 0; 1049 if (in > max) 1050 max = in; 1051 if (out > max) 1052 max = out; 1053 1054 buffer_init(&iqueue); 1055 buffer_init(&oqueue); 1056 1057 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); 1058 rset = (fd_set *)xmalloc(set_size); 1059 wset = (fd_set *)xmalloc(set_size); 1060 1061 for (;;) { 1062 memset(rset, 0, set_size); 1063 memset(wset, 0, set_size); 1064 1065 FD_SET(in, rset); 1066 olen = buffer_len(&oqueue); 1067 if (olen > 0) 1068 FD_SET(out, wset); 1069 1070 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1071 if (errno == EINTR) 1072 continue; 1073 exit(2); 1074 } 1075 1076 /* copy stdin to iqueue */ 1077 if (FD_ISSET(in, rset)) { 1078 char buf[4*4096]; 1079 len = read(in, buf, sizeof buf); 1080 if (len == 0) { 1081 debug("read eof"); 1082 exit(0); 1083 } else if (len < 0) { 1084 error("read error"); 1085 exit(1); 1086 } else { 1087 buffer_append(&iqueue, buf, len); 1088 } 1089 } 1090 /* send oqueue to stdout */ 1091 if (FD_ISSET(out, wset)) { 1092 len = write(out, buffer_ptr(&oqueue), olen); 1093 if (len < 0) { 1094 error("write error"); 1095 exit(1); 1096 } else { 1097 buffer_consume(&oqueue, len); 1098 } 1099 } 1100 /* process requests from client */ 1101 process(); 1102 } 1103 } 1104