]> andersk Git - openssh.git/blame_incremental - sftp-server.c
- millert@cvs.openbsd.org 2001/03/04 17:42:28
[openssh.git] / sftp-server.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 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"
25RCSID("$OpenBSD: sftp-server.c,v 1.22 2001/03/03 22:07:50 deraadt 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#ifdef HAVE___PROGNAME
43extern char *__progname;
44#else
45char *__progname;
46#endif
47
48/* input and output queue */
49Buffer iqueue;
50Buffer oqueue;
51
52/* portable attibutes, etc. */
53
54typedef struct Stat Stat;
55
56struct Stat {
57 char *name;
58 char *long_name;
59 Attrib attrib;
60};
61
62int
63errno_to_portable(int unixerrno)
64{
65 int ret = 0;
66
67 switch (unixerrno) {
68 case 0:
69 ret = SSH2_FX_OK;
70 break;
71 case ENOENT:
72 case ENOTDIR:
73 case EBADF:
74 case ELOOP:
75 ret = SSH2_FX_NO_SUCH_FILE;
76 break;
77 case EPERM:
78 case EACCES:
79 case EFAULT:
80 ret = SSH2_FX_PERMISSION_DENIED;
81 break;
82 case ENAMETOOLONG:
83 case EINVAL:
84 ret = SSH2_FX_BAD_MESSAGE;
85 break;
86 default:
87 ret = SSH2_FX_FAILURE;
88 break;
89 }
90 return ret;
91}
92
93int
94flags_from_portable(int pflags)
95{
96 int flags = 0;
97
98 if ((pflags & SSH2_FXF_READ) &&
99 (pflags & SSH2_FXF_WRITE)) {
100 flags = O_RDWR;
101 } else if (pflags & SSH2_FXF_READ) {
102 flags = O_RDONLY;
103 } else if (pflags & SSH2_FXF_WRITE) {
104 flags = O_WRONLY;
105 }
106 if (pflags & SSH2_FXF_CREAT)
107 flags |= O_CREAT;
108 if (pflags & SSH2_FXF_TRUNC)
109 flags |= O_TRUNC;
110 if (pflags & SSH2_FXF_EXCL)
111 flags |= O_EXCL;
112 return flags;
113}
114
115Attrib *
116get_attrib(void)
117{
118 return decode_attrib(&iqueue);
119}
120
121/* handle handles */
122
123typedef struct Handle Handle;
124struct Handle {
125 int use;
126 DIR *dirp;
127 int fd;
128 char *name;
129};
130
131enum {
132 HANDLE_UNUSED,
133 HANDLE_DIR,
134 HANDLE_FILE
135};
136
137Handle handles[100];
138
139void
140handle_init(void)
141{
142 int i;
143
144 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++)
145 handles[i].use = HANDLE_UNUSED;
146}
147
148int
149handle_new(int use, char *name, int fd, DIR *dirp)
150{
151 int i;
152
153 for(i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
154 if (handles[i].use == HANDLE_UNUSED) {
155 handles[i].use = use;
156 handles[i].dirp = dirp;
157 handles[i].fd = fd;
158 handles[i].name = name;
159 return i;
160 }
161 }
162 return -1;
163}
164
165int
166handle_is_ok(int i, int type)
167{
168 return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
169 handles[i].use == type;
170}
171
172int
173handle_to_string(int handle, char **stringp, int *hlenp)
174{
175 if (stringp == NULL || hlenp == NULL)
176 return -1;
177 *stringp = xmalloc(sizeof(int32_t));
178 PUT_32BIT(*stringp, handle);
179 *hlenp = sizeof(int32_t);
180 return 0;
181}
182
183int
184handle_from_string(char *handle, u_int hlen)
185{
186 int val;
187
188 if (hlen != sizeof(int32_t))
189 return -1;
190 val = GET_32BIT(handle);
191 if (handle_is_ok(val, HANDLE_FILE) ||
192 handle_is_ok(val, HANDLE_DIR))
193 return val;
194 return -1;
195}
196
197char *
198handle_to_name(int handle)
199{
200 if (handle_is_ok(handle, HANDLE_DIR)||
201 handle_is_ok(handle, HANDLE_FILE))
202 return handles[handle].name;
203 return NULL;
204}
205
206DIR *
207handle_to_dir(int handle)
208{
209 if (handle_is_ok(handle, HANDLE_DIR))
210 return handles[handle].dirp;
211 return NULL;
212}
213
214int
215handle_to_fd(int handle)
216{
217 if (handle_is_ok(handle, HANDLE_FILE))
218 return handles[handle].fd;
219 return -1;
220}
221
222int
223handle_close(int handle)
224{
225 int ret = -1;
226
227 if (handle_is_ok(handle, HANDLE_FILE)) {
228 ret = close(handles[handle].fd);
229 handles[handle].use = HANDLE_UNUSED;
230 } else if (handle_is_ok(handle, HANDLE_DIR)) {
231 ret = closedir(handles[handle].dirp);
232 handles[handle].use = HANDLE_UNUSED;
233 } else {
234 errno = ENOENT;
235 }
236 return ret;
237}
238
239int
240get_handle(void)
241{
242 char *handle;
243 int val = -1;
244 u_int hlen;
245
246 handle = get_string(&hlen);
247 if (hlen < 256)
248 val = handle_from_string(handle, hlen);
249 xfree(handle);
250 return val;
251}
252
253/* send replies */
254
255void
256send_msg(Buffer *m)
257{
258 int mlen = buffer_len(m);
259
260 buffer_put_int(&oqueue, mlen);
261 buffer_append(&oqueue, buffer_ptr(m), mlen);
262 buffer_consume(m, mlen);
263}
264
265void
266send_status(u_int32_t id, u_int32_t error)
267{
268 Buffer msg;
269
270 TRACE("sent status id %d error %d", id, error);
271 buffer_init(&msg);
272 buffer_put_char(&msg, SSH2_FXP_STATUS);
273 buffer_put_int(&msg, id);
274 buffer_put_int(&msg, error);
275 send_msg(&msg);
276 buffer_free(&msg);
277}
278void
279send_data_or_handle(char type, u_int32_t id, char *data, int dlen)
280{
281 Buffer msg;
282
283 buffer_init(&msg);
284 buffer_put_char(&msg, type);
285 buffer_put_int(&msg, id);
286 buffer_put_string(&msg, data, dlen);
287 send_msg(&msg);
288 buffer_free(&msg);
289}
290
291void
292send_data(u_int32_t id, char *data, int dlen)
293{
294 TRACE("sent data id %d len %d", id, dlen);
295 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
296}
297
298void
299send_handle(u_int32_t id, int handle)
300{
301 char *string;
302 int hlen;
303
304 handle_to_string(handle, &string, &hlen);
305 TRACE("sent handle id %d handle %d", id, handle);
306 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
307 xfree(string);
308}
309
310void
311send_names(u_int32_t id, int count, Stat *stats)
312{
313 Buffer msg;
314 int i;
315
316 buffer_init(&msg);
317 buffer_put_char(&msg, SSH2_FXP_NAME);
318 buffer_put_int(&msg, id);
319 buffer_put_int(&msg, count);
320 TRACE("sent names id %d count %d", id, count);
321 for (i = 0; i < count; i++) {
322 buffer_put_cstring(&msg, stats[i].name);
323 buffer_put_cstring(&msg, stats[i].long_name);
324 encode_attrib(&msg, &stats[i].attrib);
325 }
326 send_msg(&msg);
327 buffer_free(&msg);
328}
329
330void
331send_attrib(u_int32_t id, Attrib *a)
332{
333 Buffer msg;
334
335 TRACE("sent attrib id %d have 0x%x", id, a->flags);
336 buffer_init(&msg);
337 buffer_put_char(&msg, SSH2_FXP_ATTRS);
338 buffer_put_int(&msg, id);
339 encode_attrib(&msg, a);
340 send_msg(&msg);
341 buffer_free(&msg);
342}
343
344/* parse incoming */
345
346void
347process_init(void)
348{
349 Buffer msg;
350 int version = buffer_get_int(&iqueue);
351
352 TRACE("client version %d", version);
353 buffer_init(&msg);
354 buffer_put_char(&msg, SSH2_FXP_VERSION);
355 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
356 send_msg(&msg);
357 buffer_free(&msg);
358}
359
360void
361process_open(void)
362{
363 u_int32_t id, pflags;
364 Attrib *a;
365 char *name;
366 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
367
368 id = get_int();
369 name = get_string(NULL);
370 pflags = get_int(); /* portable flags */
371 a = get_attrib();
372 flags = flags_from_portable(pflags);
373 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
374 TRACE("open id %d name %s flags %d mode 0%o", id, name, pflags, mode);
375 fd = open(name, flags, mode);
376 if (fd < 0) {
377 status = errno_to_portable(errno);
378 } else {
379 handle = handle_new(HANDLE_FILE, xstrdup(name), fd, NULL);
380 if (handle < 0) {
381 close(fd);
382 } else {
383 send_handle(id, handle);
384 status = SSH2_FX_OK;
385 }
386 }
387 if (status != SSH2_FX_OK)
388 send_status(id, status);
389 xfree(name);
390}
391
392void
393process_close(void)
394{
395 u_int32_t id;
396 int handle, ret, status = SSH2_FX_FAILURE;
397
398 id = get_int();
399 handle = get_handle();
400 TRACE("close id %d handle %d", id, handle);
401 ret = handle_close(handle);
402 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
403 send_status(id, status);
404}
405
406void
407process_read(void)
408{
409 char buf[64*1024];
410 u_int32_t id, len;
411 int handle, fd, ret, status = SSH2_FX_FAILURE;
412 u_int64_t off;
413
414 id = get_int();
415 handle = get_handle();
416 off = get_int64();
417 len = get_int();
418
419 TRACE("read id %d handle %d off %llu len %d", id, handle,
420 (u_int64_t)off, len);
421 if (len > sizeof buf) {
422 len = sizeof buf;
423 log("read change len %d", len);
424 }
425 fd = handle_to_fd(handle);
426 if (fd >= 0) {
427 if (lseek(fd, off, SEEK_SET) < 0) {
428 error("process_read: seek failed");
429 status = errno_to_portable(errno);
430 } else {
431 ret = read(fd, buf, len);
432 if (ret < 0) {
433 status = errno_to_portable(errno);
434 } else if (ret == 0) {
435 status = SSH2_FX_EOF;
436 } else {
437 send_data(id, buf, ret);
438 status = SSH2_FX_OK;
439 }
440 }
441 }
442 if (status != SSH2_FX_OK)
443 send_status(id, status);
444}
445
446void
447process_write(void)
448{
449 u_int32_t id;
450 u_int64_t off;
451 u_int len;
452 int handle, fd, ret, status = SSH2_FX_FAILURE;
453 char *data;
454
455 id = get_int();
456 handle = get_handle();
457 off = get_int64();
458 data = get_string(&len);
459
460 TRACE("write id %d handle %d off %llu len %d", id, handle,
461 (u_int64_t)off, len);
462 fd = handle_to_fd(handle);
463 if (fd >= 0) {
464 if (lseek(fd, off, SEEK_SET) < 0) {
465 status = errno_to_portable(errno);
466 error("process_write: seek failed");
467 } else {
468/* XXX ATOMICIO ? */
469 ret = write(fd, data, len);
470 if (ret == -1) {
471 error("process_write: write failed");
472 status = errno_to_portable(errno);
473 } else if (ret == len) {
474 status = SSH2_FX_OK;
475 } else {
476 log("nothing at all written");
477 }
478 }
479 }
480 send_status(id, status);
481 xfree(data);
482}
483
484void
485process_do_stat(int do_lstat)
486{
487 Attrib a;
488 struct stat st;
489 u_int32_t id;
490 char *name;
491 int ret, status = SSH2_FX_FAILURE;
492
493 id = get_int();
494 name = get_string(NULL);
495 TRACE("%sstat id %d name %s", do_lstat ? "l" : "", id, name);
496 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
497 if (ret < 0) {
498 status = errno_to_portable(errno);
499 } else {
500 stat_to_attrib(&st, &a);
501 send_attrib(id, &a);
502 status = SSH2_FX_OK;
503 }
504 if (status != SSH2_FX_OK)
505 send_status(id, status);
506 xfree(name);
507}
508
509void
510process_stat(void)
511{
512 process_do_stat(0);
513}
514
515void
516process_lstat(void)
517{
518 process_do_stat(1);
519}
520
521void
522process_fstat(void)
523{
524 Attrib a;
525 struct stat st;
526 u_int32_t id;
527 int fd, ret, handle, status = SSH2_FX_FAILURE;
528
529 id = get_int();
530 handle = get_handle();
531 TRACE("fstat id %d handle %d", id, handle);
532 fd = handle_to_fd(handle);
533 if (fd >= 0) {
534 ret = fstat(fd, &st);
535 if (ret < 0) {
536 status = errno_to_portable(errno);
537 } else {
538 stat_to_attrib(&st, &a);
539 send_attrib(id, &a);
540 status = SSH2_FX_OK;
541 }
542 }
543 if (status != SSH2_FX_OK)
544 send_status(id, status);
545}
546
547struct timeval *
548attrib_to_tv(Attrib *a)
549{
550 static struct timeval tv[2];
551
552 tv[0].tv_sec = a->atime;
553 tv[0].tv_usec = 0;
554 tv[1].tv_sec = a->mtime;
555 tv[1].tv_usec = 0;
556 return tv;
557}
558
559void
560process_setstat(void)
561{
562 Attrib *a;
563 u_int32_t id;
564 char *name;
565 int ret;
566 int status = SSH2_FX_OK;
567
568 id = get_int();
569 name = get_string(NULL);
570 a = get_attrib();
571 TRACE("setstat id %d name %s", id, name);
572 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
573 ret = chmod(name, a->perm & 0777);
574 if (ret == -1)
575 status = errno_to_portable(errno);
576 }
577 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
578 ret = utimes(name, attrib_to_tv(a));
579 if (ret == -1)
580 status = errno_to_portable(errno);
581 }
582 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
583 ret = chown(name, a->uid, a->gid);
584 if (ret == -1)
585 status = errno_to_portable(errno);
586 }
587 send_status(id, status);
588 xfree(name);
589}
590
591void
592process_fsetstat(void)
593{
594 Attrib *a;
595 u_int32_t id;
596 int handle, fd, ret;
597 int status = SSH2_FX_OK;
598 char *name;
599
600 id = get_int();
601 handle = get_handle();
602 a = get_attrib();
603 TRACE("fsetstat id %d handle %d", id, handle);
604 fd = handle_to_fd(handle);
605 name = handle_to_name(handle);
606 if (fd < 0 || name == NULL) {
607 status = SSH2_FX_FAILURE;
608 } else {
609 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
610#ifdef HAVE_FCHMOD
611 ret = fchmod(fd, a->perm & 0777);
612#else
613 ret = chmod(name, a->perm & 0777);
614#endif
615 if (ret == -1)
616 status = errno_to_portable(errno);
617 }
618 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
619#ifdef HAVE_FUTIMES
620 ret = futimes(fd, attrib_to_tv(a));
621#else
622 ret = utimes(name, attrib_to_tv(a));
623#endif
624 if (ret == -1)
625 status = errno_to_portable(errno);
626 }
627 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
628#ifdef HAVE_FCHOWN
629 ret = fchown(fd, a->uid, a->gid);
630#else
631 ret = chown(name, a->uid, a->gid);
632#endif
633 if (ret == -1)
634 status = errno_to_portable(errno);
635 }
636 }
637 send_status(id, status);
638}
639
640void
641process_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 */
672char *
673ls_file(char *name, struct stat *st)
674{
675 int 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 snprintf(buf, sizeof buf, "%s %3d %-8.8s %-8.8s %8llu %s %s", mode,
704 st->st_nlink, user, group, (u_int64_t)st->st_size, tbuf, name);
705 return xstrdup(buf);
706}
707
708void
709process_readdir(void)
710{
711 DIR *dirp;
712 struct dirent *dp;
713 char *path;
714 int handle;
715 u_int32_t id;
716
717 id = get_int();
718 handle = get_handle();
719 TRACE("readdir id %d handle %d", id, handle);
720 dirp = handle_to_dir(handle);
721 path = handle_to_name(handle);
722 if (dirp == NULL || path == NULL) {
723 send_status(id, SSH2_FX_FAILURE);
724 } else {
725 struct stat st;
726 char pathname[1024];
727 Stat *stats;
728 int nstats = 10, count = 0, i;
729 stats = xmalloc(nstats * sizeof(Stat));
730 while ((dp = readdir(dirp)) != NULL) {
731 if (count >= nstats) {
732 nstats *= 2;
733 stats = xrealloc(stats, nstats * sizeof(Stat));
734 }
735/* XXX OVERFLOW ? */
736 snprintf(pathname, sizeof pathname,
737 "%s/%s", path, dp->d_name);
738 if (lstat(pathname, &st) < 0)
739 continue;
740 stat_to_attrib(&st, &(stats[count].attrib));
741 stats[count].name = xstrdup(dp->d_name);
742 stats[count].long_name = ls_file(dp->d_name, &st);
743 count++;
744 /* send up to 100 entries in one message */
745 /* XXX check packet size instead */
746 if (count == 100)
747 break;
748 }
749 if (count > 0) {
750 send_names(id, count, stats);
751 for(i = 0; i < count; i++) {
752 xfree(stats[i].name);
753 xfree(stats[i].long_name);
754 }
755 } else {
756 send_status(id, SSH2_FX_EOF);
757 }
758 xfree(stats);
759 }
760}
761
762void
763process_remove(void)
764{
765 char *name;
766 u_int32_t id;
767 int status = SSH2_FX_FAILURE;
768 int ret;
769
770 id = get_int();
771 name = get_string(NULL);
772 TRACE("remove id %d name %s", id, name);
773 ret = unlink(name);
774 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
775 send_status(id, status);
776 xfree(name);
777}
778
779void
780process_mkdir(void)
781{
782 Attrib *a;
783 u_int32_t id;
784 char *name;
785 int ret, mode, status = SSH2_FX_FAILURE;
786
787 id = get_int();
788 name = get_string(NULL);
789 a = get_attrib();
790 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
791 a->perm & 0777 : 0777;
792 TRACE("mkdir id %d name %s mode 0%o", id, name, mode);
793 ret = mkdir(name, mode);
794 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
795 send_status(id, status);
796 xfree(name);
797}
798
799void
800process_rmdir(void)
801{
802 u_int32_t id;
803 char *name;
804 int ret, status;
805
806 id = get_int();
807 name = get_string(NULL);
808 TRACE("rmdir id %d name %s", id, name);
809 ret = rmdir(name);
810 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
811 send_status(id, status);
812 xfree(name);
813}
814
815void
816process_realpath(void)
817{
818 char resolvedname[MAXPATHLEN];
819 u_int32_t id;
820 char *path;
821
822 id = get_int();
823 path = get_string(NULL);
824 if (path[0] == '\0') {
825 xfree(path);
826 path = xstrdup(".");
827 }
828 TRACE("realpath id %d path %s", id, path);
829 if (realpath(path, resolvedname) == NULL) {
830 send_status(id, errno_to_portable(errno));
831 } else {
832 Stat s;
833 attrib_clear(&s.attrib);
834 s.name = s.long_name = resolvedname;
835 send_names(id, 1, &s);
836 }
837 xfree(path);
838}
839
840void
841process_rename(void)
842{
843 u_int32_t id;
844 struct stat st;
845 char *oldpath, *newpath;
846 int ret, status = SSH2_FX_FAILURE;
847
848 id = get_int();
849 oldpath = get_string(NULL);
850 newpath = get_string(NULL);
851 TRACE("rename id %d old %s new %s", id, oldpath, newpath);
852 /* fail if 'newpath' exists */
853 if (stat(newpath, &st) == -1) {
854 ret = rename(oldpath, newpath);
855 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
856 }
857 send_status(id, status);
858 xfree(oldpath);
859 xfree(newpath);
860}
861
862void
863process_extended(void)
864{
865 u_int32_t id;
866 char *request;
867
868 id = get_int();
869 request = get_string(NULL);
870 send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
871 xfree(request);
872}
873
874/* stolen from ssh-agent */
875
876void
877process(void)
878{
879 u_int msg_len;
880 u_int type;
881 u_char *cp;
882
883 if (buffer_len(&iqueue) < 5)
884 return; /* Incomplete message. */
885 cp = (u_char *) buffer_ptr(&iqueue);
886 msg_len = GET_32BIT(cp);
887 if (msg_len > 256 * 1024) {
888 error("bad message ");
889 exit(11);
890 }
891 if (buffer_len(&iqueue) < msg_len + 4)
892 return;
893 buffer_consume(&iqueue, 4);
894 type = buffer_get_char(&iqueue);
895 switch (type) {
896 case SSH2_FXP_INIT:
897 process_init();
898 break;
899 case SSH2_FXP_OPEN:
900 process_open();
901 break;
902 case SSH2_FXP_CLOSE:
903 process_close();
904 break;
905 case SSH2_FXP_READ:
906 process_read();
907 break;
908 case SSH2_FXP_WRITE:
909 process_write();
910 break;
911 case SSH2_FXP_LSTAT:
912 process_lstat();
913 break;
914 case SSH2_FXP_FSTAT:
915 process_fstat();
916 break;
917 case SSH2_FXP_SETSTAT:
918 process_setstat();
919 break;
920 case SSH2_FXP_FSETSTAT:
921 process_fsetstat();
922 break;
923 case SSH2_FXP_OPENDIR:
924 process_opendir();
925 break;
926 case SSH2_FXP_READDIR:
927 process_readdir();
928 break;
929 case SSH2_FXP_REMOVE:
930 process_remove();
931 break;
932 case SSH2_FXP_MKDIR:
933 process_mkdir();
934 break;
935 case SSH2_FXP_RMDIR:
936 process_rmdir();
937 break;
938 case SSH2_FXP_REALPATH:
939 process_realpath();
940 break;
941 case SSH2_FXP_STAT:
942 process_stat();
943 break;
944 case SSH2_FXP_RENAME:
945 process_rename();
946 break;
947 case SSH2_FXP_EXTENDED:
948 process_extended();
949 break;
950 default:
951 error("Unknown message %d", type);
952 break;
953 }
954}
955
956int
957main(int ac, char **av)
958{
959 fd_set *rset, *wset;
960 int in, out, max;
961 ssize_t len, olen, set_size;
962
963 __progname = get_progname(av[0]);
964 handle_init();
965
966#ifdef DEBUG_SFTP_SERVER
967 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
968#endif
969
970 in = dup(STDIN_FILENO);
971 out = dup(STDOUT_FILENO);
972
973 max = 0;
974 if (in > max)
975 max = in;
976 if (out > max)
977 max = out;
978
979 buffer_init(&iqueue);
980 buffer_init(&oqueue);
981
982 set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
983 rset = (fd_set *)xmalloc(set_size);
984 wset = (fd_set *)xmalloc(set_size);
985
986 for (;;) {
987 memset(rset, 0, set_size);
988 memset(wset, 0, set_size);
989
990 FD_SET(in, rset);
991 olen = buffer_len(&oqueue);
992 if (olen > 0)
993 FD_SET(out, wset);
994
995 if (select(max+1, rset, wset, NULL, NULL) < 0) {
996 if (errno == EINTR)
997 continue;
998 exit(2);
999 }
1000
1001 /* copy stdin to iqueue */
1002 if (FD_ISSET(in, rset)) {
1003 char buf[4*4096];
1004 len = read(in, buf, sizeof buf);
1005 if (len == 0) {
1006 debug("read eof");
1007 exit(0);
1008 } else if (len < 0) {
1009 error("read error");
1010 exit(1);
1011 } else {
1012 buffer_append(&iqueue, buf, len);
1013 }
1014 }
1015 /* send oqueue to stdout */
1016 if (FD_ISSET(out, wset)) {
1017 len = write(out, buffer_ptr(&oqueue), olen);
1018 if (len < 0) {
1019 error("write error");
1020 exit(1);
1021 } else {
1022 buffer_consume(&oqueue, len);
1023 }
1024 }
1025 /* process requests from client */
1026 process();
1027 }
1028}
This page took 0.039139 seconds and 5 git commands to generate.