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