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