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