summaryrefslogtreecommitdiff
path: root/sftp-server.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2006-07-10 20:46:55 +1000
committerDamien Miller <djm@mindrot.org>2006-07-10 20:46:55 +1000
commitfef95ad81645250b83f7c83233648471d8d0edab (patch)
treea9583e7a29dc52e55ad8b0f41e56450a0506fae4 /sftp-server.c
parent917f9b6b6eb560e205a787bd8f38d4b9741c9a9f (diff)
- djm@cvs.openbsd.org 2006/07/06 10:47:57
[sftp-server.8 sftp-server.c] add commandline options to enable logging of transactions; ok markus@
Diffstat (limited to 'sftp-server.c')
-rw-r--r--sftp-server.c317
1 files changed, 261 insertions, 56 deletions
diff --git a/sftp-server.c b/sftp-server.c
index e842341cb..e882216b1 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-server.c,v 1.57 2006/03/30 09:58:16 djm Exp $ */ 1/* $OpenBSD: sftp-server.c,v 1.58 2006/07/06 10:47:57 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
4 * 4 *
@@ -26,6 +26,7 @@
26#include "log.h" 26#include "log.h"
27#include "xmalloc.h" 27#include "xmalloc.h"
28#include "misc.h" 28#include "misc.h"
29#include "uidswap.h"
29 30
30#include "sftp.h" 31#include "sftp.h"
31#include "sftp-common.h" 32#include "sftp-common.h"
@@ -34,9 +35,13 @@
34#define get_int64() buffer_get_int64(&iqueue); 35#define get_int64() buffer_get_int64(&iqueue);
35#define get_int() buffer_get_int(&iqueue); 36#define get_int() buffer_get_int(&iqueue);
36#define get_string(lenp) buffer_get_string(&iqueue, lenp); 37#define get_string(lenp) buffer_get_string(&iqueue, lenp);
37#define TRACE debug
38 38
39extern char *__progname; 39/* Our verbosity */
40LogLevel log_level = SYSLOG_LEVEL_ERROR;
41
42/* Our client */
43struct passwd *pw = NULL;
44char *client_addr = NULL;
40 45
41/* input and output queue */ 46/* input and output queue */
42Buffer iqueue; 47Buffer iqueue;
@@ -108,6 +113,33 @@ flags_from_portable(int pflags)
108 return flags; 113 return flags;
109} 114}
110 115
116static const char *
117string_from_portable(int pflags)
118{
119 static char ret[128];
120
121 *ret = '\0';
122
123#define PAPPEND(str) { \
124 if (*ret != '\0') \
125 strlcat(ret, ",", sizeof(ret)); \
126 strlcat(ret, str, sizeof(ret)); \
127 }
128
129 if (pflags & SSH2_FXF_READ)
130 PAPPEND("READ")
131 if (pflags & SSH2_FXF_WRITE)
132 PAPPEND("WRITE")
133 if (pflags & SSH2_FXF_CREAT)
134 PAPPEND("CREATE")
135 if (pflags & SSH2_FXF_TRUNC)
136 PAPPEND("TRUNCATE")
137 if (pflags & SSH2_FXF_EXCL)
138 PAPPEND("EXCL")
139
140 return ret;
141}
142
111static Attrib * 143static Attrib *
112get_attrib(void) 144get_attrib(void)
113{ 145{
@@ -122,6 +154,7 @@ struct Handle {
122 DIR *dirp; 154 DIR *dirp;
123 int fd; 155 int fd;
124 char *name; 156 char *name;
157 u_int64_t bytes_read, bytes_write;
125}; 158};
126 159
127enum { 160enum {
@@ -152,6 +185,7 @@ handle_new(int use, const char *name, int fd, DIR *dirp)
152 handles[i].dirp = dirp; 185 handles[i].dirp = dirp;
153 handles[i].fd = fd; 186 handles[i].fd = fd;
154 handles[i].name = xstrdup(name); 187 handles[i].name = xstrdup(name);
188 handles[i].bytes_read = handles[i].bytes_write = 0;
155 return i; 189 return i;
156 } 190 }
157 } 191 }
@@ -215,6 +249,36 @@ handle_to_fd(int handle)
215 return -1; 249 return -1;
216} 250}
217 251
252static void
253handle_update_read(int handle, ssize_t bytes)
254{
255 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
256 handles[handle].bytes_read += bytes;
257}
258
259static void
260handle_update_write(int handle, ssize_t bytes)
261{
262 if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
263 handles[handle].bytes_write += bytes;
264}
265
266static u_int64_t
267handle_bytes_read(int handle)
268{
269 if (handle_is_ok(handle, HANDLE_FILE))
270 return (handles[handle].bytes_read);
271 return 0;
272}
273
274static u_int64_t
275handle_bytes_write(int handle)
276{
277 if (handle_is_ok(handle, HANDLE_FILE))
278 return (handles[handle].bytes_write);
279 return 0;
280}
281
218static int 282static int
219handle_close(int handle) 283handle_close(int handle)
220{ 284{
@@ -234,6 +298,31 @@ handle_close(int handle)
234 return ret; 298 return ret;
235} 299}
236 300
301static void
302handle_log_close(int handle, char *emsg)
303{
304 if (handle_is_ok(handle, HANDLE_FILE)) {
305 logit("%s%sclose \"%s\" bytes read %llu written %llu",
306 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
307 handle_to_name(handle),
308 handle_bytes_read(handle), handle_bytes_write(handle));
309 } else {
310 logit("%s%sclosedir \"%s\"",
311 emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
312 handle_to_name(handle));
313 }
314}
315
316static void
317handle_log_exit(void)
318{
319 u_int i;
320
321 for (i = 0; i < sizeof(handles)/sizeof(Handle); i++)
322 if (handles[i].use != HANDLE_UNUSED)
323 handle_log_close(i, "forced");
324}
325
237static int 326static int
238get_handle(void) 327get_handle(void)
239{ 328{
@@ -260,10 +349,9 @@ send_msg(Buffer *m)
260 buffer_consume(m, mlen); 349 buffer_consume(m, mlen);
261} 350}
262 351
263static void 352static const char *
264send_status(u_int32_t id, u_int32_t status) 353status_to_message(u_int32_t status)
265{ 354{
266 Buffer msg;
267 const char *status_messages[] = { 355 const char *status_messages[] = {
268 "Success", /* SSH_FX_OK */ 356 "Success", /* SSH_FX_OK */
269 "End of file", /* SSH_FX_EOF */ 357 "End of file", /* SSH_FX_EOF */
@@ -276,15 +364,24 @@ send_status(u_int32_t id, u_int32_t status)
276 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ 364 "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
277 "Unknown error" /* Others */ 365 "Unknown error" /* Others */
278 }; 366 };
367 return (status_messages[MIN(status,SSH2_FX_MAX)]);
368}
279 369
280 TRACE("sent status id %u error %u", id, status); 370static void
371send_status(u_int32_t id, u_int32_t status)
372{
373 Buffer msg;
374
375 debug3("request %u: sent status %u", id, status);
376 if (log_level > SYSLOG_LEVEL_VERBOSE ||
377 (status != SSH2_FX_OK && status != SSH2_FX_EOF))
378 logit("sent status %s", status_to_message(status));
281 buffer_init(&msg); 379 buffer_init(&msg);
282 buffer_put_char(&msg, SSH2_FXP_STATUS); 380 buffer_put_char(&msg, SSH2_FXP_STATUS);
283 buffer_put_int(&msg, id); 381 buffer_put_int(&msg, id);
284 buffer_put_int(&msg, status); 382 buffer_put_int(&msg, status);
285 if (version >= 3) { 383 if (version >= 3) {
286 buffer_put_cstring(&msg, 384 buffer_put_cstring(&msg, status_to_message(status));
287 status_messages[MIN(status,SSH2_FX_MAX)]);
288 buffer_put_cstring(&msg, ""); 385 buffer_put_cstring(&msg, "");
289 } 386 }
290 send_msg(&msg); 387 send_msg(&msg);
@@ -306,7 +403,7 @@ send_data_or_handle(char type, u_int32_t id, const char *data, int dlen)
306static void 403static void
307send_data(u_int32_t id, const char *data, int dlen) 404send_data(u_int32_t id, const char *data, int dlen)
308{ 405{
309 TRACE("sent data id %u len %d", id, dlen); 406 debug("request %u: sent data len %d", id, dlen);
310 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); 407 send_data_or_handle(SSH2_FXP_DATA, id, data, dlen);
311} 408}
312 409
@@ -317,7 +414,7 @@ send_handle(u_int32_t id, int handle)
317 int hlen; 414 int hlen;
318 415
319 handle_to_string(handle, &string, &hlen); 416 handle_to_string(handle, &string, &hlen);
320 TRACE("sent handle id %u handle %d", id, handle); 417 debug("request %u: sent handle handle %d", id, handle);
321 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); 418 send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen);
322 xfree(string); 419 xfree(string);
323} 420}
@@ -332,7 +429,7 @@ send_names(u_int32_t id, int count, const Stat *stats)
332 buffer_put_char(&msg, SSH2_FXP_NAME); 429 buffer_put_char(&msg, SSH2_FXP_NAME);
333 buffer_put_int(&msg, id); 430 buffer_put_int(&msg, id);
334 buffer_put_int(&msg, count); 431 buffer_put_int(&msg, count);
335 TRACE("sent names id %u count %d", id, count); 432 debug("request %u: sent names count %d", id, count);
336 for (i = 0; i < count; i++) { 433 for (i = 0; i < count; i++) {
337 buffer_put_cstring(&msg, stats[i].name); 434 buffer_put_cstring(&msg, stats[i].name);
338 buffer_put_cstring(&msg, stats[i].long_name); 435 buffer_put_cstring(&msg, stats[i].long_name);
@@ -347,7 +444,7 @@ send_attrib(u_int32_t id, const Attrib *a)
347{ 444{
348 Buffer msg; 445 Buffer msg;
349 446
350 TRACE("sent attrib id %u have 0x%x", id, a->flags); 447 debug("request %u: sent attrib have 0x%x", id, a->flags);
351 buffer_init(&msg); 448 buffer_init(&msg);
352 buffer_put_char(&msg, SSH2_FXP_ATTRS); 449 buffer_put_char(&msg, SSH2_FXP_ATTRS);
353 buffer_put_int(&msg, id); 450 buffer_put_int(&msg, id);
@@ -364,7 +461,7 @@ process_init(void)
364 Buffer msg; 461 Buffer msg;
365 462
366 version = get_int(); 463 version = get_int();
367 TRACE("client version %d", version); 464 verbose("received client version %d", version);
368 buffer_init(&msg); 465 buffer_init(&msg);
369 buffer_put_char(&msg, SSH2_FXP_VERSION); 466 buffer_put_char(&msg, SSH2_FXP_VERSION);
370 buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 467 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
@@ -381,12 +478,14 @@ process_open(void)
381 int handle, fd, flags, mode, status = SSH2_FX_FAILURE; 478 int handle, fd, flags, mode, status = SSH2_FX_FAILURE;
382 479
383 id = get_int(); 480 id = get_int();
481 debug3("request %u: open flags %d", id, pflags);
384 name = get_string(NULL); 482 name = get_string(NULL);
385 pflags = get_int(); /* portable flags */ 483 pflags = get_int(); /* portable flags */
386 a = get_attrib(); 484 a = get_attrib();
387 flags = flags_from_portable(pflags); 485 flags = flags_from_portable(pflags);
388 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; 486 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
389 TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); 487 logit("open \"%s\" flags %s mode 0%o",
488 name, string_from_portable(pflags), mode);
390 fd = open(name, flags, mode); 489 fd = open(name, flags, mode);
391 if (fd < 0) { 490 if (fd < 0) {
392 status = errno_to_portable(errno); 491 status = errno_to_portable(errno);
@@ -412,7 +511,8 @@ process_close(void)
412 511
413 id = get_int(); 512 id = get_int();
414 handle = get_handle(); 513 handle = get_handle();
415 TRACE("close id %u handle %d", id, handle); 514 debug3("request %u: close handle %u", id, handle);
515 handle_log_close(handle, NULL);
416 ret = handle_close(handle); 516 ret = handle_close(handle);
417 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 517 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
418 send_status(id, status); 518 send_status(id, status);
@@ -431,11 +531,11 @@ process_read(void)
431 off = get_int64(); 531 off = get_int64();
432 len = get_int(); 532 len = get_int();
433 533
434 TRACE("read id %u handle %d off %llu len %d", id, handle, 534 debug("request %u: read \"%s\" (handle %d) off %llu len %d",
435 (unsigned long long)off, len); 535 id, handle_to_name(handle), handle, (unsigned long long)off, len);
436 if (len > sizeof buf) { 536 if (len > sizeof buf) {
437 len = sizeof buf; 537 len = sizeof buf;
438 logit("read change len %d", len); 538 debug2("read change len %d", len);
439 } 539 }
440 fd = handle_to_fd(handle); 540 fd = handle_to_fd(handle);
441 if (fd >= 0) { 541 if (fd >= 0) {
@@ -451,6 +551,7 @@ process_read(void)
451 } else { 551 } else {
452 send_data(id, buf, ret); 552 send_data(id, buf, ret);
453 status = SSH2_FX_OK; 553 status = SSH2_FX_OK;
554 handle_update_read(handle, ret);
454 } 555 }
455 } 556 }
456 } 557 }
@@ -472,8 +573,8 @@ process_write(void)
472 off = get_int64(); 573 off = get_int64();
473 data = get_string(&len); 574 data = get_string(&len);
474 575
475 TRACE("write id %u handle %d off %llu len %d", id, handle, 576 debug("request %u: write \"%s\" (handle %d) off %llu len %d",
476 (unsigned long long)off, len); 577 id, handle_to_name(handle), handle, (unsigned long long)off, len);
477 fd = handle_to_fd(handle); 578 fd = handle_to_fd(handle);
478 if (fd >= 0) { 579 if (fd >= 0) {
479 if (lseek(fd, off, SEEK_SET) < 0) { 580 if (lseek(fd, off, SEEK_SET) < 0) {
@@ -487,8 +588,9 @@ process_write(void)
487 status = errno_to_portable(errno); 588 status = errno_to_portable(errno);
488 } else if ((size_t)ret == len) { 589 } else if ((size_t)ret == len) {
489 status = SSH2_FX_OK; 590 status = SSH2_FX_OK;
591 handle_update_write(handle, ret);
490 } else { 592 } else {
491 logit("nothing at all written"); 593 debug2("nothing at all written");
492 } 594 }
493 } 595 }
494 } 596 }
@@ -507,7 +609,8 @@ process_do_stat(int do_lstat)
507 609
508 id = get_int(); 610 id = get_int();
509 name = get_string(NULL); 611 name = get_string(NULL);
510 TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); 612 debug3("request %u: %sstat", id, do_lstat ? "l" : "");
613 verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name);
511 ret = do_lstat ? lstat(name, &st) : stat(name, &st); 614 ret = do_lstat ? lstat(name, &st) : stat(name, &st);
512 if (ret < 0) { 615 if (ret < 0) {
513 status = errno_to_portable(errno); 616 status = errno_to_portable(errno);
@@ -543,7 +646,8 @@ process_fstat(void)
543 646
544 id = get_int(); 647 id = get_int();
545 handle = get_handle(); 648 handle = get_handle();
546 TRACE("fstat id %u handle %d", id, handle); 649 debug("request %u: fstat \"%s\" (handle %u)",
650 id, handle_to_name(handle), handle);
547 fd = handle_to_fd(handle); 651 fd = handle_to_fd(handle);
548 if (fd >= 0) { 652 if (fd >= 0) {
549 ret = fstat(fd, &st); 653 ret = fstat(fd, &st);
@@ -582,23 +686,33 @@ process_setstat(void)
582 id = get_int(); 686 id = get_int();
583 name = get_string(NULL); 687 name = get_string(NULL);
584 a = get_attrib(); 688 a = get_attrib();
585 TRACE("setstat id %u name %s", id, name); 689 debug("request %u: setstat name \"%s\"", id, name);
586 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 690 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
691 logit("set \"%s\" size %llu", name, a->size);
587 ret = truncate(name, a->size); 692 ret = truncate(name, a->size);
588 if (ret == -1) 693 if (ret == -1)
589 status = errno_to_portable(errno); 694 status = errno_to_portable(errno);
590 } 695 }
591 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 696 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
697 logit("set \"%s\" mode %04o", name, a->perm);
592 ret = chmod(name, a->perm & 0777); 698 ret = chmod(name, a->perm & 0777);
593 if (ret == -1) 699 if (ret == -1)
594 status = errno_to_portable(errno); 700 status = errno_to_portable(errno);
595 } 701 }
596 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 702 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
703 char buf[64];
704 time_t t = a->mtime;
705
706 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
707 localtime(&t));
708 logit("set \"%s\" modtime %s", name, buf);
597 ret = utimes(name, attrib_to_tv(a)); 709 ret = utimes(name, attrib_to_tv(a));
598 if (ret == -1) 710 if (ret == -1)
599 status = errno_to_portable(errno); 711 status = errno_to_portable(errno);
600 } 712 }
601 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 713 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
714 logit("set \"%s\" owner %lu group %lu", name,
715 (u_long)a->uid, (u_long)a->gid);
602 ret = chown(name, a->uid, a->gid); 716 ret = chown(name, a->uid, a->gid);
603 if (ret == -1) 717 if (ret == -1)
604 status = errno_to_portable(errno); 718 status = errno_to_portable(errno);
@@ -614,23 +728,25 @@ process_fsetstat(void)
614 u_int32_t id; 728 u_int32_t id;
615 int handle, fd, ret; 729 int handle, fd, ret;
616 int status = SSH2_FX_OK; 730 int status = SSH2_FX_OK;
617 char *name;
618 731
619 id = get_int(); 732 id = get_int();
620 handle = get_handle(); 733 handle = get_handle();
621 a = get_attrib(); 734 a = get_attrib();
622 TRACE("fsetstat id %u handle %d", id, handle); 735 debug("request %u: fsetstat handle %d", id, handle);
623 fd = handle_to_fd(handle); 736 fd = handle_to_fd(handle);
624 name = handle_to_name(handle); 737 if (fd < 0) {
625 if (fd < 0 || name == NULL) {
626 status = SSH2_FX_FAILURE; 738 status = SSH2_FX_FAILURE;
627 } else { 739 } else {
740 char *name = handle_to_name(handle);
741
628 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { 742 if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
743 logit("set \"%s\" size %llu", name, a->size);
629 ret = ftruncate(fd, a->size); 744 ret = ftruncate(fd, a->size);
630 if (ret == -1) 745 if (ret == -1)
631 status = errno_to_portable(errno); 746 status = errno_to_portable(errno);
632 } 747 }
633 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { 748 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
749 logit("set \"%s\" mode %04o", name, a->perm);
634#ifdef HAVE_FCHMOD 750#ifdef HAVE_FCHMOD
635 ret = fchmod(fd, a->perm & 0777); 751 ret = fchmod(fd, a->perm & 0777);
636#else 752#else
@@ -640,6 +756,12 @@ process_fsetstat(void)
640 status = errno_to_portable(errno); 756 status = errno_to_portable(errno);
641 } 757 }
642 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 758 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
759 char buf[64];
760 time_t t = a->mtime;
761
762 strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
763 localtime(&t));
764 logit("set \"%s\" modtime %s", name, buf);
643#ifdef HAVE_FUTIMES 765#ifdef HAVE_FUTIMES
644 ret = futimes(fd, attrib_to_tv(a)); 766 ret = futimes(fd, attrib_to_tv(a));
645#else 767#else
@@ -649,6 +771,8 @@ process_fsetstat(void)
649 status = errno_to_portable(errno); 771 status = errno_to_portable(errno);
650 } 772 }
651 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 773 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
774 logit("set \"%s\" owner %lu group %lu", name,
775 (u_long)a->uid, (u_long)a->gid);
652#ifdef HAVE_FCHOWN 776#ifdef HAVE_FCHOWN
653 ret = fchown(fd, a->uid, a->gid); 777 ret = fchown(fd, a->uid, a->gid);
654#else 778#else
@@ -671,7 +795,8 @@ process_opendir(void)
671 795
672 id = get_int(); 796 id = get_int();
673 path = get_string(NULL); 797 path = get_string(NULL);
674 TRACE("opendir id %u path %s", id, path); 798 debug3("request %u: opendir", id);
799 logit("opendir \"%s\"", path);
675 dirp = opendir(path); 800 dirp = opendir(path);
676 if (dirp == NULL) { 801 if (dirp == NULL) {
677 status = errno_to_portable(errno); 802 status = errno_to_portable(errno);
@@ -701,14 +826,15 @@ process_readdir(void)
701 826
702 id = get_int(); 827 id = get_int();
703 handle = get_handle(); 828 handle = get_handle();
704 TRACE("readdir id %u handle %d", id, handle); 829 debug("request %u: readdir \"%s\" (handle %d)", id,
830 handle_to_name(handle), handle);
705 dirp = handle_to_dir(handle); 831 dirp = handle_to_dir(handle);
706 path = handle_to_name(handle); 832 path = handle_to_name(handle);
707 if (dirp == NULL || path == NULL) { 833 if (dirp == NULL || path == NULL) {
708 send_status(id, SSH2_FX_FAILURE); 834 send_status(id, SSH2_FX_FAILURE);
709 } else { 835 } else {
710 struct stat st; 836 struct stat st;
711 char pathname[1024]; 837 char pathname[MAXPATHLEN];
712 Stat *stats; 838 Stat *stats;
713 int nstats = 10, count = 0, i; 839 int nstats = 10, count = 0, i;
714 840
@@ -755,7 +881,8 @@ process_remove(void)
755 881
756 id = get_int(); 882 id = get_int();
757 name = get_string(NULL); 883 name = get_string(NULL);
758 TRACE("remove id %u name %s", id, name); 884 debug3("request %u: remove", id);
885 logit("remove name \"%s\"", name);
759 ret = unlink(name); 886 ret = unlink(name);
760 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 887 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
761 send_status(id, status); 888 send_status(id, status);
@@ -775,7 +902,8 @@ process_mkdir(void)
775 a = get_attrib(); 902 a = get_attrib();
776 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? 903 mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ?
777 a->perm & 0777 : 0777; 904 a->perm & 0777 : 0777;
778 TRACE("mkdir id %u name %s mode 0%o", id, name, mode); 905 debug3("request %u: mkdir", id);
906 logit("mkdir name \"%s\" mode 0%o", name, mode);
779 ret = mkdir(name, mode); 907 ret = mkdir(name, mode);
780 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 908 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
781 send_status(id, status); 909 send_status(id, status);
@@ -791,7 +919,8 @@ process_rmdir(void)
791 919
792 id = get_int(); 920 id = get_int();
793 name = get_string(NULL); 921 name = get_string(NULL);
794 TRACE("rmdir id %u name %s", id, name); 922 debug3("request %u: rmdir", id);
923 logit("rmdir name \"%s\"", name);
795 ret = rmdir(name); 924 ret = rmdir(name);
796 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 925 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
797 send_status(id, status); 926 send_status(id, status);
@@ -811,7 +940,8 @@ process_realpath(void)
811 xfree(path); 940 xfree(path);
812 path = xstrdup("."); 941 path = xstrdup(".");
813 } 942 }
814 TRACE("realpath id %u path %s", id, path); 943 debug3("request %u: realpath", id);
944 verbose("realpath \"%s\"", path);
815 if (realpath(path, resolvedname) == NULL) { 945 if (realpath(path, resolvedname) == NULL) {
816 send_status(id, errno_to_portable(errno)); 946 send_status(id, errno_to_portable(errno));
817 } else { 947 } else {
@@ -834,7 +964,8 @@ process_rename(void)
834 id = get_int(); 964 id = get_int();
835 oldpath = get_string(NULL); 965 oldpath = get_string(NULL);
836 newpath = get_string(NULL); 966 newpath = get_string(NULL);
837 TRACE("rename id %u old %s new %s", id, oldpath, newpath); 967 debug3("request %u: rename", id);
968 logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
838 status = SSH2_FX_FAILURE; 969 status = SSH2_FX_FAILURE;
839 if (lstat(oldpath, &sb) == -1) 970 if (lstat(oldpath, &sb) == -1)
840 status = errno_to_portable(errno); 971 status = errno_to_portable(errno);
@@ -889,7 +1020,8 @@ process_readlink(void)
889 1020
890 id = get_int(); 1021 id = get_int();
891 path = get_string(NULL); 1022 path = get_string(NULL);
892 TRACE("readlink id %u path %s", id, path); 1023 debug3("request %u: readlink", id);
1024 verbose("readlink \"%s\"", path);
893 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) 1025 if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
894 send_status(id, errno_to_portable(errno)); 1026 send_status(id, errno_to_portable(errno));
895 else { 1027 else {
@@ -913,7 +1045,8 @@ process_symlink(void)
913 id = get_int(); 1045 id = get_int();
914 oldpath = get_string(NULL); 1046 oldpath = get_string(NULL);
915 newpath = get_string(NULL); 1047 newpath = get_string(NULL);
916 TRACE("symlink id %u old %s new %s", id, oldpath, newpath); 1048 debug3("request %u: symlink", id);
1049 logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
917 /* this will fail if 'newpath' exists */ 1050 /* this will fail if 'newpath' exists */
918 ret = symlink(oldpath, newpath); 1051 ret = symlink(oldpath, newpath);
919 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; 1052 status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
@@ -951,8 +1084,9 @@ process(void)
951 cp = buffer_ptr(&iqueue); 1084 cp = buffer_ptr(&iqueue);
952 msg_len = get_u32(cp); 1085 msg_len = get_u32(cp);
953 if (msg_len > SFTP_MAX_MSG_LENGTH) { 1086 if (msg_len > SFTP_MAX_MSG_LENGTH) {
954 error("bad message "); 1087 error("bad message from %s local user %s",
955 exit(11); 1088 client_addr, pw->pw_name);
1089 cleanup_exit(11);
956 } 1090 }
957 if (buf_len < msg_len + 4) 1091 if (buf_len < msg_len + 4)
958 return; 1092 return;
@@ -1026,7 +1160,7 @@ process(void)
1026 } 1160 }
1027 /* discard the remaining bytes from the current packet */ 1161 /* discard the remaining bytes from the current packet */
1028 if (buf_len < buffer_len(&iqueue)) 1162 if (buf_len < buffer_len(&iqueue))
1029 fatal("iqueue grows"); 1163 fatal("iqueue grew unexpectedly");
1030 consumed = buf_len - buffer_len(&iqueue); 1164 consumed = buf_len - buffer_len(&iqueue);
1031 if (msg_len < consumed) 1165 if (msg_len < consumed)
1032 fatal("msg_len %d < consumed %d", msg_len, consumed); 1166 fatal("msg_len %d < consumed %d", msg_len, consumed);
@@ -1034,24 +1168,94 @@ process(void)
1034 buffer_consume(&iqueue, msg_len - consumed); 1168 buffer_consume(&iqueue, msg_len - consumed);
1035} 1169}
1036 1170
1171/* Cleanup handler that logs active handles upon normal exit */
1172void
1173cleanup_exit(int i)
1174{
1175 if (pw != NULL && client_addr != NULL) {
1176 handle_log_exit();
1177 logit("session closed for local user %s from [%s]",
1178 pw->pw_name, client_addr);
1179 }
1180 _exit(i);
1181}
1182
1183static void
1184usage(void)
1185{
1186 extern char *__progname;
1187
1188 fprintf(stderr,
1189 "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname);
1190 exit(1);
1191}
1192
1037int 1193int
1038main(int ac, char **av) 1194main(int argc, char **argv)
1039{ 1195{
1040 fd_set *rset, *wset; 1196 fd_set *rset, *wset;
1041 int in, out, max; 1197 int in, out, max, ch, skipargs = 0, log_stderr = 0;
1042 ssize_t len, olen, set_size; 1198 ssize_t len, olen, set_size;
1199 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
1200 char *cp;
1201
1202 extern int optind;
1203 extern char *optarg;
1204 extern char *__progname;
1043 1205
1044 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1206 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1045 sanitise_stdfd(); 1207 sanitise_stdfd();
1046 1208
1047 /* XXX should use getopt */ 1209 __progname = ssh_get_progname(argv[0]);
1210 log_init(__progname, log_level, log_facility, log_stderr);
1211
1212 while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) {
1213 switch (ch) {
1214 case 'c':
1215 /*
1216 * Ignore all arguments if we are invoked as a
1217 * shell using "sftp-server -c command"
1218 */
1219 skipargs = 1;
1220 break;
1221 case 'e':
1222 log_stderr = 1;
1223 break;
1224 case 'l':
1225 log_level = log_level_number(optarg);
1226 if (log_level == SYSLOG_LEVEL_NOT_SET)
1227 error("Invalid log level \"%s\"", optarg);
1228 break;
1229 case 'f':
1230 log_facility = log_facility_number(optarg);
1231 if (log_level == SYSLOG_FACILITY_NOT_SET)
1232 error("Invalid log facility \"%s\"", optarg);
1233 break;
1234 case 'h':
1235 default:
1236 usage();
1237 }
1238 }
1048 1239
1049 __progname = ssh_get_progname(av[0]); 1240 log_init(__progname, log_level, log_facility, log_stderr);
1050 handle_init();
1051 1241
1052#ifdef DEBUG_SFTP_SERVER 1242 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
1053 log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); 1243 client_addr = xstrdup(cp);
1054#endif 1244 if ((cp = strchr(client_addr, ' ')) == NULL)
1245 fatal("Malformed SSH_CONNECTION variable: \"%s\"",
1246 getenv("SSH_CONNECTION"));
1247 *cp = '\0';
1248 } else
1249 client_addr = xstrdup("UNKNOWN");
1250
1251 if ((pw = getpwuid(getuid())) == NULL)
1252 fatal("No user found for uid %lu", (u_long)getuid());
1253 pw = pwcopy(pw);
1254
1255 logit("session opened for local user %s from [%s]",
1256 pw->pw_name, client_addr);
1257
1258 handle_init();
1055 1259
1056 in = dup(STDIN_FILENO); 1260 in = dup(STDIN_FILENO);
1057 out = dup(STDOUT_FILENO); 1261 out = dup(STDOUT_FILENO);
@@ -1086,7 +1290,8 @@ main(int ac, char **av)
1086 if (select(max+1, rset, wset, NULL, NULL) < 0) { 1290 if (select(max+1, rset, wset, NULL, NULL) < 0) {
1087 if (errno == EINTR) 1291 if (errno == EINTR)
1088 continue; 1292 continue;
1089 exit(2); 1293 error("select: %s", strerror(errno));
1294 cleanup_exit(2);
1090 } 1295 }
1091 1296
1092 /* copy stdin to iqueue */ 1297 /* copy stdin to iqueue */
@@ -1095,10 +1300,10 @@ main(int ac, char **av)
1095 len = read(in, buf, sizeof buf); 1300 len = read(in, buf, sizeof buf);
1096 if (len == 0) { 1301 if (len == 0) {
1097 debug("read eof"); 1302 debug("read eof");
1098 exit(0); 1303 cleanup_exit(0);
1099 } else if (len < 0) { 1304 } else if (len < 0) {
1100 error("read error"); 1305 error("read: %s", strerror(errno));
1101 exit(1); 1306 cleanup_exit(1);
1102 } else { 1307 } else {
1103 buffer_append(&iqueue, buf, len); 1308 buffer_append(&iqueue, buf, len);
1104 } 1309 }
@@ -1107,8 +1312,8 @@ main(int ac, char **av)
1107 if (FD_ISSET(out, wset)) { 1312 if (FD_ISSET(out, wset)) {
1108 len = write(out, buffer_ptr(&oqueue), olen); 1313 len = write(out, buffer_ptr(&oqueue), olen);
1109 if (len < 0) { 1314 if (len < 0) {
1110 error("write error"); 1315 error("write: %s", strerror(errno));
1111 exit(1); 1316 cleanup_exit(1);
1112 } else { 1317 } else {
1113 buffer_consume(&oqueue, len); 1318 buffer_consume(&oqueue, len);
1114 } 1319 }