]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
If login process crashes, log the IP address that (maybe) caused it.
authorTimo Sirainen <tss@iki.fi>
Wed, 14 Jan 2009 20:14:11 +0000 (15:14 -0500)
committerTimo Sirainen <tss@iki.fi>
Wed, 14 Jan 2009 20:14:11 +0000 (15:14 -0500)
--HG--
branch : HEAD

src/lib/failures.c
src/lib/failures.h
src/login-common/main.c
src/master/auth-process.c
src/master/child-process.c
src/master/child-process.h
src/master/log.c
src/master/login-process.c
src/master/ssl-init.c

index c76b800b0438f8c5169ba0145b90b3a6c2ec6f3c..8c24e1cbb86ac457982fdb31733472122a0a3e36 100644 (file)
@@ -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;
index 3dec3d64505ae6d3d99f535821b6c490168f6aba..1570e73ecf3a49aac434b67e42cdcc9ca0fa7e57 100644 (file)
@@ -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));
index 62ae015046e9b99f796ca44231183802da8ea2f0..7bfe419b1eaa3c91ac5d4e388bdbd28c70fe3d37 100644 (file)
@@ -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));
index 051fbb98d6ab7474a228220d9dae692d67512994..a0804be567fff9d668613bcacb38f3c6c532e299 100644 (file)
@@ -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;
index 8979699046968ad23d80605f6e72ba298c8d2106..ad285421e2083c284e2c9189d10494a956f432dc 100644 (file)
@@ -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) {
index 0385d29c31bf3d039583757e7a692452c52c280c..c98b832cefc7cf21bd44ec5b2fe02ebf9992212c 100644 (file)
@@ -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,
index 6c15d8702b0ccbc4f9ddbf86ce066b06c3128004..92c0ee340fa70f2e34b5ae873b206cdda4568809 100644 (file)
@@ -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;
index 8971d127511eee10ce1b1455ba16e2a8d0575e66..cb6de9ce02b4b80308733f82d70109b3816169b6 100644 (file)
@@ -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;
 
index 67305fe3e3f2670226688bebfc640946b611d3fc..8f3a7e43581cade5f293e379fa0d561d3bcb0847 100644 (file)
@@ -18,7 +18,7 @@
 #include <sys/stat.h>
 
 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;