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