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