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