1 /* 2 * Copyright (c) 2000, 2001, 2002 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.33 2002/02/13 00:28:13 markus 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_SIZE) { 587 ret = truncate(name, a->size); 588 if (ret == -1) 589 status = errno_to_portable(errno); 590 } 591 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 592 ret = chmod(name, a->perm & 0777); 593 if (ret == -1) 594 status = errno_to_portable(errno); 595 } 596 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 597 ret = utimes(name, attrib_to_tv(a)); 598 if (ret == -1) 599 status = errno_to_portable(errno); 600 } 601 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 602 ret = chown(name, a->uid, a->gid); 603 if (ret == -1) 604 status = errno_to_portable(errno); 605 } 606 send_status(id, status); 607 xfree(name); 608 } 609 610 static void 611 process_fsetstat(void) 612 { 613 Attrib *a; 614 u_int32_t id; 615 int handle, fd, ret; 616 int status = SSH2_FX_OK; 617 618 id = get_int(); 619 handle = get_handle(); 620 a = get_attrib(); 621 TRACE("fsetstat id %d handle %d", id, handle); 622 fd = handle_to_fd(handle); 623 if (fd < 0) { 624 status = SSH2_FX_FAILURE; 625 } else { 626 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 627 ret = ftruncate(fd, a->size); 628 if (ret == -1) 629 status = errno_to_portable(errno); 630 } 631 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 632 ret = fchmod(fd, a->perm & 0777); 633 if (ret == -1) 634 status = errno_to_portable(errno); 635 } 636 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 637 ret = futimes(fd, attrib_to_tv(a)); 638 if (ret == -1) 639 status = errno_to_portable(errno); 640 } 641 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 642 ret = fchown(fd, a->uid, a->gid); 643 if (ret == -1) 644 status = errno_to_portable(errno); 645 } 646 } 647 send_status(id, status); 648 } 649 650 static void 651 process_opendir(void) 652 { 653 DIR *dirp = NULL; 654 char *path; 655 int handle, status = SSH2_FX_FAILURE; 656 u_int32_t id; 657 658 id = get_int(); 659 path = get_string(NULL); 660 TRACE("opendir id %d path %s", id, path); 661 dirp = opendir(path); 662 if (dirp == NULL) { 663 status = errno_to_portable(errno); 664 } else { 665 handle = handle_new(HANDLE_DIR, xstrdup(path), 0, dirp); 666 if (handle < 0) { 667 closedir(dirp); 668 } else { 669 send_handle(id, handle); 670 status = SSH2_FX_OK; 671 } 672 673 } 674 if (status != SSH2_FX_OK) 675 send_status(id, status); 676 xfree(path); 677 } 678 679 /* 680 * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh 681 */ 682 static char * 683 ls_file(char *name, struct stat *st) 684 { 685 int ulen, glen, sz = 0; 686 struct passwd *pw; 687 struct group *gr; 688 struct tm *ltime = localtime(&st->st_mtime); 689 char *user, *group; 690 char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; 691 692 strmode(st->st_mode, mode); 693 if ((pw = getpwuid(st->st_uid)) != NULL) { 694 user = pw->pw_name; 695 } else { 696 snprintf(ubuf, sizeof ubuf, "%d", st->st_uid); 697 user = ubuf; 698 } 699 if ((gr = getgrgid(st->st_gid)) != NULL) { 700 group = gr->gr_name; 701 } else { 702 snprintf(gbuf, sizeof gbuf, "%d", st->st_gid); 703 group = gbuf; 704 } 705 if (ltime != NULL) { 706 if (time(NULL) - st->st_mtime < (365*24*60*60)/2) 707 sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); 708 else 709 sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); 710 } 711 if (sz == 0) 712 tbuf[0] = '\0'; 713 ulen = MAX(strlen(user), 8); 714 glen = MAX(strlen(group), 8); 715 snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode, 716 st->st_nlink, ulen, user, glen, group, 717 (unsigned long long)st->st_size, tbuf, name); 718 return xstrdup(buf); 719 } 720 721 static void 722 process_readdir(void) 723 { 724 DIR *dirp; 725 struct dirent *dp; 726 char *path; 727 int handle; 728 u_int32_t id; 729 730 id = get_int(); 731 handle = get_handle(); 732 TRACE("readdir id %d handle %d", id, handle); 733 dirp = handle_to_dir(handle); 734 path = handle_to_name(handle); 735 if (dirp == NULL || path == NULL) { 736 send_status(id, SSH2_FX_FAILURE); 737 } else { 738 struct stat st; 739 char pathname[1024]; 740 Stat *stats; 741 int nstats = 10, count = 0, i; 742 stats = xmalloc(nstats * sizeof(Stat)); 743 while ((dp = readdir(dirp)) != NULL) { 744 if (count >= nstats) { 745 nstats *= 2; 746 stats = xrealloc(stats, nstats * sizeof(Stat)); 747 } 748 /* XXX OVERFLOW ? */ 749 snprintf(pathname, sizeof pathname, "%s%s%s", path, 750 strcmp(path, "/") ? "/" : "", dp->d_name); 751 if (lstat(pathname, &st) < 0) 752 continue; 753 stat_to_attrib(&st, &(stats[count].attrib)); 754 stats[count].name = xstrdup(dp->d_name); 755 stats[count].long_name = ls_file(dp->d_name, &st); 756 count++; 757 /* send up to 100 entries in one message */ 758 /* XXX check packet size instead */ 759 if (count == 100) 760 break; 761 } 762 if (count > 0) { 763 send_names(id, count, stats); 764 for (i = 0; i < count; i++) { 765 xfree(stats[i].name); 766 xfree(stats[i].long_name); 767 } 768 } else { 769 send_status(id, SSH2_FX_EOF); 770 } 771 xfree(stats); 772 } 773 } 774 775 static void 776 process_remove(void) 777 { 778 char *name; 779 u_int32_t id; 780 int status = SSH2_FX_FAILURE; 781 int ret; 782 783 id = get_int(); 784 name = get_string(NULL); 785 TRACE("remove id %d name %s", id, name); 786 ret = unlink(name); 787 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 788 send_status(id, status); 789 xfree(name); 790 } 791 792 static void 793 process_mkdir(void) 794 { 795 Attrib *a; 796 u_int32_t id; 797 char *name; 798 int ret, mode, status = SSH2_FX_FAILURE; 799 800 id = get_int(); 801 name = get_string(NULL); 802 a = get_attrib(); 803 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 804 a->perm & 0777 : 0777; 805 TRACE("mkdir id %d name %s mode 0%o", id, name, mode); 806 ret = mkdir(name, mode); 807 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 808 send_status(id, status); 809 xfree(name); 810 } 811 812 static void 813 process_rmdir(void) 814 { 815 u_int32_t id; 816 char *name; 817 int ret, status; 818 819 id = get_int(); 820 name = get_string(NULL); 821 TRACE("rmdir id %d name %s", id, name); 822 ret = rmdir(name); 823 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 824 send_status(id, status); 825 xfree(name); 826 } 827 828 static void 829 process_realpath(void) 830 { 831 char resolvedname[MAXPATHLEN]; 832 u_int32_t id; 833 char *path; 834 835 id = get_int(); 836 path = get_string(NULL); 837 if (path[0] == '\0') { 838 xfree(path); 839 path = xstrdup("."); 840 } 841 TRACE("realpath id %d path %s", id, path); 842 if (realpath(path, resolvedname) == NULL) { 843 send_status(id, errno_to_portable(errno)); 844 } else { 845 Stat s; 846 attrib_clear(&s.attrib); 847 s.name = s.long_name = resolvedname; 848 send_names(id, 1, &s); 849 } 850 xfree(path); 851 } 852 853 static void 854 process_rename(void) 855 { 856 u_int32_t id; 857 struct stat st; 858 char *oldpath, *newpath; 859 int ret, status = SSH2_FX_FAILURE; 860 861 id = get_int(); 862 oldpath = get_string(NULL); 863 newpath = get_string(NULL); 864 TRACE("rename id %d old %s new %s", id, oldpath, newpath); 865 /* fail if 'newpath' exists */ 866 if (stat(newpath, &st) == -1) { 867 ret = rename(oldpath, newpath); 868 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 869 } 870 send_status(id, status); 871 xfree(oldpath); 872 xfree(newpath); 873 } 874 875 static void 876 process_readlink(void) 877 { 878 u_int32_t id; 879 int len; 880 char link[MAXPATHLEN]; 881 char *path; 882 883 id = get_int(); 884 path = get_string(NULL); 885 TRACE("readlink id %d path %s", id, path); 886 if ((len = readlink(path, link, sizeof(link) - 1)) == -1) 887 send_status(id, errno_to_portable(errno)); 888 else { 889 Stat s; 890 891 link[len] = '\0'; 892 attrib_clear(&s.attrib); 893 s.name = s.long_name = link; 894 send_names(id, 1, &s); 895 } 896 xfree(path); 897 } 898 899 static void 900 process_symlink(void) 901 { 902 u_int32_t id; 903 struct stat st; 904 char *oldpath, *newpath; 905 int ret, status = SSH2_FX_FAILURE; 906 907 id = get_int(); 908 oldpath = get_string(NULL); 909 newpath = get_string(NULL); 910 TRACE("symlink id %d old %s new %s", id, oldpath, newpath); 911 /* fail if 'newpath' exists */ 912 if (stat(newpath, &st) == -1) { 913 ret = symlink(oldpath, newpath); 914 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 915 } 916 send_status(id, status); 917 xfree(oldpath); 918 xfree(newpath); 919 } 920 921 static void 922 process_extended(void) 923 { 924 u_int32_t id; 925 char *request; 926 927 id = get_int(); 928 request = get_string(NULL); 929 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ 930 xfree(request); 931 } 932 933 /* stolen from ssh-agent */ 934 935 static void 936 process(void) 937 { 938 u_int msg_len; 939 u_int type; 940 u_char *cp; 941 942 if (buffer_len(&iqueue) < 5) 943 return; /* Incomplete message. */ 944 cp = buffer_ptr(&iqueue); 945 msg_len = GET_32BIT(cp); 946 if (msg_len > 256 * 1024) { 947 error("bad message "); 948 exit(11); 949 } 950 if (buffer_len(&iqueue) < msg_len + 4) 951 return; 952 buffer_consume(&iqueue, 4); 953 type = buffer_get_char(&iqueue); 954 switch (type) { 955 case SSH2_FXP_INIT: 956 process_init(); 957 break; 958 case SSH2_FXP_OPEN: 959 process_open(); 960 break; 961 case SSH2_FXP_CLOSE: 962 process_close(); 963 break; 964 case SSH2_FXP_READ: 965 process_read(); 966 break; 967 case SSH2_FXP_WRITE: 968 process_write(); 969 break; 970 case SSH2_FXP_LSTAT: 971 process_lstat(); 972 break; 973 case SSH2_FXP_FSTAT: 974 process_fstat(); 975 break; 976 case SSH2_FXP_SETSTAT: 977 process_setstat(); 978 break; 979 case SSH2_FXP_FSETSTAT: 980 process_fsetstat(); 981 break; 982 case SSH2_FXP_OPENDIR: 983 process_opendir(); 984 break; 985 case SSH2_FXP_READDIR: 986 process_readdir(); 987 break; 988 case SSH2_FXP_REMOVE: 989 process_remove(); 990 break; 991 case SSH2_FXP_MKDIR: 992 process_mkdir(); 993 break; 994 case SSH2_FXP_RMDIR: 995 process_rmdir(); 996 break; 997 case SSH2_FXP_REALPATH: 998 process_realpath(); 999 break; 1000 case SSH2_FXP_STAT: 1001 process_stat(); 1002 break; 1003 case SSH2_FXP_RENAME: 1004 process_rename(); 1005 break; 1006 case SSH2_FXP_READLINK: 1007 process_readlink(); 1008 break; 1009 case SSH2_FXP_SYMLINK: 1010 process_symlink(); 1011 break; 1012 case SSH2_FXP_EXTENDED: 1013 process_extended(); 1014 break; 1015 default: 1016 error("Unknown message %d", type); 1017 break; 1018 } 1019 } 1020 1021 int 1022 main(int ac, char **av) 1023 { 1024 fd_set *rset, *wset; 1025 int in, out, max; 1026 ssize_t len, olen, set_size; 1027 1028 /* XXX should use getopt */ 1029 1030 handle_init(); 1031 1032 #ifdef DEBUG_SFTP_SERVER 1033 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1034 #endif 1035 1036 in = dup(STDIN_FILENO); 1037 out = dup(STDOUT_FILENO); 1038 1039 max = 0; 1040 if (in > max) 1041 max = in; 1042 if (out > max) 1043 max = out; 1044 1045 buffer_init(&iqueue); 1046 buffer_init(&oqueue); 1047 1048 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); 1049 rset = (fd_set *)xmalloc(set_size); 1050 wset = (fd_set *)xmalloc(set_size); 1051 1052 for (;;) { 1053 memset(rset, 0, set_size); 1054 memset(wset, 0, set_size); 1055 1056 FD_SET(in, rset); 1057 olen = buffer_len(&oqueue); 1058 if (olen > 0) 1059 FD_SET(out, wset); 1060 1061 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1062 if (errno == EINTR) 1063 continue; 1064 exit(2); 1065 } 1066 1067 /* copy stdin to iqueue */ 1068 if (FD_ISSET(in, rset)) { 1069 char buf[4*4096]; 1070 len = read(in, buf, sizeof buf); 1071 if (len == 0) { 1072 debug("read eof"); 1073 exit(0); 1074 } else if (len < 0) { 1075 error("read error"); 1076 exit(1); 1077 } else { 1078 buffer_append(&iqueue, buf, len); 1079 } 1080 } 1081 /* send oqueue to stdout */ 1082 if (FD_ISSET(out, wset)) { 1083 len = write(out, buffer_ptr(&oqueue), olen); 1084 if (len < 0) { 1085 error("write error"); 1086 exit(1); 1087 } else { 1088 buffer_consume(&oqueue, len); 1089 } 1090 } 1091 /* process requests from client */ 1092 process(); 1093 } 1094 } 1095