]> andersk Git - openssh.git/blob - sftp-server.c
- (tim) [contrib/cygwin/README] add minires-devel requirement. Patch from
[openssh.git] / sftp-server.c
1 /*
2  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
3  *
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.
7  *
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.
15  */
16 #include "includes.h"
17 RCSID("$OpenBSD: sftp-server.c,v 1.47 2004/06/25 05:38:48 dtucker Exp $");
18
19 #include "buffer.h"
20 #include "bufaux.h"
21 #include "getput.h"
22 #include "log.h"
23 #include "xmalloc.h"
24
25 #include "sftp.h"
26 #include "sftp-common.h"
27
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
33
34 #ifdef HAVE___PROGNAME
35 extern char *__progname;
36 #else
37 char *__progname;
38 #endif
39
40 /* input and output queue */
41 Buffer iqueue;
42 Buffer oqueue;
43
44 /* Version of client */
45 int version;
46
47 /* portable attributes, etc. */
48
49 typedef struct Stat Stat;
50
51 struct Stat {
52         char *name;
53         char *long_name;
54         Attrib attrib;
55 };
56
57 static int
58 errno_to_portable(int unixerrno)
59 {
60         int ret = 0;
61
62         switch (unixerrno) {
63         case 0:
64                 ret = SSH2_FX_OK;
65                 break;
66         case ENOENT:
67         case ENOTDIR:
68         case EBADF:
69         case ELOOP:
70                 ret = SSH2_FX_NO_SUCH_FILE;
71                 break;
72         case EPERM:
73         case EACCES:
74         case EFAULT:
75                 ret = SSH2_FX_PERMISSION_DENIED;
76                 break;
77         case ENAMETOOLONG:
78         case EINVAL:
79                 ret = SSH2_FX_BAD_MESSAGE;
80                 break;
81         default:
82                 ret = SSH2_FX_FAILURE;
83                 break;
84         }
85         return ret;
86 }
87
88 static int
89 flags_from_portable(int pflags)
90 {
91         int flags = 0;
92
93         if ((pflags & SSH2_FXF_READ) &&
94             (pflags & SSH2_FXF_WRITE)) {
95                 flags = O_RDWR;
96         } else if (pflags & SSH2_FXF_READ) {
97                 flags = O_RDONLY;
98         } else if (pflags & SSH2_FXF_WRITE) {
99                 flags = O_WRONLY;
100         }
101         if (pflags & SSH2_FXF_CREAT)
102                 flags |= O_CREAT;
103         if (pflags & SSH2_FXF_TRUNC)
104                 flags |= O_TRUNC;
105         if (pflags & SSH2_FXF_EXCL)
106                 flags |= O_EXCL;
107         return flags;
108 }
109
110 static Attrib *
111 get_attrib(void)
112 {
113         return decode_attrib(&iqueue);
114 }
115
116 /* handle handles */
117
118 typedef struct Handle Handle;
119 struct Handle {
120         int use;
121         DIR *dirp;
122         int fd;
123         char *name;
124 };
125
126 enum {
127         HANDLE_UNUSED,
128         HANDLE_DIR,
129         HANDLE_FILE
130 };
131
132 Handle  handles[100];
133
134 static void
135 handle_init(void)
136 {
137         int i;
138
139         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
140                 handles[i].use = HANDLE_UNUSED;
141 }
142
143 static int
144 handle_new(int use, const char *name, int fd, DIR *dirp)
145 {
146         int i;
147
148         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
149                 if (handles[i].use == HANDLE_UNUSED) {
150                         handles[i].use = use;
151                         handles[i].dirp = dirp;
152                         handles[i].fd = fd;
153                         handles[i].name = xstrdup(name);
154                         return i;
155                 }
156         }
157         return -1;
158 }
159
160 static int
161 handle_is_ok(int i, int type)
162 {
163         return i >= 0 && i < sizeof(handles)/sizeof(Handle) &&
164             handles[i].use == type;
165 }
166
167 static int
168 handle_to_string(int handle, char **stringp, int *hlenp)
169 {
170         if (stringp == NULL || hlenp == NULL)
171                 return -1;
172         *stringp = xmalloc(sizeof(int32_t));
173         PUT_32BIT(*stringp, handle);
174         *hlenp = sizeof(int32_t);
175         return 0;
176 }
177
178 static int
179 handle_from_string(const char *handle, u_int hlen)
180 {
181         int val;
182
183         if (hlen != sizeof(int32_t))
184                 return -1;
185         val = GET_32BIT(handle);
186         if (handle_is_ok(val, HANDLE_FILE) ||
187             handle_is_ok(val, HANDLE_DIR))
188                 return val;
189         return -1;
190 }
191
192 static char *
193 handle_to_name(int handle)
194 {
195         if (handle_is_ok(handle, HANDLE_DIR)||
196             handle_is_ok(handle, HANDLE_FILE))
197                 return handles[handle].name;
198         return NULL;
199 }
200
201 static DIR *
202 handle_to_dir(int handle)
203 {
204         if (handle_is_ok(handle, HANDLE_DIR))
205                 return handles[handle].dirp;
206         return NULL;
207 }
208
209 static int
210 handle_to_fd(int handle)
211 {
212         if (handle_is_ok(handle, HANDLE_FILE))
213                 return handles[handle].fd;
214         return -1;
215 }
216
217 static int
218 handle_close(int handle)
219 {
220         int ret = -1;
221
222         if (handle_is_ok(handle, HANDLE_FILE)) {
223                 ret = close(handles[handle].fd);
224                 handles[handle].use = HANDLE_UNUSED;
225                 xfree(handles[handle].name);
226         } else if (handle_is_ok(handle, HANDLE_DIR)) {
227                 ret = closedir(handles[handle].dirp);
228                 handles[handle].use = HANDLE_UNUSED;
229                 xfree(handles[handle].name);
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 status)
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 %u error %u", id, status);
280         buffer_init(&msg);
281         buffer_put_char(&msg, SSH2_FXP_STATUS);
282         buffer_put_int(&msg, id);
283         buffer_put_int(&msg, status);
284         if (version >= 3) {
285                 buffer_put_cstring(&msg,
286                     status_messages[MIN(status,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, const 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, const char *data, int dlen)
307 {
308         TRACE("sent data id %u 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 %u 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, const 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 %u 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, const Attrib *a)
346 {
347         Buffer msg;
348
349         TRACE("sent attrib id %u 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 = get_int();
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 %u 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, 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 %u 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 %u handle %d off %llu len %d", id, handle,
434             (u_int64_t)off, len);
435         if (len > sizeof buf) {
436                 len = sizeof buf;
437                 logit("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 %u handle %d off %llu len %d", id, handle,
475             (u_int64_t)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                                 logit("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 %u 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 %u 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(const 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 status = SSH2_FX_OK, ret;
580
581         id = get_int();
582         name = get_string(NULL);
583         a = get_attrib();
584         TRACE("setstat id %u name %s", id, name);
585         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
586                 ret = truncate(name, a->size);
587                 if (ret == -1)
588                         status = errno_to_portable(errno);
589         }
590         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
591                 ret = chmod(name, a->perm & 0777);
592                 if (ret == -1)
593                         status = errno_to_portable(errno);
594         }
595         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
596                 ret = utimes(name, attrib_to_tv(a));
597                 if (ret == -1)
598                         status = errno_to_portable(errno);
599         }
600         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
601                 ret = chown(name, a->uid, a->gid);
602                 if (ret == -1)
603                         status = errno_to_portable(errno);
604         }
605         send_status(id, status);
606         xfree(name);
607 }
608
609 static void
610 process_fsetstat(void)
611 {
612         Attrib *a;
613         u_int32_t id;
614         int handle, fd, ret;
615         int status = SSH2_FX_OK;
616         char *name;
617
618         id = get_int();
619         handle = get_handle();
620         a = get_attrib();
621         TRACE("fsetstat id %u handle %d", id, handle);
622         fd = handle_to_fd(handle);
623         name = handle_to_name(handle);
624         if (fd < 0 || name == NULL) {
625                 status = SSH2_FX_FAILURE;
626         } else {
627                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
628                         ret = ftruncate(fd, a->size);
629                         if (ret == -1)
630                                 status = errno_to_portable(errno);
631                 }
632                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
633 #ifdef HAVE_FCHMOD
634                         ret = fchmod(fd, a->perm & 0777);
635 #else
636                         ret = chmod(name, a->perm & 0777);
637 #endif
638                         if (ret == -1)
639                                 status = errno_to_portable(errno);
640                 }
641                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
642 #ifdef HAVE_FUTIMES
643                         ret = futimes(fd, attrib_to_tv(a));
644 #else
645                         ret = utimes(name, attrib_to_tv(a));
646 #endif
647                         if (ret == -1)
648                                 status = errno_to_portable(errno);
649                 }
650                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
651 #ifdef HAVE_FCHOWN
652                         ret = fchown(fd, a->uid, a->gid);
653 #else
654                         ret = chown(name, a->uid, a->gid);
655 #endif
656                         if (ret == -1)
657                                 status = errno_to_portable(errno);
658                 }
659         }
660         send_status(id, status);
661 }
662
663 static void
664 process_opendir(void)
665 {
666         DIR *dirp = NULL;
667         char *path;
668         int handle, status = SSH2_FX_FAILURE;
669         u_int32_t id;
670
671         id = get_int();
672         path = get_string(NULL);
673         TRACE("opendir id %u path %s", id, path);
674         dirp = opendir(path);
675         if (dirp == NULL) {
676                 status = errno_to_portable(errno);
677         } else {
678                 handle = handle_new(HANDLE_DIR, path, 0, dirp);
679                 if (handle < 0) {
680                         closedir(dirp);
681                 } else {
682                         send_handle(id, handle);
683                         status = SSH2_FX_OK;
684                 }
685
686         }
687         if (status != SSH2_FX_OK)
688                 send_status(id, status);
689         xfree(path);
690 }
691
692 static void
693 process_readdir(void)
694 {
695         DIR *dirp;
696         struct dirent *dp;
697         char *path;
698         int handle;
699         u_int32_t id;
700
701         id = get_int();
702         handle = get_handle();
703         TRACE("readdir id %u handle %d", id, handle);
704         dirp = handle_to_dir(handle);
705         path = handle_to_name(handle);
706         if (dirp == NULL || path == NULL) {
707                 send_status(id, SSH2_FX_FAILURE);
708         } else {
709                 struct stat st;
710                 char pathname[1024];
711                 Stat *stats;
712                 int nstats = 10, count = 0, i;
713
714                 stats = xmalloc(nstats * sizeof(Stat));
715                 while ((dp = readdir(dirp)) != NULL) {
716                         if (count >= nstats) {
717                                 nstats *= 2;
718                                 stats = xrealloc(stats, nstats * sizeof(Stat));
719                         }
720 /* XXX OVERFLOW ? */
721                         snprintf(pathname, sizeof pathname, "%s%s%s", path,
722                             strcmp(path, "/") ? "/" : "", dp->d_name);
723                         if (lstat(pathname, &st) < 0)
724                                 continue;
725                         stat_to_attrib(&st, &(stats[count].attrib));
726                         stats[count].name = xstrdup(dp->d_name);
727                         stats[count].long_name = ls_file(dp->d_name, &st, 0);
728                         count++;
729                         /* send up to 100 entries in one message */
730                         /* XXX check packet size instead */
731                         if (count == 100)
732                                 break;
733                 }
734                 if (count > 0) {
735                         send_names(id, count, stats);
736                         for (i = 0; i < count; i++) {
737                                 xfree(stats[i].name);
738                                 xfree(stats[i].long_name);
739                         }
740                 } else {
741                         send_status(id, SSH2_FX_EOF);
742                 }
743                 xfree(stats);
744         }
745 }
746
747 static void
748 process_remove(void)
749 {
750         char *name;
751         u_int32_t id;
752         int status = SSH2_FX_FAILURE;
753         int ret;
754
755         id = get_int();
756         name = get_string(NULL);
757         TRACE("remove id %u name %s", id, name);
758         ret = unlink(name);
759         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
760         send_status(id, status);
761         xfree(name);
762 }
763
764 static void
765 process_mkdir(void)
766 {
767         Attrib *a;
768         u_int32_t id;
769         char *name;
770         int ret, mode, status = SSH2_FX_FAILURE;
771
772         id = get_int();
773         name = get_string(NULL);
774         a = get_attrib();
775         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
776             a->perm & 0777 : 0777;
777         TRACE("mkdir id %u name %s mode 0%o", id, name, mode);
778         ret = mkdir(name, mode);
779         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
780         send_status(id, status);
781         xfree(name);
782 }
783
784 static void
785 process_rmdir(void)
786 {
787         u_int32_t id;
788         char *name;
789         int ret, status;
790
791         id = get_int();
792         name = get_string(NULL);
793         TRACE("rmdir id %u name %s", id, name);
794         ret = rmdir(name);
795         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
796         send_status(id, status);
797         xfree(name);
798 }
799
800 static void
801 process_realpath(void)
802 {
803         char resolvedname[MAXPATHLEN];
804         u_int32_t id;
805         char *path;
806
807         id = get_int();
808         path = get_string(NULL);
809         if (path[0] == '\0') {
810                 xfree(path);
811                 path = xstrdup(".");
812         }
813         TRACE("realpath id %u path %s", id, path);
814         if (realpath(path, resolvedname) == NULL) {
815                 send_status(id, errno_to_portable(errno));
816         } else {
817                 Stat s;
818                 attrib_clear(&s.attrib);
819                 s.name = s.long_name = resolvedname;
820                 send_names(id, 1, &s);
821         }
822         xfree(path);
823 }
824
825 static void
826 process_rename(void)
827 {
828         u_int32_t id;
829         char *oldpath, *newpath;
830         int status;
831         struct stat sb;
832
833         id = get_int();
834         oldpath = get_string(NULL);
835         newpath = get_string(NULL);
836         TRACE("rename id %u old %s new %s", id, oldpath, newpath);
837         status = SSH2_FX_FAILURE;
838         if (lstat(oldpath, &sb) == -1)
839                 status = errno_to_portable(errno);
840         else if (S_ISREG(sb.st_mode)) {
841                 /* Race-free rename of regular files */
842                 if (link(oldpath, newpath) == -1) {
843                         if (errno == EOPNOTSUPP
844 #ifdef LINK_OPNOTSUPP_ERRNO
845                             || errno == LINK_OPNOTSUPP_ERRNO
846 #endif
847                             ) {
848                                 struct stat st;
849
850                                 /*
851                                  * fs doesn't support links, so fall back to
852                                  * stat+rename.  This is racy.
853                                  */
854                                 if (stat(newpath, &st) == -1) {
855                                         if (rename(oldpath, newpath) == -1)
856                                                 status =
857                                                     errno_to_portable(errno);
858                                         else
859                                                 status = SSH2_FX_OK;
860                                 }
861                         } else {
862                                 status = errno_to_portable(errno);
863                         }
864                 } else if (unlink(oldpath) == -1) {
865                         status = errno_to_portable(errno);
866                         /* clean spare link */
867                         unlink(newpath);
868                 } else
869                         status = SSH2_FX_OK;
870         } else if (stat(newpath, &sb) == -1) {
871                 if (rename(oldpath, newpath) == -1)
872                         status = errno_to_portable(errno);
873                 else
874                         status = SSH2_FX_OK;
875         }
876         send_status(id, status);
877         xfree(oldpath);
878         xfree(newpath);
879 }
880
881 static void
882 process_readlink(void)
883 {
884         u_int32_t id;
885         int len;
886         char buf[MAXPATHLEN];
887         char *path;
888
889         id = get_int();
890         path = get_string(NULL);
891         TRACE("readlink id %u path %s", id, path);
892         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
893                 send_status(id, errno_to_portable(errno));
894         else {
895                 Stat s;
896
897                 buf[len] = '\0';
898                 attrib_clear(&s.attrib);
899                 s.name = s.long_name = buf;
900                 send_names(id, 1, &s);
901         }
902         xfree(path);
903 }
904
905 static void
906 process_symlink(void)
907 {
908         u_int32_t id;
909         char *oldpath, *newpath;
910         int ret, status;
911
912         id = get_int();
913         oldpath = get_string(NULL);
914         newpath = get_string(NULL);
915         TRACE("symlink id %u old %s new %s", id, oldpath, newpath);
916         /* this will fail if 'newpath' exists */
917         ret = symlink(oldpath, newpath);
918         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
919         send_status(id, status);
920         xfree(oldpath);
921         xfree(newpath);
922 }
923
924 static void
925 process_extended(void)
926 {
927         u_int32_t id;
928         char *request;
929
930         id = get_int();
931         request = get_string(NULL);
932         send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
933         xfree(request);
934 }
935
936 /* stolen from ssh-agent */
937
938 static void
939 process(void)
940 {
941         u_int msg_len;
942         u_int buf_len;
943         u_int consumed;
944         u_int type;
945         u_char *cp;
946
947         buf_len = buffer_len(&iqueue);
948         if (buf_len < 5)
949                 return;         /* Incomplete message. */
950         cp = buffer_ptr(&iqueue);
951         msg_len = GET_32BIT(cp);
952         if (msg_len > 256 * 1024) {
953                 error("bad message ");
954                 exit(11);
955         }
956         if (buf_len < msg_len + 4)
957                 return;
958         buffer_consume(&iqueue, 4);
959         buf_len -= 4;
960         type = buffer_get_char(&iqueue);
961         switch (type) {
962         case SSH2_FXP_INIT:
963                 process_init();
964                 break;
965         case SSH2_FXP_OPEN:
966                 process_open();
967                 break;
968         case SSH2_FXP_CLOSE:
969                 process_close();
970                 break;
971         case SSH2_FXP_READ:
972                 process_read();
973                 break;
974         case SSH2_FXP_WRITE:
975                 process_write();
976                 break;
977         case SSH2_FXP_LSTAT:
978                 process_lstat();
979                 break;
980         case SSH2_FXP_FSTAT:
981                 process_fstat();
982                 break;
983         case SSH2_FXP_SETSTAT:
984                 process_setstat();
985                 break;
986         case SSH2_FXP_FSETSTAT:
987                 process_fsetstat();
988                 break;
989         case SSH2_FXP_OPENDIR:
990                 process_opendir();
991                 break;
992         case SSH2_FXP_READDIR:
993                 process_readdir();
994                 break;
995         case SSH2_FXP_REMOVE:
996                 process_remove();
997                 break;
998         case SSH2_FXP_MKDIR:
999                 process_mkdir();
1000                 break;
1001         case SSH2_FXP_RMDIR:
1002                 process_rmdir();
1003                 break;
1004         case SSH2_FXP_REALPATH:
1005                 process_realpath();
1006                 break;
1007         case SSH2_FXP_STAT:
1008                 process_stat();
1009                 break;
1010         case SSH2_FXP_RENAME:
1011                 process_rename();
1012                 break;
1013         case SSH2_FXP_READLINK:
1014                 process_readlink();
1015                 break;
1016         case SSH2_FXP_SYMLINK:
1017                 process_symlink();
1018                 break;
1019         case SSH2_FXP_EXTENDED:
1020                 process_extended();
1021                 break;
1022         default:
1023                 error("Unknown message %d", type);
1024                 break;
1025         }
1026         /* discard the remaining bytes from the current packet */
1027         if (buf_len < buffer_len(&iqueue))
1028                 fatal("iqueue grows");
1029         consumed = buf_len - buffer_len(&iqueue);
1030         if (msg_len < consumed)
1031                 fatal("msg_len %d < consumed %d", msg_len, consumed);
1032         if (msg_len > consumed)
1033                 buffer_consume(&iqueue, msg_len - consumed);
1034 }
1035
1036 int
1037 main(int ac, char **av)
1038 {
1039         fd_set *rset, *wset;
1040         int in, out, max;
1041         ssize_t len, olen, set_size;
1042
1043         /* XXX should use getopt */
1044
1045         __progname = ssh_get_progname(av[0]);
1046         handle_init();
1047
1048 #ifdef DEBUG_SFTP_SERVER
1049         log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0);
1050 #endif
1051
1052         in = dup(STDIN_FILENO);
1053         out = dup(STDOUT_FILENO);
1054
1055 #ifdef HAVE_CYGWIN
1056         setmode(in, O_BINARY);
1057         setmode(out, O_BINARY);
1058 #endif
1059
1060         max = 0;
1061         if (in > max)
1062                 max = in;
1063         if (out > max)
1064                 max = out;
1065
1066         buffer_init(&iqueue);
1067         buffer_init(&oqueue);
1068
1069         set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1070         rset = (fd_set *)xmalloc(set_size);
1071         wset = (fd_set *)xmalloc(set_size);
1072
1073         for (;;) {
1074                 memset(rset, 0, set_size);
1075                 memset(wset, 0, set_size);
1076
1077                 FD_SET(in, rset);
1078                 olen = buffer_len(&oqueue);
1079                 if (olen > 0)
1080                         FD_SET(out, wset);
1081
1082                 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1083                         if (errno == EINTR)
1084                                 continue;
1085                         exit(2);
1086                 }
1087
1088                 /* copy stdin to iqueue */
1089                 if (FD_ISSET(in, rset)) {
1090                         char buf[4*4096];
1091                         len = read(in, buf, sizeof buf);
1092                         if (len == 0) {
1093                                 debug("read eof");
1094                                 exit(0);
1095                         } else if (len < 0) {
1096                                 error("read error");
1097                                 exit(1);
1098                         } else {
1099                                 buffer_append(&iqueue, buf, len);
1100                         }
1101                 }
1102                 /* send oqueue to stdout */
1103                 if (FD_ISSET(out, wset)) {
1104                         len = write(out, buffer_ptr(&oqueue), olen);
1105                         if (len < 0) {
1106                                 error("write error");
1107                                 exit(1);
1108                         } else {
1109                                 buffer_consume(&oqueue, len);
1110                         }
1111                 }
1112                 /* process requests from client */
1113                 process();
1114         }
1115 }
This page took 0.12538 seconds and 5 git commands to generate.