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