X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/4191cb150300d310ab5fa22ce2cfb02b6f6051b0..fa1c8faf169384bebaa8d172f491574c45ae2aa4:/src/src/log.c diff --git a/src/src/log.c b/src/src/log.c index 6126b2058..f85823520 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -2,9 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ -/* Copyright (c) The Exim Maintainers 2020 - 2021 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* Functions for writing log files. The code for maintaining datestamped log files was originally contributed by Tony Sheen. */ @@ -12,7 +13,6 @@ log files was originally contributed by Tony Sheen. */ #include "exim.h" -#define LOG_NAME_SIZE 256 #define MAX_SYSLOG_LEN 870 #define LOG_MODE_FILE 1 @@ -30,7 +30,6 @@ static uschar *log_names[] = { US"main", US"reject", US"panic", US"debug" }; static uschar mainlog_name[LOG_NAME_SIZE]; static uschar rejectlog_name[LOG_NAME_SIZE]; -static uschar debuglog_name[LOG_NAME_SIZE]; static uschar *mainlog_datestamp = NULL; static uschar *rejectlog_datestamp = NULL; @@ -55,66 +54,68 @@ static size_t pid_position[2]; number definitions in macros.h */ static const uschar * exim_errstrings[] = { - US"", - US"unknown error", - US"user slash", - US"exist race", - US"not regular", - US"not directory", - US"bad ugid", - US"bad mode", - US"inode changed", - US"lock failed", - US"bad address2", - US"forbid pipe", - US"forbid file", - US"forbid reply", - US"missing pipe", - US"missing file", - US"missing reply", - US"bad redirect", - US"smtp closed", - US"smtp format", - US"spool format", - US"not absolute", - US"Exim-imposed quota", - US"held", - US"Delivery filter process failure", - US"Delivery add/remove header failure", - US"Delivery write incomplete error", - US"Some expansion failed", - US"Failed to get gid", - US"Failed to get uid", - US"Unset or non-existent transport", - US"MBX length mismatch", - US"Lookup failed routing or in smtp tpt", - US"Can't match format in appendfile", - US"Creation outside home in appendfile", - US"Can't check a list; lookup defer", - US"DNS lookup defer", - US"Failed to start TLS session", - US"Mandatory TLS session not started", - US"Failed to chown a file", - US"Failed to create a pipe", - US"When verifying", - US"When required by client", - US"Used internally in smtp transport", - US"RCPT gave 4xx error", - US"MAIL gave 4xx error", - US"DATA gave 4xx error", - US"Negotiation failed for proxy configured host", - US"Authenticator 'other' failure", - US"target not supporting SMTPUTF8", - US"host is local", - US"tainted filename", - - US"Not time for routing", - US"Not time for local delivery", - US"Not time for any remote host", - US"Local-only delivery", - US"Domain in queue_domains", - US"Transport concurrency limit", - US"Event requests alternate response", + [0] = US"", + [- ERRNO_UNKNOWNERROR] = US"unknown error", + [- ERRNO_USERSLASH] = US"user slash", + [- ERRNO_EXISTRACE] = US"exist race", + [- ERRNO_NOTREGULAR] = US"not regular", + [- ERRNO_NOTDIRECTORY] = US"not directory", + [- ERRNO_BADUGID] = US"bad ugid", + [- ERRNO_BADMODE] = US"bad mode", + [- ERRNO_INODECHANGED] = US"inode changed", + [- ERRNO_LOCKFAILED] = US"lock failed", + [- ERRNO_BADADDRESS2] = US"bad address2", + [- ERRNO_FORBIDPIPE] = US"forbid pipe", + [- ERRNO_FORBIDFILE] = US"forbid file", + [- ERRNO_FORBIDREPLY] = US"forbid reply", + [- ERRNO_MISSINGPIPE] = US"missing pipe", + [- ERRNO_MISSINGFILE] = US"missing file", + [- ERRNO_MISSINGREPLY] = US"missing reply", + [- ERRNO_BADREDIRECT] = US"bad redirect", + [- ERRNO_SMTPCLOSED] = US"smtp closed", + [- ERRNO_SMTPFORMAT] = US"smtp format", + [- ERRNO_SPOOLFORMAT] = US"spool format", + [- ERRNO_NOTABSOLUTE] = US"not absolute", + [- ERRNO_EXIMQUOTA] = US"Exim-imposed quota", + [- ERRNO_HELD] = US"held", + [- ERRNO_FILTER_FAIL] = US"Delivery filter process failure", + [- ERRNO_CHHEADER_FAIL] = US"Delivery add/remove header failure", + [- ERRNO_WRITEINCOMPLETE] = US"Delivery write incomplete error", + [- ERRNO_EXPANDFAIL] = US"Some expansion failed", + [- ERRNO_GIDFAIL] = US"Failed to get gid", + [- ERRNO_UIDFAIL] = US"Failed to get uid", + [- ERRNO_BADTRANSPORT] = US"Unset or non-existent transport", + [- ERRNO_MBXLENGTH] = US"MBX length mismatch", + [- ERRNO_UNKNOWNHOST] = US"Lookup failed routing or in smtp tpt", + [- ERRNO_FORMATUNKNOWN] = US"Can't match format in appendfile", + [- ERRNO_BADCREATE] = US"Creation outside home in appendfile", + [- ERRNO_LISTDEFER] = US"Can't check a list; lookup defer", + [- ERRNO_DNSDEFER] = US"DNS lookup defer", + [- ERRNO_TLSFAILURE] = US"Failed to start TLS session", + [- ERRNO_TLSREQUIRED] = US"Mandatory TLS session not started", + [- ERRNO_CHOWNFAIL] = US"Failed to chown a file", + [- ERRNO_PIPEFAIL] = US"Failed to create a pipe", + [- ERRNO_CALLOUTDEFER] = US"When verifying", + [- ERRNO_AUTHFAIL] = US"When required by client", + [- ERRNO_CONNECTTIMEOUT] = US"Used internally in smtp transport", + [- ERRNO_RCPT4XX] = US"RCPT gave 4xx error", + [- ERRNO_MAIL4XX] = US"MAIL gave 4xx error", + [- ERRNO_DATA4XX] = US"DATA gave 4xx error", + [- ERRNO_PROXYFAIL] = US"Negotiation failed for proxy configured host", + [- ERRNO_AUTHPROB] = US"Authenticator 'other' failure", + [- ERRNO_UTF8_FWD] = US"target not supporting SMTPUTF8", + [- ERRNO_HOST_IS_LOCAL] = US"host is local", + [- ERRNO_TAINT] = US"tainted filename", + + [- ERRNO_RRETRY] = US"Not time for routing", + + [- ERRNO_LRETRY] = US"Not time for local delivery", + [- ERRNO_HRETRY] = US"Not time for any remote host", + [- ERRNO_LOCAL_ONLY] = US"Local-only delivery", + [- ERRNO_QUEUE_DOMAIN] = US"Domain in queue_domains", + [- ERRNO_TRETRY] = US"Transport concurrency limit", + + [- ERRNO_EVENT] = US"Event requests alternate response", }; @@ -266,7 +267,7 @@ Returns: a file descriptor, or < 0 on failure (errno set) */ static int -log_open_already_exim(uschar * const name) +log_open_already_exim(const uschar * const name) { int fd = -1; const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK; @@ -390,7 +391,7 @@ Returns: a file descriptor, or < 0 on failure (errno set) */ int -log_open_as_exim(uschar * const name) +log_open_as_exim(const uschar * const name) { int fd = -1; const uid_t euid = geteuid(); @@ -473,7 +474,7 @@ Returns: nothing */ static void -open_log(int *fd, int type, uschar *tag) +open_log(int * fd, int type, const uschar * tag) { uid_t euid; BOOL ok, ok2; @@ -529,8 +530,8 @@ switch (type) default: /* Remove any datestamp if this is the panic log. This is rare, so there's no - need to optimize getting the datestamp length. We remove one non-alphanumeric - char afterwards if at the start, otherwise one before. */ + need to optimize getting the datestamp length. We remove one non-alphanumeric + char afterwards if at the start, otherwise one before. */ if (string_datestamp_offset >= 0) { uschar * from = buffer + string_datestamp_offset; @@ -683,11 +684,11 @@ Returns: length actually written, persisting an errno from write() */ ssize_t -write_to_fd_buf(int fd, const uschar *buf, size_t length) +write_to_fd_buf(int fd, const uschar * buf, size_t length) { ssize_t wrote; size_t total_written = 0; -const uschar *p = buf; +const uschar * p = buf; size_t left = length; while (1) @@ -710,6 +711,12 @@ while (1) return total_written; } +static inline ssize_t +write_gstring_to_fd_buf(int fd, const gstring * g) +{ +return write_to_fd_buf(fd, g->s, g->ptr); +} + static void @@ -805,7 +812,7 @@ log_write(unsigned int selector, int flags, const char *format, ...) { int paniclogfd; ssize_t written_len; -gstring gs = { .size = LOG_BUFFER_SIZE-1, .ptr = 0, .s = log_buffer }; +gstring gs = { .size = LOG_BUFFER_SIZE-2, .ptr = 0, .s = log_buffer }; gstring * g; va_list ap; @@ -951,11 +958,9 @@ DEBUG(D_any|D_v) } va_end(ap); - g->size = LOG_BUFFER_SIZE; - g = string_catn(g, US"\n", 1); - debug_printf("%s", string_from_gstring(g)); + debug_printf("%Y\n", g); - gs.size = LOG_BUFFER_SIZE-1; /* Having used the buffer for debug output, */ + gs.size = LOG_BUFFER_SIZE-2; /* Having used the buffer for debug output, */ gs.ptr = 0; /* reset it for the real use. */ gs.s = log_buffer; } @@ -990,7 +995,7 @@ if (LOGGING(pid)) if (!syslog_pid) pid_position[1] = g->ptr; /* … and end+1 of the PID */ } -if (f.really_exim && message_id[0] != 0) +if (f.really_exim && message_id[0]) g = string_fmt_append(g, "%s ", message_id); if (flags & LOG_CONFIG) @@ -1027,16 +1032,17 @@ if ( flags & LOG_RECIPIENTS && g->ptr < LOG_BUFFER_SIZE - 6 && raw_recipients_count > 0) { - int i; g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " for", NULL); - for (i = 0; i < raw_recipients_count; i++) + for (int i = 0; i < raw_recipients_count; i++) { - uschar * s = raw_recipients[i]; + const uschar * s = raw_recipients[i]; if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break; g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s); } } +/* actual size, now we are placing the newline (and space for NUL) */ +gs.size = LOG_BUFFER_SIZE; g = string_catn(g, US"\n", 1); string_from_gstring(g); @@ -1111,7 +1117,7 @@ if ( flags & LOG_MAIN /* Failing to write to the log is disastrous */ - written_len = write_to_fd_buf(mainlogfd, g->s, g->ptr); + written_len = write_gstring_to_fd_buf(mainlogfd, g); if (written_len != g->ptr) { log_write_failed(US"main log", g->ptr, written_len); @@ -1170,8 +1176,8 @@ if (flags & LOG_REJECT) g = g2; else /* Buffer is full; truncate */ { - g->ptr -= 100; /* For message and separator */ - if (g->s[g->ptr-1] == '\n') g->ptr--; + gstring_trim(g, 100); /* For message and separator */ + gstring_trim_trailing(g, '\n'); g = string_cat(g, US"\n*** truncated ***\n"); break; } @@ -1226,7 +1232,7 @@ if (flags & LOG_REJECT) if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino; } - written_len = write_to_fd_buf(rejectlogfd, g->s, g->ptr); + written_len = write_gstring_to_fd_buf(rejectlogfd, g); if (written_len != g->ptr) { log_write_failed(US"reject log", g->ptr, written_len); @@ -1261,7 +1267,7 @@ if (flags & LOG_PANIC) if (panic_save_buffer) (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer)); - written_len = write_to_fd_buf(paniclogfd, g->s, g->ptr); + written_len = write_gstring_to_fd_buf(paniclogfd, g); if (written_len != g->ptr) { int save_errno = errno; @@ -1278,7 +1284,10 @@ if (flags & LOG_PANIC) /* Give up if the DIE flag is set */ if ((flags & LOG_PANIC_DIE) != LOG_PANIC) - die(NULL, US"Unexpected failure, please try later"); + if (panic_coredump) + kill(getpid(), SIGSEGV); /* deliberate trap */ + else + die(NULL, US"Unexpected failure, please try later"); } } @@ -1363,8 +1372,9 @@ Returns: nothing on success - bomb out on failure */ void -decode_bits(unsigned int *selector, size_t selsize, int *notall, - uschar *string, bit_table *options, int count, uschar *which, int flags) +decode_bits(unsigned int * selector, size_t selsize, int * notall, + const uschar * string, bit_table * options, int count, uschar * which, + int flags) { uschar *errmsg; if (!string) return; @@ -1373,7 +1383,7 @@ if (*string == '=') { char *end; /* Not uschar */ memset(selector, 0, sizeof(*selector)*selsize); - *selector = strtoul(CS string+1, &end, 0); + *selector = strtoul(CCS string+1, &end, 0); if (!*end) return; errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which, string); @@ -1385,9 +1395,9 @@ if (*string == '=') else for(;;) { BOOL adding; - uschar *s; + const uschar * s; int len; - bit_table *start, *end; + bit_table * start, * end; Uskip_whitespace(&string); if (!*string) return; @@ -1483,7 +1493,7 @@ immediately but only upon a trigger - but we'd need another cmdline option to pass the name through child_exxec_exim(). */ void -debug_logging_activate(uschar *tag_name, uschar *opts) +debug_logging_activate(const uschar * tag_name, const uschar * opts) { if (debug_file) { @@ -1519,9 +1529,27 @@ else } +void +debug_logging_from_spool(const uschar * filename) +{ +if (debug_fd < 0) + { + Ustrncpy(debuglog_name, filename, sizeof(debuglog_name)); + if ((debug_fd = log_open_as_exim(filename)) >= 0) + debug_file = fdopen(debug_fd, "w"); + DEBUG(D_deliver) debug_printf("debug enabled by spoolfile\n"); + } +/* +else DEBUG(D_deliver) + debug_printf("debug already active; ignoring spoolfile '%s'\n", filename); +*/ +} + + void debug_logging_stop(BOOL kill) { +debug_printf("debug terminated by %s\n", kill ? "kill" : "stop"); debug_pretrigger_discard(); if (!debug_file || !debuglog_name[0]) return;