Welcome OpenSSH 4.2.
[dragonfly.git] / crypto / openssh-4 / sftp-server.c
blob6870e7732039ec94661aea29fd3f703da0a31f9c
1 /*
2 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
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.
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.
16 #include "includes.h"
17 RCSID("$OpenBSD: sftp-server.c,v 1.48 2005/06/17 02:44:33 djm Exp $");
19 #include "buffer.h"
20 #include "bufaux.h"
21 #include "getput.h"
22 #include "log.h"
23 #include "xmalloc.h"
25 #include "sftp.h"
26 #include "sftp-common.h"
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
34 extern char *__progname;
36 /* input and output queue */
37 Buffer iqueue;
38 Buffer oqueue;
40 /* Version of client */
41 int version;
43 /* portable attributes, etc. */
45 typedef struct Stat Stat;
47 struct Stat {
48 char *name;
49 char *long_name;
50 Attrib attrib;
53 static int
54 errno_to_portable(int unixerrno)
56 int ret = 0;
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;
81 return ret;
84 static int
85 flags_from_portable(int pflags)
87 int flags = 0;
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;
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;
106 static Attrib *
107 get_attrib(void)
109 return decode_attrib(&iqueue);
112 /* handle handles */
114 typedef struct Handle Handle;
115 struct Handle {
116 int use;
117 DIR *dirp;
118 int fd;
119 char *name;
122 enum {
123 HANDLE_UNUSED,
124 HANDLE_DIR,
125 HANDLE_FILE
128 Handle handles[100];
130 static void
131 handle_init(void)
133 u_int i;
135 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
136 handles[i].use = HANDLE_UNUSED;
139 static int
140 handle_new(int use, const char *name, int fd, DIR *dirp)
142 u_int i;
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;
153 return -1;
156 static int
157 handle_is_ok(int i, int type)
159 return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
160 handles[i].use == type;
163 static int
164 handle_to_string(int handle, char **stringp, int *hlenp)
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;
174 static int
175 handle_from_string(const char *handle, u_int hlen)
177 int val;
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;
188 static char *
189 handle_to_name(int handle)
191 if (handle_is_ok(handle, HANDLE_DIR)||
192 handle_is_ok(handle, HANDLE_FILE))
193 return handles[handle].name;
194 return NULL;
197 static DIR *
198 handle_to_dir(int handle)
200 if (handle_is_ok(handle, HANDLE_DIR))
201 return handles[handle].dirp;
202 return NULL;
205 static int
206 handle_to_fd(int handle)
208 if (handle_is_ok(handle, HANDLE_FILE))
209 return handles[handle].fd;
210 return -1;
213 static int
214 handle_close(int handle)
216 int ret = -1;
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;
229 return ret;
232 static int
233 get_handle(void)
235 char *handle;
236 int val = -1;
237 u_int hlen;
239 handle = get_string(&hlen);
240 if (hlen < 256)
241 val = handle_from_string(handle, hlen);
242 xfree(handle);
243 return val;
246 /* send replies */
248 static void
249 send_msg(Buffer *m)
251 int mlen = buffer_len(m);
253 buffer_put_int(&oqueue, mlen);
254 buffer_append(&oqueue, buffer_ptr(m), mlen);
255 buffer_consume(m, mlen);
258 static void
259 send_status(u_int32_t id, u_int32_t status)
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 */
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, "");
285 send_msg(&msg);
286 buffer_free(&msg);
288 static void
289 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
291 Buffer msg;
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);
301 static void
302 send_data(u_int32_t id, const char *data, int dlen)
304 TRACE("sent data id %u len %d", id, dlen);
305 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
308 static void
309 send_handle(u_int32_t id, int handle)
311 char *string;
312 int hlen;
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);
320 static void
321 send_names(u_int32_t id, int count, const Stat *stats)
323 Buffer msg;
324 int i;
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);
336 send_msg(&msg);
337 buffer_free(&msg);
340 static void
341 send_attrib(u_int32_t id, const Attrib *a)
343 Buffer msg;
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);
354 /* parse incoming */
356 static void
357 process_init(void)
359 Buffer msg;
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);
370 static void
371 process_open(void)
373 u_int32_t id, pflags;
374 Attrib *a;
375 char *name;
376 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
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;
397 if (status != SSH2_FX_OK)
398 send_status(id, status);
399 xfree(name);
402 static void
403 process_close(void)
405 u_int32_t id;
406 int handle, ret, status = SSH2_FX_FAILURE;
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);
416 static void
417 process_read(void)
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;
424 id = get_int();
425 handle = get_handle();
426 off = get_int64();
427 len = get_int();
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);
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;
452 if (status != SSH2_FX_OK)
453 send_status(id, status);
456 static void
457 process_write(void)
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;
465 id = get_int();
466 handle = get_handle();
467 off = get_int64();
468 data = get_string(&len);
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 < 0) {
481 error("process_write: write failed");
482 status = errno_to_portable(errno);
483 } else if ((size_t)ret == len) {
484 status = SSH2_FX_OK;
485 } else {
486 logit("nothing at all written");
490 send_status(id, status);
491 xfree(data);
494 static void
495 process_do_stat(int do_lstat)
497 Attrib a;
498 struct stat st;
499 u_int32_t id;
500 char *name;
501 int ret, status = SSH2_FX_FAILURE;
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;
514 if (status != SSH2_FX_OK)
515 send_status(id, status);
516 xfree(name);
519 static void
520 process_stat(void)
522 process_do_stat(0);
525 static void
526 process_lstat(void)
528 process_do_stat(1);
531 static void
532 process_fstat(void)
534 Attrib a;
535 struct stat st;
536 u_int32_t id;
537 int fd, ret, handle, status = SSH2_FX_FAILURE;
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;
553 if (status != SSH2_FX_OK)
554 send_status(id, status);
557 static struct timeval *
558 attrib_to_tv(const Attrib *a)
560 static struct timeval tv[2];
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;
569 static void
570 process_setstat(void)
572 Attrib *a;
573 u_int32_t id;
574 char *name;
575 int status = SSH2_FX_OK, ret;
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);
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);
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);
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);
601 send_status(id, status);
602 xfree(name);
605 static void
606 process_fsetstat(void)
608 Attrib *a;
609 u_int32_t id;
610 int handle, fd, ret;
611 int status = SSH2_FX_OK;
612 char *name;
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);
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);
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);
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);
656 send_status(id, status);
659 static void
660 process_opendir(void)
662 DIR *dirp = NULL;
663 char *path;
664 int handle, status = SSH2_FX_FAILURE;
665 u_int32_t id;
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;
683 if (status != SSH2_FX_OK)
684 send_status(id, status);
685 xfree(path);
688 static void
689 process_readdir(void)
691 DIR *dirp;
692 struct dirent *dp;
693 char *path;
694 int handle;
695 u_int32_t id;
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;
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));
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;
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);
736 } else {
737 send_status(id, SSH2_FX_EOF);
739 xfree(stats);
743 static void
744 process_remove(void)
746 char *name;
747 u_int32_t id;
748 int status = SSH2_FX_FAILURE;
749 int ret;
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);
760 static void
761 process_mkdir(void)
763 Attrib *a;
764 u_int32_t id;
765 char *name;
766 int ret, mode, status = SSH2_FX_FAILURE;
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);
780 static void
781 process_rmdir(void)
783 u_int32_t id;
784 char *name;
785 int ret, status;
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);
796 static void
797 process_realpath(void)
799 char resolvedname[MAXPATHLEN];
800 u_int32_t id;
801 char *path;
803 id = get_int();
804 path = get_string(NULL);
805 if (path[0] == '\0') {
806 xfree(path);
807 path = xstrdup(".");
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);
818 xfree(path);
821 static void
822 process_rename(void)
824 u_int32_t id;
825 char *oldpath, *newpath;
826 int status;
827 struct stat sb;
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
844 struct stat st;
847 * fs doesn't support links, so fall back to
848 * stat+rename. This is racy.
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;
857 } else {
858 status = errno_to_portable(errno);
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;
872 send_status(id, status);
873 xfree(oldpath);
874 xfree(newpath);
877 static void
878 process_readlink(void)
880 u_int32_t id;
881 int len;
882 char buf[MAXPATHLEN];
883 char *path;
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;
893 buf[len] = '\0';
894 attrib_clear(&s.attrib);
895 s.name = s.long_name = buf;
896 send_names(id, 1, &s);
898 xfree(path);
901 static void
902 process_symlink(void)
904 u_int32_t id;
905 char *oldpath, *newpath;
906 int ret, status;
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);
920 static void
921 process_extended(void)
923 u_int32_t id;
924 char *request;
926 id = get_int();
927 request = get_string(NULL);
928 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
929 xfree(request);
932 /* stolen from ssh-agent */
934 static void
935 process(void)
937 u_int msg_len;
938 u_int buf_len;
939 u_int consumed;
940 u_int type;
941 u_char *cp;
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);
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;
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);
1033 main(int ac, char **av)
1035 fd_set *rset, *wset;
1036 int in, out, max;
1037 ssize_t len, olen, set_size;
1039 /* XXX should use getopt */
1041 __progname = ssh_get_progname(av[0]);
1042 handle_init();
1044 #ifdef DEBUG_SFTP_SERVER
1045 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1046 #endif
1048 in = dup(STDIN_FILENO);
1049 out = dup(STDOUT_FILENO);
1051 #ifdef HAVE_CYGWIN
1052 setmode(in, O_BINARY);
1053 setmode(out, O_BINARY);
1054 #endif
1056 max = 0;
1057 if (in > max)
1058 max = in;
1059 if (out > max)
1060 max = out;
1062 buffer_init(&iqueue);
1063 buffer_init(&oqueue);
1065 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1066 rset = (fd_set *)xmalloc(set_size);
1067 wset = (fd_set *)xmalloc(set_size);
1069 for (;;) {
1070 memset(rset, 0, set_size);
1071 memset(wset, 0, set_size);
1073 FD_SET(in, rset);
1074 olen = buffer_len(&oqueue);
1075 if (olen > 0)
1076 FD_SET(out, wset);
1078 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1079 if (errno == EINTR)
1080 continue;
1081 exit(2);
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);
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);
1108 /* process requests from client */
1109 process();