1 /* 2 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 #include "includes.h" 25 RCSID("$OpenBSD: sftp-server.c,v 1.30 2001/07/31 12:42:50 jakob Exp $"); 26 27 #include "buffer.h" 28 #include "bufaux.h" 29 #include "getput.h" 30 #include "log.h" 31 #include "xmalloc.h" 32 33 #include "sftp.h" 34 #include "sftp-common.h" 35 36 /* helper */ 37 #define get_int64() buffer_get_int64(&iqueue); 38 #define get_int() buffer_get_int(&iqueue); 39 #define get_string(lenp) buffer_get_string(&iqueue, lenp); 40 #define TRACE debug 41 42 /* input and output queue */ 43 Buffer iqueue; 44 Buffer oqueue; 45 46 /* Version of client */ 47 int version; 48 49 /* portable attibutes, etc. */ 50 51 typedef struct Stat Stat; 52 53 struct Stat { 54 char *name; 55 char *long_name; 56 Attrib attrib; 57 }; 58 59 static int 60 errno_to_portable(int unixerrno) 61 { 62 int ret = 0; 63 64 switch (unixerrno) { 65 case 0: 66 ret = SSH2_FX_OK; 67 break; 68 case ENOENT: 69 case ENOTDIR: 70 case EBADF: 71 case ELOOP: 72 ret = SSH2_FX_NO_SUCH_FILE; 73 break; 74 case EPERM: 75 case EACCES: 76 case EFAULT: 77 ret = SSH2_FX_PERMISSION_DENIED; 78 break; 79 case ENAMETOOLONG: 80 case EINVAL: 81 ret = SSH2_FX_BAD_MESSAGE; 82 break; 83 default: 84 ret = SSH2_FX_FAILURE; 85 break; 86 } 87 return ret; 88 } 89 90 static int 91 flags_from_portable(int pflags) 92 { 93 int flags = 0; 94 95 if ((pflags & SSH2_FXF_READ) && 96 (pflags & SSH2_FXF_WRITE)) { 97 flags = O_RDWR; 98 } else if (pflags & SSH2_FXF_READ) { 99 flags = O_RDONLY; 100 } else if (pflags & SSH2_FXF_WRITE) { 101 flags = O_WRONLY; 102 } 103 if (pflags & SSH2_FXF_CREAT) 104 flags |= O_CREAT; 105 if (pflags & SSH2_FXF_TRUNC) 106 flags |= O_TRUNC; 107 if (pflags & SSH2_FXF_EXCL) 108 flags |= O_EXCL; 109 return flags; 110 } 111 112 static Attrib * 113 get_attrib(void) 114 { 115 return decode_attrib(&iqueue); 116 } 117 118 /* handle handles */ 119 120 typedef struct Handle Handle; 121 struct Handle { 122 int use; 123 DIR *dirp; 124 int fd; 125 char *name; 126 }; 127 128 enum { 129 HANDLE_UNUSED, 130 HANDLE_DIR, 131 HANDLE_FILE 132 }; 133 134 Handle handles[100]; 135 136 static void 137 handle_init(void) 138 { 139 int i; 140 141 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) 142 handles[i].use = HANDLE_UNUSED; 143 } 144 145 static int 146 handle_new(int use, char *name, int fd, DIR *dirp) 147 { 148 int i; 149 150 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) { 151 if (handles[i].use == HANDLE_UNUSED) { 152 handles[i].use = use; 153 handles[i].dirp = dirp; 154 handles[i].fd = fd; 155 handles[i].name = name; 156 return i; 157 } 158 } 159 return -1; 160 } 161 162 static int 163 handle_is_ok(int i, int type) 164 { 165 return i >= 0 && i < sizeof(handles)/sizeof(Handle) && 166 handles[i].use == type; 167 } 168 169 static int 170 handle_to_string(int handle, char **stringp, int *hlenp) 171 { 172 if (stringp == NULL || hlenp == NULL) 173 return -1; 174 *stringp = xmalloc(sizeof(int32_t)); 175 PUT_32BIT(*stringp, handle); 176 *hlenp = sizeof(int32_t); 177 return 0; 178 } 179 180 static int 181 handle_from_string(char *handle, u_int hlen) 182 { 183 int val; 184 185 if (hlen != sizeof(int32_t)) 186 return -1; 187 val = GET_32BIT(handle); 188 if (handle_is_ok(val, HANDLE_FILE) || 189 handle_is_ok(val, HANDLE_DIR)) 190 return val; 191 return -1; 192 } 193 194 static char * 195 handle_to_name(int handle) 196 { 197 if (handle_is_ok(handle, HANDLE_DIR)|| 198 handle_is_ok(handle, HANDLE_FILE)) 199 return handles[handle].name; 200 return NULL; 201 } 202 203 static DIR * 204 handle_to_dir(int handle) 205 { 206 if (handle_is_ok(handle, HANDLE_DIR)) 207 return handles[handle].dirp; 208 return NULL; 209 } 210 211 static int 212 handle_to_fd(int handle) 213 { 214 if (handle_is_ok(handle, HANDLE_FILE)) 215 return handles[handle].fd; 216 return -1; 217 } 218 219 static int 220 handle_close(int handle) 221 { 222 int ret = -1; 223 224 if (handle_is_ok(handle, HANDLE_FILE)) { 225 ret = close(handles[handle].fd); 226 handles[handle].use = HANDLE_UNUSED; 227 } else if (handle_is_ok(handle, HANDLE_DIR)) { 228 ret = closedir(handles[handle].dirp); 229 handles[handle].use = HANDLE_UNUSED; 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 %d error %d", 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, 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, char *data, int dlen) 307 { 308 TRACE("sent data id %d 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 %d 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, 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 %d 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, Attrib *a) 346 { 347 Buffer msg; 348 349 TRACE("sent attrib id %d 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 = buffer_get_int(&iqueue); 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 %d 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, xstrdup(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 %d 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 %d handle %d off %llu len %d", id, handle, 434 (unsigned long long)off, len); 435 if (len > sizeof buf) { 436 len = sizeof buf; 437 log("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 %d handle %d off %llu len %d", id, handle, 475 (unsigned long long)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 log("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 %d 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 %d 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(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 ret; 580 int status = SSH2_FX_OK; 581 582 id = get_int(); 583 name = get_string(NULL); 584 a = get_attrib(); 585 TRACE("setstat id %d name %s", id, name); 586 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 587 ret = chmod(name, a->perm & 0777); 588 if (ret == -1) 589 status = errno_to_portable(errno); 590 } 591 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 592 ret = utimes(name, attrib_to_tv(a)); 593 if (ret == -1) 594 status = errno_to_portable(errno); 595 } 596 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 597 ret = chown(name, a->uid, a->gid); 598 if (ret == -1) 599 status = errno_to_portable(errno); 600 } 601 send_status(id, status); 602 xfree(name); 603 } 604 605 static void 606 process_fsetstat(void) 607 { 608 Attrib *a; 609 u_int32_t id; 610 int handle, fd, ret; 611 int status = SSH2_FX_OK; 612 613 id = get_int(); 614 handle = get_handle(); 615 a = get_attrib(); 616 TRACE("fsetstat id %d handle %d", id, handle); 617 fd = handle_to_fd(handle); 618 if (fd < 0) { 619 status = SSH2_FX_FAILURE; 620 } else { 621 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 622 ret = fchmod(fd, a->perm & 0777); 623 if (ret == -1) 624 status = errno_to_portable(errno); 625 } 626 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 627 ret = futimes(fd, attrib_to_tv(a)); 628 if (ret == -1) 629 status = errno_to_portable(errno); 630 } 631 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 632 ret = fchown(fd, a->uid, a->gid); 633 if (ret == -1) 634 status = errno_to_portable(errno); 635 } 636 } 637 send_status(id, status); 638 } 639 640 static void 641 process_opendir(void) 642 { 643 DIR *dirp = NULL; 644 char *path; 645 int handle, status = SSH2_FX_FAILURE; 646 u_int32_t id; 647 648 id = get_int(); 649 path = get_string(NULL); 650 TRACE("opendir id %d path %s", id, path); 651 dirp = opendir(path); 652 if (dirp == NULL) { 653 status = errno_to_portable(errno); 654 } else { 655 handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); 656 if (handle < 0) { 657 closedir(dirp); 658 } else { 659 send_handle(id, handle); 660 status = SSH2_FX_OK; 661 } 662 663 } 664 if (status != SSH2_FX_OK) 665 send_status(id, status); 666 xfree(path); 667 } 668 669 /* 670 * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh 671 */ 672 static char * 673 ls_file(char *name, struct stat *st) 674 { 675 int ulen, glen, sz = 0; 676 struct passwd *pw; 677 struct group *gr; 678 struct tm *ltime = localtime(&st->st_mtime); 679 char *user, *group; 680 char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; 681 682 strmode(st->st_mode, mode); 683 if ((pw = getpwuid(st->st_uid)) != NULL) { 684 user = pw->pw_name; 685 } else { 686 snprintf(ubuf, sizeof ubuf, "%d", st->st_uid); 687 user = ubuf; 688 } 689 if ((gr = getgrgid(st->st_gid)) != NULL) { 690 group = gr->gr_name; 691 } else { 692 snprintf(gbuf, sizeof gbuf, "%d", st->st_gid); 693 group = gbuf; 694 } 695 if (ltime != NULL) { 696 if (time(NULL) - st->st_mtime < (365*24*60*60)/2) 697 sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); 698 else 699 sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); 700 } 701 if (sz == 0) 702 tbuf[0] = '\0'; 703 ulen = MAX(strlen(user), 8); 704 glen = MAX(strlen(group), 8); 705 snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode, 706 st->st_nlink, ulen, user, glen, group, 707 (unsigned long long)st->st_size, tbuf, name); 708 return xstrdup(buf); 709 } 710 711 static void 712 process_readdir(void) 713 { 714 DIR *dirp; 715 struct dirent *dp; 716 char *path; 717 int handle; 718 u_int32_t id; 719 720 id = get_int(); 721 handle = get_handle(); 722 TRACE("readdir id %d handle %d", id, handle); 723 dirp = handle_to_dir(handle); 724 path = handle_to_name(handle); 725 if (dirp == NULL || path == NULL) { 726 send_status(id, SSH2_FX_FAILURE); 727 } else { 728 struct stat st; 729 char pathname[1024]; 730 Stat *stats; 731 int nstats = 10, count = 0, i; 732 stats = xmalloc(nstats * sizeof(Stat)); 733 while ((dp = readdir(dirp)) != NULL) { 734 if (count >= nstats) { 735 nstats *= 2; 736 stats = xrealloc(stats, nstats * sizeof(Stat)); 737 } 738 /* XXX OVERFLOW ? */ 739 snprintf(pathname, sizeof pathname, "%s%s%s", path, 740 strcmp(path, "/") ? "/" : "", dp->d_name); 741 if (lstat(pathname, &st) < 0) 742 continue; 743 stat_to_attrib(&st, &(stats[count].attrib)); 744 stats[count].name = xstrdup(dp->d_name); 745 stats[count].long_name = ls_file(dp->d_name, &st); 746 count++; 747 /* send up to 100 entries in one message */ 748 /* XXX check packet size instead */ 749 if (count == 100) 750 break; 751 } 752 if (count > 0) { 753 send_names(id, count, stats); 754 for(i = 0; i < count; i++) { 755 xfree(stats[i].name); 756 xfree(stats[i].long_name); 757 } 758 } else { 759 send_status(id, SSH2_FX_EOF); 760 } 761 xfree(stats); 762 } 763 } 764 765 static void 766 process_remove(void) 767 { 768 char *name; 769 u_int32_t id; 770 int status = SSH2_FX_FAILURE; 771 int ret; 772 773 id = get_int(); 774 name = get_string(NULL); 775 TRACE("remove id %d name %s", id, name); 776 ret = unlink(name); 777 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 778 send_status(id, status); 779 xfree(name); 780 } 781 782 static void 783 process_mkdir(void) 784 { 785 Attrib *a; 786 u_int32_t id; 787 char *name; 788 int ret, mode, status = SSH2_FX_FAILURE; 789 790 id = get_int(); 791 name = get_string(NULL); 792 a = get_attrib(); 793 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 794 a->perm & 0777 : 0777; 795 TRACE("mkdir id %d name %s mode 0%o", id, name, mode); 796 ret = mkdir(name, mode); 797 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 798 send_status(id, status); 799 xfree(name); 800 } 801 802 static void 803 process_rmdir(void) 804 { 805 u_int32_t id; 806 char *name; 807 int ret, status; 808 809 id = get_int(); 810 name = get_string(NULL); 811 TRACE("rmdir id %d name %s", id, name); 812 ret = rmdir(name); 813 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 814 send_status(id, status); 815 xfree(name); 816 } 817 818 static void 819 process_realpath(void) 820 { 821 char resolvedname[MAXPATHLEN]; 822 u_int32_t id; 823 char *path; 824 825 id = get_int(); 826 path = get_string(NULL); 827 if (path[0] == '\0') { 828 xfree(path); 829 path = xstrdup("."); 830 } 831 TRACE("realpath id %d path %s", id, path); 832 if (realpath(path, resolvedname) == NULL) { 833 send_status(id, errno_to_portable(errno)); 834 } else { 835 Stat s; 836 attrib_clear(&s.attrib); 837 s.name = s.long_name = resolvedname; 838 send_names(id, 1, &s); 839 } 840 xfree(path); 841 } 842 843 static void 844 process_rename(void) 845 { 846 u_int32_t id; 847 struct stat st; 848 char *oldpath, *newpath; 849 int ret, status = SSH2_FX_FAILURE; 850 851 id = get_int(); 852 oldpath = get_string(NULL); 853 newpath = get_string(NULL); 854 TRACE("rename id %d old %s new %s", id, oldpath, newpath); 855 /* fail if 'newpath' exists */ 856 if (stat(newpath, &st) == -1) { 857 ret = rename(oldpath, newpath); 858 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 859 } 860 send_status(id, status); 861 xfree(oldpath); 862 xfree(newpath); 863 } 864 865 static void 866 process_readlink(void) 867 { 868 u_int32_t id; 869 int len; 870 char link[MAXPATHLEN]; 871 char *path; 872 873 id = get_int(); 874 path = get_string(NULL); 875 TRACE("readlink id %d path %s", id, path); 876 if ((len = readlink(path, link, sizeof(link) - 1)) == -1) 877 send_status(id, errno_to_portable(errno)); 878 else { 879 Stat s; 880 881 link[len] = '\0'; 882 attrib_clear(&s.attrib); 883 s.name = s.long_name = link; 884 send_names(id, 1, &s); 885 } 886 xfree(path); 887 } 888 889 static void 890 process_symlink(void) 891 { 892 u_int32_t id; 893 struct stat st; 894 char *oldpath, *newpath; 895 int ret, status = SSH2_FX_FAILURE; 896 897 id = get_int(); 898 oldpath = get_string(NULL); 899 newpath = get_string(NULL); 900 TRACE("symlink id %d old %s new %s", id, oldpath, newpath); 901 /* fail if 'newpath' exists */ 902 if (stat(newpath, &st) == -1) { 903 ret = symlink(oldpath, newpath); 904 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 905 } 906 send_status(id, status); 907 xfree(oldpath); 908 xfree(newpath); 909 } 910 911 static void 912 process_extended(void) 913 { 914 u_int32_t id; 915 char *request; 916 917 id = get_int(); 918 request = get_string(NULL); 919 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 920 xfree(request); 921 } 922 923 /* stolen from ssh-agent */ 924 925 static void 926 process(void) 927 { 928 u_int msg_len; 929 u_int type; 930 u_char *cp; 931 932 if (buffer_len(&iqueue) < 5) 933 return; /* Incomplete message. */ 934 cp = (u_char *) buffer_ptr(&iqueue); 935 msg_len = GET_32BIT(cp); 936 if (msg_len > 256 * 1024) { 937 error("bad message "); 938 exit(11); 939 } 940 if (buffer_len(&iqueue) < msg_len + 4) 941 return; 942 buffer_consume(&iqueue, 4); 943 type = buffer_get_char(&iqueue); 944 switch (type) { 945 case SSH2_FXP_INIT: 946 process_init(); 947 break; 948 case SSH2_FXP_OPEN: 949 process_open(); 950 break; 951 case SSH2_FXP_CLOSE: 952 process_close(); 953 break; 954 case SSH2_FXP_READ: 955 process_read(); 956 break; 957 case SSH2_FXP_WRITE: 958 process_write(); 959 break; 960 case SSH2_FXP_LSTAT: 961 process_lstat(); 962 break; 963 case SSH2_FXP_FSTAT: 964 process_fstat(); 965 break; 966 case SSH2_FXP_SETSTAT: 967 process_setstat(); 968 break; 969 case SSH2_FXP_FSETSTAT: 970 process_fsetstat(); 971 break; 972 case SSH2_FXP_OPENDIR: 973 process_opendir(); 974 break; 975 case SSH2_FXP_READDIR: 976 process_readdir(); 977 break; 978 case SSH2_FXP_REMOVE: 979 process_remove(); 980 break; 981 case SSH2_FXP_MKDIR: 982 process_mkdir(); 983 break; 984 case SSH2_FXP_RMDIR: 985 process_rmdir(); 986 break; 987 case SSH2_FXP_REALPATH: 988 process_realpath(); 989 break; 990 case SSH2_FXP_STAT: 991 process_stat(); 992 break; 993 case SSH2_FXP_RENAME: 994 process_rename(); 995 break; 996 case SSH2_FXP_READLINK: 997 process_readlink(); 998 break; 999 case SSH2_FXP_SYMLINK: 1000 process_symlink(); 1001 break; 1002 case SSH2_FXP_EXTENDED: 1003 process_extended(); 1004 break; 1005 default: 1006 error("Unknown message %d", type); 1007 break; 1008 } 1009 } 1010 1011 int 1012 main(int ac, char **av) 1013 { 1014 fd_set *rset, *wset; 1015 int in, out, max; 1016 ssize_t len, olen, set_size; 1017 1018 /* XXX should use getopt */ 1019 1020 handle_init(); 1021 1022 #ifdef DEBUG_SFTP_SERVER 1023 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1024 #endif 1025 1026 in = dup(STDIN_FILENO); 1027 out = dup(STDOUT_FILENO); 1028 1029 max = 0; 1030 if (in > max) 1031 max = in; 1032 if (out > max) 1033 max = out; 1034 1035 buffer_init(&iqueue); 1036 buffer_init(&oqueue); 1037 1038 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); 1039 rset = (fd_set *)xmalloc(set_size); 1040 wset = (fd_set *)xmalloc(set_size); 1041 1042 for (;;) { 1043 memset(rset, 0, set_size); 1044 memset(wset, 0, set_size); 1045 1046 FD_SET(in, rset); 1047 olen = buffer_len(&oqueue); 1048 if (olen > 0) 1049 FD_SET(out, wset); 1050 1051 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1052 if (errno == EINTR) 1053 continue; 1054 exit(2); 1055 } 1056 1057 /* copy stdin to iqueue */ 1058 if (FD_ISSET(in, rset)) { 1059 char buf[4*4096]; 1060 len = read(in, buf, sizeof buf); 1061 if (len == 0) { 1062 debug("read eof"); 1063 exit(0); 1064 } else if (len < 0) { 1065 error("read error"); 1066 exit(1); 1067 } else { 1068 buffer_append(&iqueue, buf, len); 1069 } 1070 } 1071 /* send oqueue to stdout */ 1072 if (FD_ISSET(out, wset)) { 1073 len = write(out, buffer_ptr(&oqueue), olen); 1074 if (len < 0) { 1075 error("write error"); 1076 exit(1); 1077 } else { 1078 buffer_consume(&oqueue, len); 1079 } 1080 } 1081 /* process requests from client */ 1082 process(); 1083 } 1084 } 1085