mirror of
https://github.com/InfrastructureServices/vsftpd.git
synced 2025-04-19 01:24:02 +03:00
404 lines
11 KiB
C
404 lines
11 KiB
C
/*
|
|
* Part of Very Secure FTPd
|
|
* Licence: GPL v2
|
|
* Author: Chris Evans
|
|
*
|
|
* logging.c
|
|
*/
|
|
|
|
#include "logging.h"
|
|
#include "tunables.h"
|
|
#include "utility.h"
|
|
#include "str.h"
|
|
#include "sysutil.h"
|
|
#include "sysstr.h"
|
|
#include "session.h"
|
|
|
|
/* File local functions */
|
|
static int vsf_log_type_is_transfer(enum EVSFLogEntryType type);
|
|
static void vsf_log_common(struct vsf_session* p_sess, int succeeded,
|
|
enum EVSFLogEntryType what,
|
|
const struct mystr* p_str);
|
|
static void vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess,
|
|
struct mystr* p_str, int succeeded,
|
|
enum EVSFLogEntryType what,
|
|
const struct mystr* p_log_str);
|
|
static void vsf_log_do_log_wuftpd_format(struct vsf_session* p_sess,
|
|
struct mystr* p_str, int succeeded);
|
|
static void vsf_log_do_log_to_file(int fd, struct mystr* p_str);
|
|
|
|
void
|
|
vsf_log_init(struct vsf_session* p_sess)
|
|
{
|
|
if (!tunable_xferlog_enable && !tunable_dual_log_enable)
|
|
{
|
|
return;
|
|
}
|
|
if (tunable_dual_log_enable || tunable_xferlog_std_format)
|
|
{
|
|
int retval = -1;
|
|
if (tunable_xferlog_file)
|
|
{
|
|
retval = vsf_sysutil_create_or_open_file_append(tunable_xferlog_file,
|
|
0600);
|
|
}
|
|
if (vsf_sysutil_retval_is_error(retval))
|
|
{
|
|
die2("failed to open xferlog log file:", tunable_xferlog_file);
|
|
}
|
|
p_sess->xferlog_fd = retval;
|
|
}
|
|
if (tunable_dual_log_enable || !tunable_xferlog_std_format)
|
|
{
|
|
if (!tunable_syslog_enable)
|
|
{
|
|
int retval = -1;
|
|
if (tunable_vsftpd_log_file)
|
|
{
|
|
retval = vsf_sysutil_create_or_open_file_append(tunable_vsftpd_log_file,
|
|
0600);
|
|
}
|
|
if (vsf_sysutil_retval_is_error(retval))
|
|
{
|
|
die2("failed to open vsftpd log file:", tunable_vsftpd_log_file);
|
|
}
|
|
p_sess->vsftpd_log_fd = retval;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
vsf_log_type_is_transfer(enum EVSFLogEntryType type)
|
|
{
|
|
return (type == kVSFLogEntryDownload || type == kVSFLogEntryUpload);
|
|
}
|
|
|
|
void
|
|
vsf_log_start_entry(struct vsf_session* p_sess, enum EVSFLogEntryType what)
|
|
{
|
|
if (p_sess->log_type != 0)
|
|
{
|
|
bug("non null log_type in vsf_log_start_entry");
|
|
}
|
|
p_sess->log_type = (unsigned long) what;
|
|
p_sess->log_start_sec = 0;
|
|
p_sess->log_start_usec = 0;
|
|
p_sess->transfer_size = 0;
|
|
str_empty(&p_sess->log_str);
|
|
if (vsf_log_type_is_transfer(what))
|
|
{
|
|
p_sess->log_start_sec = vsf_sysutil_get_time_sec();
|
|
p_sess->log_start_usec = vsf_sysutil_get_time_usec();
|
|
}
|
|
}
|
|
|
|
void
|
|
vsf_log_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
|
|
struct mystr* p_str)
|
|
{
|
|
vsf_log_common(p_sess, 1, what, p_str);
|
|
}
|
|
|
|
void
|
|
vsf_log_failed_line(struct vsf_session* p_sess, enum EVSFLogEntryType what,
|
|
struct mystr* p_str)
|
|
{
|
|
vsf_log_common(p_sess, 0, what, p_str);
|
|
}
|
|
|
|
int
|
|
vsf_log_entry_pending(struct vsf_session* p_sess)
|
|
{
|
|
if (p_sess->log_type == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
vsf_log_clear_entry(struct vsf_session* p_sess)
|
|
{
|
|
p_sess->log_type = 0;
|
|
}
|
|
|
|
void
|
|
vsf_log_do_log(struct vsf_session* p_sess, int succeeded)
|
|
{
|
|
vsf_log_common(p_sess, succeeded, (enum EVSFLogEntryType) p_sess->log_type,
|
|
&p_sess->log_str);
|
|
p_sess->log_type = 0;
|
|
}
|
|
|
|
static void
|
|
vsf_log_common(struct vsf_session* p_sess, int succeeded,
|
|
enum EVSFLogEntryType what, const struct mystr* p_str)
|
|
{
|
|
static struct mystr s_log_str;
|
|
/* Handle xferlog line if appropriate */
|
|
if (p_sess->xferlog_fd != -1 && vsf_log_type_is_transfer(what))
|
|
{
|
|
vsf_log_do_log_wuftpd_format(p_sess, &s_log_str, succeeded);
|
|
vsf_log_do_log_to_file(p_sess->xferlog_fd, &s_log_str);
|
|
}
|
|
/* Handle vsftpd.log line if appropriate */
|
|
if (p_sess->vsftpd_log_fd != -1)
|
|
{
|
|
vsf_log_do_log_vsftpd_format(p_sess, &s_log_str, succeeded, what, p_str);
|
|
vsf_log_do_log_to_file(p_sess->vsftpd_log_fd, &s_log_str);
|
|
}
|
|
/* Handle syslog() line if appropriate */
|
|
if (tunable_syslog_enable)
|
|
{
|
|
int severe = 0;
|
|
vsf_log_do_log_vsftpd_format(p_sess, &s_log_str, succeeded, what, p_str);
|
|
if (what == kVSFLogEntryLogin && !succeeded)
|
|
{
|
|
severe = 1;
|
|
}
|
|
str_syslog(&s_log_str, severe);
|
|
}
|
|
}
|
|
|
|
static void
|
|
vsf_log_do_log_to_file(int fd, struct mystr* p_str)
|
|
{
|
|
if (!tunable_no_log_lock)
|
|
{
|
|
int retval = vsf_sysutil_lock_file_write(fd);
|
|
if (vsf_sysutil_retval_is_error(retval))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if (tunable_wc_logs_enable)
|
|
{
|
|
str_replace_unprintable_with_hex_wc(p_str);
|
|
}
|
|
else
|
|
{
|
|
str_replace_unprintable_with_hex(p_str);
|
|
}
|
|
str_append_char(p_str, '\n');
|
|
/* Ignore write failure; maybe the disk filled etc. */
|
|
(void) str_write_loop(p_str, fd);
|
|
if (!tunable_no_log_lock)
|
|
{
|
|
vsf_sysutil_unlock_file(fd);
|
|
}
|
|
}
|
|
|
|
static void
|
|
vsf_log_do_log_wuftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
|
|
int succeeded)
|
|
{
|
|
static struct mystr s_filename_str;
|
|
long delta_sec;
|
|
enum EVSFLogEntryType what = (enum EVSFLogEntryType) p_sess->log_type;
|
|
/* Date - vsf_sysutil_get_current_date updates cached time */
|
|
str_alloc_text(p_str, vsf_sysutil_get_current_date());
|
|
str_append_char(p_str, ' ');
|
|
/* Transfer time (in seconds) */
|
|
delta_sec = vsf_sysutil_get_time_sec() - p_sess->log_start_sec;
|
|
if (delta_sec <= 0)
|
|
{
|
|
delta_sec = 1;
|
|
}
|
|
str_append_ulong(p_str, (unsigned long) delta_sec);
|
|
str_append_char(p_str, ' ');
|
|
/* Remote host name */
|
|
str_append_str(p_str, &p_sess->remote_ip_str);
|
|
str_append_char(p_str, ' ');
|
|
/* Bytes transferred */
|
|
str_append_filesize_t(p_str, p_sess->transfer_size);
|
|
str_append_char(p_str, ' ');
|
|
/* Filename */
|
|
str_copy(&s_filename_str, &p_sess->log_str);
|
|
str_replace_char(&s_filename_str, ' ', '_');
|
|
str_append_str(p_str, &s_filename_str);
|
|
str_append_char(p_str, ' ');
|
|
/* Transfer type (ascii/binary) */
|
|
if (p_sess->is_ascii)
|
|
{
|
|
str_append_text(p_str, "a ");
|
|
}
|
|
else
|
|
{
|
|
str_append_text(p_str, "b ");
|
|
}
|
|
/* Special action flag - tar, gzip etc. */
|
|
str_append_text(p_str, "_ ");
|
|
/* Direction of transfer */
|
|
if (what == kVSFLogEntryUpload)
|
|
{
|
|
str_append_text(p_str, "i ");
|
|
}
|
|
else
|
|
{
|
|
str_append_text(p_str, "o ");
|
|
}
|
|
/* Access mode: anonymous/real user, and identity */
|
|
if (p_sess->is_anonymous && !p_sess->is_guest)
|
|
{
|
|
str_append_text(p_str, "a ");
|
|
str_append_str(p_str, &p_sess->anon_pass_str);
|
|
}
|
|
else
|
|
{
|
|
if (p_sess->is_guest)
|
|
{
|
|
str_append_text(p_str, "g ");
|
|
}
|
|
else
|
|
{
|
|
str_append_text(p_str, "r ");
|
|
}
|
|
str_append_str(p_str, &p_sess->user_str);
|
|
}
|
|
str_append_char(p_str, ' ');
|
|
/* Service name, authentication method, authentication user id */
|
|
str_append_text(p_str, "ftp 0 * ");
|
|
/* Completion status */
|
|
if (succeeded)
|
|
{
|
|
str_append_char(p_str, 'c');
|
|
}
|
|
else
|
|
{
|
|
str_append_char(p_str, 'i');
|
|
}
|
|
}
|
|
|
|
static void
|
|
vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
|
|
int succeeded, enum EVSFLogEntryType what,
|
|
const struct mystr* p_log_str)
|
|
{
|
|
str_empty(p_str);
|
|
if (!tunable_syslog_enable)
|
|
{
|
|
/* Date - vsf_sysutil_get_current_date updates cached time */
|
|
str_append_text(p_str, vsf_sysutil_get_current_date());
|
|
/* Pid */
|
|
str_append_text(p_str, " [pid ");
|
|
str_append_ulong(p_str, vsf_sysutil_getpid());
|
|
str_append_text(p_str, "] ");
|
|
}
|
|
/* User */
|
|
if (!str_isempty(&p_sess->user_str))
|
|
{
|
|
str_append_char(p_str, '[');
|
|
str_append_str(p_str, &p_sess->user_str);
|
|
str_append_text(p_str, "] ");
|
|
}
|
|
/* And the action */
|
|
if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput &&
|
|
what != kVSFLogEntryConnection && what != kVSFLogEntryDebug)
|
|
{
|
|
if (succeeded)
|
|
{
|
|
str_append_text(p_str, "OK ");
|
|
}
|
|
else
|
|
{
|
|
str_append_text(p_str, "FAIL ");
|
|
}
|
|
}
|
|
switch (what)
|
|
{
|
|
case kVSFLogEntryDownload:
|
|
str_append_text(p_str, "DOWNLOAD");
|
|
break;
|
|
case kVSFLogEntryUpload:
|
|
str_append_text(p_str, "UPLOAD");
|
|
break;
|
|
case kVSFLogEntryMkdir:
|
|
str_append_text(p_str, "MKDIR");
|
|
break;
|
|
case kVSFLogEntryLogin:
|
|
str_append_text(p_str, "LOGIN");
|
|
break;
|
|
case kVSFLogEntryFTPInput:
|
|
str_append_text(p_str, "FTP command");
|
|
break;
|
|
case kVSFLogEntryFTPOutput:
|
|
str_append_text(p_str, "FTP response");
|
|
break;
|
|
case kVSFLogEntryConnection:
|
|
str_append_text(p_str, "CONNECT");
|
|
break;
|
|
case kVSFLogEntryDelete:
|
|
str_append_text(p_str, "DELETE");
|
|
break;
|
|
case kVSFLogEntryRename:
|
|
str_append_text(p_str, "RENAME");
|
|
break;
|
|
case kVSFLogEntryRmdir:
|
|
str_append_text(p_str, "RMDIR");
|
|
break;
|
|
case kVSFLogEntryChmod:
|
|
str_append_text(p_str, "CHMOD");
|
|
break;
|
|
case kVSFLogEntryDebug:
|
|
str_append_text(p_str, "DEBUG");
|
|
break;
|
|
case kVSFLogEntryNull:
|
|
/* Fall through */
|
|
default:
|
|
bug("bad entry_type in vsf_log_do_log");
|
|
break;
|
|
}
|
|
str_append_text(p_str, ": Client \"");
|
|
str_append_str(p_str, &p_sess->remote_ip_str);
|
|
str_append_char(p_str, '"');
|
|
if (what == kVSFLogEntryLogin && !str_isempty(&p_sess->anon_pass_str))
|
|
{
|
|
str_append_text(p_str, ", anon password \"");
|
|
str_append_str(p_str, &p_sess->anon_pass_str);
|
|
str_append_char(p_str, '"');
|
|
}
|
|
if (!str_isempty(p_log_str))
|
|
{
|
|
str_append_text(p_str, ", \"");
|
|
str_append_str(p_str, p_log_str);
|
|
str_append_char(p_str, '"');
|
|
}
|
|
if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput &&
|
|
what != kVSFLogEntryDebug)
|
|
{
|
|
if (p_sess->transfer_size)
|
|
{
|
|
str_append_text(p_str, ", ");
|
|
str_append_filesize_t(p_str, p_sess->transfer_size);
|
|
str_append_text(p_str, " bytes");
|
|
}
|
|
if (vsf_log_type_is_transfer(what))
|
|
{
|
|
long delta_sec = vsf_sysutil_get_time_sec() - p_sess->log_start_sec;
|
|
long delta_usec = vsf_sysutil_get_time_usec() - p_sess->log_start_usec;
|
|
double time_delta = (double) delta_sec + ((double) delta_usec /
|
|
(double) 1000000);
|
|
double kbyte_rate;
|
|
if (time_delta <= 0)
|
|
{
|
|
time_delta = 0.1;
|
|
}
|
|
kbyte_rate =
|
|
((double) p_sess->transfer_size / time_delta) / (double) 1024;
|
|
str_append_text(p_str, ", ");
|
|
str_append_double(p_str, kbyte_rate);
|
|
str_append_text(p_str, "Kbyte/sec");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
vsf_log_die(const char* p_text)
|
|
{
|
|
struct mystr log_str = INIT_MYSTR;
|
|
|
|
str_append_text(&log_str, "ERROR: ");
|
|
str_append_text(&log_str, p_text);
|
|
str_syslog(&log_str, 1);
|
|
}
|