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