]> andersk Git - openssh.git/blob - sftp-server.c
02c897c1199365e1af48b4f5836f7052f1ca24ae
[openssh.git] / sftp-server.c
1 /* $OpenBSD: sftp-server.c,v 1.67 2006/07/26 02:35:17 stevesk Exp $ */
2 /*
3  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include "includes.h"
18
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_SYS_TIME_H
23 # include <sys/time.h>
24 #endif
25
26 #include <dirent.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <pwd.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33
34 #include "buffer.h"
35 #include "bufaux.h"
36 #include "log.h"
37 #include "xmalloc.h"
38 #include "misc.h"
39 #include "uidswap.h"
40
41 #include "sftp.h"
42 #include "sftp-common.h"
43
44 /* helper */
45 #define get_int64()                     buffer_get_int64(&iqueue);
46 #define get_int()                       buffer_get_int(&iqueue);
47 #define get_string(lenp)                buffer_get_string(&iqueue, lenp);
48
49 /* Our verbosity */
50 LogLevel log_level = SYSLOG_LEVEL_ERROR;
51
52 /* Our client */
53 struct passwd *pw = NULL;
54 char *client_addr = NULL;
55
56 /* input and output queue */
57 Buffer iqueue;
58 Buffer oqueue;
59
60 /* Version of client */
61 int version;
62
63 /* portable attributes, etc. */
64
65 typedef struct Stat Stat;
66
67 struct Stat {
68         char *name;
69         char *long_name;
70         Attrib attrib;
71 };
72
73 static int
74 errno_to_portable(int unixerrno)
75 {
76         int ret = 0;
77
78         switch (unixerrno) {
79         case 0:
80                 ret = SSH2_FX_OK;
81                 break;
82         case ENOENT:
83         case ENOTDIR:
84         case EBADF:
85         case ELOOP:
86                 ret = SSH2_FX_NO_SUCH_FILE;
87                 break;
88         case EPERM:
89         case EACCES:
90         case EFAULT:
91                 ret = SSH2_FX_PERMISSION_DENIED;
92                 break;
93         case ENAMETOOLONG:
94         case EINVAL:
95                 ret = SSH2_FX_BAD_MESSAGE;
96                 break;
97         default:
98                 ret = SSH2_FX_FAILURE;
99                 break;
100         }
101         return ret;
102 }
103
104 static int
105 flags_from_portable(int pflags)
106 {
107         int flags = 0;
108
109         if ((pflags & SSH2_FXF_READ) &&
110             (pflags & SSH2_FXF_WRITE)) {
111                 flags = O_RDWR;
112         } else if (pflags & SSH2_FXF_READ) {
113                 flags = O_RDONLY;
114         } else if (pflags & SSH2_FXF_WRITE) {
115                 flags = O_WRONLY;
116         }
117         if (pflags & SSH2_FXF_CREAT)
118                 flags |= O_CREAT;
119         if (pflags & SSH2_FXF_TRUNC)
120                 flags |= O_TRUNC;
121         if (pflags & SSH2_FXF_EXCL)
122                 flags |= O_EXCL;
123         return flags;
124 }
125
126 static const char *
127 string_from_portable(int pflags)
128 {
129         static char ret[128];
130
131         *ret = '\0';
132
133 #define PAPPEND(str)    {                               \
134                 if (*ret != '\0')                       \
135                         strlcat(ret, ",", sizeof(ret)); \
136                 strlcat(ret, str, sizeof(ret));         \
137         }
138
139         if (pflags & SSH2_FXF_READ)
140                 PAPPEND("READ")
141         if (pflags & SSH2_FXF_WRITE)
142                 PAPPEND("WRITE")
143         if (pflags & SSH2_FXF_CREAT)
144                 PAPPEND("CREATE")
145         if (pflags & SSH2_FXF_TRUNC)
146                 PAPPEND("TRUNCATE")
147         if (pflags & SSH2_FXF_EXCL)
148                 PAPPEND("EXCL")
149
150         return ret;
151 }
152
153 static Attrib *
154 get_attrib(void)
155 {
156         return decode_attrib(&iqueue);
157 }
158
159 /* handle handles */
160
161 typedef struct Handle Handle;
162 struct Handle {
163         int use;
164         DIR *dirp;
165         int fd;
166         char *name;
167         u_int64_t bytes_read, bytes_write;
168 };
169
170 enum {
171         HANDLE_UNUSED,
172         HANDLE_DIR,
173         HANDLE_FILE
174 };
175
176 Handle  handles[100];
177
178 static void
179 handle_init(void)
180 {
181         u_int i;
182
183         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
184                 handles[i].use = HANDLE_UNUSED;
185 }
186
187 static int
188 handle_new(int use, const char *name, int fd, DIR *dirp)
189 {
190         u_int i;
191
192         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) {
193                 if (handles[i].use == HANDLE_UNUSED) {
194                         handles[i].use = use;
195                         handles[i].dirp = dirp;
196                         handles[i].fd = fd;
197                         handles[i].name = xstrdup(name);
198                         handles[i].bytes_read = handles[i].bytes_write = 0;
199                         return i;
200                 }
201         }
202         return -1;
203 }
204
205 static int
206 handle_is_ok(int i, int type)
207 {
208         return i >= 0 && (u_int)i < sizeof(handles)/sizeof(Handle) &&
209             handles[i].use == type;
210 }
211
212 static int
213 handle_to_string(int handle, char **stringp, int *hlenp)
214 {
215         if (stringp == NULL || hlenp == NULL)
216                 return -1;
217         *stringp = xmalloc(sizeof(int32_t));
218         put_u32(*stringp, handle);
219         *hlenp = sizeof(int32_t);
220         return 0;
221 }
222
223 static int
224 handle_from_string(const char *handle, u_int hlen)
225 {
226         int val;
227
228         if (hlen != sizeof(int32_t))
229                 return -1;
230         val = get_u32(handle);
231         if (handle_is_ok(val, HANDLE_FILE) ||
232             handle_is_ok(val, HANDLE_DIR))
233                 return val;
234         return -1;
235 }
236
237 static char *
238 handle_to_name(int handle)
239 {
240         if (handle_is_ok(handle, HANDLE_DIR)||
241             handle_is_ok(handle, HANDLE_FILE))
242                 return handles[handle].name;
243         return NULL;
244 }
245
246 static DIR *
247 handle_to_dir(int handle)
248 {
249         if (handle_is_ok(handle, HANDLE_DIR))
250                 return handles[handle].dirp;
251         return NULL;
252 }
253
254 static int
255 handle_to_fd(int handle)
256 {
257         if (handle_is_ok(handle, HANDLE_FILE))
258                 return handles[handle].fd;
259         return -1;
260 }
261
262 static void
263 handle_update_read(int handle, ssize_t bytes)
264 {
265         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
266                 handles[handle].bytes_read += bytes;
267 }
268
269 static void
270 handle_update_write(int handle, ssize_t bytes)
271 {
272         if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
273                 handles[handle].bytes_write += bytes;
274 }
275
276 static u_int64_t
277 handle_bytes_read(int handle)
278 {
279         if (handle_is_ok(handle, HANDLE_FILE))
280                 return (handles[handle].bytes_read);
281         return 0;
282 }
283
284 static u_int64_t
285 handle_bytes_write(int handle)
286 {
287         if (handle_is_ok(handle, HANDLE_FILE))
288                 return (handles[handle].bytes_write);
289         return 0;
290 }
291
292 static int
293 handle_close(int handle)
294 {
295         int ret = -1;
296
297         if (handle_is_ok(handle, HANDLE_FILE)) {
298                 ret = close(handles[handle].fd);
299                 handles[handle].use = HANDLE_UNUSED;
300                 xfree(handles[handle].name);
301         } else if (handle_is_ok(handle, HANDLE_DIR)) {
302                 ret = closedir(handles[handle].dirp);
303                 handles[handle].use = HANDLE_UNUSED;
304                 xfree(handles[handle].name);
305         } else {
306                 errno = ENOENT;
307         }
308         return ret;
309 }
310
311 static void
312 handle_log_close(int handle, char *emsg)
313 {
314         if (handle_is_ok(handle, HANDLE_FILE)) {
315                 logit("%s%sclose \"%s\" bytes read %llu written %llu",
316                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
317                     handle_to_name(handle),
318                     handle_bytes_read(handle), handle_bytes_write(handle));
319         } else {
320                 logit("%s%sclosedir \"%s\"",
321                     emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
322                     handle_to_name(handle));
323         }
324 }
325
326 static void
327 handle_log_exit(void)
328 {
329         u_int i;
330
331         for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
332                 if (handles[i].use != HANDLE_UNUSED)
333                         handle_log_close(i, "forced");
334 }
335
336 static int
337 get_handle(void)
338 {
339         char *handle;
340         int val = -1;
341         u_int hlen;
342
343         handle = get_string(&hlen);
344         if (hlen < 256)
345                 val = handle_from_string(handle, hlen);
346         xfree(handle);
347         return val;
348 }
349
350 /* send replies */
351
352 static void
353 send_msg(Buffer *m)
354 {
355         int mlen = buffer_len(m);
356
357         buffer_put_int(&oqueue, mlen);
358         buffer_append(&oqueue, buffer_ptr(m), mlen);
359         buffer_consume(m, mlen);
360 }
361
362 static const char *
363 status_to_message(u_int32_t status)
364 {
365         const char *status_messages[] = {
366                 "Success",                      /* SSH_FX_OK */
367                 "End of file",                  /* SSH_FX_EOF */
368                 "No such file",                 /* SSH_FX_NO_SUCH_FILE */
369                 "Permission denied",            /* SSH_FX_PERMISSION_DENIED */
370                 "Failure",                      /* SSH_FX_FAILURE */
371                 "Bad message",                  /* SSH_FX_BAD_MESSAGE */
372                 "No connection",                /* SSH_FX_NO_CONNECTION */
373                 "Connection lost",              /* SSH_FX_CONNECTION_LOST */
374                 "Operation unsupported",        /* SSH_FX_OP_UNSUPPORTED */
375                 "Unknown error"                 /* Others */
376         };
377         return (status_messages[MIN(status,SSH2_FX_MAX)]);
378 }
379
380 static void
381 send_status(u_int32_t id, u_int32_t status)
382 {
383         Buffer msg;
384
385         debug3("request %u: sent status %u", id, status);
386         if (log_level > SYSLOG_LEVEL_VERBOSE ||
387             (status != SSH2_FX_OK && status != SSH2_FX_EOF))
388                 logit("sent status %s", status_to_message(status));
389         buffer_init(&msg);
390         buffer_put_char(&msg, SSH2_FXP_STATUS);
391         buffer_put_int(&msg, id);
392         buffer_put_int(&msg, status);
393         if (version >= 3) {
394                 buffer_put_cstring(&msg, status_to_message(status));
395                 buffer_put_cstring(&msg, "");
396         }
397         send_msg(&msg);
398         buffer_free(&msg);
399 }
400 static void
401 send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
402 {
403         Buffer msg;
404
405         buffer_init(&msg);
406         buffer_put_char(&msg, type);
407         buffer_put_int(&msg, id);
408         buffer_put_string(&msg, data, dlen);
409         send_msg(&msg);
410         buffer_free(&msg);
411 }
412
413 static void
414 send_data(u_int32_t id, const char *data, int dlen)
415 {
416         debug("request %u: sent data len %d", id, dlen);
417         send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
418 }
419
420 static void
421 send_handle(u_int32_t id, int handle)
422 {
423         char *string;
424         int hlen;
425
426         handle_to_string(handle, &string, &hlen);
427         debug("request %u: sent handle handle %d", id, handle);
428         send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
429         xfree(string);
430 }
431
432 static void
433 send_names(u_int32_t id, int count, const Stat *stats)
434 {
435         Buffer msg;
436         int i;
437
438         buffer_init(&msg);
439         buffer_put_char(&msg, SSH2_FXP_NAME);
440         buffer_put_int(&msg, id);
441         buffer_put_int(&msg, count);
442         debug("request %u: sent names count %d", id, count);
443         for (i = 0; i < count; i++) {
444                 buffer_put_cstring(&msg, stats[i].name);
445                 buffer_put_cstring(&msg, stats[i].long_name);
446                 encode_attrib(&msg, &stats[i].attrib);
447         }
448         send_msg(&msg);
449         buffer_free(&msg);
450 }
451
452 static void
453 send_attrib(u_int32_t id, const Attrib *a)
454 {
455         Buffer msg;
456
457         debug("request %u: sent attrib have 0x%x", id, a->flags);
458         buffer_init(&msg);
459         buffer_put_char(&msg, SSH2_FXP_ATTRS);
460         buffer_put_int(&msg, id);
461         encode_attrib(&msg, a);
462         send_msg(&msg);
463         buffer_free(&msg);
464 }
465
466 /* parse incoming */
467
468 static void
469 process_init(void)
470 {
471         Buffer msg;
472
473         version = get_int();
474         verbose("received client version %d", version);
475         buffer_init(&msg);
476         buffer_put_char(&msg, SSH2_FXP_VERSION);
477         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
478         send_msg(&msg);
479         buffer_free(&msg);
480 }
481
482 static void
483 process_open(void)
484 {
485         u_int32_t id, pflags;
486         Attrib *a;
487         char *name;
488         int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
489
490         id = get_int();
491         name = get_string(NULL);
492         pflags = get_int();             /* portable flags */
493         debug3("request %u: open flags %d", id, pflags);
494         a = get_attrib();
495         flags = flags_from_portable(pflags);
496         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
497         logit("open \"%s\" flags %s mode 0%o",
498             name, string_from_portable(pflags), mode);
499         fd = open(name, flags, mode);
500         if (fd < 0) {
501                 status = errno_to_portable(errno);
502         } else {
503                 handle = handle_new(HANDLE_FILE, name, fd, NULL);
504                 if (handle < 0) {
505                         close(fd);
506                 } else {
507                         send_handle(id, handle);
508                         status = SSH2_FX_OK;
509                 }
510         }
511         if (status != SSH2_FX_OK)
512                 send_status(id, status);
513         xfree(name);
514 }
515
516 static void
517 process_close(void)
518 {
519         u_int32_t id;
520         int handle, ret, status = SSH2_FX_FAILURE;
521
522         id = get_int();
523         handle = get_handle();
524         debug3("request %u: close handle %u", id, handle);
525         handle_log_close(handle, NULL);
526         ret = handle_close(handle);
527         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
528         send_status(id, status);
529 }
530
531 static void
532 process_read(void)
533 {
534         char buf[64*1024];
535         u_int32_t id, len;
536         int handle, fd, ret, status = SSH2_FX_FAILURE;
537         u_int64_t off;
538
539         id = get_int();
540         handle = get_handle();
541         off = get_int64();
542         len = get_int();
543
544         debug("request %u: read \"%s\" (handle %d) off %llu len %d",
545             id, handle_to_name(handle), handle, (unsigned long long)off, len);
546         if (len > sizeof buf) {
547                 len = sizeof buf;
548                 debug2("read change len %d", len);
549         }
550         fd = handle_to_fd(handle);
551         if (fd >= 0) {
552                 if (lseek(fd, off, SEEK_SET) < 0) {
553                         error("process_read: seek failed");
554                         status = errno_to_portable(errno);
555                 } else {
556                         ret = read(fd, buf, len);
557                         if (ret < 0) {
558                                 status = errno_to_portable(errno);
559                         } else if (ret == 0) {
560                                 status = SSH2_FX_EOF;
561                         } else {
562                                 send_data(id, buf, ret);
563                                 status = SSH2_FX_OK;
564                                 handle_update_read(handle, ret);
565                         }
566                 }
567         }
568         if (status != SSH2_FX_OK)
569                 send_status(id, status);
570 }
571
572 static void
573 process_write(void)
574 {
575         u_int32_t id;
576         u_int64_t off;
577         u_int len;
578         int handle, fd, ret, status = SSH2_FX_FAILURE;
579         char *data;
580
581         id = get_int();
582         handle = get_handle();
583         off = get_int64();
584         data = get_string(&len);
585
586         debug("request %u: write \"%s\" (handle %d) off %llu len %d",
587             id, handle_to_name(handle), handle, (unsigned long long)off, len);
588         fd = handle_to_fd(handle);
589         if (fd >= 0) {
590                 if (lseek(fd, off, SEEK_SET) < 0) {
591                         status = errno_to_portable(errno);
592                         error("process_write: seek failed");
593                 } else {
594 /* XXX ATOMICIO ? */
595                         ret = write(fd, data, len);
596                         if (ret < 0) {
597                                 error("process_write: write failed");
598                                 status = errno_to_portable(errno);
599                         } else if ((size_t)ret == len) {
600                                 status = SSH2_FX_OK;
601                                 handle_update_write(handle, ret);
602                         } else {
603                                 debug2("nothing at all written");
604                         }
605                 }
606         }
607         send_status(id, status);
608         xfree(data);
609 }
610
611 static void
612 process_do_stat(int do_lstat)
613 {
614         Attrib a;
615         struct stat st;
616         u_int32_t id;
617         char *name;
618         int ret, status = SSH2_FX_FAILURE;
619
620         id = get_int();
621         name = get_string(NULL);
622         debug3("request %u: %sstat", id, do_lstat ? "l" : "");
623         verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
624         ret = do_lstat ? lstat(name, &st) : stat(name, &st);
625         if (ret < 0) {
626                 status = errno_to_portable(errno);
627         } else {
628                 stat_to_attrib(&st, &a);
629                 send_attrib(id, &a);
630                 status = SSH2_FX_OK;
631         }
632         if (status != SSH2_FX_OK)
633                 send_status(id, status);
634         xfree(name);
635 }
636
637 static void
638 process_stat(void)
639 {
640         process_do_stat(0);
641 }
642
643 static void
644 process_lstat(void)
645 {
646         process_do_stat(1);
647 }
648
649 static void
650 process_fstat(void)
651 {
652         Attrib a;
653         struct stat st;
654         u_int32_t id;
655         int fd, ret, handle, status = SSH2_FX_FAILURE;
656
657         id = get_int();
658         handle = get_handle();
659         debug("request %u: fstat \"%s\" (handle %u)",
660             id, handle_to_name(handle), handle);
661         fd = handle_to_fd(handle);
662         if (fd  >= 0) {
663                 ret = fstat(fd, &st);
664                 if (ret < 0) {
665                         status = errno_to_portable(errno);
666                 } else {
667                         stat_to_attrib(&st, &a);
668                         send_attrib(id, &a);
669                         status = SSH2_FX_OK;
670                 }
671         }
672         if (status != SSH2_FX_OK)
673                 send_status(id, status);
674 }
675
676 static struct timeval *
677 attrib_to_tv(const Attrib *a)
678 {
679         static struct timeval tv[2];
680
681         tv[0].tv_sec = a->atime;
682         tv[0].tv_usec = 0;
683         tv[1].tv_sec = a->mtime;
684         tv[1].tv_usec = 0;
685         return tv;
686 }
687
688 static void
689 process_setstat(void)
690 {
691         Attrib *a;
692         u_int32_t id;
693         char *name;
694         int status = SSH2_FX_OK, ret;
695
696         id = get_int();
697         name = get_string(NULL);
698         a = get_attrib();
699         debug("request %u: setstat name \"%s\"", id, name);
700         if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
701                 logit("set \"%s\" size %llu", name, a->size);
702                 ret = truncate(name, a->size);
703                 if (ret == -1)
704                         status = errno_to_portable(errno);
705         }
706         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
707                 logit("set \"%s\" mode %04o", name, a->perm);
708                 ret = chmod(name, a->perm & 0777);
709                 if (ret == -1)
710                         status = errno_to_portable(errno);
711         }
712         if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
713                 char buf[64];
714                 time_t t = a->mtime;
715
716                 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
717                     localtime(&t));
718                 logit("set \"%s\" modtime %s", name, buf);
719                 ret = utimes(name, attrib_to_tv(a));
720                 if (ret == -1)
721                         status = errno_to_portable(errno);
722         }
723         if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
724                 logit("set \"%s\" owner %lu group %lu", name,
725                     (u_long)a->uid, (u_long)a->gid);
726                 ret = chown(name, a->uid, a->gid);
727                 if (ret == -1)
728                         status = errno_to_portable(errno);
729         }
730         send_status(id, status);
731         xfree(name);
732 }
733
734 static void
735 process_fsetstat(void)
736 {
737         Attrib *a;
738         u_int32_t id;
739         int handle, fd, ret;
740         int status = SSH2_FX_OK;
741
742         id = get_int();
743         handle = get_handle();
744         a = get_attrib();
745         debug("request %u: fsetstat handle %d", id, handle);
746         fd = handle_to_fd(handle);
747         if (fd < 0) {
748                 status = SSH2_FX_FAILURE;
749         } else {
750                 char *name = handle_to_name(handle);
751
752                 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
753                         logit("set \"%s\" size %llu", name, a->size);
754                         ret = ftruncate(fd, a->size);
755                         if (ret == -1)
756                                 status = errno_to_portable(errno);
757                 }
758                 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
759                         logit("set \"%s\" mode %04o", name, a->perm);
760 #ifdef HAVE_FCHMOD
761                         ret = fchmod(fd, a->perm & 0777);
762 #else
763                         ret = chmod(name, a->perm & 0777);
764 #endif
765                         if (ret == -1)
766                                 status = errno_to_portable(errno);
767                 }
768                 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
769                         char buf[64];
770                         time_t t = a->mtime;
771
772                         strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
773                             localtime(&t));
774                         logit("set \"%s\" modtime %s", name, buf);
775 #ifdef HAVE_FUTIMES
776                         ret = futimes(fd, attrib_to_tv(a));
777 #else
778                         ret = utimes(name, attrib_to_tv(a));
779 #endif
780                         if (ret == -1)
781                                 status = errno_to_portable(errno);
782                 }
783                 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
784                         logit("set \"%s\" owner %lu group %lu", name,
785                             (u_long)a->uid, (u_long)a->gid);
786 #ifdef HAVE_FCHOWN
787                         ret = fchown(fd, a->uid, a->gid);
788 #else
789                         ret = chown(name, a->uid, a->gid);
790 #endif
791                         if (ret == -1)
792                                 status = errno_to_portable(errno);
793                 }
794         }
795         send_status(id, status);
796 }
797
798 static void
799 process_opendir(void)
800 {
801         DIR *dirp = NULL;
802         char *path;
803         int handle, status = SSH2_FX_FAILURE;
804         u_int32_t id;
805
806         id = get_int();
807         path = get_string(NULL);
808         debug3("request %u: opendir", id);
809         logit("opendir \"%s\"", path);
810         dirp = opendir(path);
811         if (dirp == NULL) {
812                 status = errno_to_portable(errno);
813         } else {
814                 handle = handle_new(HANDLE_DIR, path, 0, dirp);
815                 if (handle < 0) {
816                         closedir(dirp);
817                 } else {
818                         send_handle(id, handle);
819                         status = SSH2_FX_OK;
820                 }
821
822         }
823         if (status != SSH2_FX_OK)
824                 send_status(id, status);
825         xfree(path);
826 }
827
828 static void
829 process_readdir(void)
830 {
831         DIR *dirp;
832         struct dirent *dp;
833         char *path;
834         int handle;
835         u_int32_t id;
836
837         id = get_int();
838         handle = get_handle();
839         debug("request %u: readdir \"%s\" (handle %d)", id,
840             handle_to_name(handle), handle);
841         dirp = handle_to_dir(handle);
842         path = handle_to_name(handle);
843         if (dirp == NULL || path == NULL) {
844                 send_status(id, SSH2_FX_FAILURE);
845         } else {
846                 struct stat st;
847                 char pathname[MAXPATHLEN];
848                 Stat *stats;
849                 int nstats = 10, count = 0, i;
850
851                 stats = xcalloc(nstats, sizeof(Stat));
852                 while ((dp = readdir(dirp)) != NULL) {
853                         if (count >= nstats) {
854                                 nstats *= 2;
855                                 stats = xrealloc(stats, nstats, sizeof(Stat));
856                         }
857 /* XXX OVERFLOW ? */
858                         snprintf(pathname, sizeof pathname, "%s%s%s", path,
859                             strcmp(path, "/") ? "/" : "", dp->d_name);
860                         if (lstat(pathname, &st) < 0)
861                                 continue;
862                         stat_to_attrib(&st, &(stats[count].attrib));
863                         stats[count].name = xstrdup(dp->d_name);
864                         stats[count].long_name = ls_file(dp->d_name, &st, 0);
865                         count++;
866                         /* send up to 100 entries in one message */
867                         /* XXX check packet size instead */
868                         if (count == 100)
869                                 break;
870                 }
871                 if (count > 0) {
872                         send_names(id, count, stats);
873                         for (i = 0; i < count; i++) {
874                                 xfree(stats[i].name);
875                                 xfree(stats[i].long_name);
876                         }
877                 } else {
878                         send_status(id, SSH2_FX_EOF);
879                 }
880                 xfree(stats);
881         }
882 }
883
884 static void
885 process_remove(void)
886 {
887         char *name;
888         u_int32_t id;
889         int status = SSH2_FX_FAILURE;
890         int ret;
891
892         id = get_int();
893         name = get_string(NULL);
894         debug3("request %u: remove", id);
895         logit("remove name \"%s\"", name);
896         ret = unlink(name);
897         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
898         send_status(id, status);
899         xfree(name);
900 }
901
902 static void
903 process_mkdir(void)
904 {
905         Attrib *a;
906         u_int32_t id;
907         char *name;
908         int ret, mode, status = SSH2_FX_FAILURE;
909
910         id = get_int();
911         name = get_string(NULL);
912         a = get_attrib();
913         mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
914             a->perm & 0777 : 0777;
915         debug3("request %u: mkdir", id);
916         logit("mkdir name \"%s\" mode 0%o", name, mode);
917         ret = mkdir(name, mode);
918         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
919         send_status(id, status);
920         xfree(name);
921 }
922
923 static void
924 process_rmdir(void)
925 {
926         u_int32_t id;
927         char *name;
928         int ret, status;
929
930         id = get_int();
931         name = get_string(NULL);
932         debug3("request %u: rmdir", id);
933         logit("rmdir name \"%s\"", name);
934         ret = rmdir(name);
935         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
936         send_status(id, status);
937         xfree(name);
938 }
939
940 static void
941 process_realpath(void)
942 {
943         char resolvedname[MAXPATHLEN];
944         u_int32_t id;
945         char *path;
946
947         id = get_int();
948         path = get_string(NULL);
949         if (path[0] == '\0') {
950                 xfree(path);
951                 path = xstrdup(".");
952         }
953         debug3("request %u: realpath", id);
954         verbose("realpath \"%s\"", path);
955         if (realpath(path, resolvedname) == NULL) {
956                 send_status(id, errno_to_portable(errno));
957         } else {
958                 Stat s;
959                 attrib_clear(&s.attrib);
960                 s.name = s.long_name = resolvedname;
961                 send_names(id, 1, &s);
962         }
963         xfree(path);
964 }
965
966 static void
967 process_rename(void)
968 {
969         u_int32_t id;
970         char *oldpath, *newpath;
971         int status;
972         struct stat sb;
973
974         id = get_int();
975         oldpath = get_string(NULL);
976         newpath = get_string(NULL);
977         debug3("request %u: rename", id);
978         logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
979         status = SSH2_FX_FAILURE;
980         if (lstat(oldpath, &sb) == -1)
981                 status = errno_to_portable(errno);
982         else if (S_ISREG(sb.st_mode)) {
983                 /* Race-free rename of regular files */
984                 if (link(oldpath, newpath) == -1) {
985                         if (errno == EOPNOTSUPP
986 #ifdef LINK_OPNOTSUPP_ERRNO
987                             || errno == LINK_OPNOTSUPP_ERRNO
988 #endif
989                             ) {
990                                 struct stat st;
991
992                                 /*
993                                  * fs doesn't support links, so fall back to
994                                  * stat+rename.  This is racy.
995                                  */
996                                 if (stat(newpath, &st) == -1) {
997                                         if (rename(oldpath, newpath) == -1)
998                                                 status =
999                                                     errno_to_portable(errno);
1000                                         else
1001                                                 status = SSH2_FX_OK;
1002                                 }
1003                         } else {
1004                                 status = errno_to_portable(errno);
1005                         }
1006                 } else if (unlink(oldpath) == -1) {
1007                         status = errno_to_portable(errno);
1008                         /* clean spare link */
1009                         unlink(newpath);
1010                 } else
1011                         status = SSH2_FX_OK;
1012         } else if (stat(newpath, &sb) == -1) {
1013                 if (rename(oldpath, newpath) == -1)
1014                         status = errno_to_portable(errno);
1015                 else
1016                         status = SSH2_FX_OK;
1017         }
1018         send_status(id, status);
1019         xfree(oldpath);
1020         xfree(newpath);
1021 }
1022
1023 static void
1024 process_readlink(void)
1025 {
1026         u_int32_t id;
1027         int len;
1028         char buf[MAXPATHLEN];
1029         char *path;
1030
1031         id = get_int();
1032         path = get_string(NULL);
1033         debug3("request %u: readlink", id);
1034         verbose("readlink \"%s\"", path);
1035         if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
1036                 send_status(id, errno_to_portable(errno));
1037         else {
1038                 Stat s;
1039
1040                 buf[len] = '\0';
1041                 attrib_clear(&s.attrib);
1042                 s.name = s.long_name = buf;
1043                 send_names(id, 1, &s);
1044         }
1045         xfree(path);
1046 }
1047
1048 static void
1049 process_symlink(void)
1050 {
1051         u_int32_t id;
1052         char *oldpath, *newpath;
1053         int ret, status;
1054
1055         id = get_int();
1056         oldpath = get_string(NULL);
1057         newpath = get_string(NULL);
1058         debug3("request %u: symlink", id);
1059         logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
1060         /* this will fail if 'newpath' exists */
1061         ret = symlink(oldpath, newpath);
1062         status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1063         send_status(id, status);
1064         xfree(oldpath);
1065         xfree(newpath);
1066 }
1067
1068 static void
1069 process_extended(void)
1070 {
1071         u_int32_t id;
1072         char *request;
1073
1074         id = get_int();
1075         request = get_string(NULL);
1076         send_status(id, SSH2_FX_OP_UNSUPPORTED);                /* MUST */
1077         xfree(request);
1078 }
1079
1080 /* stolen from ssh-agent */
1081
1082 static void
1083 process(void)
1084 {
1085         u_int msg_len;
1086         u_int buf_len;
1087         u_int consumed;
1088         u_int type;
1089         u_char *cp;
1090
1091         buf_len = buffer_len(&iqueue);
1092         if (buf_len < 5)
1093                 return;         /* Incomplete message. */
1094         cp = buffer_ptr(&iqueue);
1095         msg_len = get_u32(cp);
1096         if (msg_len > SFTP_MAX_MSG_LENGTH) {
1097                 error("bad message from %s local user %s",
1098                     client_addr, pw->pw_name);
1099                 cleanup_exit(11);
1100         }
1101         if (buf_len < msg_len + 4)
1102                 return;
1103         buffer_consume(&iqueue, 4);
1104         buf_len -= 4;
1105         type = buffer_get_char(&iqueue);
1106         switch (type) {
1107         case SSH2_FXP_INIT:
1108                 process_init();
1109                 break;
1110         case SSH2_FXP_OPEN:
1111                 process_open();
1112                 break;
1113         case SSH2_FXP_CLOSE:
1114                 process_close();
1115                 break;
1116         case SSH2_FXP_READ:
1117                 process_read();
1118                 break;
1119         case SSH2_FXP_WRITE:
1120                 process_write();
1121                 break;
1122         case SSH2_FXP_LSTAT:
1123                 process_lstat();
1124                 break;
1125         case SSH2_FXP_FSTAT:
1126                 process_fstat();
1127                 break;
1128         case SSH2_FXP_SETSTAT:
1129                 process_setstat();
1130                 break;
1131         case SSH2_FXP_FSETSTAT:
1132                 process_fsetstat();
1133                 break;
1134         case SSH2_FXP_OPENDIR:
1135                 process_opendir();
1136                 break;
1137         case SSH2_FXP_READDIR:
1138                 process_readdir();
1139                 break;
1140         case SSH2_FXP_REMOVE:
1141                 process_remove();
1142                 break;
1143         case SSH2_FXP_MKDIR:
1144                 process_mkdir();
1145                 break;
1146         case SSH2_FXP_RMDIR:
1147                 process_rmdir();
1148                 break;
1149         case SSH2_FXP_REALPATH:
1150                 process_realpath();
1151                 break;
1152         case SSH2_FXP_STAT:
1153                 process_stat();
1154                 break;
1155         case SSH2_FXP_RENAME:
1156                 process_rename();
1157                 break;
1158         case SSH2_FXP_READLINK:
1159                 process_readlink();
1160                 break;
1161         case SSH2_FXP_SYMLINK:
1162                 process_symlink();
1163                 break;
1164         case SSH2_FXP_EXTENDED:
1165                 process_extended();
1166                 break;
1167         default:
1168                 error("Unknown message %d", type);
1169                 break;
1170         }
1171         /* discard the remaining bytes from the current packet */
1172         if (buf_len < buffer_len(&iqueue))
1173                 fatal("iqueue grew unexpectedly");
1174         consumed = buf_len - buffer_len(&iqueue);
1175         if (msg_len < consumed)
1176                 fatal("msg_len %d < consumed %d", msg_len, consumed);
1177         if (msg_len > consumed)
1178                 buffer_consume(&iqueue, msg_len - consumed);
1179 }
1180
1181 /* Cleanup handler that logs active handles upon normal exit */
1182 void
1183 cleanup_exit(int i)
1184 {
1185         if (pw != NULL && client_addr != NULL) {
1186                 handle_log_exit();
1187                 logit("session closed for local user %s from [%s]",
1188                     pw->pw_name, client_addr);
1189         }
1190         _exit(i);
1191 }
1192
1193 static void
1194 usage(void)
1195 {
1196         extern char *__progname;
1197
1198         fprintf(stderr,
1199             "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1200         exit(1);
1201 }
1202
1203 int
1204 main(int argc, char **argv)
1205 {
1206         fd_set *rset, *wset;
1207         int in, out, max, ch, skipargs = 0, log_stderr = 0;
1208         ssize_t len, olen, set_size;
1209         SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1210         char *cp;
1211
1212         extern char *optarg;
1213         extern char *__progname;
1214
1215         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1216         sanitise_stdfd();
1217
1218         __progname = ssh_get_progname(argv[0]);
1219         log_init(__progname, log_level, log_facility, log_stderr);
1220
1221         while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1222                 switch (ch) {
1223                 case 'c':
1224                         /*
1225                          * Ignore all arguments if we are invoked as a
1226                          * shell using "sftp-server -c command" 
1227                          */
1228                         skipargs = 1;
1229                         break;
1230                 case 'e':
1231                         log_stderr = 1;
1232                         break;
1233                 case 'l':
1234                         log_level = log_level_number(optarg);
1235                         if (log_level == SYSLOG_LEVEL_NOT_SET)
1236                                 error("Invalid log level \"%s\"", optarg);
1237                         break;
1238                 case 'f':
1239                         log_facility = log_facility_number(optarg);
1240                         if (log_level == SYSLOG_FACILITY_NOT_SET)
1241                                 error("Invalid log facility \"%s\"", optarg);
1242                         break;
1243                 case 'h':
1244                 default:
1245                         usage();
1246                 }
1247         }
1248
1249         log_init(__progname, log_level, log_facility, log_stderr);
1250
1251         if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1252                 client_addr = xstrdup(cp);
1253                 if ((cp = strchr(client_addr, ' ')) == NULL)
1254                         fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1255                             getenv("SSH_CONNECTION"));
1256                 *cp = '\0';
1257         } else
1258                 client_addr = xstrdup("UNKNOWN");
1259
1260         if ((pw = getpwuid(getuid())) == NULL)
1261                 fatal("No user found for uid %lu", (u_long)getuid());
1262         pw = pwcopy(pw);
1263
1264         logit("session opened for local user %s from [%s]",
1265             pw->pw_name, client_addr);
1266
1267         handle_init();
1268
1269         in = dup(STDIN_FILENO);
1270         out = dup(STDOUT_FILENO);
1271
1272 #ifdef HAVE_CYGWIN
1273         setmode(in, O_BINARY);
1274         setmode(out, O_BINARY);
1275 #endif
1276
1277         max = 0;
1278         if (in > max)
1279                 max = in;
1280         if (out > max)
1281                 max = out;
1282
1283         buffer_init(&iqueue);
1284         buffer_init(&oqueue);
1285
1286         set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
1287         rset = (fd_set *)xmalloc(set_size);
1288         wset = (fd_set *)xmalloc(set_size);
1289
1290         for (;;) {
1291                 memset(rset, 0, set_size);
1292                 memset(wset, 0, set_size);
1293
1294                 FD_SET(in, rset);
1295                 olen = buffer_len(&oqueue);
1296                 if (olen > 0)
1297                         FD_SET(out, wset);
1298
1299                 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1300                         if (errno == EINTR)
1301                                 continue;
1302                         error("select: %s", strerror(errno));
1303                         cleanup_exit(2);
1304                 }
1305
1306                 /* copy stdin to iqueue */
1307                 if (FD_ISSET(in, rset)) {
1308                         char buf[4*4096];
1309                         len = read(in, buf, sizeof buf);
1310                         if (len == 0) {
1311                                 debug("read eof");
1312                                 cleanup_exit(0);
1313                         } else if (len < 0) {
1314                                 error("read: %s", strerror(errno));
1315                                 cleanup_exit(1);
1316                         } else {
1317                                 buffer_append(&iqueue, buf, len);
1318                         }
1319                 }
1320                 /* send oqueue to stdout */
1321                 if (FD_ISSET(out, wset)) {
1322                         len = write(out, buffer_ptr(&oqueue), olen);
1323                         if (len < 0) {
1324                                 error("write: %s", strerror(errno));
1325                                 cleanup_exit(1);
1326                         } else {
1327                                 buffer_consume(&oqueue, len);
1328                         }
1329                 }
1330                 /* process requests from client */
1331                 process();
1332         }
1333 }
This page took 0.194387 seconds and 3 git commands to generate.