From: Timo Sirainen Date: Wed, 14 Jan 2009 20:14:11 +0000 (-0500) Subject: If login process crashes, log the IP address that (maybe) caused it. X-Git-Tag: 1.2.beta1~115 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=be0185d71b19869700ac936fa9d09fb4ce950ae3;p=thirdparty%2Fdovecot%2Fcore.git If login process crashes, log the IP address that (maybe) caused it. --HG-- branch : HEAD --- diff --git a/src/lib/failures.c b/src/lib/failures.c index c76b800b04..8c24e1cbb8 100644 --- a/src/lib/failures.c +++ b/src/lib/failures.c @@ -3,6 +3,7 @@ #include "lib.h" #include "ioloop.h" #include "str.h" +#include "network.h" #include "backtrace-string.h" #include "printf-format-fix.h" #include "write-full.h" @@ -456,6 +457,16 @@ void i_set_failure_timestamp_format(const char *fmt) log_stamp_format = i_strdup(fmt); } +void i_set_failure_ip(const struct ip_addr *ip) +{ + const char *str; + + if (error_handler == i_internal_error_handler) { + str = t_strdup_printf("\x01Oip=%s\n", net_ip2addr(ip)); + (void)write_full(2, str, strlen(str)); + } +} + void i_set_failure_exit_callback(void (*callback)(int *status)) { failure_exit_callback = callback; diff --git a/src/lib/failures.h b/src/lib/failures.h index 3dec3d6450..1570e73ecf 100644 --- a/src/lib/failures.h +++ b/src/lib/failures.h @@ -1,6 +1,8 @@ #ifndef FAILURES_H #define FAILURES_H +struct ip_addr; + /* Default exit status codes that we could use. */ enum fatal_exit_status { FATAL_LOGOPEN = 80, /* Can't open log file */ @@ -78,9 +80,12 @@ void i_set_info_file(const char *path); /* Set the failure prefix. */ void i_set_failure_prefix(const char *prefix); - /* Prefix failures with a timestamp. fmt is in strftime() format. */ void i_set_failure_timestamp_format(const char *fmt); +/* When logging with internal error protocol, update the process's current + IP address. This is mainly used by the master process to log some IP + address if the process crash. */ +void i_set_failure_ip(const struct ip_addr *ip); /* Call the callback before exit()ing. The callback may update the status. */ void i_set_failure_exit_callback(void (*callback)(int *status)); diff --git a/src/login-common/main.c b/src/login-common/main.c index 62ae015046..7bfe419b1e 100644 --- a/src/login-common/main.c +++ b/src/login-common/main.c @@ -90,6 +90,7 @@ static void login_accept(void *context) i_error("accept() failed: %m"); return; } + i_set_failure_ip(&remote_ip); if (net_getsockname(fd, &local_ip, &local_port) < 0) { memset(&local_ip, 0, sizeof(local_ip)); @@ -121,6 +122,7 @@ static void login_accept_ssl(void *context) i_error("accept() failed: %m"); return; } + i_set_failure_ip(&remote_ip); if (net_getsockname(fd, &local_ip, &local_port) < 0) { memset(&local_ip, 0, sizeof(local_ip)); diff --git a/src/master/auth-process.c b/src/master/auth-process.c index 051fbb98d6..a0804be567 100644 --- a/src/master/auth-process.c +++ b/src/master/auth-process.c @@ -60,9 +60,9 @@ struct auth_process { bool have_initialized_auth_processes = FALSE; static struct child_process auth_child_process = - { PROCESS_TYPE_AUTH, 0 }; + { MEMBER(type) PROCESS_TYPE_AUTH }; static struct child_process auth_worker_child_process = - { PROCESS_TYPE_AUTH_WORKER, 0 }; + { MEMBER(type) PROCESS_TYPE_AUTH_WORKER }; static struct timeout *to; static unsigned int auth_tag; diff --git a/src/master/child-process.c b/src/master/child-process.c index 8979699046..ad285421e2 100644 --- a/src/master/child-process.c +++ b/src/master/child-process.c @@ -3,6 +3,7 @@ #include "common.h" #include "lib-signals.h" #include "hash.h" +#include "str.h" #include "env-util.h" #include "syslog-util.h" #include "child-process.h" @@ -132,12 +133,15 @@ static void sigchld_handler(int signo ATTR_UNUSED, struct child_process *process; const char *process_type_name, *msg; enum process_type process_type; + string_t *str; pid_t pid; int status; bool abnormal_exit; + str = t_str_new(128); while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { /* get the type and remove from hash */ + str_truncate(str, 0); process = child_process_lookup(pid); if (process == NULL) process_type = PROCESS_TYPE_UNKNOWN; @@ -168,14 +172,27 @@ static void sigchld_handler(int signo ATTR_UNUSED, process_type); msg = msg == NULL ? "" : t_strconcat(" (", msg, ")", NULL); - i_error("child %s (%s) returned error %d%s", - dec2str(pid), process_type_name, - status, msg); + str_printfa(str, + "child %s (%s) returned error %d%s", + dec2str(pid), process_type_name, + status, msg); } } else if (WIFSIGNALED(status)) { - i_error("child %s (%s) killed with signal %d", - dec2str(pid), process_type_name, - WTERMSIG(status)); + str_printfa(str, "child %s (%s) killed with signal %d", + dec2str(pid), process_type_name, + WTERMSIG(status)); + } + + if (str_len(str) > 0) { + if (process != NULL && process->ip.family != 0) { + if (!process->ip_changed) + str_append(str, " (ip="); + else + str_append(str, " (latest ip="); + str_printfa(str, "%s)", + net_ip2addr(&process->ip)); + } + i_error("%s", str_c(str)); } if (destroy_callbacks[process_type] != NULL) { diff --git a/src/master/child-process.h b/src/master/child-process.h index 0385d29c31..c98b832cef 100644 --- a/src/master/child-process.h +++ b/src/master/child-process.h @@ -16,8 +16,10 @@ enum process_type { struct child_process { enum process_type type; - + struct ip_addr ip; + unsigned int allow_change_ip:1; unsigned int seen_fatal:1; + unsigned int ip_changed:1; }; typedef void child_process_destroy_callback_t(struct child_process *process, diff --git a/src/master/log.c b/src/master/log.c index 6c15d8702b..92c0ee340f 100644 --- a/src/master/log.c +++ b/src/master/log.c @@ -17,6 +17,7 @@ struct log_io { struct io *io; struct istream *stream; pid_t pid; + struct ip_addr ip; time_t log_stamp; unsigned int log_counter; @@ -129,6 +130,20 @@ static int log_it(struct log_io *log_io, const char *line, bool continues) if (process != NULL) process->seen_fatal = TRUE; break; + case 'O': + /* logging option. ignore unknown ones. */ + if (strncmp(line, "ip=", 3) == 0) { + process = child_process_lookup(log_io->pid); + if (process != NULL && + (process->allow_change_ip || + process->ip.family == 0)) { + if (process->ip.family != 0) + process->ip_changed = TRUE; + net_addr2ip(line + 3, &process->ip); + } + } + log_io->next_log_type = '\0'; + return 1; default: log_type = LOG_TYPE_ERROR; break; diff --git a/src/master/login-process.c b/src/master/login-process.c index 8971d12751..cb6de9ce02 100644 --- a/src/master/login-process.c +++ b/src/master/login-process.c @@ -472,8 +472,11 @@ login_process_new(struct login_group *group, pid_t pid, int fd, p->io = io_add(fd, IO_READ, login_process_input, p); p->output = o_stream_create_fd(fd, sizeof(struct master_login_reply)*10, FALSE); - if (!inetd_child) + if (!inetd_child) { + if (!group->set->login_process_per_connection) + p->process.allow_change_ip = TRUE; child_process_add(pid, &p->process); + } p->state = LOGIN_STATE_LISTENING; diff --git a/src/master/ssl-init.c b/src/master/ssl-init.c index 67305fe3e3..8f3a7e4358 100644 --- a/src/master/ssl-init.c +++ b/src/master/ssl-init.c @@ -18,7 +18,7 @@ #include static struct child_process ssl_param_child_process = - { PROCESS_TYPE_SSL_PARAM, 0 }; + { MEMBER(type) PROCESS_TYPE_SSL_PARAM }; static struct timeout *to; static char *generating_path = NULL;