sftp-server.c revision 137015
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" 17RCSID("$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 34extern char *__progname; 35 36/* input and output queue */ 37Buffer iqueue; 38Buffer oqueue; 39 40/* Version of client */ 41int version; 42 43/* portable attributes, etc. */ 44 45typedef struct Stat Stat; 46 47struct Stat { 48 char *name; 49 char *long_name; 50 Attrib attrib; 51}; 52 53static int 54errno_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 84static int 85flags_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 106static Attrib * 107get_attrib(void) 108{ 109 return decode_attrib(&iqueue); 110} 111 112/* handle handles */ 113 114typedef struct Handle Handle; 115struct Handle { 116 int use; 117 DIR *dirp; 118 int fd; 119 char *name; 120}; 121 122enum { 123 HANDLE_UNUSED, 124 HANDLE_DIR, 125 HANDLE_FILE 126}; 127 128Handle handles[100]; 129 130static void 131handle_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 139static int 140handle_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 156static int 157handle_is_ok(int i, int type) 158{ 159 return i >= 0 && i < sizeof(handles)/sizeof(Handle) && 160 handles[i].use == type; 161} 162 163static int 164handle_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 174static int 175handle_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 188static char * 189handle_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 197static DIR * 198handle_to_dir(int handle) 199{ 200 if (handle_is_ok(handle, HANDLE_DIR)) 201 return handles[handle].dirp; 202 return NULL; 203} 204 205static int 206handle_to_fd(int handle) 207{ 208 if (handle_is_ok(handle, HANDLE_FILE)) 209 return handles[handle].fd; 210 return -1; 211} 212 213static int 214handle_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 232static int 233get_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 248static void 249send_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 258static void 259send_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} 288static void 289send_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 301static void 302send_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 308static void 309send_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 320static void 321send_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 340static void 341send_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 356static void 357process_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 370static void 371process_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 402static void 403process_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 416static void 417process_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 456static void 457process_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 494static void 495process_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 519static void 520process_stat(void) 521{ 522 process_do_stat(0); 523} 524 525static void 526process_lstat(void) 527{ 528 process_do_stat(1); 529} 530 531static void 532process_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 557static struct timeval * 558attrib_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 569static void 570process_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 605static void 606process_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 659static void 660process_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 688static void 689process_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 743static void 744process_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 760static void 761process_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 780static void 781process_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 796static void 797process_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 821static void 822process_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 877static void 878process_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 901static void 902process_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 920static void 921process_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 934static void 935process(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 1032int 1033main(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