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