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