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