summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c352
1 files changed, 287 insertions, 65 deletions
diff --git a/sftp-server.c b/sftp-server.c
index 7060c44ad..64777beff 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,3 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.71 2007/01/03 07:22:36 stevesk Exp $ */
1/* 2/*
2 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
3 * 4 *
@@ -13,15 +14,33 @@
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 16 */
17
16#include "includes.h" 18#include "includes.h"
17RCSID("$OpenBSD: sftp-server.c,v 1.50 2006/01/02 01:20:31 djm Exp $");
18 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"
19#include "buffer.h" 40#include "buffer.h"
20#include "bufaux.h"
21#include "getput.h"
22#include "log.h" 41#include "log.h"
23#include "xmalloc.h"
24#include "misc.h" 42#include "misc.h"
43#include "uidswap.h"
25 44
26#include "sftp.h" 45#include "sftp.h"
27#include "sftp-common.h" 46#include "sftp-common.h"
@@ -30,9 +49,13 @@ RCSID("$OpenBSD: sftp-server.c,v 1.50 2006/01/02 01:20:31 djm Exp $");
30#define get_int64() buffer_get_int64(&iqueue); 49#define get_int64() buffer_get_int64(&iqueue);
31#define get_int() buffer_get_int(&iqueue); 50#define get_int() buffer_get_int(&iqueue);
32#define get_string(lenp) buffer_get_string(&iqueue, lenp); 51#define get_string(lenp) buffer_get_string(&iqueue, lenp);
33#define TRACE debug
34 52
35extern char *__progname; 53/* Our verbosity */
54LogLevel log_level = SYSLOG_LEVEL_ERROR;
55
56/* Our client */
57struct passwd *pw = NULL;
58char *client_addr = NULL;
36 59
37/* input and output queue */ 60/* input and output queue */
38Buffer iqueue; 61Buffer iqueue;
@@ -104,6 +127,33 @@ flags_from_portable(int pflags)
104 return flags; 127 return flags;
105} 128}
106 129
130static const char *
131string_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
107static Attrib * 157static Attrib *
108get_attrib(void) 158get_attrib(void)
109{ 159{
@@ -118,6 +168,7 @@ struct Handle {
118 DIR *dirp; 168 DIR *dirp;
119 int fd; 169 int fd;
120 char *name; 170 char *name;
171 u_int64_t bytes_read, bytes_write;
121}; 172};
122 173
123enum { 174enum {
@@ -148,6 +199,7 @@ handle_new(int use, const char *name, int fd, DIR *dirp)
148 handles[i].dirp = dirp; 199 handles[i].dirp = dirp;
149 handles[i].fd = fd; 200 handles[i].fd = fd;
150 handles[i].name = xstrdup(name); 201 handles[i].name = xstrdup(name);
202 handles[i].bytes_read = handles[i].bytes_write = 0;
151 return i; 203 return i;
152 } 204 }
153 } 205 }
@@ -167,7 +219,7 @@ handle_to_string(int handle, char **stringp, int *hlenp)
167 if (stringp == NULL || hlenp == NULL) 219 if (stringp == NULL || hlenp == NULL)
168 return -1; 220 return -1;
169 *stringp = xmalloc(sizeof(int32_t)); 221 *stringp = xmalloc(sizeof(int32_t));
170 PUT_32BIT(*stringp, handle); 222 put_u32(*stringp, handle);
171 *hlenp = sizeof(int32_t); 223 *hlenp = sizeof(int32_t);
172 return 0; 224 return 0;
173} 225}
@@ -179,7 +231,7 @@ handle_from_string(const char *handle, u_int hlen)
179 231
180 if (hlen != sizeof(int32_t)) 232 if (hlen != sizeof(int32_t))
181 return -1; 233 return -1;
182 val = GET_32BIT(handle); 234 val = get_u32(handle);
183 if (handle_is_ok(val, HANDLE_FILE) || 235 if (handle_is_ok(val, HANDLE_FILE) ||
184 handle_is_ok(val, HANDLE_DIR)) 236 handle_is_ok(val, HANDLE_DIR))
185 return val; 237 return val;
@@ -211,6 +263,36 @@ handle_to_fd(int handle)
211 return -1; 263 return -1;
212} 264}
213 265
266static void
267handle_update_read(int handle, ssize_t bytes)
268{
269 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
270 handles[handle].bytes_read += bytes;
271}
272
273static void
274handle_update_write(int handle, ssize_t bytes)
275{
276 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
277 handles[handle].bytes_write += bytes;
278}
279
280static u_int64_t
281handle_bytes_read(int handle)
282{
283 if (handle_is_ok(handle, HANDLE_FILE))
284 return (handles[handle].bytes_read);
285 return 0;
286}
287
288static u_int64_t
289handle_bytes_write(int handle)
290{
291 if (handle_is_ok(handle, HANDLE_FILE))
292 return (handles[handle].bytes_write);
293 return 0;
294}
295
214static int 296static int
215handle_close(int handle) 297handle_close(int handle)
216{ 298{
@@ -230,6 +312,31 @@ handle_close(int handle)
230 return ret; 312 return ret;
231} 313}
232 314
315static void
316handle_log_close(int handle, char *emsg)
317{
318 if (handle_is_ok(handle, HANDLE_FILE)) {
319 logit("%s%sclose \"%s\" bytes read %llu written %llu",
320 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
321 handle_to_name(handle),
322 handle_bytes_read(handle), handle_bytes_write(handle));
323 } else {
324 logit("%s%sclosedir \"%s\"",
325 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
326 handle_to_name(handle));
327 }
328}
329
330static void
331handle_log_exit(void)
332{
333 u_int i;
334
335 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
336 if (handles[i].use != HANDLE_UNUSED)
337 handle_log_close(i, "forced");
338}
339
233static int 340static int
234get_handle(void) 341get_handle(void)
235{ 342{
@@ -256,10 +363,9 @@ send_msg(Buffer *m)
256 buffer_consume(m, mlen); 363 buffer_consume(m, mlen);
257} 364}
258 365
259static void 366static const char *
260send_status(u_int32_t id, u_int32_t status) 367status_to_message(u_int32_t status)
261{ 368{
262 Buffer msg;
263 const char *status_messages[] = { 369 const char *status_messages[] = {
264 "Success", /* SSH_FX_OK */ 370 "Success", /* SSH_FX_OK */
265 "End of file", /* SSH_FX_EOF */ 371 "End of file", /* SSH_FX_EOF */
@@ -272,15 +378,24 @@ send_status(u_int32_t id, u_int32_t status)
272 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ 378 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
273 "Unknown error" /* Others */ 379 "Unknown error" /* Others */
274 }; 380 };
381 return (status_messages[MIN(status,SSH2_FX_MAX)]);
382}
383
384static void
385send_status(u_int32_t id, u_int32_t status)
386{
387 Buffer msg;
275 388
276 TRACE("sent status id %u error %u", id, status); 389 debug3("request %u: sent status %u", id, status);
390 if (log_level > SYSLOG_LEVEL_VERBOSE ||
391 (status != SSH2_FX_OK && status != SSH2_FX_EOF))
392 logit("sent status %s", status_to_message(status));
277 buffer_init(&msg); 393 buffer_init(&msg);
278 buffer_put_char(&msg, SSH2_FXP_STATUS); 394 buffer_put_char(&msg, SSH2_FXP_STATUS);
279 buffer_put_int(&msg, id); 395 buffer_put_int(&msg, id);
280 buffer_put_int(&msg, status); 396 buffer_put_int(&msg, status);
281 if (version >= 3) { 397 if (version >= 3) {
282 buffer_put_cstring(&msg, 398 buffer_put_cstring(&msg, status_to_message(status));
283 status_messages[MIN(status,SSH2_FX_MAX)]);
284 buffer_put_cstring(&msg, ""); 399 buffer_put_cstring(&msg, "");
285 } 400 }
286 send_msg(&msg); 401 send_msg(&msg);
@@ -302,7 +417,7 @@ send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
302static void 417static void
303send_data(u_int32_t id, const char *data, int dlen) 418send_data(u_int32_t id, const char *data, int dlen)
304{ 419{
305 TRACE("sent data id %u len %d", id, dlen); 420 debug("request %u: sent data len %d", id, dlen);
306 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); 421 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
307} 422}
308 423
@@ -313,7 +428,7 @@ send_handle(u_int32_t id, int handle)
313 int hlen; 428 int hlen;
314 429
315 handle_to_string(handle, &string, &hlen); 430 handle_to_string(handle, &string, &hlen);
316 TRACE("sent handle id %u handle %d", id, handle); 431 debug("request %u: sent handle handle %d", id, handle);
317 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); 432 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
318 xfree(string); 433 xfree(string);
319} 434}
@@ -328,7 +443,7 @@ send_names(u_int32_t id, int count, const Stat *stats)
328 buffer_put_char(&msg, SSH2_FXP_NAME); 443 buffer_put_char(&msg, SSH2_FXP_NAME);
329 buffer_put_int(&msg, id); 444 buffer_put_int(&msg, id);
330 buffer_put_int(&msg, count); 445 buffer_put_int(&msg, count);
331 TRACE("sent names id %u count %d", id, count); 446 debug("request %u: sent names count %d", id, count);
332 for (i = 0; i < count; i++) { 447 for (i = 0; i < count; i++) {
333 buffer_put_cstring(&msg, stats[i].name); 448 buffer_put_cstring(&msg, stats[i].name);
334 buffer_put_cstring(&msg, stats[i].long_name); 449 buffer_put_cstring(&msg, stats[i].long_name);
@@ -343,7 +458,7 @@ send_attrib(u_int32_t id, const Attrib *a)
343{ 458{
344 Buffer msg; 459 Buffer msg;
345 460
346 TRACE("sent attrib id %u have 0x%x", id, a->flags); 461 debug("request %u: sent attrib have 0x%x", id, a->flags);
347 buffer_init(&msg); 462 buffer_init(&msg);
348 buffer_put_char(&msg, SSH2_FXP_ATTRS); 463 buffer_put_char(&msg, SSH2_FXP_ATTRS);
349 buffer_put_int(&msg, id); 464 buffer_put_int(&msg, id);
@@ -360,7 +475,7 @@ process_init(void)
360 Buffer msg; 475 Buffer msg;
361 476
362 version = get_int(); 477 version = get_int();
363 TRACE("client version %d", version); 478 verbose("received client version %d", version);
364 buffer_init(&msg); 479 buffer_init(&msg);
365 buffer_put_char(&msg, SSH2_FXP_VERSION); 480 buffer_put_char(&msg, SSH2_FXP_VERSION);
366 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 481 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
@@ -379,10 +494,12 @@ process_open(void)
379 id = get_int(); 494 id = get_int();
380 name = get_string(NULL); 495 name = get_string(NULL);
381 pflags = get_int(); /* portable flags */ 496 pflags = get_int(); /* portable flags */
497 debug3("request %u: open flags %d", id, pflags);
382 a = get_attrib(); 498 a = get_attrib();
383 flags = flags_from_portable(pflags); 499 flags = flags_from_portable(pflags);
384 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; 500 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
385 TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); 501 logit("open \"%s\" flags %s mode 0%o",
502 name, string_from_portable(pflags), mode);
386 fd = open(name, flags, mode); 503 fd = open(name, flags, mode);
387 if (fd < 0) { 504 if (fd < 0) {
388 status = errno_to_portable(errno); 505 status = errno_to_portable(errno);
@@ -408,7 +525,8 @@ process_close(void)
408 525
409 id = get_int(); 526 id = get_int();
410 handle = get_handle(); 527 handle = get_handle();
411 TRACE("close id %u handle %d", id, handle); 528 debug3("request %u: close handle %u", id, handle);
529 handle_log_close(handle, NULL);
412 ret = handle_close(handle); 530 ret = handle_close(handle);
413 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 531 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
414 send_status(id, status); 532 send_status(id, status);
@@ -427,11 +545,11 @@ process_read(void)
427 off = get_int64(); 545 off = get_int64();
428 len = get_int(); 546 len = get_int();
429 547
430 TRACE("read id %u handle %d off %llu len %d", id, handle, 548 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
431 (unsigned long long)off, len); 549 id, handle_to_name(handle), handle, (unsigned long long)off, len);
432 if (len > sizeof buf) { 550 if (len > sizeof buf) {
433 len = sizeof buf; 551 len = sizeof buf;
434 logit("read change len %d", len); 552 debug2("read change len %d", len);
435 } 553 }
436 fd = handle_to_fd(handle); 554 fd = handle_to_fd(handle);
437 if (fd >= 0) { 555 if (fd >= 0) {
@@ -447,6 +565,7 @@ process_read(void)
447 } else { 565 } else {
448 send_data(id, buf, ret); 566 send_data(id, buf, ret);
449 status = SSH2_FX_OK; 567 status = SSH2_FX_OK;
568 handle_update_read(handle, ret);
450 } 569 }
451 } 570 }
452 } 571 }
@@ -468,8 +587,8 @@ process_write(void)
468 off = get_int64(); 587 off = get_int64();
469 data = get_string(&len); 588 data = get_string(&len);
470 589
471 TRACE("write id %u handle %d off %llu len %d", id, handle, 590 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
472 (unsigned long long)off, len); 591 id, handle_to_name(handle), handle, (unsigned long long)off, len);
473 fd = handle_to_fd(handle); 592 fd = handle_to_fd(handle);
474 if (fd >= 0) { 593 if (fd >= 0) {
475 if (lseek(fd, off, SEEK_SET) < 0) { 594 if (lseek(fd, off, SEEK_SET) < 0) {
@@ -483,8 +602,9 @@ process_write(void)
483 status = errno_to_portable(errno); 602 status = errno_to_portable(errno);
484 } else if ((size_t)ret == len) { 603 } else if ((size_t)ret == len) {
485 status = SSH2_FX_OK; 604 status = SSH2_FX_OK;
605 handle_update_write(handle, ret);
486 } else { 606 } else {
487 logit("nothing at all written"); 607 debug2("nothing at all written");
488 } 608 }
489 } 609 }
490 } 610 }
@@ -503,7 +623,8 @@ process_do_stat(int do_lstat)
503 623
504 id = get_int(); 624 id = get_int();
505 name = get_string(NULL); 625 name = get_string(NULL);
506 TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); 626 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
627 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
507 ret = do_lstat ? lstat(name, &st) : stat(name, &st); 628 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
508 if (ret < 0) { 629 if (ret < 0) {
509 status = errno_to_portable(errno); 630 status = errno_to_portable(errno);
@@ -539,9 +660,10 @@ process_fstat(void)
539 660
540 id = get_int(); 661 id = get_int();
541 handle = get_handle(); 662 handle = get_handle();
542 TRACE("fstat id %u handle %d", id, handle); 663 debug("request %u: fstat \"%s\" (handle %u)",
664 id, handle_to_name(handle), handle);
543 fd = handle_to_fd(handle); 665 fd = handle_to_fd(handle);
544 if (fd >= 0) { 666 if (fd >= 0) {
545 ret = fstat(fd, &st); 667 ret = fstat(fd, &st);
546 if (ret < 0) { 668 if (ret < 0) {
547 status = errno_to_portable(errno); 669 status = errno_to_portable(errno);
@@ -578,23 +700,33 @@ process_setstat(void)
578 id = get_int(); 700 id = get_int();
579 name = get_string(NULL); 701 name = get_string(NULL);
580 a = get_attrib(); 702 a = get_attrib();
581 TRACE("setstat id %u name %s", id, name); 703 debug("request %u: setstat name \"%s\"", id, name);
582 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 704 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
705 logit("set \"%s\" size %llu", name, a->size);
583 ret = truncate(name, a->size); 706 ret = truncate(name, a->size);
584 if (ret == -1) 707 if (ret == -1)
585 status = errno_to_portable(errno); 708 status = errno_to_portable(errno);
586 } 709 }
587 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 710 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
711 logit("set \"%s\" mode %04o", name, a->perm);
588 ret = chmod(name, a->perm & 0777); 712 ret = chmod(name, a->perm & 0777);
589 if (ret == -1) 713 if (ret == -1)
590 status = errno_to_portable(errno); 714 status = errno_to_portable(errno);
591 } 715 }
592 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 716 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
717 char buf[64];
718 time_t t = a->mtime;
719
720 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
721 localtime(&t));
722 logit("set \"%s\" modtime %s", name, buf);
593 ret = utimes(name, attrib_to_tv(a)); 723 ret = utimes(name, attrib_to_tv(a));
594 if (ret == -1) 724 if (ret == -1)
595 status = errno_to_portable(errno); 725 status = errno_to_portable(errno);
596 } 726 }
597 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 727 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
728 logit("set \"%s\" owner %lu group %lu", name,
729 (u_long)a->uid, (u_long)a->gid);
598 ret = chown(name, a->uid, a->gid); 730 ret = chown(name, a->uid, a->gid);
599 if (ret == -1) 731 if (ret == -1)
600 status = errno_to_portable(errno); 732 status = errno_to_portable(errno);
@@ -610,23 +742,25 @@ process_fsetstat(void)
610 u_int32_t id; 742 u_int32_t id;
611 int handle, fd, ret; 743 int handle, fd, ret;
612 int status = SSH2_FX_OK; 744 int status = SSH2_FX_OK;
613 char *name;
614 745
615 id = get_int(); 746 id = get_int();
616 handle = get_handle(); 747 handle = get_handle();
617 a = get_attrib(); 748 a = get_attrib();
618 TRACE("fsetstat id %u handle %d", id, handle); 749 debug("request %u: fsetstat handle %d", id, handle);
619 fd = handle_to_fd(handle); 750 fd = handle_to_fd(handle);
620 name = handle_to_name(handle); 751 if (fd < 0) {
621 if (fd < 0 || name == NULL) {
622 status = SSH2_FX_FAILURE; 752 status = SSH2_FX_FAILURE;
623 } else { 753 } else {
754 char *name = handle_to_name(handle);
755
624 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 756 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
757 logit("set \"%s\" size %llu", name, a->size);
625 ret = ftruncate(fd, a->size); 758 ret = ftruncate(fd, a->size);
626 if (ret == -1) 759 if (ret == -1)
627 status = errno_to_portable(errno); 760 status = errno_to_portable(errno);
628 } 761 }
629 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 762 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
763 logit("set \"%s\" mode %04o", name, a->perm);
630#ifdef HAVE_FCHMOD 764#ifdef HAVE_FCHMOD
631 ret = fchmod(fd, a->perm & 0777); 765 ret = fchmod(fd, a->perm & 0777);
632#else 766#else
@@ -636,6 +770,12 @@ process_fsetstat(void)
636 status = errno_to_portable(errno); 770 status = errno_to_portable(errno);
637 } 771 }
638 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 772 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
773 char buf[64];
774 time_t t = a->mtime;
775
776 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
777 localtime(&t));
778 logit("set \"%s\" modtime %s", name, buf);
639#ifdef HAVE_FUTIMES 779#ifdef HAVE_FUTIMES
640 ret = futimes(fd, attrib_to_tv(a)); 780 ret = futimes(fd, attrib_to_tv(a));
641#else 781#else
@@ -645,6 +785,8 @@ process_fsetstat(void)
645 status = errno_to_portable(errno); 785 status = errno_to_portable(errno);
646 } 786 }
647 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 787 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
788 logit("set \"%s\" owner %lu group %lu", name,
789 (u_long)a->uid, (u_long)a->gid);
648#ifdef HAVE_FCHOWN 790#ifdef HAVE_FCHOWN
649 ret = fchown(fd, a->uid, a->gid); 791 ret = fchown(fd, a->uid, a->gid);
650#else 792#else
@@ -667,7 +809,8 @@ process_opendir(void)
667 809
668 id = get_int(); 810 id = get_int();
669 path = get_string(NULL); 811 path = get_string(NULL);
670 TRACE("opendir id %u path %s", id, path); 812 debug3("request %u: opendir", id);
813 logit("opendir \"%s\"", path);
671 dirp = opendir(path); 814 dirp = opendir(path);
672 if (dirp == NULL) { 815 if (dirp == NULL) {
673 status = errno_to_portable(errno); 816 status = errno_to_portable(errno);
@@ -697,22 +840,23 @@ process_readdir(void)
697 840
698 id = get_int(); 841 id = get_int();
699 handle = get_handle(); 842 handle = get_handle();
700 TRACE("readdir id %u handle %d", id, handle); 843 debug("request %u: readdir \"%s\" (handle %d)", id,
844 handle_to_name(handle), handle);
701 dirp = handle_to_dir(handle); 845 dirp = handle_to_dir(handle);
702 path = handle_to_name(handle); 846 path = handle_to_name(handle);
703 if (dirp == NULL || path == NULL) { 847 if (dirp == NULL || path == NULL) {
704 send_status(id, SSH2_FX_FAILURE); 848 send_status(id, SSH2_FX_FAILURE);
705 } else { 849 } else {
706 struct stat st; 850 struct stat st;
707 char pathname[1024]; 851 char pathname[MAXPATHLEN];
708 Stat *stats; 852 Stat *stats;
709 int nstats = 10, count = 0, i; 853 int nstats = 10, count = 0, i;
710 854
711 stats = xmalloc(nstats * sizeof(Stat)); 855 stats = xcalloc(nstats, sizeof(Stat));
712 while ((dp = readdir(dirp)) != NULL) { 856 while ((dp = readdir(dirp)) != NULL) {
713 if (count >= nstats) { 857 if (count >= nstats) {
714 nstats *= 2; 858 nstats *= 2;
715 stats = xrealloc(stats, nstats * sizeof(Stat)); 859 stats = xrealloc(stats, nstats, sizeof(Stat));
716 } 860 }
717/* XXX OVERFLOW ? */ 861/* XXX OVERFLOW ? */
718 snprintf(pathname, sizeof pathname, "%s%s%s", path, 862 snprintf(pathname, sizeof pathname, "%s%s%s", path,
@@ -751,7 +895,8 @@ process_remove(void)
751 895
752 id = get_int(); 896 id = get_int();
753 name = get_string(NULL); 897 name = get_string(NULL);
754 TRACE("remove id %u name %s", id, name); 898 debug3("request %u: remove", id);
899 logit("remove name \"%s\"", name);
755 ret = unlink(name); 900 ret = unlink(name);
756 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 901 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
757 send_status(id, status); 902 send_status(id, status);
@@ -771,7 +916,8 @@ process_mkdir(void)
771 a = get_attrib(); 916 a = get_attrib();
772 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 917 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
773 a->perm & 0777 : 0777; 918 a->perm & 0777 : 0777;
774 TRACE("mkdir id %u name %s mode 0%o", id, name, mode); 919 debug3("request %u: mkdir", id);
920 logit("mkdir name \"%s\" mode 0%o", name, mode);
775 ret = mkdir(name, mode); 921 ret = mkdir(name, mode);
776 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 922 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
777 send_status(id, status); 923 send_status(id, status);
@@ -787,7 +933,8 @@ process_rmdir(void)
787 933
788 id = get_int(); 934 id = get_int();
789 name = get_string(NULL); 935 name = get_string(NULL);
790 TRACE("rmdir id %u name %s", id, name); 936 debug3("request %u: rmdir", id);
937 logit("rmdir name \"%s\"", name);
791 ret = rmdir(name); 938 ret = rmdir(name);
792 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 939 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
793 send_status(id, status); 940 send_status(id, status);
@@ -807,7 +954,8 @@ process_realpath(void)
807 xfree(path); 954 xfree(path);
808 path = xstrdup("."); 955 path = xstrdup(".");
809 } 956 }
810 TRACE("realpath id %u path %s", id, path); 957 debug3("request %u: realpath", id);
958 verbose("realpath \"%s\"", path);
811 if (realpath(path, resolvedname) == NULL) { 959 if (realpath(path, resolvedname) == NULL) {
812 send_status(id, errno_to_portable(errno)); 960 send_status(id, errno_to_portable(errno));
813 } else { 961 } else {
@@ -830,7 +978,8 @@ process_rename(void)
830 id = get_int(); 978 id = get_int();
831 oldpath = get_string(NULL); 979 oldpath = get_string(NULL);
832 newpath = get_string(NULL); 980 newpath = get_string(NULL);
833 TRACE("rename id %u old %s new %s", id, oldpath, newpath); 981 debug3("request %u: rename", id);
982 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
834 status = SSH2_FX_FAILURE; 983 status = SSH2_FX_FAILURE;
835 if (lstat(oldpath, &sb) == -1) 984 if (lstat(oldpath, &sb) == -1)
836 status = errno_to_portable(errno); 985 status = errno_to_portable(errno);
@@ -885,7 +1034,8 @@ process_readlink(void)
885 1034
886 id = get_int(); 1035 id = get_int();
887 path = get_string(NULL); 1036 path = get_string(NULL);
888 TRACE("readlink id %u path %s", id, path); 1037 debug3("request %u: readlink", id);
1038 verbose("readlink \"%s\"", path);
889 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) 1039 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
890 send_status(id, errno_to_portable(errno)); 1040 send_status(id, errno_to_portable(errno));
891 else { 1041 else {
@@ -909,7 +1059,8 @@ process_symlink(void)
909 id = get_int(); 1059 id = get_int();
910 oldpath = get_string(NULL); 1060 oldpath = get_string(NULL);
911 newpath = get_string(NULL); 1061 newpath = get_string(NULL);
912 TRACE("symlink id %u old %s new %s", id, oldpath, newpath); 1062 debug3("request %u: symlink", id);
1063 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
913 /* this will fail if 'newpath' exists */ 1064 /* this will fail if 'newpath' exists */
914 ret = symlink(oldpath, newpath); 1065 ret = symlink(oldpath, newpath);
915 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 1066 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
@@ -945,10 +1096,11 @@ process(void)
945 if (buf_len < 5) 1096 if (buf_len < 5)
946 return; /* Incomplete message. */ 1097 return; /* Incomplete message. */
947 cp = buffer_ptr(&iqueue); 1098 cp = buffer_ptr(&iqueue);
948 msg_len = GET_32BIT(cp); 1099 msg_len = get_u32(cp);
949 if (msg_len > SFTP_MAX_MSG_LENGTH) { 1100 if (msg_len > SFTP_MAX_MSG_LENGTH) {
950 error("bad message "); 1101 error("bad message from %s local user %s",
951 exit(11); 1102 client_addr, pw->pw_name);
1103 cleanup_exit(11);
952 } 1104 }
953 if (buf_len < msg_len + 4) 1105 if (buf_len < msg_len + 4)
954 return; 1106 return;
@@ -1022,7 +1174,7 @@ process(void)
1022 } 1174 }
1023 /* discard the remaining bytes from the current packet */ 1175 /* discard the remaining bytes from the current packet */
1024 if (buf_len < buffer_len(&iqueue)) 1176 if (buf_len < buffer_len(&iqueue))
1025 fatal("iqueue grows"); 1177 fatal("iqueue grew unexpectedly");
1026 consumed = buf_len - buffer_len(&iqueue); 1178 consumed = buf_len - buffer_len(&iqueue);
1027 if (msg_len < consumed) 1179 if (msg_len < consumed)
1028 fatal("msg_len %d < consumed %d", msg_len, consumed); 1180 fatal("msg_len %d < consumed %d", msg_len, consumed);
@@ -1030,24 +1182,93 @@ process(void)
1030 buffer_consume(&iqueue, msg_len - consumed); 1182 buffer_consume(&iqueue, msg_len - consumed);
1031} 1183}
1032 1184
1185/* Cleanup handler that logs active handles upon normal exit */
1186void
1187cleanup_exit(int i)
1188{
1189 if (pw != NULL && client_addr != NULL) {
1190 handle_log_exit();
1191 logit("session closed for local user %s from [%s]",
1192 pw->pw_name, client_addr);
1193 }
1194 _exit(i);
1195}
1196
1197static void
1198usage(void)
1199{
1200 extern char *__progname;
1201
1202 fprintf(stderr,
1203 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1204 exit(1);
1205}
1206
1033int 1207int
1034main(int ac, char **av) 1208main(int argc, char **argv)
1035{ 1209{
1036 fd_set *rset, *wset; 1210 fd_set *rset, *wset;
1037 int in, out, max; 1211 int in, out, max, ch, skipargs = 0, log_stderr = 0;
1038 ssize_t len, olen, set_size; 1212 ssize_t len, olen, set_size;
1213 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1214 char *cp;
1215
1216 extern char *optarg;
1217 extern char *__progname;
1039 1218
1040 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1219 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1041 sanitise_stdfd(); 1220 sanitise_stdfd();
1042 1221
1043 /* XXX should use getopt */ 1222 __progname = ssh_get_progname(argv[0]);
1223 log_init(__progname, log_level, log_facility, log_stderr);
1224
1225 while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1226 switch (ch) {
1227 case 'c':
1228 /*
1229 * Ignore all arguments if we are invoked as a
1230 * shell using "sftp-server -c command"
1231 */
1232 skipargs = 1;
1233 break;
1234 case 'e':
1235 log_stderr = 1;
1236 break;
1237 case 'l':
1238 log_level = log_level_number(optarg);
1239 if (log_level == SYSLOG_LEVEL_NOT_SET)
1240 error("Invalid log level \"%s\"", optarg);
1241 break;
1242 case 'f':
1243 log_facility = log_facility_number(optarg);
1244 if (log_level == SYSLOG_FACILITY_NOT_SET)
1245 error("Invalid log facility \"%s\"", optarg);
1246 break;
1247 case 'h':
1248 default:
1249 usage();
1250 }
1251 }
1044 1252
1045 __progname = ssh_get_progname(av[0]); 1253 log_init(__progname, log_level, log_facility, log_stderr);
1046 handle_init();
1047 1254
1048#ifdef DEBUG_SFTP_SERVER 1255 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1049 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1256 client_addr = xstrdup(cp);
1050#endif 1257 if ((cp = strchr(client_addr, ' ')) == NULL)
1258 fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1259 getenv("SSH_CONNECTION"));
1260 *cp = '\0';
1261 } else
1262 client_addr = xstrdup("UNKNOWN");
1263
1264 if ((pw = getpwuid(getuid())) == NULL)
1265 fatal("No user found for uid %lu", (u_long)getuid());
1266 pw = pwcopy(pw);
1267
1268 logit("session opened for local user %s from [%s]",
1269 pw->pw_name, client_addr);
1270
1271 handle_init();
1051 1272
1052 in = dup(STDIN_FILENO); 1273 in = dup(STDIN_FILENO);
1053 out = dup(STDOUT_FILENO); 1274 out = dup(STDOUT_FILENO);
@@ -1082,7 +1303,8 @@ main(int ac, char **av)
1082 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1303 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1083 if (errno == EINTR) 1304 if (errno == EINTR)
1084 continue; 1305 continue;
1085 exit(2); 1306 error("select: %s", strerror(errno));
1307 cleanup_exit(2);
1086 } 1308 }
1087 1309
1088 /* copy stdin to iqueue */ 1310 /* copy stdin to iqueue */
@@ -1091,10 +1313,10 @@ main(int ac, char **av)
1091 len = read(in, buf, sizeof buf); 1313 len = read(in, buf, sizeof buf);
1092 if (len == 0) { 1314 if (len == 0) {
1093 debug("read eof"); 1315 debug("read eof");
1094 exit(0); 1316 cleanup_exit(0);
1095 } else if (len < 0) { 1317 } else if (len < 0) {
1096 error("read error"); 1318 error("read: %s", strerror(errno));
1097 exit(1); 1319 cleanup_exit(1);
1098 } else { 1320 } else {
1099 buffer_append(&iqueue, buf, len); 1321 buffer_append(&iqueue, buf, len);
1100 } 1322 }
@@ -1103,8 +1325,8 @@ main(int ac, char **av)
1103 if (FD_ISSET(out, wset)) { 1325 if (FD_ISSET(out, wset)) {
1104 len = write(out, buffer_ptr(&oqueue), olen); 1326 len = write(out, buffer_ptr(&oqueue), olen);
1105 if (len < 0) { 1327 if (len < 0) {
1106 error("write error"); 1328 error("write: %s", strerror(errno));
1107 exit(1); 1329 cleanup_exit(1);
1108 } else { 1330 } else {
1109 buffer_consume(&oqueue, len); 1331 buffer_consume(&oqueue, len);
1110 } 1332 }