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