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