commit eb39a357cb57fdf83b89c9039dd6e7a7983fd5df Merge: d997c8cd3 dddc92898 Author: Jeremy Harris Date: Tue Oct 28 13:26:04 2025 +0000 Merge branch '4.next' diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 5a15b0a6b..e24ef95f2 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -539,8 +539,7 @@ transport-filter.pl: config ../src/transport-filter.src # are thrown away by the linker. OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o -OBJ_EXPERIMENTAL = bmi_spam.o \ - dane.o \ +OBJ_EXPERIMENTAL = dane.o \ dcc.o \ imap_utf7.o \ utf8.o \ @@ -938,7 +937,6 @@ spool_mbox.o: $(HDRS) spool_mbox.c # Dependencies for EXPERIMENTAL_* modules -bmi_spam.o: $(HDRS) bmi_spam.c dane.o: $(HDRS) dane.c dane-openssl.c dcc.o: $(HDRS) dcc.h dcc.c imap_utf7.o: $(HDRS) imap_utf7.c diff --git a/src/exim_monitor/em_globals.c b/src/exim_monitor/em_globals.c index 491a9dda6..5627a2277 100644 --- a/src/exim_monitor/em_globals.c +++ b/src/exim_monitor/em_globals.c @@ -44,11 +44,6 @@ uschar actioned_message[24]; uschar *action_required; uschar *alternate_config = NULL; -#ifdef EXPERIMENTAL_BRIGHTMAIL -int bmi_run = 0; -uschar *bmi_verdicts = NULL; -#endif - int body_max = 20000; uschar *exim_path = US BIN_DIRECTORY "/exim" diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index d35962f98..8f55be0b5 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -32,9 +32,9 @@ d="lookups" mkdir $d cd $d # Makefile is generated -for f in README cdb.c dbmdb.c dnsdb.c dsearch.c ibase.c json.c ldap.c \ +for f in README cdb.c dbmdb.c dnsdb.c dsearch.c json.c ldap.c \ lmdb.c lsearch.c mysql.c nis.c nisplus.c nmh.c oracle.c passwd.c \ - pgsql.c readsock.c redis.c spf.c sqlite.c testdb.c whoson.c \ + pgsql.c psl.c readsock.c redis.c spf.c sqlite.c testdb.c whoson.c \ lf_functions.h lf_check_file.c lf_quote.c lf_sqlperform.c do ln -s ../../src/$d/$f $f @@ -155,7 +155,7 @@ do done # EXPERIMENTAL_* -for f in bmi_spam.c bmi_spam.h dcc.c dcc.h dane.c dane-openssl.c \ +for f in dcc.c dcc.h dane.c dane-openssl.c \ danessl.h imap_utf7.c utf8.c xclient.c do ln -s ../src/$f $f diff --git a/src/scripts/lookups-Makefile b/src/scripts/lookups-Makefile index 0617e31cd..6555e820c 100755 --- a/src/scripts/lookups-Makefile +++ b/src/scripts/lookups-Makefile @@ -101,7 +101,8 @@ want_dynamic() { want_at_all() { local want_name="$1" - local re="(LOOKUP|EXPERIMENTAL)_${want_name}[ $tab]*=[ $tab]*." + # SUPPORT is here purely for the spf lookup + local re="(LOOKUP|EXPERIMENTAL|SUPPORT)_${want_name}[ $tab]*=[ $tab]*." env | ${egrep} -q "^$re" if [ $? -eq 0 ]; then return 0; fi ${egrep} -q "^[ $tab]*$re" "$defs_source" @@ -156,23 +157,18 @@ exec > "$target" sed -n "1,/$tag_marker/p" < "$input" for name_mod in \ - CDB DBM:dbmdb DNSDB DSEARCH IBASE JSON LMDB LDAP LSEARCH MYSQL NIS NISPLUS \ - NMH ORACLE PASSWD PGSQL REDIS SQLITE TESTDB WHOSON + CDB DBM:dbmdb DNSDB DSEARCH JSON LMDB LDAP LSEARCH MYSQL NIS NISPLUS \ + NMH ORACLE PASSWD PGSQL PSL REDIS SQLITE SPF TESTDB WHOSON do emit_module_rule $name_mod done -# Because the variable is SUPPORT_SPF and not LOOKUP_SPF we -# always include spf.o and compile a dummy if SUPPORT_SPF is not -# defined. - -OBJ="${OBJ} spf.o" - # readsock is always wanted as it implements the ${readsock } expansion -OBJ="${OBJ} readsock.o" +OBJ_ALWAYS="${OBJ_ALWAYS} readsock.o" echo "MODS = $MODS" echo "OBJ = $OBJ" +echo "OBJ_ALWAYS = $OBJ_ALWAYS" sed -n "/$tag_marker/,\$p" < "$input" diff --git a/src/src/EDITME b/src/src/EDITME index 3a9b167de..998406359 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -436,7 +436,6 @@ LOOKUP_DNSDB=yes # LOOKUP_CDB=yes # LOOKUP_DSEARCH=yes -# LOOKUP_IBASE=yes # LOOKUP_JSON=yes # LOOKUP_LDAP=yes # LOOKUP_LMDB=yes @@ -448,6 +447,7 @@ LOOKUP_DNSDB=yes # LOOKUP_ORACLE=yes # LOOKUP_PASSWD=yes # LOOKUP_PGSQL=yes +# LOOKUP_PSL=yes # LOOKUP_REDIS=yes # LOOKUP_SQLITE=yes # LOOKUP_SQLITE_PC=sqlite3 @@ -461,9 +461,6 @@ LOOKUP_DNSDB=yes # LOOKUP_NWILDLSEARCH=yes -# For IBASE you may need: -#LIBS += -lfbclient - #------------------------------------------------------------------------------ # If you have set LOOKUP_LDAP, you should set LDAP_LIB_TYPE to indicate # which LDAP library you have. Unfortunately, though most of their functions @@ -512,7 +509,7 @@ SUPPORT_DANE=yes # the command for linking Exim itself, not on any auxiliary programs. You # don't need to set LOOKUP_INCLUDE if the relevant directories are already # specified in INCLUDE. The settings below are just examples; -lpq is for -# PostgreSQL, -lgds is for Interbase, -lsqlite3 is for SQLite, -lhiredis +# PostgreSQL, -lsqlite3 is for SQLite, -lhiredis # is for Redis, -ljansson for JSON. # # You do not need to use this for any lookup information added via pkg-config. @@ -526,15 +523,16 @@ SUPPORT_DANE=yes # LOOKUP_INCLUDE=-I /usr/local/ldap/include -I /usr/local/mysql/include -I /usr/local/pgsql/include # LOOKUP_INCLUDE +=-I /usr/local/include -# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lgds -lsqlite3 -llmdb +# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lsqlite3 -llmdb # LOOKUP_LIBS=-L/usr/local/lib -lldap -llber # Some platforms may need this for LOOKUP_NIS: #LOOKUP_LIBS += -lnsl + +# These lookup types need appropriate libraries #LOOKUP_LIBS += -ljansson #LOOKUP_LIBS += -lhiredis -#------------------------------------------------------------------------------ # If you included LOOKUP_LMDB above you will need the library. Depending # on where installed you may also need an include directory # @@ -542,6 +540,7 @@ SUPPORT_DANE=yes # LOOKUP_LIBS += -llmdb # For dynamic-modules builds, use instead LOOKUP_LMDB_INCLUDE & LOOKUP_LMDB_LIBS +# LOOKUP_PSL will require that SUPPORT_I18N is defined (but needs no libraries) #------------------------------------------------------------------------------ # Compiling the Exim monitor: If you want to compile the Exim monitor, a @@ -694,15 +693,6 @@ DISABLE_MAL_MKS=yes # support. You must have SPF and DKIM support enabled also. # EXPERIMENTAL_ARC=yes -# Uncomment the following lines to add Brightmail AntiSpam support. You need -# to have the Brightmail client SDK installed. Please check the experimental -# documentation for implementation details. You need to edit the CFLAGS and -# LDFLAGS lines. - -# EXPERIMENTAL_BRIGHTMAIL=yes -# CFLAGS += -I/opt/brightmail/bsdk-6.0/include -# LDFLAGS += -lxml2_single -lbmiclient_single -L/opt/brightmail/bsdk-6.0/lib - # Uncomment the following to include extra information in fail DSN message (bounces) # EXPERIMENTAL_DSN_INFO=yes diff --git a/src/src/acl.c b/src/src/acl.c index 80a17c937..36fb850c8 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -63,9 +63,6 @@ enum { ACLC_ACL, ACLC_ADD_HEADER, ACLC_ATRN_DOMAINS, ACLC_AUTHENTICATED, -#ifdef EXPERIMENTAL_BRIGHTMAIL - ACLC_BMI_OPTIN, -#endif ACLC_CONDITION, ACLC_CONTINUE, ACLC_CONTROL, @@ -168,19 +165,6 @@ static condition_def conditions[] = { ACL_BIT_NOTSMTP_START | ACL_BIT_CONNECT | ACL_BIT_HELO), }, -#ifdef EXPERIMENTAL_BRIGHTMAIL - [ACLC_BMI_OPTIN] = { US"bmi_optin", ACD_EXP | ACD_MOD, - FORBIDDEN(ACL_BIT_AUTH | - ACL_BIT_CONNECT | ACL_BIT_HELO | - ACL_BIT_DATA | ACL_BIT_MIME | - ACL_BIT_PRDR | - ACL_BIT_ETRN | ACL_BIT_EXPN | - ACL_BIT_MAILAUTH | - ACL_BIT_MAIL | ACL_BIT_STARTTLS | - ACL_BIT_VRFY | ACL_BIT_PREDATA | - ACL_BIT_NOTSMTP_START), - }, -#endif [ACLC_CONDITION] = { US"condition", ACD_EXP, FORBIDDEN(0) }, [ACLC_CONTINUE] = { US"continue", ACD_EXP | ACD_MOD, @@ -433,9 +417,6 @@ static condition_module condition_modules[] = { enum { CONTROL_AUTH_UNADVERTISED, -#ifdef EXPERIMENTAL_BRIGHTMAIL - CONTROL_BMI_RUN, -#endif CONTROL_CASEFUL_LOCAL_PART, CONTROL_CASELOWER_LOCAL_PART, CONTROL_CUTTHROUGH_DELIVERY, @@ -493,10 +474,6 @@ static control_def controls_list[] = { (unsigned) ~(ACL_BIT_CONNECT | ACL_BIT_HELO) }, -#ifdef EXPERIMENTAL_BRIGHTMAIL -[CONTROL_BMI_RUN] = - { US"bmi_run", FALSE, 0 }, -#endif [CONTROL_CASEFUL_LOCAL_PART] = { US"caseful_local_part", FALSE, (unsigned) ~ACL_BIT_RCPT }, [CONTROL_CASELOWER_LOCAL_PART] = @@ -3460,17 +3437,6 @@ for (; cb; cb = cb->next) &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL) : FAIL; break; - #ifdef EXPERIMENTAL_BRIGHTMAIL - case ACLC_BMI_OPTIN: - { - int old_pool = store_pool; - store_pool = POOL_PERM; - bmi_current_optin = string_copy(arg); - store_pool = old_pool; - } - break; - #endif - case ACLC_CONDITION: /* The true/false parsing here should be kept in sync with that used in expand.c when dealing with ECOND_BOOL so that we don't have too many @@ -3512,12 +3478,6 @@ for (; cb; cb = cb->next) f.allow_auth_unadvertised = TRUE; break; -#ifdef EXPERIMENTAL_BRIGHTMAIL - case CONTROL_BMI_RUN: - bmi_run = 1; - break; -#endif - #ifndef DISABLE_DKIM case CONTROL_DKIM_VERIFY: f.dkim_disable_verify = TRUE; diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index df861f6c4..2f6a56626 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -343,7 +343,7 @@ auth_info cram_md5_auth_info = { .options_block = &auth_cram_md5_option_defaults, .options_len = sizeof(auth_cram_md5_options_block), .init = auth_cram_md5_init, -# ifdef DYNLOOKUP +# if AUTH_CRAM_MD5==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index 8d39945bc..0ccb1f5fe 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -521,7 +521,7 @@ auth_info cyrus_sasl_auth_info = { .options_block = &auth_cyrus_sasl_option_defaults, .options_len = sizeof(auth_cyrus_sasl_options_block), .init = auth_cyrus_sasl_init, -# ifdef DYNLOOKUP +# if AUTH_CYRUS_SASL==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index 5319878e2..118e95f29 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -564,7 +564,7 @@ auth_info dovecot_auth_info = { .options_block = &auth_dovecot_option_defaults, .options_len = sizeof(auth_dovecot_options_block), .init = auth_dovecot_init, -# ifdef DYNLOOKUP +# if AUTH_DOVECOT==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/external.c b/src/src/auths/external.c index 0cdfcdcfe..883c9cae8 100644 --- a/src/src/auths/external.c +++ b/src/src/auths/external.c @@ -172,7 +172,7 @@ auth_info external_auth_info = { .options_block = &auth_external_option_defaults, .options_len = sizeof(auth_external_options_block), .init = auth_external_init, -# ifdef DYNLOOKUP +# if AUTH_EXTERNAL==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/gsasl.c b/src/src/auths/gsasl.c index 9c315fc92..ad4c9b479 100644 --- a/src/src/auths/gsasl.c +++ b/src/src/auths/gsasl.c @@ -1073,7 +1073,7 @@ auth_info gsasl_auth_info = { .options_block = &auth_gsasl_option_defaults, .options_len = sizeof(auth_gsasl_options_block), .init = auth_gsasl_init, -# ifdef DYNLOOKUP +# if AUTH_GSASL==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/heimdal_gssapi.c b/src/src/auths/heimdal_gssapi.c index 8014e61bb..1c79112c3 100644 --- a/src/src/auths/heimdal_gssapi.c +++ b/src/src/auths/heimdal_gssapi.c @@ -625,7 +625,7 @@ auth_info heimdal_gssapi_auth_info = { .options_block = &auth_heimdal_gssapi_option_defaults, .options_len = sizeof(auth_heimdal_gssapi_options_block), .init = auth_heimdal_gssapi_init, -# ifdef DYNLOOKUP +# if AUTH_HEIMDAL_GSSAPI==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c index 598311e65..772b49ff9 100644 --- a/src/src/auths/plaintext.c +++ b/src/src/auths/plaintext.c @@ -194,7 +194,7 @@ auth_info plaintext_auth_info = { .options_block = &auth_plaintext_option_defaults, .options_len = sizeof(auth_plaintext_options_block), .init = auth_plaintext_init, -# ifdef DYNLOOKUP +# if AUTH_PLAINTEXT==2 .dyn_magic = AUTH_MAGIC, # endif }, @@ -204,5 +204,5 @@ auth_info plaintext_auth_info = { .macros_create = NULL, }; -#endif /*AUTH_PLAINTEST*/ +#endif /*AUTH_PLAINTEXT*/ /* End of plaintext.c */ diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c index 8bd95813e..3e2cccde9 100644 --- a/src/src/auths/spa.c +++ b/src/src/auths/spa.c @@ -389,7 +389,7 @@ auth_info spa_auth_info = { .options_block = &auth_spa_option_defaults, .options_len = sizeof(auth_spa_options_block), .init = auth_spa_init, -# ifdef DYNLOOKUP +# if AUTH_SPA==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/auths/tls.c b/src/src/auths/tls.c index b427d29aa..d44750098 100644 --- a/src/src/auths/tls.c +++ b/src/src/auths/tls.c @@ -108,7 +108,7 @@ auth_info tls_auth_info = { .options_block = &auth_tls_option_defaults, .options_len = sizeof(auth_tls_options_block), .init = auth_tls_init, -# ifdef DYNLOOKUP +# if AUTH_TLS==2 .dyn_magic = AUTH_MAGIC, # endif }, diff --git a/src/src/bmi_spam.c b/src/src/bmi_spam.c index 03e8defa6..e69de29bb 100644 --- a/src/src/bmi_spam.c +++ b/src/src/bmi_spam.c @@ -1,477 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Code for calling Brightmail AntiSpam. - Copyright (c) Tom Kistner 2004 - License: GPL */ -/* Copyright (c) The Exim Maintainers 2021 - 2022 */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "exim.h" -#ifdef EXPERIMENTAL_BRIGHTMAIL - -#include "bmi_spam.h" - -uschar *bmi_current_optin = NULL; - -uschar *bmi_process_message(header_line *header_list, int data_fd) { - BmiSystem *system = NULL; - BmiMessage *message = NULL; - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - const BmiVerdict *verdict = NULL; - FILE *data_file; - uschar data_buffer[4096]; - uschar localhost[] = "127.0.0.1"; - uschar *host_address; - uschar *verdicts = NULL; - int i,j; - - err = bmiInitSystem(BMI_VERSION, CS bmi_config_file, &system); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: could not initialize Brightmail system.", (int)err_loc, (int)err_type); - return NULL; - } - - err = bmiInitMessage(system, &message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: could not initialize Brightmail message.", (int)err_loc, (int)err_type); - bmiFreeSystem(system); - return NULL; - } - - /* Send IP address of sending host */ - if (sender_host_address == NULL) - host_address = localhost; - else - host_address = sender_host_address; - err = bmiProcessConnection(CS host_address, message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, CS host_address); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - /* Send envelope sender address */ - err = bmiProcessFROM(CS sender_address, message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, CS sender_address); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - /* Send envelope recipients */ - for(i=0;ibmi_optin != NULL) && (Ustrlen(r->bmi_optin) > 1)) { - debug_printf("passing bmiOptin string: %s\n", r->bmi_optin); - bmiOptinInit(&optin); - err = bmiOptinMset(optin, r->bmi_optin, ':'); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - log_write(0, LOG_PANIC|LOG_MAIN, - "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, CS r->address, CS r->bmi_optin); - if (optin != NULL) - bmiOptinFree(optin); - optin = NULL; - }; - }; - - err = bmiAccumulateTO(CS r->address, optin, message); - - if (optin != NULL) - bmiOptinFree(optin); - - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, CS r->address); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - }; - err = bmiEndTO(message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiEndTO() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - /* Send message headers */ - while (header_list != NULL) { - /* skip deleted headers */ - if (header_list->type == '*') { - header_list = header_list->next; - continue; - }; - err = bmiAccumulateHeaders(CCS header_list->text, header_list->slen, message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiAccumulateHeaders() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - header_list = header_list->next; - }; - err = bmiEndHeaders(message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiEndHeaders() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - /* Send body */ - data_file = fdopen(data_fd,"r"); - do { - j = fread(data_buffer, 1, sizeof(data_buffer), data_file); - if (j > 0) { - err = bmiAccumulateBody(CCS data_buffer, j, message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiAccumulateBody() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - }; - } while (j > 0); - err = bmiEndBody(message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiEndBody() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - - /* End message */ - err = bmiEndMessage(message); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiEndMessage() failed.", (int)err_loc, (int)err_type); - bmiFreeMessage(message); - bmiFreeSystem(system); - return NULL; - }; - - /* Get store for the verdict string. Since we are processing message data, assume that - the verdict is tainted. XXX this should use a growable-string */ - - verdicts = store_get(1, GET_TAINTED); - *verdicts = '\0'; - - for ( err = bmiAccessFirstVerdict(message, &verdict); - verdict; - err = bmiAccessNextVerdict(message, verdict, &verdict) ) { - char *verdict_str; - - err = bmiCreateStrFromVerdict(verdict,&verdict_str); - if (!store_extend(verdicts, - Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) { - /* can't allocate more store */ - return NULL; - }; - if (*verdicts != '\0') - Ustrcat(verdicts, US ":"); - Ustrcat(verdicts, US verdict_str); - bmiFreeStr(verdict_str); - }; - - DEBUG(D_receive) debug_printf("bmi verdicts: %s\n", verdicts); - - if (Ustrlen(verdicts) == 0) - return NULL; - else - return verdicts; -} - - -int bmi_get_delivery_status(uschar *base64_verdict) { - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - BmiVerdict *verdict = NULL; - int rc = 1; /* deliver by default */ - - /* always deliver when there is no verdict */ - if (base64_verdict == NULL) - return 1; - - /* create verdict from base64 string */ - err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict); - return 1; - }; - - err = bmiVerdictError(verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - /* deliver normally due to error */ - rc = 1; - } - else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) { - /* deliver normally */ - rc = 1; - } - else if (bmiVerdictAccessDestination(verdict) == NULL) { - /* do not deliver */ - rc = 0; - } - else { - /* deliver to alternate location */ - rc = 1; - }; - - bmiFreeVerdict(verdict); - return rc; -} - - -uschar *bmi_get_alt_location(uschar *base64_verdict) { - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - BmiVerdict *verdict = NULL; - uschar *rc = NULL; - - /* always deliver when there is no verdict */ - if (base64_verdict == NULL) - return NULL; - - /* create verdict from base64 string */ - err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict); - return NULL; - }; - - err = bmiVerdictError(verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - /* deliver normally due to error */ - rc = NULL; - } - else if (bmiVerdictDestinationIsDefault(verdict) == BMI_TRUE) { - /* deliver normally */ - rc = NULL; - } - else if (bmiVerdictAccessDestination(verdict) == NULL) { - /* do not deliver */ - rc = NULL; - } - else { - /* deliver to alternate location */ - rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1, GET_TAINTED); - Ustrcpy(rc, bmiVerdictAccessDestination(verdict)); - rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0'; - }; - - bmiFreeVerdict(verdict); - return rc; -} - -uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) { - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - BmiVerdict *verdict = NULL; - const BmiRecipient *recipient = NULL; - const char *verdict_str = NULL; - uschar *verdict_ptr; - uschar *verdict_buffer = NULL; - int sep = 0; - - /* return nothing if there are no verdicts available */ - if (bmi_verdicts == NULL) - return NULL; - - /* allocate room for the b64 verdict string */ - verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1, GET_TAINTED); - - /* loop through verdicts */ - verdict_ptr = bmi_verdicts; - while ((verdict_str = CCS string_nextinlist(&verdict_ptr, &sep, - verdict_buffer, - Ustrlen(bmi_verdicts)+1)) != NULL) { - - /* create verdict from base64 string */ - err = bmiCreateVerdictFromStr(verdict_str, &verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, verdict_str); - return NULL; - }; - - /* loop through rcpts for this verdict */ - for ( recipient = bmiVerdictAccessFirstRecipient(verdict); - recipient != NULL; - recipient = bmiVerdictAccessNextRecipient(verdict, recipient)) { - uschar *rcpt_local_part; - uschar *rcpt_domain; - - /* compare address against our subject */ - rcpt_local_part = US bmiRecipientAccessAddress(recipient); - rcpt_domain = Ustrchr(rcpt_local_part,'@'); - if (rcpt_domain == NULL) { - rcpt_domain = US""; - } - else { - *rcpt_domain = '\0'; - rcpt_domain++; - }; - - if ( (strcmpic(rcpt_local_part, bmi_local_part) == 0) && - (strcmpic(rcpt_domain, bmi_domain) == 0) ) { - /* found verdict */ - bmiFreeVerdict(verdict); - return US verdict_str; - }; - }; - - bmiFreeVerdict(verdict); - }; - - return NULL; -} - - -uschar *bmi_get_base64_tracker_verdict(uschar *base64_verdict) { - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - BmiVerdict *verdict = NULL; - uschar *rc = NULL; - - /* always deliver when there is no verdict */ - if (base64_verdict == NULL) - return NULL; - - /* create verdict from base64 string */ - err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict); - return NULL; - }; - - /* create old tracker string from verdict */ - err = bmiCreateOldStrFromVerdict(verdict, &rc); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateOldStrFromVerdict() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict); - return NULL; - }; - - bmiFreeVerdict(verdict); - return rc; -} - - -int bmi_check_rule(uschar *base64_verdict, uschar *option_list) { - BmiError err; - BmiErrorLocation err_loc; - BmiErrorType err_type; - BmiVerdict *verdict = NULL; - int rc = 0; - uschar *rule_num; - uschar *rule_ptr; - uschar rule_buffer[32]; - int sep = 0; - - - /* no verdict -> no rule fired */ - if (base64_verdict == NULL) - return 0; - - /* create verdict from base64 string */ - err = bmiCreateVerdictFromStr(CS base64_verdict, &verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - err_loc = bmiErrorGetLocation(err); - err_type = bmiErrorGetType(err); - log_write(0, LOG_PANIC, - "bmi error [loc %d type %d]: bmiCreateVerdictFromStr() failed. [%s]", (int)err_loc, (int)err_type, base64_verdict); - return 0; - }; - - err = bmiVerdictError(verdict); - if (bmiErrorIsFatal(err) == BMI_TRUE) { - /* error -> no rule fired */ - bmiFreeVerdict(verdict); - return 0; - } - - /* loop through numbers */ - /* option_list doesn't seem to be expanded so cannot be tainted. If it ever is we - will trap here */ - rule_ptr = option_list; - while ((rule_num = string_nextinlist(&rule_ptr, &sep, - rule_buffer, sizeof(rule_buffer)))) { - int rule_int = -1; - - /* try to translate to int */ - (void)sscanf(rule_num, "%d", &rule_int); - if (rule_int > 0) { - debug_printf("checking rule #%d\n", rule_int); - /* check if rule fired on the message */ - if (bmiVerdictRuleFired(verdict, rule_int) == BMI_TRUE) { - debug_printf("rule #%d fired\n", rule_int); - rc = 1; - break; - }; - }; - }; - - bmiFreeVerdict(verdict); - return rc; -}; - -#endif diff --git a/src/src/bmi_spam.h b/src/src/bmi_spam.h index bb1c859a9..e69de29bb 100644 --- a/src/src/bmi_spam.h +++ b/src/src/bmi_spam.h @@ -1,23 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Code for calling Brightmail AntiSpam. - Copyright (c) Tom Kistner 2004 - License: GPL */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifdef EXPERIMENTAL_BRIGHTMAIL - -#include - -extern uschar *bmi_process_message(header_line *, int); -extern uschar *bmi_get_base64_verdict(uschar *, uschar *); -extern uschar *bmi_get_base64_tracker_verdict(uschar *); -extern int bmi_get_delivery_status(uschar *); -extern uschar *bmi_get_alt_location(uschar *); -extern int bmi_check_rule(uschar *,uschar *); - -extern uschar *bmi_current_optin; - -#endif diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index ebf67ad57..05bdcd6d3 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -102,7 +102,6 @@ Do not put spaces between # and the 'define'. #define LOOKUP_DBM #define LOOKUP_DNSDB #define LOOKUP_DSEARCH -#define LOOKUP_IBASE #define LOOKUP_JSON #define LOOKUP_LDAP #define LOOKUP_LMDB @@ -113,6 +112,7 @@ Do not put spaces between # and the 'define'. #define LOOKUP_ORACLE #define LOOKUP_PASSWD #define LOOKUP_PGSQL +#define LOOKUP_PSL #define LOOKUP_REDIS #define LOOKUP_SQLITE #define LOOKUP_TESTDB @@ -217,7 +217,6 @@ Do not put spaces between # and the 'define'. /* EXPERIMENTAL features */ #define EXPERIMENTAL_ARC -#define EXPERIMENTAL_BRIGHTMAIL #define EXPERIMENTAL_DCC #define EXPERIMENTAL_DSN_INFO #define EXPERIMENTAL_NMH diff --git a/src/src/configure.default b/src/src/configure.default index 633c6539e..c05ed182e 100644 --- a/src/src/configure.default +++ b/src/src/configure.default @@ -260,21 +260,6 @@ host_lookup = * dns_dnssec_ok = 1 -# The settings below cause Exim to make RFC 1413 (ident) callbacks -# for all incoming SMTP calls. You can limit the hosts to which these -# calls are made, and/or change the timeout that is used. If you set -# the timeout to zero, all RFC 1413 calls are disabled. RFC 1413 calls -# are cheap and can provide useful information for tracing problem -# messages, but some hosts and firewalls have problems with them. -# This can result in a timeout instead of an immediate refused -# connection, leading to delays on starting up SMTP sessions. -# (The default was reduced from 30s to 5s for release 4.61. and to -# disabled for release 4.86) -# -#rfc1413_hosts = * -#rfc1413_query_timeout = 5s - - # Enable an efficiency feature. We advertise the feature; clients # may request to use it. For multi-recipient mails we then can # reject or accept per-user after the message is received. diff --git a/src/src/daemon.c b/src/src/daemon.c index a31ef1eb5..824fe0187 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -479,20 +479,9 @@ if (pid == 0) signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); - /* Attempt to get an id from the sending machine via the RFC 1413 - protocol. We do this in the sub-process in order not to hold up the - main process if there is any delay. Then set up the fullhost information - in case there is no HELO/EHLO. + /* Set up the fullhost information in case there is no HELO/EHLO. */ - If debugging is enabled only for the daemon, we must turn if off while - finding the id, but turn it on again afterwards so that information about the - incoming connection is output. */ - - if (f.debug_daemon) debug_selector = 0; - verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); - debug_selector = save_debug_selector; - DEBUG(D_any) debug_printf("Process %d is handling incoming connection from %s\n", (int)getpid(), sender_fullhost); diff --git a/src/src/deliver.c b/src/src/deliver.c index 21a610859..497c62e81 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -206,13 +206,6 @@ router_var = addr->prop.variables; deliver_domain = addr->domain; self_hostname = addr->self_hostname; -#ifdef EXPERIMENTAL_BRIGHTMAIL -bmi_deliver = 1; /* deliver by default */ -bmi_alt_location = NULL; -bmi_base64_verdict = NULL; -bmi_base64_tracker_verdict = NULL; -#endif - /* If there's only one address we can set everything. */ if (!addr->next) @@ -269,17 +262,6 @@ if (!addr->next) } } -#ifdef EXPERIMENTAL_BRIGHTMAIL - /* Set expansion variables related to Brightmail AntiSpam */ - bmi_base64_verdict = bmi_get_base64_verdict(deliver_localpart_orig, deliver_domain_orig); - bmi_base64_tracker_verdict = bmi_get_base64_tracker_verdict(bmi_base64_verdict); - /* get message delivery status (0 - don't deliver | 1 - deliver) */ - bmi_deliver = bmi_get_delivery_status(bmi_base64_verdict); - /* if message is to be delivered, get eventual alternate location */ - if (bmi_deliver == 1) - bmi_alt_location = bmi_get_alt_location(bmi_base64_verdict); -#endif - } /* For multiple addresses, don't set local part, and leave the domain and @@ -1059,7 +1041,7 @@ else s = addr->domain; #ifdef SUPPORT_I18N if (testflag(addr, af_utf8_downcvt)) - s = string_localpart_utf8_to_alabel(s, NULL); + s = string_domain_utf8_to_alabel(US s, NULL); #endif g = string_cat(g, s); } @@ -2656,10 +2638,12 @@ if (addr->special_action == SPECIAL_WARN) /* Check transport for the given concurrency limit. Return TRUE if over the limit (or an expansion failure), else FALSE and if there was a limit, -the key for the hints database used for the concurrency count. */ +the key for the hints database used for the concurrency count +and a string for observability. */ static BOOL -tpt_parallel_check(transport_instance * tp, address_item * addr, uschar ** key) +tpt_parallel_check(const transport_instance * tp, address_item * addr, + uschar ** key, uschar ** state) { const uschar * trname = tp->drinst.name; unsigned max_parallel; @@ -2679,22 +2663,22 @@ if (expand_string_message) if (max_parallel > 0) { uschar * serialize_key = string_sprintf("tpt-serialize-%s", trname); - if (!enq_start(serialize_key, max_parallel)) + unsigned running; + if (!(running = enq_start(serialize_key, max_parallel))) { - address_item * next; DEBUG(D_transport) debug_printf("skipping tpt %s because concurrency limit %u reached\n", trname, max_parallel); do { - next = addr->next; addr->message = US"concurrency limit reached for transport"; addr->basic_errno = ERRNO_TRETRY; post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_TRANSPORT, 0); - } while ((addr = next)); + } while ((addr = addr->next)); return TRUE; } *key = serialize_key; + *state = string_sprintf(" (%u/max_parallel:%u)", running, max_parallel); } return FALSE; } @@ -2731,7 +2715,7 @@ while (addr_local) int logflags = LOG_MAIN; int logchar = f.dont_deliver? '*' : '='; transport_instance * tp; - uschar * serialize_key = NULL; + uschar * serialize_key = NULL, * tpt_dummy; const uschar * trname; /* Pick the first undelivered address off the chain */ @@ -3018,7 +3002,7 @@ while (addr_local) We use a hints DB entry, incremented here and decremented after the transport (and any shadow transport) completes. */ - if (tpt_parallel_check(tp, addr, &serialize_key)) + if (tpt_parallel_check(tp, addr, &serialize_key, &tpt_dummy)) { if (expand_string_message) { @@ -3996,20 +3980,22 @@ can be created, or when waiting for the last ones to complete. It must wait for the completion of one subprocess, empty the control block slot, and return a pointer to the address chain. -Arguments: none -Returns: pointer to the chain of addresses handled by the process; - NULL if no subprocess found - this is an unexpected error +Arguments: + reason: observability: reason for call + +Returns: pointer to the chain of addresses handled by the process; + NULL if no subprocess found - this is an unexpected error */ static address_item * -par_wait(void) +par_wait(const uschar * reason) { int poffset, status; address_item * addrlist; pid_t pid; set_process_info("delivering %s: waiting for a remote delivery subprocess " - "to finish", message_id); + "to finish (%s)", message_id, reason); /* Loop until either a subprocess completes, or there are no subprocesses in existence - in which case give an error return. We cannot proceed just by @@ -4256,16 +4242,17 @@ log and proceed as if all done. Arguments: max maximum number of subprocesses to leave running fallback TRUE if processing fallback hosts + reason observability: reason for call Returns: nothing */ static void -par_reduce(int max, BOOL fallback) +par_reduce(int max, BOOL fallback, const uschar * reason) { while (parcount > max) { - address_item * doneaddr = par_wait(); + address_item * doneaddr = par_wait(reason); if (!doneaddr) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -4357,6 +4344,7 @@ static BOOL do_remote_deliveries(BOOL fallback) { int parmax, poffset; +const uschar * plimit_reason = US"remote_max_parallel"; parcount = 0; /* Number of executing subprocesses */ @@ -4364,7 +4352,8 @@ parcount = 0; /* Number of executing subprocesses */ We use a local variable (parmax) to hold the maximum number of processes; this gets reduced from remote_max_parallel if we can't create enough pipes. */ -if (continue_transport) remote_max_parallel = 1; +if (continue_transport) + { remote_max_parallel = 1; plimit_reason = US"continue_transport"; } parmax = remote_max_parallel; /* If the data for keeping a list of processes hasn't yet been @@ -4388,12 +4377,12 @@ for (int delivery_count = 0; addr_remote; delivery_count++) uid_t uid; gid_t gid; int pfd[2]; - int address_count = 1, address_count_max; + unsigned address_count = 1, address_count_max; BOOL pipe_done = FALSE, multi_domain, use_initgroups; transport_instance * tp; address_item ** anchor = &addr_remote; address_item * addr = addr_remote, * last = addr, * next; - uschar * serialize_key = NULL, * panicmsg; + uschar * serialize_key = NULL, * tpt_parallel_level, * panicmsg; /* Pull the first address right off the list. */ @@ -4457,7 +4446,7 @@ So look out for the place it gets used. unlimited, which is forced for the MUA wrapper case and if the value could vary depending on the messages. For those, we only split (below) by (tpt,dest,erraddr,hdrs) and rely on the - transport splitting further by max_rcp. So we potentially lose some + transport splitting further by max_rcpt. So we potentially lose some parallellism. */ GET_OPTION("max_rcpt"); @@ -4573,7 +4562,8 @@ Does that also apply to address_data? last = next; address_count++; } - else anchor = &(next->next); + else + anchor = &next->next; deliver_set_expansions(NULL); } @@ -4591,7 +4581,8 @@ Does that also apply to address_data? The hints DB entry is decremented in par_reduce(), when we reap the transport process. */ - if (tpt_parallel_check(tp, addr, &serialize_key)) + tpt_parallel_level = US""; + if (tpt_parallel_check(tp, addr, &serialize_key, &tpt_parallel_level)) if ((panicmsg = expand_string_message)) goto panic_continue; else @@ -4788,9 +4779,12 @@ parmax * tpt-max is exceeded? */ while (!pipe_done) { - if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0) pipe_done = TRUE; - else if (parcount > 0) parmax = parcount; - else break; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0) + pipe_done = TRUE; + else if (parcount > 0) + { parmax = parcount; plimit_reason = US"fildesc limit"; } + else + break; /* We need to make the reading end of the pipe non-blocking. There are two different options for this. Exim is cunningly (I hope!) coded so @@ -4811,7 +4805,7 @@ all pipes, so I do not see a reason to use non-blocking IO here to finish. If we ran out of file descriptors, parmax will have been reduced from its initial value of remote_max_parallel. */ - par_reduce(parmax - 1, fallback); + par_reduce(parmax - 1, fallback, plimit_reason); } /* If we failed to create a pipe and there were no processes to wait @@ -4956,7 +4950,9 @@ do_remote_deliveries par_reduce par_wait par_read_pipe of bytes written. */ (void)close(pfd[pipe_read]); - set_process_info("delivering %s using %s", message_id, tp->drinst.name); + set_process_info("delivering %s (%u addr%s) using %s%s", + message_id, address_count, address_count>1?"s":"", + tp->drinst.name, tpt_parallel_level); debug_print_string(tp->debug_string); { @@ -5364,7 +5360,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe if (continue_transport) { - par_reduce(0, fallback); + par_reduce(0, fallback, US"continue_transport wait-complete"); if (!*continue_next_id && continue_wait_db) { dbfn_close_multi(continue_wait_db); continue_wait_db = NULL; } @@ -5393,7 +5389,7 @@ panic_continue: /* Reached the end of the list of addresses. Wait for all the subprocesses that are still running and post-process their addresses. */ -par_reduce(0, fallback); +par_reduce(0, fallback, US"delivery wait-all-complete"); return TRUE; } diff --git a/src/src/dns.c b/src/src/dns.c index 4c8f1dd14..dd754f6c9 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -841,15 +841,14 @@ if ((rc = dns_fail_cache_hit(name, type)) > 0) #ifdef SUPPORT_I18N /* Convert all names to a-label form before doing lookup */ { - uschar * alabel; + const uschar * alabel; uschar * errstr = NULL; DEBUG(D_dns) if (string_is_utf8(name)) debug_printf_indent("convert utf8 '%s' to alabel for for lookup\n", name); if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr) { - DEBUG(D_dns) - debug_printf_indent("DNS name '%s' utf8 conversion to alabel failed: %s\n", name, - errstr); + DEBUG(D_dns) debug_printf_indent( + "DNS name '%s' utf8 conversion to alabel failed: %s\n", name, errstr); f.host_find_failed_syntax = TRUE; return DNS_NOMATCH; } diff --git a/src/src/drtables.c b/src/src/drtables.c index adbf7d539..5993b5c29 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -31,200 +31,52 @@ transport_info * transports_available = NULL; #ifndef MACRO_PREDEF -gstring * -auth_show_supported(gstring * g) +static gstring * +dr_show_list(gstring * g, const uschar ** list, const uschar * label, + const uschar * class) { -uschar * b = US"" /* static-build authenticatornames */ -#if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5!=2 - " cram_md5" -#endif -#if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL!=2 - " cyrus_sasl" -#endif -#if defined(AUTH_DOVECOT) && AUTH_DOVECOT!=2 - " dovecot" -#endif -#if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL!=2 - " external" -#endif -#if defined(AUTH_GSASL) && AUTH_GSASL!=2 - " gsasl" -#endif -#if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI!=2 - " heimdal_gssapi" -#endif -#if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT!=2 - " plaintext" -#endif -#if defined(AUTH_SPA) && AUTH_SPA!=2 - " spa" -#endif -#if defined(AUTH_TLS) && AUTH_TLS!=2 - " tls" -#endif - ; - -uschar * d = US"" /* dynamic-module authenticator names */ -#if defined(AUTH_CRAM_MD5) && AUTH_CRAM_MD5==2 - " cram_md5" -#endif -#if defined(AUTH_CYRUS_SASL) && AUTH_CYRUS_SASL==2 - " cyrus_sasl" -#endif -#if defined(AUTH_DOVECOT) && AUTH_DOVECOT==2 - " dovecot" -#endif -#if defined(AUTH_EXTERNAL) && AUTH_EXTERNAL==2 - " external" -#endif -#if defined(AUTH_GSASL) && AUTH_GSASL==2 - " gsasl" -#endif -#if defined(AUTH_HEIMDAL_GSSAPI) && AUTH_HEIMDAL_GSSAPI==2 - " heimdal_gssapi" -#endif -#if defined(AUTH_PLAINTEXT) && AUTH_PLAINTEXT==2 - " plaintext" -#endif -#if defined(AUTH_SPA) && AUTH_SPA==2 - " spa" -#endif -#if defined(AUTH_TLS) && AUTH_TLS==2 - " tls" -#endif - ; +if (*list) + { + const uschar ** ele = list; + g = string_fmt_append(g, "%s (%s): ", class, label); + while (*ele) ele++; + while (--ele >= list) g = string_fmt_append(g, " %s", *ele); + g = string_catn(g, US"\n", 1); + } +return g; +} -if (*b) g = string_fmt_append(g, "Authenticators (built-in):%s\n", b); -if (*d) g = string_fmt_append(g, "Authenticators (dynamic): %s\n", d); +static gstring * +dr_show_supported(gstring * g, + const uschar ** statics, const uschar ** dynamics, const uschar * class) +{ +g = dr_show_list(g, statics, US"built-in", class); +g = dr_show_list(g, dynamics, US"dynamic", class); return g; } gstring * -route_show_supported(gstring * g) +auth_show_supported(gstring * g) { -uschar * b = US"" /* static-build router names */ -#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2 - " accept" -#endif -#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2 - " dnslookup" -#endif -# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2 - " ipliteral" -#endif -#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2 - " iplookup" -#endif -#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2 - " manualroute" -#endif -#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2 - " redirect" -#endif -#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2 - " queryprogram" -#endif - ; - -uschar * d = US"" /* dynamic-module router names */ -#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2 - " accept" -#endif -#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2 - " dnslookup" -#endif -# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2 - " ipliteral" -#endif -#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2 - " iplookup" -#endif -#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2 - " manualroute" -#endif -#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2 - " redirect" -#endif -#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2 - " queryprogram" -#endif - ; +return dr_show_supported(g, avail_static_auths, avail_dynamic_auths, + US"Authenticators"); +} -if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b); -if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d); -return g; +gstring * +route_show_supported(gstring * g) +{ +return dr_show_supported(g, avail_static_routers, avail_dynamic_routers, + US"Routers"); } gstring * transport_show_supported(gstring * g) { -uschar * b = US"" /* static-build transportnames */ -#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2 - " appendfile" -# ifdef SUPPORT_MAILDIR - "/maildir" -# endif -# ifdef SUPPORT_MAILSTORE - "/mailstore" -# endif -# ifdef SUPPORT_MBX - "/mbx" -# endif -#endif -#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2 - " autoreply" -#endif -#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2 - " lmtp" -#endif -#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2 - " pipe" -#endif -#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2 - " queuefile" -#endif -#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2 - " smtp" -#endif - ; - -uschar * d = US"" /* dynamic-module transportnames */ -#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2 - " appendfile" -# ifdef SUPPORT_MAILDIR - "/maildir" -# endif -# ifdef SUPPORT_MAILSTORE - "/mailstore" -# endif -# ifdef SUPPORT_MBX - "/mbx" -# endif -#endif -#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2 - " autoreply" -#endif -#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2 - " lmtp" -#endif -#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2 - " pipe" -#endif -#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2 - " queuefile" -#endif -#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2 - " smtp" -#endif - ; - -if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b); -if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d); -return g; +return dr_show_supported(g, avail_static_transports, avail_dynamic_transports, + US"Transports"); } - static void add_lookup_to_tree(lookup_info * li) { @@ -271,77 +123,6 @@ return li; -/* These need to be at file level for old versions of gcc (2.95.2 reported), -which give parse errors on an extern in function scope. Each entry needs -to also be invoked in init_lookup_list() below */ - -#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 -extern lookup_module_info cdb_lookup_module_info; -#endif -#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 -extern lookup_module_info dbmdb_lookup_module_info; -#endif -#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 -extern lookup_module_info dnsdb_lookup_module_info; -#endif -#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 -extern lookup_module_info dsearch_lookup_module_info; -#endif -#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 -extern lookup_module_info ibase_lookup_module_info; -#endif -#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 -extern lookup_module_info json_lookup_module_info; -#endif -#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 -extern lookup_module_info ldap_lookup_module_info; -#endif -#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 -extern lookup_module_info lsearch_lookup_module_info; -#endif -#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 -extern lookup_module_info mysql_lookup_module_info; -#endif -#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 -extern lookup_module_info nis_lookup_module_info; -#endif -#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 -extern lookup_module_info nisplus_lookup_module_info; -#endif -#if defined(EXPERIMENTAL_NMH) && EXPERIMENTAL_NMH!=2 -extern lookup_module_info nmh_lookup_module_info; -#endif -#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 -extern lookup_module_info oracle_lookup_module_info; -#endif -#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 -extern lookup_module_info passwd_lookup_module_info; -#endif -#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 -extern lookup_module_info pgsql_lookup_module_info; -#endif -#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 -extern lookup_module_info redis_lookup_module_info; -#endif -#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2 -extern lookup_module_info lmdb_lookup_module_info; -#endif -#if defined(EXIM_HAVE_SPF) -extern lookup_module_info spf_lookup_module_info; /* see below */ -#endif -#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 -extern lookup_module_info sqlite_lookup_module_info; -#endif -#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 -extern lookup_module_info testdb_lookup_module_info; -#endif -#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 -extern lookup_module_info whoson_lookup_module_info; -#endif - -extern lookup_module_info readsock_lookup_module_info; - - #ifdef LOOKUP_MODULE_DIR static void * mod_open(const uschar * name, const uschar * class, uschar ** errstr) @@ -381,13 +162,13 @@ static BOOL lookup_mod_load(const uschar * name, uschar ** errstr) { void * dl; -struct lookup_module_info * info; +lookup_module_info * info; const char * errormsg; if (!(dl = mod_open(name, US"lookup", errstr))) return FALSE; -info = (struct lookup_module_info *) dlsym(dl, "_lookup_module_info"); +info = (lookup_module_info *) dlsym(dl, "_lookup_module_info"); if ((errormsg = dlerror())) { EARLY_DEBUG(D_any, "%s does not appear to be a lookup module (%s)\n", name, errormsg); @@ -426,6 +207,45 @@ return TRUE; #endif /*LOOKUP_MODULE_DIR*/ +/* Look at all the lookup module files and add a name from each lookup type */ + +gstring * +lookup_dynamic_supported(gstring * g) +{ +#ifdef LOOKUP_MODULE_DIR +DIR * dd; +const pcre2_code * regex_islookupmod = regex_must_compile( + US"^([a-z0-9]+)_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE); + +if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) + g = string_cat(g, US"FAIL exim_opendir"); +else + for (struct dirent * ent; ent = readdir(dd); ) + { + void * dl; + uschar * errstr; + + if ( regex_match_and_setup(regex_islookupmod, US ent->d_name, 0, 0) + && (dl = mod_open(expand_nstring[1], US"lookup", &errstr)) + ) + { + lookup_module_info * lmi= + (lookup_module_info *) dlsym(dl, "_lookup_module_info"); + + if ( ! dlerror() + && lmi->magic == LOOKUP_MODULE_INFO_MAGIC + ) + for (lookup_info ** lip = lmi->lookups; + lip < lmi->lookups + lmi->lookupcount; lip++) + g = string_fmt_append(g, " %s", (*lip)->name); + + dlclose(dl); + } + } +#endif /*!LOOKUP_MODULE_DIR*/ +return g; +} + misc_module_info * misc_module_list = NULL; @@ -612,99 +432,8 @@ if (lookup_list_init_done) return; lookup_list_init_done = TRUE; -#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2 -addlookupmodule(&cdb_lookup_module_info); -#endif - -#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2 -addlookupmodule(&dbmdb_lookup_module_info); -#endif - -#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2 -addlookupmodule(&dnsdb_lookup_module_info); -#endif - -#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2 -addlookupmodule(&dsearch_lookup_module_info); -#endif - -#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2 -addlookupmodule(&ibase_lookup_module_info); -#endif - -#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2 -addlookupmodule(&ldap_lookup_module_info); -#endif - -#if defined(LOOKUP_JSON) && LOOKUP_JSON!=2 -addlookupmodule(&json_lookup_module_info); -#endif - -#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2 -addlookupmodule(&lsearch_lookup_module_info); -#endif - -#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2 -addlookupmodule(&mysql_lookup_module_info); -#endif - -#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2 -addlookupmodule(&nis_lookup_module_info); -#endif - -#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2 -addlookupmodule(&nisplus_lookup_module_info); -#endif - -#if defined(EXPERIMENTAL_NMH) && EXPERIMENTAL_NMH!=2 -addlookupmodule(&nmh_lookup_module_info); -#endif - -#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2 -addlookupmodule(&oracle_lookup_module_info); -#endif - -#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2 -addlookupmodule(&passwd_lookup_module_info); -#endif - -#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2 -addlookupmodule(&pgsql_lookup_module_info); -#endif - -#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2 -addlookupmodule(&redis_lookup_module_info); -#endif - -#if defined(LOOKUP_LMDB) && LOOKUP_LMDB!=2 -addlookupmodule(&lmdb_lookup_module_info); -#endif - -#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2 -addlookupmodule(&sqlite_lookup_module_info); -#endif - -#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2 -addlookupmodule(&testdb_lookup_module_info); -#endif - -#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2 -addlookupmodule(&whoson_lookup_module_info); -#endif - -/* This is provided by the spf "misc" module, and the lookup aspect is always -linked statically whether or not the "misc" module (and hence libspf2) is -dynamic-load. */ - -#ifdef EXIM_HAVE_SPF -addlookupmodule(&spf_lookup_module_info); -#endif - -/* This is a custom expansion, and not available as either -a list-syntax lookup or a lookup expansion. However, it is -implemented by a lookup module. */ - -addlookupmodule(&readsock_lookup_module_info); +for (lookup_module_info ** avi = avail_static_lookups; *avi; avi++) + addlookupmodule(*avi); DEBUG(D_lookup) debug_printf_indent("Total %d built-in lookups\n", lookup_list_count); @@ -727,10 +456,7 @@ else EARLY_DEBUG(D_lookup, "Loading lookup modules from %s\n", LOOKUP_MODULE_DIR); while ((ent = readdir(dd))) - { - char * name = ent->d_name; - int len = (int)strlen(name); - if (regex_match_and_setup(regex_islookupmod, US name, 0, 0)) + if (regex_match_and_setup(regex_islookupmod, US ent->d_name, 0, 0)) { uschar * errstr; if (lookup_mod_load(expand_nstring[1], &errstr)) @@ -741,7 +467,6 @@ else log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr); } } - } closedir(dd); } diff --git a/src/src/enq.c b/src/src/enq.c index 842f2d6ba..8129b3b2b 100644 --- a/src/src/enq.c +++ b/src/src/enq.c @@ -23,24 +23,24 @@ connections. It is also called when ETRN is listed for serialization. We open the misc database and look for a record, which implies an existing connection or ETRN run. If increasing the count would take us past the given limit -value return FALSE. If not, bump it and return TRUE. If not found, create +value return FALSE. If not, bump it and return the new count. If not found, create one with value 1 and return TRUE. Arguments: key string on which to serialize lim parallelism limit -Returns: TRUE if OK to proceed; FALSE otherwise +Returns: >0 if OK to proceed; 0 otherwise */ -BOOL -enq_start(uschar *key, unsigned lim) +unsigned +enq_start(uschar * key, unsigned lim) { const dbdata_serialize * serial_record; dbdata_serialize new_record; open_db dbblock; -open_db *dbm_file; +open_db * dbm_file; DEBUG(D_transport) debug_printf("check serialized: %s\n", key); @@ -60,7 +60,7 @@ if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60) dbfn_close(dbm_file); DEBUG(D_transport) debug_printf("outstanding serialization record for %s\n", key); - return FALSE; + return 0; } new_record.count = serial_record->count + 1; } @@ -73,7 +73,7 @@ DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n", key, new_record.count); dbfn_write(dbm_file, key, &new_record, (int)sizeof(dbdata_serialize)); dbfn_close(dbm_file); -return TRUE; +return new_record.count; } diff --git a/src/src/exim.c b/src/src/exim.c index b1d77576f..88ed33a8e 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1074,153 +1074,12 @@ lookup_show_supported(gstring * g) { gstring * b = NULL, * d = NULL; -#ifdef LOOKUP_LSEARCH -# if LOOKUP_LSEARCH!=2 - b = string_cat(b, US" lsearch wildlsearch nwildlsearch iplsearch"); -# else - d = string_cat(d, US" lsearch wildlsearch nwildlsearch iplsearch"); -# endif -#endif -#ifdef LOOKUP_CDB -# if LOOKUP_CDB!=2 - b = string_cat(b, US" cdb"); -# else - d = string_cat(d, US" cdb"); -# endif -#endif -#ifdef LOOKUP_DBM -# if LOOKUP_DBM!=2 - b = string_cat(b, US" dbm dbmjz dbmnz"); -# else - d = string_cat(d, US" dbm dbmjz dbmnz"); -# endif -#endif -#ifdef LOOKUP_DNSDB -# if LOOKUP_DNSDB!=2 - b = string_cat(b, US" dnsdb"); -# else - d = string_cat(d, US" dnsdb"); -# endif -#endif -#ifdef LOOKUP_DSEARCH -# if LOOKUP_DSEARCH!=2 - b = string_cat(b, US" dsearch"); -# else - d = string_cat(d, US" dsearch"); -# endif -#endif -#ifdef LOOKUP_IBASE -# if LOOKUP_IBASE!=2 - b = string_cat(b, US" ibase"); -# else - d = string_cat(d, US" ibase"); -# endif -#endif -#ifdef LOOKUP_JSON -# if LOOKUP_JSON!=2 - b = string_cat(b, US" json"); -# else - d = string_cat(d, US" json"); -# endif -#endif -#ifdef LOOKUP_LDAP -# if LOOKUP_LDAP!=2 - b = string_cat(b, US" ldap ldapdn ldapm"); -# else - d = string_cat(d, US" ldap ldapdn ldapm"); -# endif -#endif -#ifdef LOOKUP_LMDB -# if LOOKUP_LMDB!=2 - b = string_cat(b, US" lmdb"); -# else - d = string_cat(d, US" lmdb"); -# endif -#endif -#ifdef LOOKUP_MYSQL -# if LOOKUP_MYSQL!=2 - b = string_cat(b, US" mysql"); -# else - d = string_cat(d, US" mysql"); -# endif -#endif -#ifdef LOOKUP_NIS -# if LOOKUP_NIS!=2 - b = string_cat(b, US" nis nis0"); -# else - d = string_cat(d, US" nis nis0"); -# endif -#endif -#ifdef LOOKUP_NISPLUS -# if LOOKUP_NISPLUS!=2 - b = string_cat(b, US" nisplus"); -# else - d = string_cat(d, US" nisplus"); -# endif -#endif -#ifdef EXPERIMENTAL_NMH -# if EXPERIMENTAL_NMH!=2 - b = string_cat(b, US" nmh"); -# else - d = string_cat(d, US" nmh"); -# endif -#endif -#ifdef LOOKUP_ORACLE -# if LOOKUP_ORACLE!=2 - b = string_cat(b, US" oracle"); -# else - d = string_cat(d, US" oracle"); -# endif -#endif -#ifdef LOOKUP_PASSWD -# if LOOKUP_PASSWD!=2 - b = string_cat(b, US" passwd"); -# else - d = string_cat(d, US" passwd"); -# endif -#endif -#ifdef LOOKUP_PGSQL -# if LOOKUP_PGSQL!=2 - b = string_cat(b, US" pgsql"); -# else - d = string_cat(d, US" pgsql"); -# endif -#endif -#ifdef LOOKUP_REDIS -# if LOOKUP_REDIS!=2 - b = string_cat(b, US" redis"); -# else - d = string_cat(d, US" redis"); -# endif -#endif -#ifdef EXIM_HAVE_SPF -# if EXIM_HAVE_SPF !=2 - b = string_cat(b, US" spf"); -# else - d = string_cat(d, US" spf"); -# endif -#endif -#ifdef LOOKUP_SQLITE -# if LOOKUP_SQLITE!=2 - b = string_cat(b, US" sqlite"); -# else - d = string_cat(d, US" sqlite"); -# endif -#endif -#ifdef LOOKUP_TESTDB -# if LOOKUP_TESTDB!=2 - b = string_cat(b, US" testdb"); -# else - d = string_cat(d, US" testdb"); -# endif -#endif -#ifdef LOOKUP_WHOSON -# if LOOKUP_WHOSON!=2 - b = string_cat(b, US" whoson"); -# else - d = string_cat(d, US" whoson"); -# endif -#endif +for (lookup_module_info ** lmip = avail_static_lookups; *lmip; lmip++) + for (lookup_info ** lip = (*lmip)->lookups; + lip < (*lmip)->lookups + (*lmip)->lookupcount; lip++) + b = string_fmt_append(b, " %s", (*lip)->name); + +d = lookup_dynamic_supported(d); if (b) g = string_fmt_append(g, "Lookups (built-in):%Y\n", b); if (d) g = string_fmt_append(g, "Lookups (dynamic): %Y\n", d); @@ -1369,9 +1228,6 @@ g = string_cat(g, US"Support for:"); #ifdef EXPERIMENTAL_ARC g = string_cat(g, US" Experimental_ARC"); #endif -#ifdef EXPERIMENTAL_BRIGHTMAIL - g = string_cat(g, US" Experimental_Brightmail"); -#endif #ifdef EXPERIMENTAL_DCC g = string_cat(g, US" Experimental_DCC"); #endif @@ -1965,7 +1821,6 @@ BOOL arg_queue_only = FALSE; BOOL bi_option = FALSE; BOOL checking = FALSE; BOOL count_queue = FALSE; -BOOL expansion_test = FALSE; BOOL extract_recipients = FALSE; BOOL flag_G = FALSE; BOOL flag_n = FALSE; @@ -2483,7 +2338,7 @@ on the second character (the one after '-'), to save some effort. */ -bem: Ditto, but read a message from a file first */ case 'e': - expansion_test = checking = TRUE; + f.expansion_test = checking = TRUE; if (*argrest == 'm') { if (++i >= argc) { badarg = TRUE; break; } @@ -2914,14 +2769,9 @@ on the second character (the one after '-'), to save some effort. */ case 'd': - /* -dropcr: Set this option. Now a no-op, retained for compatibility only. */ - - if (Ustrcmp(argrest, "ropcr") == 0) - /* drop_cr = TRUE */ ; - /* -dp: Set up a debug pretrigger buffer with given size. */ - else if (Ustrcmp(argrest, "p") == 0) + if (Ustrcmp(argrest, "p") == 0) if (++i >= argc) badarg = TRUE; else @@ -4070,9 +3920,9 @@ if ( (smtp_input || extract_recipients || recipients_arg < argc) || smtp_input && (sender_address || filter_test != FTEST_NONE || extract_recipients) || deliver_selectstring && !qrunners - || msg_action == MSG_LOAD && (!expansion_test || expansion_test_message) + || msg_action == MSG_LOAD && (!f.expansion_test || expansion_test_message) || atrn_mode - && ( f.daemon_listen || expansion_test || filter_test != FTEST_NONE + && ( f.daemon_listen || f.expansion_test || filter_test != FTEST_NONE || checking /* || bi_option || info_stdout || receiving_message || malware_test_file || list_queue || list_config || list_options || version_printed || msg_action_arg > 0 || qrunners @@ -4230,7 +4080,7 @@ if (( /* EITHER */ real_uid != root_uid && /* Not root, and */ !f.running_in_test_harness /* Not fudged */ ) || /* OR */ - expansion_test /* expansion testing */ + f.expansion_test /* expansion testing */ || /* OR */ filter_test != FTEST_NONE) /* Filter testing */ { @@ -4960,7 +4810,7 @@ needed in transports so we lost the optimisation. */ /* -be can add macro definitions, needing to link to the macro structure chain. Otherwise, make the memory used for config data readonly. */ - if (!expansion_test) + if (!f.expansion_test) store_writeprotect(POOL_CONFIG); #ifdef MEASURE_TIMING @@ -5498,7 +5348,7 @@ from stdin if there aren't any. If -Mset was specified, load the message so that its variables can be used, but restrict this facility to admin users. Otherwise, if -bem was used, read a message from stdin. */ -if (expansion_test) +if (f.expansion_test) { set_process_info("expansion-test"); dns_init(FALSE, FALSE, FALSE); @@ -5615,9 +5465,7 @@ if (raw_active_hostname) /* Handle host checking: this facility mocks up an incoming SMTP call from a given IP address so that the blocking and relay configuration can be tested. Unless a sender_ident was set by -oMt, we discard it (the default is the -caller's login name). An RFC 1413 call is made only if we are running in the -test harness and an incoming interface and both ports are specified, because -there is no TCP/IP call to find the ident for. */ +caller's login name). */ if (host_checking) { @@ -5625,12 +5473,7 @@ if (host_checking) int size; if (!sender_ident_set) - { sender_ident = NULL; - if (f.running_in_test_harness && sender_host_port - && interface_address && interface_port) - verify_get_ident(test_harness_identd_port); - } /* In case the given address is a non-canonical IPv6 address, canonicalize it. Use the compressed form for IPv6. */ @@ -5653,7 +5496,6 @@ if (host_checking) debug_file = stderr; debug_fd = fileno(debug_file); dprintf(smtp_out_fd, "\n**** SMTP testing session as if from host %s\n" - "**** but without any ident (RFC 1413) callback.\n" "**** This is not for real!\n\n", sender_host_address); @@ -5765,14 +5607,12 @@ sendmail error modes other than -oem ever actually used? Later: yes.) */ if (!smtp_input) error_handling = arg_error_handling; /* If this is an inetd call, ensure that stderr is closed to prevent panic -logging being sent down the socket and make an identd call to get the -sender_ident. */ +logging being sent down the socket. */ else if (f.is_inetd && !atrn_mode) { (void)fclose(stderr); exim_nullstd(); /* Re-open to /dev/null */ - verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); set_process_info("handling incoming connection from %s via inetd", sender_fullhost); diff --git a/src/src/exim.h b/src/src/exim.h index 8109c2a7c..fa56f2c2c 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -156,8 +156,6 @@ configuration file. We also use this for some other short strings, such as queue names. Also TLS ciphersuite name (no real known limit since the protocols use integers, but max seen in reality is 45 octets). - -RFC 1413 gives us the 512 limit on IDENT protocol userids. */ #define EXIM_EMAILADDR_MAX 256 @@ -541,9 +539,6 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #endif #include "osfunctions.h" -#ifdef EXPERIMENTAL_BRIGHTMAIL -# include "bmi_spam.h" -#endif #if defined(SUPPORT_SPF) || defined(EXPERIMENTAL_SPF_PERL) # include "miscmods/spf.h" # include "miscmods/spf_api.h" diff --git a/src/src/expand.c b/src/src/expand.c index e852c27c7..554d68ba6 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -474,12 +474,6 @@ static var_entry var_table[] = { { "authentication_failed",vtype_int, &authentication_failed }, #ifdef WITH_CONTENT_SCAN { "av_failed", vtype_int, &av_failed }, -#endif -#ifdef EXPERIMENTAL_BRIGHTMAIL - { "bmi_alt_location", vtype_stringptr, &bmi_alt_location }, - { "bmi_base64_tracker_verdict", vtype_stringptr, &bmi_base64_tracker_verdict }, - { "bmi_base64_verdict", vtype_stringptr, &bmi_base64_verdict }, - { "bmi_deliver", vtype_int, &bmi_deliver }, #endif { "body_linecount", vtype_int, &body_linecount }, { "body_zerocount", vtype_int, &body_zerocount }, diff --git a/src/src/functions.h b/src/src/functions.h index 0825b1b57..a29dddbed 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -218,7 +218,7 @@ extern void dscp_list_to_stream(FILE *); extern BOOL dscp_lookup(const uschar *, int, int *, int *, int *); extern void enq_end(uschar *); -extern BOOL enq_start(uschar *, unsigned); +extern unsigned enq_start(uschar *, unsigned); #ifndef DISABLE_EVENT extern uschar *event_raise(const uschar *, const uschar *, const uschar *, int *); extern void msg_event_raise(const uschar *, const address_item *); @@ -319,6 +319,7 @@ extern void log_write_die(unsigned, int, const char * format, ...) PRINTF_FUNCTION(3,4) NORETURN; extern const lookup_info * lookup_with_acq_num(unsigned); +extern gstring *lookup_dynamic_supported(gstring *); #ifdef LOOKUP_MODULE_DIR extern BOOL lookup_one_mod_load(const uschar *, uschar **); #endif @@ -601,11 +602,11 @@ extern const uschar *string_printing2(const uschar *, int); extern uschar *string_split_message(uschar *); extern uschar *string_unprinting(uschar *); #ifdef SUPPORT_I18N -extern uschar *string_address_utf8_to_alabel(const uschar *, uschar **); +extern const uschar *string_address_utf8_to_alabel(const uschar *, uschar **); extern uschar *string_domain_alabel_to_utf8(const uschar *, uschar **); -extern uschar *string_domain_utf8_to_alabel(const uschar *, uschar **); +extern const uschar *string_domain_utf8_to_alabel(const uschar *, uschar **); extern uschar *string_localpart_alabel_to_utf8(const uschar *, uschar **); -extern uschar *string_localpart_utf8_to_alabel(const uschar *, uschar **); +extern const uschar *string_localpart_utf8_to_alabel(const uschar *, uschar **); #endif #define string_format(buf, siz, fmt, ...) \ @@ -695,7 +696,6 @@ extern int verify_check_given_host(const uschar **, const host_item *); extern int verify_check_this_host(const uschar **, unsigned int *, const uschar*, const uschar *, const uschar **); extern address_item *verify_checked_sender(const uschar *); -extern void verify_get_ident(int); extern void verify_quota(uschar *); extern int verify_quota_call(const uschar *, int, int, uschar **); extern BOOL verify_sender(int *, uschar **); diff --git a/src/src/globals.c b/src/src/globals.c index 3eda97628..be2b7ec13 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -58,10 +58,6 @@ BOOL opt_perl_taintmode = FALSE; tree_node *dlobj_anchor = NULL; #endif -#ifdef LOOKUP_IBASE -uschar *ibase_servers = NULL; -#endif - #ifdef LOOKUP_LDAP uschar *eldap_ca_cert_dir = NULL; uschar *eldap_ca_cert_file = NULL; @@ -265,6 +261,7 @@ struct global_flags f = .enable_dollar_recipients = FALSE, .expand_string_forcedfail = FALSE, + .expansion_test = FALSE, .filter_running = FALSE, @@ -366,7 +363,6 @@ BOOL disable_fsync = FALSE; #endif BOOL disable_ipv6 = FALSE; BOOL dns_csa_use_reverse = TRUE; -BOOL drop_cr = FALSE; /* No longer used */ BOOL envelope_to_remove = TRUE; BOOL exim_gid_set = TRUE; /* This gid is always set */ @@ -585,15 +581,6 @@ uschar *base62_chars= US"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; uschar *bi_command = NULL; uschar *big_buffer = NULL; int big_buffer_size = BIG_BUFFER_SIZE; -#ifdef EXPERIMENTAL_BRIGHTMAIL -uschar *bmi_alt_location = NULL; -uschar *bmi_base64_tracker_verdict = NULL; -uschar *bmi_base64_verdict = NULL; -uschar *bmi_config_file = US"/opt/brightmail/etc/brightmail.cfg"; -int bmi_deliver = 1; -int bmi_run = 0; -uschar *bmi_verdicts = NULL; -#endif int bsmtp_transaction_linecount = 0; int body_8bitmime = 0; int body_linecount = 0; @@ -720,7 +707,6 @@ bit_table debug_options[] = { /* must be in alphabetical order and use BIT_TABLE(D, filter), BIT_TABLE(D, hints_lookup), BIT_TABLE(D, host_lookup), - BIT_TABLE(D, ident), BIT_TABLE(D, interface), BIT_TABLE(D, lists), BIT_TABLE(D, load), @@ -1003,7 +989,6 @@ bit_table log_options[] = { /* must be in alphabetical order, BIT_TABLE(L, dnssec), BIT_TABLE(L, etrn), BIT_TABLE(L, host_lookup_failed), - BIT_TABLE(L, ident_timeout), BIT_TABLE(L, incoming_interface), BIT_TABLE(L, incoming_port), BIT_TABLE(L, lost_incoming_connection), @@ -1245,7 +1230,7 @@ const pcre2_code *regex_whitelisted_macro = NULL; uschar *regex_match_string = NULL; #endif int remote_delivery_count = 0; -int remote_max_parallel = 4; +int remote_max_parallel = 6; uschar *remote_sort_domains = NULL; int retry_data_expire = 7*24*60*60; int retry_interval_max = 24*60*60; @@ -1253,8 +1238,6 @@ int retry_maximum_timeout = 0; /* set from retry config */ retry_config *retries = NULL; const uschar *return_path = NULL; int rewrite_existflags = 0; -uschar *rfc1413_hosts = US"@[]"; -int rfc1413_query_timeout = 0; uid_t root_gid = ROOT_GID; uid_t root_uid = ROOT_UID; @@ -1416,7 +1399,6 @@ uid_t system_filter_uid = (uid_t)-1; blob tcp_fastopen_nodata = { .data = NULL, .len = 0 }; tfo_state_t tcp_out_fastopen = TFO_NOT_USED; -int test_harness_identd_port = IDENT_PORT; int test_harness_load_avg = 0; int thismessage_size_limit = 0; int timeout_frozen_after = 0; diff --git a/src/src/globals.h b/src/src/globals.h index cb6b91c5a..ccd790cc2 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -40,10 +40,6 @@ extern BOOL opt_perl_taintmode; /* Enable taint mode in Perl */ extern tree_node *dlobj_anchor; /* Tree of dynamically-loaded objects */ #endif -#ifdef LOOKUP_IBASE -extern uschar *ibase_servers; -#endif - #ifdef LOOKUP_LDAP extern uschar *eldap_ca_cert_dir; /* Directory with CA certificates */ extern uschar *eldap_ca_cert_file; /* CA certificate file */ @@ -123,6 +119,7 @@ typedef struct { BOOL channelbind_exporter:1; /* channelbinding is EXPORTER not UNIQUE */ BOOL on_connect:1; /* For older MTAs that don't STARTTLS */ BOOL verify_override:1; /* certificate_verified only due to tls_try_verify_hosts */ + BOOL smtp_quit:1; /* QUIT has been sent or received */ } tls_support; extern tls_support tls_in; extern tls_support tls_out; @@ -234,6 +231,7 @@ extern struct global_flags { BOOL enable_dollar_recipients :1; /* Make $recipients available */ BOOL expand_string_forcedfail :1; /* TRUE if failure was "expected" */ + BOOL expansion_test :1; /* TRUE for -be test mode */ BOOL filter_running :1; /* TRUE while running a filter */ @@ -392,19 +390,19 @@ extern int av_failed; /* TRUE if the AV process failed */ extern uschar *av_scanner; /* AntiVirus scanner to use for the malware condition */ #endif +extern lookup_module_info * avail_static_lookups[];/* List of built-in lookup drivers */ + +extern const uschar * avail_static_auths[]; /* List of built-in driver names */ +extern const uschar * avail_dynamic_auths[]; /* List of dynamic-load driver names */ +extern const uschar * avail_static_routers[]; +extern const uschar * avail_dynamic_routers[]; +extern const uschar * avail_static_transports[]; +extern const uschar * avail_dynamic_transports[]; + extern uschar *base62_chars; /* Table of base-62 characters */ extern uschar *bi_command; /* Command for -bi option */ extern uschar *big_buffer; /* Used for various temp things */ extern int big_buffer_size; /* Current size (can expand) */ -#ifdef EXPERIMENTAL_BRIGHTMAIL -extern uschar *bmi_alt_location; /* expansion variable that contains the alternate location for the rcpt (available during routing) */ -extern uschar *bmi_base64_tracker_verdict; /* expansion variable with base-64 encoded OLD verdict string (available during routing) */ -extern uschar *bmi_base64_verdict; /* expansion variable with base-64 encoded verdict string (available during routing) */ -extern uschar *bmi_config_file; /* Brightmail config file */ -extern int bmi_deliver; /* Flag that determines if the message should be delivered to the rcpt (available during routing) */ -extern int bmi_run; /* Flag that determines if message should be run through Brightmail server */ -extern uschar *bmi_verdicts; /* BASE64-encoded verdicts with recipient lists */ -#endif extern int bsmtp_transaction_linecount; /* Start of last transaction */ extern int body_8bitmime; /* sender declared BODY= ; 7=7BIT, 8=8BITMIME */ extern uschar *bounce_message_file; /* Template file */ @@ -575,8 +573,6 @@ extern uschar *dnslist_value; /* DNS (black) list IP address */ extern tree_node *domainlist_anchor; /* Tree of defined domain lists */ extern int domainlist_count; /* Number defined */ -/* This option is now a no-opt, retained for compatibility */ -extern BOOL drop_cr; /* For broken local MUAs */ extern const uschar *driver_srcfile; /* For debug & errors */ extern int driver_srcline; /* For debug & errors */ @@ -923,8 +919,6 @@ extern int retry_maximum_timeout; /* The maximum timeout */ extern const uschar *return_path; /* Return path for a message */ extern BOOL return_path_remove; /* Remove return-path headers */ extern int rewrite_existflags; /* Indicate which headers have rewrites */ -extern uschar *rfc1413_hosts; /* RFC hosts */ -extern int rfc1413_query_timeout; /* Timeout on RFC 1413 calls */ /* extern BOOL rfc821_domains; */ /* If set, syntax is 821, not 822 => being abolished */ extern uid_t root_gid; /* The gid for root */ extern uid_t root_uid; /* The uid for root */ @@ -1065,7 +1059,6 @@ extern BOOL system_filter_uid_set; /* TRUE if uid set */ extern blob tcp_fastopen_nodata; /* for zero-data TFO connect requests */ extern BOOL tcp_nodelay; /* Controls TCP_NODELAY on daemon */ extern tfo_state_t tcp_out_fastopen; /* TCP fast open */ -extern int test_harness_identd_port; /* For use when testing */ extern int test_harness_load_avg; /* For use when testing */ extern int thismessage_size_limit; /* Limit for this message */ extern int timeout_frozen_after; /* Max time to keep frozen messages */ diff --git a/src/src/local_scan.h b/src/src/local_scan.h index a97fb4612..355487b0d 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -160,9 +160,6 @@ typedef struct recipient_item { const uschar *errors_to; /* the errors_to address or NULL */ uschar *orcpt; /* DSN orcpt */ int dsn_flags; /* DSN flags */ -#ifdef EXPERIMENTAL_BRIGHTMAIL - uschar *bmi_optin; -#endif } recipient_item; diff --git a/src/src/lookupapi.h b/src/src/lookupapi.h index 2e857c5d3..b8ec17880 100644 --- a/src/src/lookupapi.h +++ b/src/src/lookupapi.h @@ -18,9 +18,10 @@ */ typedef struct lookup_info { - uschar *name; /* e.g. "lsearch" */ - int type; /* query/singlekey/abs-file */ - unsigned acq_num; /* acquisition number */ + uschar * name; /* e.g. "lsearch" */ + int type; /* query/singlekey/abs-file */ + unsigned acq_num; /* acquisition number */ + void *(*open)( /* open function */ const uschar *, /* file name for those that have one */ uschar **); /* for error message */ @@ -60,9 +61,9 @@ typedef struct lookup_info { /* Version 5 change: version report now adds to a gstring */ typedef struct lookup_module_info { - uint magic; + uint magic; lookup_info **lookups; - uint lookupcount; + uint lookupcount; } lookup_module_info; /* End of lookupapi.h */ diff --git a/src/src/lookups/Makefile b/src/src/lookups/Makefile index 74e705e37..d794fe895 100644 --- a/src/src/lookups/Makefile +++ b/src/src/lookups/Makefile @@ -8,17 +8,38 @@ # extra variable definitions and prepended to it and module build rules # interpolated below. This is done by scripts/lookups-Makefile. -# When adding a new driver here, attend also to scripts/lookups-Makefile -# and scripts/MakeLinks +# When adding a new driver here, attend also to scripts/lookups-Makefile, +# and scripts/MakeLinks. # MAGIC-TAG-MODS-OBJ-RULES-GO-HERE +OBJS = $(OBJ) $(OBJ_ALWAYS) + +# This assumes that the driver and object-file names match +AVAIL= $(OBJS:.o=) + all: Makefile lookups.a $(MODS) -lookups.a: $(OBJ) +# We assume here that the driver name is used as the prefix for +# its module_info struct. +avail_static_lookups.c: Makefile + @echo "make $@" + $(FE)echo '/* File built by lookups/Makefile */' >$@ + $(FE)echo '#include "../exim.h"' >>$@ + $(FE)for f in $(AVAIL); do \ + echo "extern lookup_module_info $${f}_lookup_module_info;" >>$@; \ + done + $(FE)echo 'lookup_module_info * avail_static_lookups[] = {' >>$@ + $(FE)for f in $(AVAIL); do \ + echo "& $${f}_lookup_module_info," >>$@; \ + done + $(FE)echo 'NULL };' >>$@ +avail_static_lookups.o: $(HDRS) avail_static_lookups.c + +lookups.a: avail_static_lookups.o $(OBJS) @$(RM_COMMAND) -f lookups.a @echo "$(AR) lookups.a" - @$(AR) lookups.a $(OBJ) + @$(AR) lookups.a avail_static_lookups.o $(OBJS) $(RANLIB) $@ .SUFFIXES: .o .c .so @@ -32,7 +53,6 @@ cdb.o cdb.so: $(HDRS) cdb.c dbmdb.o dbmdb.so: $(HDRS) dbmdb.c dnsdb.o dnsdb.so: $(HDRS) dnsdb.c dsearch.o dsearch.so: $(HDRS) dsearch.c -ibase.o ibase.so: $(HDRS) ibase.c ldap.o ldap.so: $(HDRS) ldap.c lmdb.o lmdb.so: $(HDRS) lmdb.c json.o json.so: $(HDRS) json.c @@ -44,6 +64,7 @@ nmh.o nmh.so: $(HDRS) nmh.c oracle.o oracle.so: $(HDRS) oracle.c passwd.o passwd.so: $(HDRS) passwd.c pgsql.o pgsql.so: $(HDRS) pgsql.c +psl.o psl.so: $(HDRS) psl.c readsock.o readsock.so: $(HDRS) readsock.c redis.o redis.so: $(HDRS) redis.c spf.o spf.so: $(HDRS) spf.c diff --git a/src/src/lookups/ibase.c b/src/src/lookups/ibase.c deleted file mode 100644 index 141681aab..000000000 --- a/src/src/lookups/ibase.c +++ /dev/null @@ -1,550 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ -/* Copyright (c) University of Cambridge 1995 - 2018 */ -/* See the file NOTICE for conditions of use and distribution. */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* The code in this module was contributed by Ard Biesheuvel. */ - -#include "../exim.h" -#include "lf_functions.h" - -#include /* The system header */ - -/* Structure and anchor for caching connections. */ - -typedef struct ibase_connection { - struct ibase_connection *next; - uschar *server; - isc_db_handle dbh; - isc_tr_handle transh; -} ibase_connection; - -static ibase_connection *ibase_connections = NULL; - - -#if defined(_LP64) || defined(__LP64__) || defined(__arch64__) || defined(_WIN64) -# define ISC_NULL 0 -#else -# define ISC_NULL NULL -#endif - -/************************************************* -* Open entry point * -*************************************************/ - -/* See local README for interface description. */ - -static void *ibase_open(const uschar * filename, uschar ** errmsg) -{ -return (void *) (1); /* Just return something non-null */ -} - - - -/************************************************* -* Tidy entry point * -*************************************************/ - -/* See local README for interface description. */ - -static void -ibase_tidy(void) -{ -ibase_connection *cn; -ISC_STATUS status[20]; - -while ((cn = ibase_connections)) - { - ibase_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close Interbase connection: %s\n", - cn->server); - isc_commit_transaction(status, &cn->transh); - isc_detach_database(status, &cn->dbh); - } -} - -static int -fetch_field(uschar * buffer, int buffer_size, XSQLVAR * var) -{ -if (buffer_size < var->sqllen) - return 0; - -switch (var->sqltype & ~1) - { - case SQL_VARYING: - strncpy(CS buffer, &var->sqldata[2], *(short *) var->sqldata); - return *(short *) var->sqldata; - case SQL_TEXT: - strncpy(CS buffer, var->sqldata, var->sqllen); - return var->sqllen; - case SQL_SHORT: - return sprintf(CS buffer, "%d", *(short *) var->sqldata); - case SQL_LONG: - return sprintf(CS buffer, "%ld", *(ISC_LONG *) var->sqldata); - #ifdef SQL_INT64 - case SQL_INT64: - return sprintf(CS buffer, "%lld", *(ISC_INT64 *) var->sqldata); - #endif - default: - /* not implemented */ - return 0; - } -} - -/************************************************* -* Internal search function * -*************************************************/ - -/* This function is called from the find entry point to do the search for a -single server. - -Arguments: - query the query string - server the server string - resultptr where to store the result - errmsg where to point an error message - defer_break TRUE if no more servers are to be tried after DEFER - -The server string is of the form "host:dbname|user|password". The host can be -host:port. This string is in a nextinlist temporary buffer, so can be -overwritten. - -Returns: OK, FAIL, or DEFER -*/ - -static int -perform_ibase_search(const uschar * query, uschar * server, uschar ** resultptr, - uschar ** errmsg, BOOL * defer_break) -{ -isc_stmt_handle stmth; -XSQLDA *out_sqlda; -XSQLVAR *var; -int i; -rmark reset_point; - -uschar buffer[256]; -ISC_STATUS status[20], *statusp = status; - -gstring * result = NULL; -int yield = DEFER; -ibase_connection *cn; -uschar *server_copy = NULL; -uschar *sdata[3]; - -/* Disaggregate the parameters from the server argument. The order is host, -database, user, password. We can write to the string, since it is in a -nextinlist temporary buffer. The copy of the string that is used for caching -has the password removed. This copy is also used for debugging output. */ - -for (int i = 2; i > 0; i--) - { - uschar * pp = Ustrrchr(server, '|'); - - if (!pp) - { - *errmsg = string_sprintf("incomplete Interbase server data: %s", - i == 3 ? server : server_copy); - *defer_break = TRUE; - return DEFER; - } - *pp++ = 0; - sdata[i] = pp; - if (i == 2) - server_copy = string_copy(server); /* sans password */ - } -sdata[0] = server; /* What's left at the start */ - -/* See if we have a cached connection to the server */ - -for (cn = ibase_connections; cn; cn = cn->next) - if (Ustrcmp(cn->server, server_copy) == 0) - break; - -/* Use a previously cached connection ? */ - -if (cn) - { - static char db_info_options[] = { isc_info_base_level }; - - /* test if the connection is alive */ - if (isc_database_info(status, &cn->dbh, sizeof(db_info_options), - db_info_options, sizeof(buffer), CS buffer)) - { - /* error occurred: assume connection is down */ - DEBUG(D_lookup) - debug_printf("Interbase cleaning up cached connection: %s\n", cn->server); - isc_detach_database(status, &cn->dbh); - } - else - DEBUG(D_lookup) - debug_printf_indent("Interbase using cached connection for %s\n", - server_copy); - } -else - { - cn = store_get(sizeof(ibase_connection), GET_UNTAINTED); - cn->server = server_copy; - cn->dbh = ISC_NULL; - cn->transh = ISC_NULL; - cn->next = ibase_connections; - ibase_connections = cn; - } - -/* If no cached connection, we must set one up. */ - -if (!cn->dbh || !cn->transh) - { - uschar * dpb; - short dpb_length; - static char trans_options[] = - { isc_tpb_version3, isc_tpb_read, isc_tpb_read_committed, - isc_tpb_rec_version }; - - /* Construct the database parameter buffer. */ - dpb = buffer; - *dpb++ = isc_dpb_version1; - *dpb++ = isc_dpb_user_name; - *dpb++ = Ustrlen(sdata[1]); - for (uschar * p = sdata[1]; *p;) *dpb++ = *p++; - *dpb++ = isc_dpb_password; - *dpb++ = Ustrlen(sdata[2]); - for (uschar * p = sdata[2]; *p;) *dpb++ = *p++; - dpb_length = dpb - buffer; - - DEBUG(D_lookup) - debug_printf_indent("new Interbase connection: database=%s user=%s\n", - sdata[0], sdata[1]); - - /* Connect to the database */ - if (isc_attach_database(status, 0, CS sdata[0], &cn->dbh, - dpb_length, CS buffer)) - { - isc_interprete(CS buffer, &statusp); - *errmsg = string_sprintf("Interbase attach() failed: %s", buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - - /* Now start a read-only read-committed transaction */ - if (isc_start_transaction(status, &cn->transh, 1, &cn->dbh, - sizeof(trans_options), trans_options)) - { - isc_interprete(CS buffer, &statusp); - isc_detach_database(status, &cn->dbh); - *errmsg = string_sprintf("Interbase start_transaction() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - } - -/* Run the query */ -if (isc_dsql_allocate_statement(status, &cn->dbh, &stmth)) - { - isc_interprete(CS buffer, &statusp); - *errmsg = string_sprintf("Interbase alloc_statement() failed: %s", buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - -/* Lacking any information, assume that the data is untainted */ -reset_point = store_mark(); -out_sqlda = store_get(XSQLDA_LENGTH(1), GET_UNTAINTED); -out_sqlda->version = SQLDA_VERSION1; -out_sqlda->sqln = 1; - -if (isc_dsql_prepare(status, &cn->transh, &stmth, 0, CCS query, 1, out_sqlda)) - { - isc_interprete(CS buffer, &statusp); - reset_point = store_reset(reset_point); - out_sqlda = NULL; - *errmsg = string_sprintf("Interbase prepare_statement() failed: %s", buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - -/* re-allocate the output structure if there's more than one field */ -if (out_sqlda->sqln < out_sqlda->sqld) - { - XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld), GET_UNTAINTED); - if (isc_dsql_describe - (status, &stmth, out_sqlda->version, new_sqlda)) - { - isc_interprete(CS buffer, &statusp); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - reset_point = store_reset(reset_point); - out_sqlda = NULL; - *errmsg = string_sprintf("Interbase describe_statement() failed: %s", - buffer); - *defer_break = FALSE; - goto IBASE_EXIT; - } - out_sqlda = new_sqlda; - } - -/* allocate storage for every returned field */ -for (i = 0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++) - { - switch (var->sqltype & ~1) - { - case SQL_VARYING: - var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2, GET_UNTAINTED); - break; - case SQL_TEXT: - var->sqldata = CS store_get(sizeof(char) * var->sqllen, GET_UNTAINTED); - break; - case SQL_SHORT: - var->sqldata = CS store_get(sizeof(short), GET_UNTAINTED); - break; - case SQL_LONG: - var->sqldata = CS store_get(sizeof(ISC_LONG), GET_UNTAINTED); - break; -#ifdef SQL_INT64 - case SQL_INT64: - var->sqldata = CS store_get(sizeof(ISC_INT64), GET_UNTAINTED); - break; -#endif - case SQL_FLOAT: - var->sqldata = CS store_get(sizeof(float), GET_UNTAINTED); - break; - case SQL_DOUBLE: - var->sqldata = CS store_get(sizeof(double), GET_UNTAINTED); - break; -#ifdef SQL_TIMESTAMP - case SQL_DATE: - var->sqldata = CS store_get(sizeof(ISC_QUAD), GET_UNTAINTED); - break; -#else - case SQL_TIMESTAMP: - var->sqldata = CS store_get(sizeof(ISC_TIMESTAMP), GET_UNTAINTED); - break; - case SQL_TYPE_DATE: - var->sqldata = CS store_get(sizeof(ISC_DATE), GET_UNTAINTED); - break; - case SQL_TYPE_TIME: - var->sqldata = CS store_get(sizeof(ISC_TIME), GET_UNTAINTED); - break; - #endif - } - if (var->sqltype & 1) - var->sqlind = (short *) store_get(sizeof(short), GET_UNTAINTED); - } - -/* finally, we're ready to execute the statement */ -if (isc_dsql_execute(status, &cn->transh, &stmth, out_sqlda->version, NULL)) - { - isc_interprete(CS buffer, &statusp); - *errmsg = string_sprintf("Interbase describe_statement() failed: %s", buffer); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - *defer_break = FALSE; - goto IBASE_EXIT; - } - -while (isc_dsql_fetch(status, &stmth, out_sqlda->version, out_sqlda) != 100L) - { - /* check if an error occurred */ - if (status[0] & status[1]) - { - isc_interprete(CS buffer, &statusp); - *errmsg = string_sprintf("Interbase fetch() failed: %s", buffer); - isc_dsql_free_statement(status, &stmth, DSQL_drop); - *defer_break = FALSE; - goto IBASE_EXIT; - } - - if (result) - result = string_catn(result, US "\n", 1); - - /* Find the number of fields returned. If this is one, we don't add field - names to the data. Otherwise we do. */ - if (out_sqlda->sqld == 1) - { - if (out_sqlda->sqlvar[0].sqlind == NULL || *out_sqlda->sqlvar[0].sqlind != -1) /* NULL value yields nothing */ - result = string_catn(result, US buffer, - fetch_field(buffer, sizeof(buffer), &out_sqlda->sqlvar[0])); - } - - else - for (int i = 0; i < out_sqlda->sqld; i++) - { - int len = fetch_field(buffer, sizeof(buffer), &out_sqlda->sqlvar[i]); - - result = string_catn(result, US out_sqlda->sqlvar[i].aliasname, - out_sqlda->sqlvar[i].aliasname_length); - result = string_catn(result, US "=", 1); - - /* Quote the value if it contains spaces or is empty */ - - if (*out_sqlda->sqlvar[i].sqlind == -1) /* NULL value */ - result = string_catn(result, US "\"\"", 2); - - else if (buffer[0] == 0 || Ustrchr(buffer, ' ') != NULL) - { - result = string_catn(result, US "\"", 1); - for (int j = 0; j < len; j++) - { - if (buffer[j] == '\"' || buffer[j] == '\\') - result = string_catn(result, US "\\", 1); - result = string_catn(result, US buffer + j, 1); - } - result = string_catn(result, US "\"", 1); - } - else - result = string_catn(result, US buffer, len); - result = string_catn(result, US " ", 1); - } - } - -/* If result is NULL then no data has been found and so we return FAIL. -Otherwise, we must terminate the string which has been built; string_cat() -always leaves enough room for a terminating zero. */ - -if (!result) - { - yield = FAIL; - *errmsg = US "Interbase: no data found"; - } -else - gstring_release_unused(result); - - -/* Get here by goto from various error checks. */ - -IBASE_EXIT: - -if (stmth) - isc_dsql_free_statement(status, &stmth, DSQL_drop); - -/* Non-NULL result indicates a successful result */ - -if (result) - { - *resultptr = string_from_gstring(result); - return OK; - } -else - { - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); - return yield; /* FAIL or DEFER */ - } -} - - - - -/************************************************* -* Find entry point * -*************************************************/ - -/* See local README for interface description. The handle and filename -arguments are not used. Loop through a list of servers while the query is -deferred with a retryable error. */ - -static int -ibase_find(void * handle, const uschar * filename, const uschar * query, - int length, uschar ** result, uschar ** errmsg, uint * do_cache, - const uschar * opts) -{ -uschar * server; -const uschar * list = ibase_servers; - -DEBUG(D_lookup) debug_printf_indent("Interbase query: %s\n", query); - -for (int sep = 0; server = string_nextinlist(&list, &sep, NULL, 0); ) - { - BOOL defer_break = FALSE; - int rc = perform_ibase_search(query, server, result, errmsg, &defer_break); - if (rc != DEFER || defer_break) - return rc; - } - -if (!ibase_servers) - *errmsg = US "no Interbase servers defined (ibase_servers option)"; - -return DEFER; -} - - - -/************************************************* -* Quote entry point * -*************************************************/ - -/* The only characters that need to be quoted (with backslash) are newline, -tab, carriage return, backspace, backslash itself, and the quote characters. -Percent, and underscore and not escaped. They are only special in contexts -where they can be wild cards, and this isn't usually the case for data inserted -from messages, since that isn't likely to be treated as a pattern of any kind. -Sadly, MySQL doesn't seem to behave like other programs. If you use something -like "where id="ab\%cd" it does not treat the string as "ab%cd". So you really -can't quote "on spec". - -Arguments: - s the string to be quoted - opt additional option text or NULL if none - idx lookup type index - -Returns: the processed string or NULL for a bad option -*/ - -static uschar * -ibase_quote(uschar * s, const uschar * opt, unsigned idx) -{ -gstring * quoted = store_get_quoted(1, s, idx, US"ibase"); - -if (opt) - return NULL; /* No options recognized */ - -for (uschar c; c = *s; s++) - { - if (c == '\'') quoted = string_catn(quoted, US"\\", 1); - quoted = string_catn(quoted, s, 1); - } -gstring_release_unused(quoted); -return(string_from_gstring(quoted)); -} - - - -/************************************************* -* Version reporting entry point * -*************************************************/ - -/* See local README for interface description. */ - -#include "../version.h" - -gstring * -ibase_version_report(gstring * g) -{ -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: ibase: Exim version %s\n", EXIM_VERSION_STR)); -#endif -return g; -} - - -static lookup_info _lookup_info = { - .name = US"ibase", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = ibase_open, /* open function */ - .check = NULL, /* no check function */ - .find = ibase_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = ibase_tidy, /* tidy function */ - .quote = ibase_quote, /* quoting function */ - .version_report = ibase_version_report /* version reporting */ -}; - -#ifdef DYNLOOKUP -#define ibase_lookup_module_info _lookup_module_info -#endif - -static lookup_info *_lookup_list[] = { &_lookup_info }; -lookup_module_info ibase_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; - -/* End of lookups/ibase.c */ diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 624b947d6..a6e99f567 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1580,7 +1580,7 @@ static lookup_info ldap_lookup_info = { .close = NULL, /* no close function */ .tidy = eldap_tidy, /* tidy function */ .quote = eldap_quote, /* quoting function */ - .version_report = ldap_version_report /* version reporting */ + .version_report = ldap_version_report /* version reporting */ }; static lookup_info ldapdn_lookup_info = { @@ -1592,7 +1592,7 @@ static lookup_info ldapdn_lookup_info = { .close = NULL, /* no close function */ .tidy = eldap_tidy, /* sic */ /* tidy function */ .quote = eldap_quote, /* sic */ /* quoting function */ - .version_report = NULL /* no version reporting (redundant) */ + .version_report = NULL /* no version reporting (redundant) */ }; static lookup_info ldapm_lookup_info = { @@ -1604,7 +1604,7 @@ static lookup_info ldapm_lookup_info = { .close = NULL, /* no close function */ .tidy = eldap_tidy, /* sic */ /* tidy function */ .quote = eldap_quote, /* sic */ /* quoting function */ - .version_report = NULL /* no version reporting (redundant) */ + .version_report = NULL /* no version reporting (redundant) */ }; static lookup_info ldapauth_lookup_info = { @@ -1616,7 +1616,7 @@ static lookup_info ldapauth_lookup_info = { .close = NULL, /* no close function */ .tidy = eldap_tidy, /* sic */ /* tidy function */ .quote = NULL, /* NO quoting function */ - .version_report = NULL /* no version reporting (redundant) */ + .version_report = NULL /* no version reporting (redundant) */ }; #ifdef DYNLOOKUP diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c index c85cda5d5..89a9e6c80 100644 --- a/src/src/lookups/lsearch.c +++ b/src/src/lookups/lsearch.c @@ -474,7 +474,7 @@ static lookup_info wildlsearch_lookup_info = { }; #ifdef DYNLOOKUP -#define lsearch_lookup_module_info _lookup_module_info +# define lsearch_lookup_module_info _lookup_module_info #endif static lookup_info *_lookup_list[] = { &iplsearch_lookup_info, diff --git a/src/src/lookups/psl.c b/src/src/lookups/psl.c new file mode 100644 index 000000000..1592fe32d --- /dev/null +++ b/src/src/lookups/psl.c @@ -0,0 +1,252 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../exim.h" + +#ifndef SUPPORT_I18N +# error PSL lookup requires internationalisation support +#endif + + +/************************************************* +* Open entry point * +*************************************************/ + +/* See local README for interface description */ + +static void * +psl_open(const uschar * filename, uschar ** errmsg) +{ +FILE * f = fopen(CCS filename, "r"); +if (f) return (void *) f; +*errmsg = US strerror(errno); +return NULL; +} + +static void +psl_close(void * handle) +{ +(void) fclose(handle); +} + + + + +/************************************************* +* Generic "find" implementation * +*************************************************/ + +static int +psl_gen_find(void * handle, const uschar * keystring, + int length, uschar ** result, uschar ** errmsg, BOOL is_regdom) +{ +uschar rulebuf[128], * res = NULL; +const uschar * s, * k, * kmatch; +unsigned res_label_cnt = 0, nlabels; +BOOL key_utf8; + +/* Ensure key is punycode and lowercase */ + +if ((key_utf8 = string_is_utf8(keystring))) + { + DEBUG(D_lookup) debug_printf_indent("converting utf8 key %q\n", keystring); + if (!(keystring = string_domain_utf8_to_alabel(keystring, errmsg))) + return FAIL; + length = Ustrlen(keystring); + DEBUG(D_lookup) debug_printf_indent(" result %q\n", keystring); + } +else + for (k = keystring; *k; k++) + if (isupper(*k)) { keystring = string_copylc(keystring); break; } + +while ((s = US fgets(CS rulebuf, sizeof(rulebuf), handle))) + { + const uschar * r; + + if (!*s || *s == '\n') continue; /* empty line */ + if (s[0] == '/' && s[1] == '/') continue; /* comment line */ + + nlabels = 1; + if ((r = US strsep(CSS &s, " \n\t"))) + { + BOOL exception = *r == '!'; + const uschar * t; + + /* We convert any utf8 to punycode before starting comparison. It might + be more efficient to wait until hitting a top-bit-set byte? */ + if (!(t = string_domain_utf8_to_alabel(r, errmsg))) + goto fail; + if (t != r) + { + DEBUG(D_lookup) debug_printf_indent("converting utf8 psl entry %q\n" + " result %q\n", r, t); + r = t; + } + + for (s = r + Ustrlen(r), k = keystring + length; ; ) + { + uschar rch = s[-1]; + + if (rch == '.') /* label separator */ + nlabels++; + if (rch == '*') /* wildcard in rule (assume leading) */ + { + /* take the current label from the key */ + while (k > keystring && k[-1] != '.') + k--; + s = k; + /* s is the match */ + /* k is the key trail after the regdom. label */ + /* nlabels describes k */ + break; /* - match */ + } + if (rch == '!') /* exception rule */ + { + if (!is_regdom) + /* Remove the LH label then treat as a match */ + while (TRUE) + if (!*s || *s++ == '.') break; + + /* s is the match, or the regdom */ + /* nlabels don't care */ + res = string_copy_taint(s, GET_UNTAINTED); + goto found; /* ER's have priority; stop reading file */ + } + + s--; k--; + + if (rch != *k) /* character difference */ + goto nonmatch; + if (k <= keystring && !exception) /* ran out of key */ + goto nonmatch; + if (s == r) /* run out of rule */ + if (k[-1] != '.') /* key has prefix on rule */ + goto nonmatch; + else + break; /* out of rule: s is the match */ + } + + if (nlabels > res_label_cnt) + { /* new longest match (by cnt of labels) */ + res = string_copy_taint(s, GET_UNTAINTED); + res_label_cnt = nlabels; + kmatch = k; + } + + nonmatch: + } + } + /* kmatch is the key trail after the regdom. label */ + /* res_label_cnt describes kmatch */ + +if (is_regdom && res) /* prepend label from key to pub-suffix */ + { + s = kmatch; + /* back up one label in key */ + if (s-- <= keystring) goto fail; /* there must ba a dot */ + if (s-- <= keystring) goto fail; /* there must ba at least one ch */ + while (s > keystring && s[-1] != '.') s--; + res = string_sprintf("%.*s%s", (int)(kmatch - s), s, res); + } + +found: + +if (key_utf8 && res) + { + if (!(*result = string_domain_alabel_to_utf8(res, errmsg))) + goto fail; + DEBUG(D_lookup) + debug_printf_indent("utf8 converting result %q\n to %q\n", res, *result); + } +else + *result = res; + +rewind(handle); +return OK; + +fail: +rewind(handle); +return FAIL; +} + + + +/************************************************* +* Find entry points for pub-suffix and regdom * +*************************************************/ + +/* See local README for interface description */ + +static int +psl_find(void * handle, const uschar * filename, const uschar * keystring, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) +{ +return psl_gen_find(handle, keystring, length, result, errmsg, FALSE); +} + +static int +regdom_find(void * handle, const uschar * filename, const uschar * keystring, + int length, uschar ** result, uschar ** errmsg, uint * do_cache, + const uschar * opts) +{ +return psl_gen_find(handle, keystring, length, result, errmsg, TRUE); +} + + + + +/************************************************* +* Version reporting entry point * +*************************************************/ + +/* See local README for interface description. */ + +#include "../version.h" + +gstring * +psl_version_report(gstring * g) +{ +#ifdef DYNLOOKUP +g = string_fmt_append(g, "Library version: psl: Exim version %s\n", EXIM_VERSION_STR); +#endif +return g; +} + +static lookup_info psl_lookup_info = { + .name = US"psl", /* lookup name */ + .type = lookup_absfile, /* lookup from file */ + .open = psl_open, /* open function */ + .check = NULL, /* no check function */ + .find = psl_find, /* find function */ + .close = psl_close, /* close function */ + .tidy = NULL, /* no tidy function */ + .quote = NULL, /* no quoting function */ + .version_report = psl_version_report /* version reporting */ +}; + +static lookup_info regdom_lookup_info = { + .name = US"regdom", /* lookup name */ + .type = lookup_absfile, /* lookup from file */ + .open = psl_open, /* open function */ + .check = NULL, /* no check function */ + .find = regdom_find, /* find function */ + .close = psl_close, /* close function */ + .tidy = NULL, /* no tidy function */ + .quote = NULL, /* no quoting function */ + .version_report = NULL /* no version reporting (redundant) */ +}; + +#ifdef DYNLOOKUP +#define psl_lookup_module_info _lookup_module_info +#endif + +static lookup_info *_lookup_list[] = { &psl_lookup_info, ®dom_lookup_info }; +lookup_module_info psl_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 2 }; + +/* End of lookups/psl.c */ diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index ac03983c2..e1931ca0f 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -15,13 +15,6 @@ of the License, or (at your option) any later version. */ #include "../exim.h" - -#ifndef EXIM_HAVE_SPF -static void dummy(int x); -static void dummy2(int x) { dummy(x-1); } -static void dummy(int x) { dummy2(x-1); } -#else - #include "lf_functions.h" #ifndef EXPERIMENTAL_SPF_PERL @@ -119,4 +112,3 @@ static lookup_info spf_lookup_info = { static lookup_info *_lookup_list[] = { &spf_lookup_info }; lookup_module_info spf_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; -#endif /* EXIM_HAVE_SPF */ diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index 48287131a..caa6bf7c3 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -8,7 +8,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* Create a static data structure with the predefined macros, to be -included in the main Exim build */ +included in the main Exim build. Also, table for various drivers. */ #include "exim.h" #include "macro_predef.h" @@ -203,9 +203,6 @@ due to conflicts with other common macros. */ #ifdef EXPERIMENTAL_ARC builtin_macro_create(US"_HAVE_ARC"); #endif -#ifdef EXPERIMENTAL_BRIGHTMAIL - builtin_macro_create(US"_HAVE_BRIGHTMAIL"); -#endif #ifdef SUPPORT_DANE builtin_macro_create(US"_HAVE_DANE"); #endif @@ -252,9 +249,6 @@ due to conflicts with other common macros. */ #ifdef LOOKUP_DSEARCH builtin_macro_create(US"_HAVE_LOOKUP_DSEARCH"); #endif -#ifdef LOOKUP_IBASE - builtin_macro_create(US"_HAVE_LOOKUP_IBASE"); -#endif #ifdef LOOKUP_LMDB builtin_macro_create(US"_HAVE_LMDB"); builtin_macro_create(US"_HAVE_LOOKUP_LMDB"); @@ -283,6 +277,10 @@ due to conflicts with other common macros. */ #ifdef LOOKUP_PGSQL builtin_macro_create(US"_HAVE_LOOKUP_PGSQL"); #endif +#ifdef LOOKUP_PSL + builtin_macro_create(US"_HAVE_LOOKUP_PSL"); + builtin_macro_create(US"_HAVE_LOOKUP_REGDOM"); +#endif #ifdef LOOKUP_REDIS builtin_macro_create(US"_HAVE_LOOKUP_REDIS"); #endif @@ -322,9 +320,6 @@ exp_features(void) #ifdef EXPERIMENTAL_ARC builtin_macro_create(US"_EXP_ARC"); #endif -#ifdef EXPERIMENTAL_BRIGHTMAIL - builtin_macro_create(US"_EXP_BMI"); -#endif #ifdef EXPERIMENTAL_DCC builtin_macro_create(US"_EXP_DCC"); #endif @@ -358,6 +353,41 @@ params_dkim(); #endif } +/******************************************************************************/ +static void +avail_append(const driver_info * di) +{ +const uschar * avail_string = di->avail_string; +if (!avail_string) avail_string = di->driver_name; + printf(" US\"%s\",", avail_string); +} + +static void +avail_list(const driver_info * drtable, const uschar * tag, + const uschar * group, BOOL magic) +{ +printf("const uschar * avail_%s_%s[] = {", group, tag); +for (const driver_info * di = drtable; di; di = di->next) + if (!!di->dyn_magic == magic) avail_append(di); +printf(" NULL};\n"); +} + +static void +avail_drs(const driver_info * drtable, const uschar * tag) +{ +avail_list(drtable, tag, US"static", FALSE); +avail_list(drtable, tag, US"dynamic", TRUE); +} + +static void +avail(void) +{ +avail_drs((driver_info *)auths_available, US"auths"); +avail_drs((driver_info *)routers_available, US"routers"); +avail_drs((driver_info *)transports_available, US"transports"); +} + +/******************************************************************************/ int main(void) @@ -368,8 +398,10 @@ exp_features(); options(); expansions(); params(); - printf("macro_item * macros = &p%u;\n", mp_index-1); printf("macro_item * mlast = &p0;\n"); + +avail(); + exit(0); } diff --git a/src/src/macros.h b/src/src/macros.h index 75563d86b..2e0efc9b8 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -90,10 +90,6 @@ don't make the file descriptors two-way. */ #define pipe_read 0 #define pipe_write 1 -/* The RFC 1413 ident port */ - -#define IDENT_PORT 113 - /* A macro to simplify testing bits in lookup types */ #define mac_islookup(li,b) ((li)->type & (b)) @@ -385,26 +381,25 @@ enum { DEBUG_BIT(filter), DEBUG_BIT(hints_lookup), DEBUG_BIT(host_lookup), - DEBUG_BIT(ident), DEBUG_BIT(interface), DEBUG_BIT(lists), - DEBUG_BIT(load), /* 15 */ - DEBUG_BIT(lookup), + DEBUG_BIT(load), + DEBUG_BIT(lookup), /* 15 */ DEBUG_BIT(memory), DEBUG_BIT(noutf8), DEBUG_BIT(pid), DEBUG_BIT(process_info), DEBUG_BIT(queue_run), DEBUG_BIT(receive), - DEBUG_BIT(resolver), /* 23 */ - DEBUG_BIT(retry), + DEBUG_BIT(resolver), + DEBUG_BIT(retry), /* 23 */ DEBUG_BIT(rewrite), DEBUG_BIT(route), DEBUG_BIT(timestamp), DEBUG_BIT(tls), DEBUG_BIT(transport), DEBUG_BIT(uid), - DEBUG_BIT(verify), /* 31 */ + DEBUG_BIT(verify), /* 30 - one spare! */ }; /* Multi-bit debug masks */ @@ -474,7 +469,6 @@ enum logbit { Li_dkim, Li_dkim_verbose, Li_dnssec, - Li_ident_timeout, Li_incoming_interface, Li_incoming_port, Li_millisec, diff --git a/src/src/queue.c b/src/src/queue.c index b3d972f41..97238ba1a 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -351,7 +351,8 @@ Returns: nothing */ void -queue_run(qrunner * q, const uschar * start_id, const uschar * stop_id, BOOL recurse) +queue_run(qrunner * q, const uschar * start_id, const uschar * stop_id, + BOOL recurse) { BOOL force_delivery = q->queue_run_force || deliver_selectstring || deliver_selectstring_sender; @@ -519,6 +520,10 @@ for (int i = queue_run_in_order ? -1 : 0; #endif nelem(qpid) - 1]) { /* The child table is maxed out; wait for the oldest */ + /*XXX It might be nicer to wait for the first one + that happens to complete. */ + set_process_info("running queue (ph 1): parallel limit %u", + nelem(qpid)); DEBUG(D_queue_run) debug_printf("q2stage waiting for child %d\n", (int)qpid[0]); waitpid(qpid[0], NULL, 0); @@ -799,15 +804,20 @@ turned off. */ if (q->queue_2stage) { + unsigned active; + for (active = 0; active < nelem(qpid); active++) + if (!qpid[active]) { --active; break; } - /* wait for last children */ - for (int i = 0; i < nelem(qpid); i++) + /* wait for all first-stage children */ + for (unsigned i = 0; i < nelem(qpid); i++) if (qpid[i]) { - DEBUG(D_queue_run) debug_printf("q2stage reaped child %d\n", (int)qpid[i]); + set_process_info("running queue (ph 1): wait-all, child %u/%u", + i+1, active); waitpid(qpid[i], NULL, 0); + DEBUG(D_queue_run) debug_printf("q2stage reaped child %d\n", (int)qpid[i]); } - else break; + else break; /* should be no holes in table, so we're done */ #ifdef MEASURE_TIMING report_time_since(×tamp_startup, US"queue_run phase 1 done"); diff --git a/src/src/readconf.c b/src/src/readconf.c index cec89f9bb..f4da20b6a 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -79,9 +79,6 @@ static optionlist optionlist_config[] = { { "av_scanner", opt_stringptr, {&av_scanner} }, #endif { "bi_command", opt_stringptr, {&bi_command} }, -#ifdef EXPERIMENTAL_BRIGHTMAIL - { "bmi_config_file", opt_stringptr, {&bmi_config_file} }, -#endif { "bounce_message_file", opt_stringptr, {&bounce_message_file} }, { "bounce_message_text", opt_stringptr, {&bounce_message_text} }, { "bounce_return_body", opt_bool, {&bounce_return_body} }, @@ -143,9 +140,6 @@ static optionlist optionlist_config[] = { { "dns_retry", opt_int, {&dns_retry} }, { "dns_trust_aa", opt_stringptr, {&dns_trust_aa} }, { "dns_use_edns0", opt_int, {&dns_use_edns0} }, - /* This option is now a no-op, retained for compatibility */ - { "drop_cr", opt_bool, {&drop_cr} }, -/*********************************************************/ { "dsn_advertise_hosts", opt_stringptr, {&dsn_advertise_hosts} }, { "dsn_from", opt_stringptr, {&dsn_from} }, { "envelope_to_remove", opt_bool, {&envelope_to_remove} }, @@ -191,9 +185,6 @@ static optionlist optionlist_config[] = { { "hosts_treat_as_local", opt_stringptr, {&hosts_treat_as_local} }, #ifdef EXPERIMENTAL_XCLIENT { "hosts_xclient", opt_stringptr, {&hosts_xclient} }, -#endif -#ifdef LOOKUP_IBASE - { "ibase_servers", opt_stringptr, {&ibase_servers} }, #endif { "ignore_bounce_errors_after", opt_time, {&ignore_bounce_errors_after} }, { "ignore_fromline_hosts", opt_stringptr, {&ignore_fromline_hosts} }, @@ -307,9 +298,6 @@ static optionlist optionlist_config[] = { { "retry_interval_max", opt_time, {&retry_interval_max} }, { "return_path_remove", opt_bool, {&return_path_remove} }, { "return_size_limit", opt_mkint|opt_hidden, {&bounce_return_size_limit} }, - { "rfc1413_hosts", opt_stringptr, {&rfc1413_hosts} }, - { "rfc1413_port", opt_int|opt_hidden, {&test_harness_identd_port} }, - { "rfc1413_query_timeout", opt_time, {&rfc1413_query_timeout} }, { "sender_unqualified_hosts", opt_stringptr, {&sender_unqualified_hosts} }, { "slow_lookup_log", opt_int, {&slow_lookup_log} }, { "smtp_accept_keepalive", opt_bool, {&smtp_accept_keepalive} }, @@ -987,8 +975,13 @@ if (*s) for (macro_item * m = *s == '_' ? macros : macros_user; m; m = m->next) { int moveby; - EARLY_DEBUG(D_any, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, - m->name, (int) Ustrlen(ss)-1, ss); + DEBUG(D_any) + if (f.expansion_test) + printf("macro '%s' -> '%s'\n", m->name, m->replacement); + else + EARLY_DEBUG(D_any, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, + m->name, (int) Ustrlen(ss)-1, ss); + /* Expand the buffer if necessary */ while (*newlen - m->namelen + m->replen + 1 > big_buffer_size) @@ -3824,13 +3817,12 @@ for (di = *info_anchor; di; di = di->next) /* Potentially a loadable module. Look for a file with the right name. */ if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) - { log_write(0, LOG_MAIN|LOG_PANIC, - "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR); - } + "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR); else { - uschar * fname = string_sprintf("%s_%s." DYNLIB_FN_EXT, d->driver_name, class), * sname; + uschar * fname = string_sprintf("%s_%s." DYNLIB_FN_EXT, + d->driver_name, class); const char * errormsg; DEBUG(D_any) debug_printf("Loading %s %s driver from %s\n", diff --git a/src/src/receive.c b/src/src/receive.c index 9d8bfa89c..cde09c40a 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -533,11 +533,6 @@ if (recipients_count >= recipients_list_max) recipients_list[recipients_count].address = recipient; recipients_list[recipients_count].pno = pno; -#ifdef EXPERIMENTAL_BRIGHTMAIL -recipients_list[recipients_count].bmi_optin = bmi_current_optin; -/* reset optin string pointer for next recipient */ -bmi_current_optin = NULL; -#endif recipients_list[recipients_count].orcpt = NULL; recipients_list[recipients_count].dsn_flags = 0; recipients_list[recipients_count++].errors_to = NULL; @@ -3982,14 +3977,6 @@ if (fake_response != OK) f.deliver_firsttime = TRUE; -#ifdef EXPERIMENTAL_BRIGHTMAIL -if (bmi_run == 1) - { /* rewind data file */ - lseek(data_fd, (long int)spool_data_start_offset(message_id), SEEK_SET); - bmi_verdicts = bmi_process_message(header_list, data_fd); - } -#endif - /* Update the timestamp in our Received: header to account for any time taken by an ACL or by local_scan(). The new time is the time that all reception processing is complete. */ diff --git a/src/src/route.c b/src/src/route.c index 534198a85..778e524c1 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -35,16 +35,6 @@ optionlist optionlist_routers[] = { LOFF(address_data) }, { "address_test", opt_bool|opt_public, LOFF(address_test) }, -#ifdef EXPERIMENTAL_BRIGHTMAIL - { "bmi_deliver_alternate", opt_bool | opt_public, - LOFF(bmi_deliver_alternate) }, - { "bmi_deliver_default", opt_bool | opt_public, - LOFF(bmi_deliver_default) }, - { "bmi_dont_deliver", opt_bool | opt_public, - LOFF(bmi_dont_deliver) }, - { "bmi_rule", opt_stringptr|opt_public, - LOFF(bmi_rule) }, -#endif { "cannot_route_message", opt_stringptr | opt_public, LOFF(cannot_route_message) }, { "caseful_local_part", opt_bool | opt_public, @@ -1095,48 +1085,6 @@ if (r->condition) } } -#ifdef EXPERIMENTAL_BRIGHTMAIL -/* check if a specific Brightmail AntiSpam rule fired on the message */ -if (r->bmi_rule) - { - DEBUG(D_route) debug_printf_indent("checking bmi_rule\n"); - if (bmi_check_rule(bmi_base64_verdict, r->bmi_rule) == 0) - { /* none of the rules fired */ - DEBUG(D_route) - debug_printf_indent("%s router skipped: none of bmi_rule rules fired\n", rname); - return SKIP; - } - } - -/* check if message should not be delivered */ -if (r->bmi_dont_deliver && bmi_deliver == 1) - { - DEBUG(D_route) - debug_printf_indent("%s router skipped: bmi_dont_deliver is FALSE\n", rname); - return SKIP; - } - -/* check if message should go to an alternate location */ -if ( r->bmi_deliver_alternate - && (bmi_deliver == 0 || !bmi_alt_location) - ) - { - DEBUG(D_route) - debug_printf_indent("%s router skipped: bmi_deliver_alternate is FALSE\n", rname); - return SKIP; - } - -/* check if message should go to default location */ -if ( r->bmi_deliver_default - && (bmi_deliver == 0 || bmi_alt_location) - ) - { - DEBUG(D_route) - debug_printf_indent("%s router skipped: bmi_deliver_default is FALSE\n", rname); - return SKIP; - } -#endif - /* All the checks passed. */ return OK; diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c index 09992b85f..9986c39aa 100644 --- a/src/src/routers/accept.c +++ b/src/src/routers/accept.c @@ -156,7 +156,7 @@ router_info accept_router_info = .options_block = &accept_router_option_defaults, .options_len = sizeof(accept_router_options_block), .init = accept_router_init, -# ifdef DYNLOOKUP +# if ROUTER_ACCEPT==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 97e273dca..5df6ea8f9 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -484,7 +484,7 @@ router_info dnslookup_router_info = .options_block = &dnslookup_router_option_defaults, .options_len = sizeof(dnslookup_router_options_block), .init = dnslookup_router_init, -# ifdef DYNLOOKUP +# if ROUTER_DNSLOOKUP==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c index 9052f2d48..022592c9e 100644 --- a/src/src/routers/ipliteral.c +++ b/src/src/routers/ipliteral.c @@ -218,7 +218,7 @@ router_info ipliteral_router_info = .options_block = &ipliteral_router_option_defaults, .options_len = sizeof(ipliteral_router_options_block), .init = ipliteral_router_init, -# ifdef DYNLOOKUP +# if ROUTER_IPLITERAL==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index 1f3945bc8..5d9c04d71 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -433,7 +433,7 @@ router_info iplookup_router_info = .options_block = &iplookup_router_option_defaults, .options_len = sizeof(iplookup_router_options_block), .init = iplookup_router_init, -# ifdef DYNLOOKUP +# if ROUTER_IPLOOKUP==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 5a4c72bb0..589db7ead 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -517,7 +517,7 @@ router_info manualroute_router_info = .options_block = &manualroute_router_option_defaults, .options_len = sizeof(manualroute_router_options_block), .init = manualroute_router_init, -# ifdef DYNLOOKUP +# if ROUTER_MANUALROUTE==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 92a2524ab..3e12ec0d7 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -549,7 +549,7 @@ router_info queryprogram_router_info = .options_block = &queryprogram_router_option_defaults, .options_len = sizeof(queryprogram_router_options_block), .init = queryprogram_router_init, -# ifdef DYNLOOKUP +# if ROUTER_QUERYPROGRAM==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 6d0574c14..e90ad2147 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -804,7 +804,7 @@ router_info redirect_router_info = .options_block = &redirect_router_option_defaults, .options_len = sizeof(redirect_router_options_block), .init = redirect_router_init, -# ifdef DYNLOOKUP +# if ROUTER_REDIRECT==2 .dyn_magic = ROUTER_MAGIC, # endif }, diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index b5a054a16..e6c9dbacc 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1780,10 +1780,7 @@ memset(sender_address_cache, 0, sizeof(sender_address_cache)); memset(sender_domain_cache, 0, sizeof(sender_domain_cache)); authenticated_sender = NULL; -#ifdef EXPERIMENTAL_BRIGHTMAIL - bmi_run = 0; - bmi_verdicts = NULL; -#endif +dnslist_domain = dnslist_matched = NULL; dsn_ret = 0; dsn_envid = NULL; diff --git a/src/src/spool_in.c b/src/src/spool_in.c index ff9edfc2e..b475c3955 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -263,11 +263,6 @@ f.spool_file_wireformat = FALSE; #endif tree_nonrecipients = NULL; -#ifdef EXPERIMENTAL_BRIGHTMAIL -bmi_run = 0; -bmi_verdicts = NULL; -#endif - #ifndef DISABLE_DKIM f.dkim_disable_verify = FALSE; # ifdef COMPILE_UTILITY @@ -615,10 +610,6 @@ for (;;) body_linecount = Uatoi(var + 14); else if (Ustrncmp(p, "ody_zerocount", 13) == 0) body_zerocount = Uatoi(var + 14); -#ifdef EXPERIMENTAL_BRIGHTMAIL - else if (Ustrncmp(p, "mi_verdicts ", 12) == 0) - bmi_verdicts = string_copy_taint(var + 13, proto_mem); -#endif break; case 'd': diff --git a/src/src/spool_out.c b/src/src/spool_out.c index e5cded966..91b776df2 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -269,15 +269,12 @@ if (spam_score_int) spool_var_write(fp, US"spam_score_int", spam_score_int); if (f.deliver_manual_thaw) fprintf(fp, "-manual_thaw\n"); if (f.sender_set_untrusted) fprintf(fp, "-sender_set_untrusted\n"); -#ifdef EXPERIMENTAL_BRIGHTMAIL -if (bmi_verdicts) spool_var_write(fp, US"bmi_verdicts", bmi_verdicts); -#endif - #ifndef DISABLE_TLS if (tls_in.certificate_verified) fprintf(fp, "-tls_certificate_verified\n"); if (tls_in.cipher) spool_var_write(fp, US"tls_cipher", tls_in.cipher); if (tls_in.peercert) { + /* -- marks as tainted */ if (tls_export_cert(big_buffer, big_buffer_size, tls_in.peercert)) fprintf(fp, "--tls_peercert %s\n", CS big_buffer); } diff --git a/src/src/structs.h b/src/src/structs.h index 8f3eaacbf..147819dd5 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -153,6 +153,7 @@ typedef struct driver_instance { typedef struct driver_info { struct driver_info * next; uschar *driver_name; /* Name of driver */ + uschar *avail_string; /* if set, display rather than name */ optionlist *options; /* Table of private options names */ int *options_count; /* -> Number of entries in table */ @@ -299,9 +300,6 @@ typedef struct router_instance { driver_instance drinst; uschar *address_data; /* Arbitrary data */ -#ifdef EXPERIMENTAL_BRIGHTMAIL - uschar *bmi_rule; /* Brightmail AntiSpam rule checking */ -#endif uschar *cannot_route_message; /* Used when routing fails */ uschar *condition; /* General condition */ uschar *current_directory; /* For use during delivery */ @@ -330,11 +328,6 @@ typedef struct router_instance { uschar *transport_name; /* Transport name */ BOOL address_test; /* Use this router when testing addresses */ -#ifdef EXPERIMENTAL_BRIGHTMAIL - BOOL bmi_deliver_alternate; /* TRUE => BMI said that message should be delivered to alternate location */ - BOOL bmi_deliver_default; /* TRUE => BMI said that message should be delivered to default location */ - BOOL bmi_dont_deliver; /* TRUE => BMI said that message should not be delivered at all */ -#endif BOOL expn; /* Use this router when processing EXPN */ BOOL caseful_local_part; /* TRUE => don't lowercase */ BOOL check_local_user; /* TRUE => check local user */ diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 66359bb3e..80fb419d0 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -578,16 +578,23 @@ msg = rc == GNUTLS_E_FATAL_ALERT_RECEIVED (void) tls_error(when, msg, state->host, &errstr); -if (state->host) - log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s", - state->host->name, state->host->address, errstr); -else +if (!state->host) { uschar * conn_info = smtp_get_connection_info(); if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5; /* I'd like to get separated H= here, but too hard for now */ log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr); } +else if ( !tls_out.smtp_quit +#ifdef GNUTLS_E_PREMATURE_TERMINATION + || rc != GNUTLS_E_PREMATURE_TERMINATION +#endif + ) + log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s", + state->host->name, state->host->address, errstr); +else DEBUG(D_tls) + debug_printf("H=%s [%s] TLS error on connection %s\n", + state->host->name, state->host->address, errstr); } @@ -3523,7 +3530,7 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) debug_printf(" extract session data: %s\n", US gnutls_strerror(rc)); } else DEBUG(D_tls) - debug_printf(" host not resmable; not saving ticket\n"); + debug_printf(" host not resumable; not saving ticket\n"); } } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 66661e94e..d5a6d368d 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -509,6 +509,22 @@ return host ? FAIL : DEFER; } +static void +tls_debug_err(SSL * ssl, uschar * where, int rc) +{ +BIO * bio = BIO_new(BIO_s_mem()); +char * buf = NULL; +size_t len; +int error = SSL_get_error(ssl, rc); + +ERR_error_string_n(ERR_peek_error(), ssl_errstring, sizeof(ssl_errstring)); +ERR_print_errors(bio); +len = BIO_get_mem_data(bio, &buf); +debug_printf("%s: error %d\n%.*s\n", where, error, (int)len, buf); +BIO_free (bio); +} + + /************************************************** * General library initalisation * @@ -983,24 +999,24 @@ DEBUG(D_tls) if (where & SSL_CB_HANDSHAKE_DONE) g = string_append_listele(g, ',', US"hshake_done"); if (where & SSL_CB_LOOP) - debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); + debug_printf("SSL %Y: %s\n", g, SSL_state_string_long(s)); else if (where & SSL_CB_ALERT) - debug_printf("SSL %s %s:%s\n", g->s, + debug_printf("SSL %Y %s:%s\n", g, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); else if (where & SSL_CB_EXIT) { if (ret <= 0) - debug_printf("SSL %s: %s in %s\n", g->s, + debug_printf("SSL %Y: %s in %s\n", g, ret == 0 ? "failed" : "error", SSL_state_string_long(s)); } else if (where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)) - debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); + debug_printf("SSL %Y: %s\n", g, SSL_state_string_long(s)); } } #ifdef OPENSSL_HAVE_KEYLOG_CB static void -keylog_callback(const SSL *ssl, const char *line) +keylog_callback(const SSL * ssl, const char * line) { char * filename; FILE * fp; @@ -4533,11 +4549,10 @@ static BOOL tls_refill(unsigned lim) { SSL * ssl = state_server.lib_state.lib_ssl; -int error; -int inbytes; +int error, inbytes; -DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, - ssl_xfer_buffer, ssl_xfer_buffer_size); +DEBUG(D_tls) debug_printf("Calling SSL_read(tls_refill %p, %p, %u)\n", + ssl, ssl_xfer_buffer, ssl_xfer_buffer_size); ERR_clear_error(); if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout); @@ -4579,8 +4594,9 @@ switch(error) uschar * conn_info = smtp_get_connection_info(); if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5; /* I'd like to get separated H= here, but too hard for now */ - ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); + ERR_error_string_n(ERR_peek_error(), ssl_errstring, sizeof(ssl_errstring)); log_write(0, LOG_MAIN, "TLS error (SSL_read): on %s %s", conn_info, ssl_errstring); + DEBUG(D_tls) tls_debug_err(ssl, US"SSL_read", inbytes); ssl_xfer_error = TRUE; return FALSE; } @@ -4701,29 +4717,30 @@ Only used by the client-side TLS. */ int -tls_read(void * ct_ctx, uschar *buff, size_t len) +tls_read(void * ct_ctx, uschar * buff, size_t len) { SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : state_server.lib_state.lib_ssl; int inbytes; int error; -DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl, - buff, (unsigned int)len); +DEBUG(D_tls) debug_printf("Calling SSL_read(tls_read %p, %p, %u)\n", + ssl, buff, (unsigned int)len); ERR_clear_error(); inbytes = SSL_read(ssl, CS buff, len); error = SSL_get_error(ssl, inbytes); -if (error == SSL_ERROR_ZERO_RETURN) - { - DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); - return -1; - } -else if (error != SSL_ERROR_NONE) - return -1; +if (error == SSL_ERROR_NONE) + return inbytes; -return inbytes; +else DEBUG(D_tls) + if (error == SSL_ERROR_ZERO_RETURN) + debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); + else + tls_debug_err(ssl, US"SSL_read", inbytes); +ERR_clear_error(); +return -1; } @@ -4861,12 +4878,9 @@ if ((o_ctx ? tls_out.active.sock : tls_in.active.sock) < 0) tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent(" SMTP(TLS shutdown)>>\n"); -rc = SSL_shutdown(ssl); -if (rc < 0) DEBUG(D_tls) - { - ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); - debug_printf("SSL_shutdown: %s\n", ssl_errstring); - } +ERR_clear_error(); +if ((rc = SSL_shutdown(ssl)) < 0) + DEBUG(D_tls) tls_debug_err(ssl, US"SSL_shutdown", rc); } /************************************************* @@ -4905,6 +4919,7 @@ if (do_shutdown > TLS_NO_SHUTDOWN) tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ + ERR_clear_error(); if ( ( do_shutdown >= TLS_SHUTDOWN_WONLY || (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ ) @@ -4919,11 +4934,7 @@ if (do_shutdown > TLS_NO_SHUTDOWN) ALARM_CLR(0); } - if (rc < 0) DEBUG(D_tls) - { - ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); - debug_printf("SSL_shutdown: %s\n", ssl_errstring); - } + if (rc < 0) DEBUG(D_tls) tls_debug_err(*sslp, US"SSL_shutdown", rc); } if (!o_ctx) /* server side */ diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c index 6bbea7516..43d362904 100644 --- a/src/src/tlscert-gnu.c +++ b/src/src/tlscert-gnu.c @@ -150,6 +150,7 @@ if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz)) != GNUTLS_E_SHORT_MEMORY_BUFFER) return g_err("gi0", __FUNCTION__, ret); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ cp = store_get(siz, GET_TAINTED); if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz)) < 0) return g_err("gi1", __FUNCTION__, ret); @@ -226,14 +227,15 @@ return algo < 0 ? NULL : string_copy(US gnutls_sign_get_name(algo)); uschar * tls_cert_subject(void * cert, const uschar * mod) { -uschar * cp = NULL; +uschar * cp; int ret; size_t siz = 0; -if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz)) +if ((ret = gnutls_x509_crt_get_dn(cert, NULL, &siz)) != GNUTLS_E_SHORT_MEMORY_BUFFER) return g_err("gs0", __FUNCTION__, ret); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ cp = store_get(siz, GET_TAINTED); if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz)) < 0) return g_err("gs1", __FUNCTION__, ret); @@ -262,6 +264,7 @@ ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert, if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) return g_err("ge0", __FUNCTION__, ret); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ cp1 = store_get(siz*4 + 1, GET_TAINTED); ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert, @@ -317,6 +320,7 @@ for (int index = 0;; index++) return g_err("gs0", __FUNCTION__, ret); } + /*XXX we might want to distinguish ourcert from peercert (but this is safe) */ ele = store_get(siz+1, GET_TAINTED); if ((ret = gnutls_x509_crt_get_subject_alt_name( (gnutls_x509_crt_t)cert, index, ele, &siz, NULL)) < 0) @@ -347,7 +351,8 @@ tls_cert_ocsp_uri(void * cert, const uschar * mod) gnutls_datum_t uri; int ret; uschar sep = '\n'; -gstring * list = NULL; +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +gstring * list = string_get_tainted(0, GET_TAINTED); if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -381,7 +386,8 @@ tls_cert_crl_uri(void * cert, const uschar * mod) { int ret; uschar sep = '\n'; -gstring * list = NULL; +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +gstring * list = string_get_tainted(0, GET_TAINTED); if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -394,7 +400,7 @@ for (int index = 0;; index++) (gnutls_x509_crt_t)cert, index, NULL, &siz, NULL, NULL)) { case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE: - return string_from_gstring(list); + return gstring_length(list) > 0 ? string_from_gstring(list) : NULL; case GNUTLS_E_SHORT_MEMORY_BUFFER: break; default: @@ -449,6 +455,7 @@ if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, NULL, &siz)) != GNUTLS_E_SHORT_MEMORY_BUFFER) return g_err("gf0", __FUNCTION__, ret); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ cp = store_get(siz*3+1, GET_TAINTED); if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0) return g_err("gf1", __FUNCTION__, ret); diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index cdac8f6b2..5e3ce22a4 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -213,7 +213,9 @@ uschar * tls_cert_issuer(void * cert, const uschar * mod) { uschar * cp = x509_name_copy(X509_get_issuer_name((X509 *)cert)); -return mod ? tls_field_from_dn(cp, mod) : cp; +if (mod) cp = tls_field_from_dn(cp, mod); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +return cp ? string_copy_taint(cp, GET_TAINTED) : cp; } uschar * @@ -312,7 +314,9 @@ uschar * tls_cert_subject(void * cert, const uschar * mod) { uschar * cp = x509_name_copy(X509_get_subject_name((X509 *)cert)); -return mod ? tls_field_from_dn(cp, mod) : cp; +if (mod) cp = tls_field_from_dn(cp, mod); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +return cp ? string_copy_taint(cp, GET_TAINTED) : cp; } uschar * @@ -345,6 +349,7 @@ M_ASN1_OCTET_STRING_print(bp, adata); /* binary data, DER encoded */ /* just dump for now */ len = BIO_get_mem_data(bp, &cp1); +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ cp3 = cp2 = store_get(len*3+1, GET_TAINTED); while(len) @@ -360,14 +365,13 @@ return cp3; uschar * tls_cert_subject_altname(void * cert, const uschar * mod) { -gstring * list = NULL; STACK_OF(GENERAL_NAME) * san = (STACK_OF(GENERAL_NAME) *) X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL); uschar osep = '\n'; -uschar * tag = US""; -uschar * ele; -int match = -1; -int len; +uschar * tag = US"", * ele; +int match = -1, len; +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +gstring * list = string_get_tainted(0, GET_TAINTED); if (!san) return NULL; @@ -417,7 +421,7 @@ while (sk_GENERAL_NAME_num(san) > 0) } sk_GENERAL_NAME_free(san); -return string_from_gstring(list); +return gstring_length(list) > 0 ? string_from_gstring(list) : NULL; } uschar * @@ -427,7 +431,8 @@ STACK_OF(ACCESS_DESCRIPTION) * ads = (STACK_OF(ACCESS_DESCRIPTION) *) X509_get_ext_d2i((X509 *)cert, NID_info_access, NULL, NULL); int adsnum = sk_ACCESS_DESCRIPTION_num(ads); uschar sep = '\n'; -gstring * list = NULL; +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +gstring * list = string_get_tainted(0, GET_TAINTED); if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -442,7 +447,7 @@ for (int i = 0; i < adsnum; i++) ASN1_STRING_length(ad->location->d.ia5)); } sk_ACCESS_DESCRIPTION_free(ads); -return string_from_gstring(list); +return gstring_length(list) > 0 ? string_from_gstring(list) : NULL; } uschar * @@ -453,7 +458,8 @@ STACK_OF(DIST_POINT) * dps = (STACK_OF(DIST_POINT) *) NULL, NULL); DIST_POINT * dp; uschar sep = '\n'; -gstring * list = NULL; +/*XXX we might want to distinguish ourcert from peercert (but this is safe) */ +gstring * list = string_get_tainted(0, GET_TAINTED); if (mod) if (*mod == '>' && *++mod) sep = *mod++; @@ -473,7 +479,7 @@ if (dps) for (int i = 0, dpsnum = sk_DIST_POINT_num(dps); i < dpsnum; i++) ASN1_STRING_length(np->d.uniformResourceIdentifier)); } sk_DIST_POINT_free(dps); -return string_from_gstring(list); +return gstring_length(list) > 0 ? string_from_gstring(list) : NULL; } diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index ebf11b7f7..cad14b889 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -3343,12 +3343,23 @@ ret_panic: transport_info appendfile_transport_info = { .drinfo = { .driver_name = US"appendfile", + .avail_string = US" appendfile" +# ifdef SUPPORT_MAILDIR + "/maildir" +# endif +# ifdef SUPPORT_MAILSTORE + "/mailstore" +# endif +# ifdef SUPPORT_MBX + "/mbx" +# endif + , .options = appendfile_transport_options, .options_count = &appendfile_transport_options_count, .options_block = &appendfile_transport_option_defaults, /* private options defaults */ .options_len = sizeof(appendfile_transport_options_block), .init = appendfile_transport_init, -# ifdef DYNLOOKUP +# if TRANSPORT_APPENDFILE==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 62eb888d0..d9d9d7a9d 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -817,7 +817,7 @@ transport_info autoreply_transport_info = { .options_block = &autoreply_transport_option_defaults, .options_len = sizeof(autoreply_transport_options_block), .init = autoreply_transport_init, -# ifdef DYNLOOKUP +# if TRANSPORT_AUTOREPLY==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index 3403dce7a..322dfbb71 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -825,7 +825,7 @@ transport_info lmtp_transport_info = { .options_block = &lmtp_transport_option_defaults, .options_len = sizeof(lmtp_transport_options_block), .init = lmtp_transport_init, -# ifdef DYNLOOKUP +# if TRANSPORT_LMTP==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 68036ce03..fd248113a 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -1142,7 +1142,7 @@ transport_info pipe_transport_info = { .options_block = &pipe_transport_option_defaults, .options_len = sizeof(pipe_transport_options_block), .init = pipe_transport_init, -# ifdef DYNLOOKUP +# if TRANSPORT_PIPE==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index 7ae71a8da..5bd02682e 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -300,7 +300,7 @@ transport_info queuefile_transport_info = { .options_block = &queuefile_transport_option_defaults, .options_len = sizeof(queuefile_transport_options_block), .init = queuefile_transport_init, -# ifdef DYNLOOKUP +# if EXPERIMENTAL_QUEUEFILE==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index e9dc0957c..36b6370fd 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2381,6 +2381,7 @@ if (continue_hostname && continue_proxy_cipher) if (write(0, "QUIT\r\n", 6) < 0) DEBUG(D_any) debug_printf("stupid compiler\n"); close(0); + tls_out.active.sock = -1; continue_hostname = continue_proxy_cipher = NULL; f.continue_more = FALSE; continue_sequence = 1; /* Ensure proper logging of non-cont-conn */ @@ -2882,6 +2883,7 @@ else if (write(0, "QUIT\r\n", 6) < 0) DEBUG(D_any) debug_printf("stupid compiler\n"); close(0); + tls_out.active.sock = -1; continue_hostname = continue_proxy_cipher = NULL; f.continue_more = FALSE; continue_sequence = 1; /* Ensure proper logging of non-cont-conn */ @@ -3027,6 +3029,7 @@ if ( smtp_peer_options & OPTION_TLS sx->send_quit = FALSE; goto TLS_FAILED; } + tls_out.smtp_quit = FALSE; sx->send_tlsclose = TRUE; # ifdef TCP_FASTOPEN @@ -3484,7 +3487,10 @@ FAILED: SEND_QUIT: if (sx->send_quit) + { (void)smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n"); + tls_out.smtp_quit = TRUE; + } #ifndef DISABLE_TLS if (sx->cctx.tls_ctx) @@ -4476,6 +4482,7 @@ else HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(shutdown)>>\n"); shutdown(sx->cctx.sock, SHUT_WR); /* flush output buffer, with TCP FIN */ } + tls_out.smtp_quit = TRUE; } if (smtp_peer_options & OPTION_CHUNKING && sx->cmd_count > 1) @@ -5170,6 +5177,10 @@ if (sx->send_quit) { /* Use _MORE to get QUIT in FIN segment */ (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n"); #ifndef DISABLE_TLS + /* This flag is a custom hack to avoid logging, under GnuTLS, Google's + habit of just dropping the TCP conn (which violates TLS spec) */ + tls_out.smtp_quit = TRUE; + if (sx->cctx.tls_ctx && sx->send_tlsclose) { # ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */ @@ -5357,6 +5368,7 @@ sx.outblock.cmd_count = 0; sx.outblock.authenticating = FALSE; (void)smtp_write_command(&sx, SCMD_FLUSH, "QUIT\r\n"); +tls_out.smtp_quit = TRUE; (void)smtp_read_response(&sx, buffer, sizeof(buffer), '2', ob->command_timeout); (void)close(cctx.sock); } @@ -6545,7 +6557,7 @@ transport_info smtp_transport_info = { .options_block = &smtp_transport_option_defaults, .options_len = sizeof(smtp_transport_options_block), .init = smtp_transport_init, -# ifdef DYNLOOKUP +# if TRANSPORT_SMTP==2 .dyn_magic = TRANSPORT_MAGIC, # endif }, diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index df6c9e963..49e3c8b96 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -202,7 +202,7 @@ typedef struct { unsigned avoid_option; uschar * igquotstr; - uschar * helo_data; + const uschar * helo_data; #ifdef EXPERIMENTAL_DSN_INFO uschar * smtp_greeting; uschar * helo_response; diff --git a/src/src/utf8.c b/src/src/utf8.c index c05853838..6cb104ddd 100644 --- a/src/src/utf8.c +++ b/src/src/utf8.c @@ -47,37 +47,40 @@ The *err string pointer should be null before the call Return NULL for error, with optional errstr pointer filled in */ -uschar * +const uschar * string_domain_utf8_to_alabel(const uschar * utf8, uschar ** err) { -uschar * s1, * s; +const uschar * cs; +uschar * t, * s; int rc; #ifdef SUPPORT_I18N_2008 /* Avoid lowercasing plain-ascii domains */ if (!string_is_utf8(utf8)) - return string_copy(utf8); + return utf8; /* Only lowercase is accepted by the library call. A pity since we lose any mixed-case annotation. This does not really matter for a domain. */ { + const uschar * cs1; uschar c; - for (s1 = s = US utf8; (c = *s1); s1++) if (!(c & 0x80) && isupper(c)) + for (cs1 = cs = utf8; (c = *cs1); cs1++) if (!(c & 0x80) && isupper(c)) { s = string_copy(utf8); - for (s1 = s + (s1 - utf8); (c = *s1); s1++) if (!(c & 0x80) && isupper(c)) - *s1 = tolower(c); + for (t = s + (cs1 - utf8); (c = *t); t++) if (!(c & 0x80) && isupper(c)) + *t = tolower(c); + cs = s; break; } } -if ((rc = idn2_lookup_u8((const uint8_t *) s, &s1, IDN2_NFC_INPUT)) != IDN2_OK) +if ((rc = idn2_lookup_u8((const uint8_t *) cs, &t, IDN2_NFC_INPUT)) != IDN2_OK) { if (err) *err = US idn2_strerror(rc); return NULL; } #else s = US stringprep_utf8_nfkc_normalize(CCS utf8, -1); -if ( (rc = idna_to_ascii_8z(CCS s, CSS &s1, IDNA_ALLOW_UNASSIGNED)) +if ( (rc = idna_to_ascii_8z(CCS s, CSS &t, IDNA_ALLOW_UNASSIGNED)) != IDNA_SUCCESS) { free(s); @@ -86,9 +89,9 @@ if ( (rc = idna_to_ascii_8z(CCS s, CSS &s1, IDNA_ALLOW_UNASSIGNED)) } free(s); #endif -s = string_copy(s1); -free(s1); -return s; +cs = string_copy(t); +free(t); +return cs; } @@ -132,7 +135,7 @@ return s; /* the *err string pointer should be null before the call */ -uschar * +const uschar * string_localpart_utf8_to_alabel(const uschar * utf8, uschar ** err) { size_t ucs4_len = 0; @@ -141,7 +144,7 @@ size_t p_len; uschar * res; int rc; -if (!string_is_utf8(utf8)) return string_copy(utf8); +if (!string_is_utf8(utf8)) return utf8; p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len); if (!p || !ucs4_len) @@ -212,10 +215,10 @@ The *err string pointer should be null before the call. Return NULL on error, with (optional) errstring pointer filled in */ -uschar * +const uschar * string_address_utf8_to_alabel(const uschar * utf8, uschar ** err) { -uschar * l, * d; +const uschar * l, * d; if (!*utf8) return string_copy(utf8); diff --git a/src/src/utils/eximstats.src b/src/src/utils/eximstats.src index 84b60ceaa..41912c1fb 100644 --- a/src/src/utils/eximstats.src +++ b/src/src/utils/eximstats.src @@ -1852,7 +1852,7 @@ EoText sub generate_parser { my $parser = ' my($ip,$host,$email,$edomain,$domain,$thissize,$size,$old,$new); - my($tod,$m_hour,$m_min,$id,$flag,$extra,$length); + my($tod,$m_hour,$m_min,$id,$flag,$offset,$length); my($seconds,$queued,$rcpt_time,$local_domain); my $rej_id = 0; while (<$fh>) { @@ -1865,72 +1865,68 @@ sub generate_parser { $length = length($_); next if ($length < 38); next unless /^ - (\\d{4}\\-\\d\\d-\\d\\d\\s # 1: YYYYMMDD HHMMSS - (\\d\\d) # 2: HH - : - (\\d\\d) # 3: MM - :\\d\\d - ) - (\\.\\d+)? # 4: subseconds - (\s[-+]\\d\\d\\d\\d)? # 5: tz-offset - (\s\\[\\d+\\])? # 6: pid + (\\d{4}\\-\\d\\d-\\d\\d\\s # 1: YYYYMMDD HHMMSS 11 + (\\d\\d) # 2: HH 2 + : # 1 + (\\d\\d) # 3: MM 2 + :\\d\\d # 3 + ) # = 19 + (\\.\\d+)? # 4: subseconds (var) + (\s[-+]\\d{4})? # 5: tz-offset 6 + (\s\\[\\d+\\])? # 6: pid (var) /ox; + $offset = 19; $tod = defined($5) ? $1 . $5 : $1; ($m_hour,$m_min) = ($2,$3); + # watch for subsecond precision + if (defined($4)) { + $offset += length($4); + next if ($length < 19 + $offset); + } + # PH - watch for GMT offsets in the timestamp. if (defined($5)) { - $extra = 6; + $offset += 6; next if ($length < 44); - } - else { - $extra = 0; - } - - # watch for subsecond precision - if (defined($4)) { - $extra += length($4); - next if ($length < 38 + $extra); + next if ($length < 19 + $offset); } # PH - watch for PID added after the timestamp. if (defined($6)) { - $extra += length($6); - next if ($length < 38 + $extra); + $offset += length($6); + next if ($length < 19 + $offset); } - # jgh 2025/09/30 - I really dislike this magic "20" offset... - # It would be better to develop it from the substrings captured so far. + # skip space after the initial groups + $offset++; - # $id = substr($_, 20 + $extra, 16); # old ID was 16 chars - $id = substr($_, 20 + $extra, 23); # new ID is 23 chars + $id = substr($_, $offset, 23); # new ID is 23 chars, old 16 $id =~ s/(\S+).*/$1/; - # - # jgh 2025/09/30 - very fragile when this word was not an ID; - # could be shorter than 16. - $extra += length($id) - 16; - # 37 = 20+16+1 so next field after ID. Assuming there was really an ID. - $flag = substr($_, 37 + $extra, 2); + # skip ID and space + $offset += length($id) + 1; + + $flag = substr($_, $offset, 2); # jgh 2025/09/30 - - # 2020-05-12 17:31:41.630 [23229] auth_login authenticator failed for (User) [185.143.75.81]:28556 I=[192.168.56.110]:25: 535 Incorrect authentication data (set_id=dropped@kiev.ua) - # OTOH the "refused" and "dropped" probably are referring to connectios - # rather than messages. + # 2020-05-12 17:31:41.630 [23229] auth_login authenticator failed for (User) [185.143.75.81]:28556 I=[192.168.56.110]:25: 535 Incorrect authentication data (set_id=dropped@foo.us) + # We now count these as cause for connection-drop, since the client often + # does on getting an auth-fail (distributed password-guessing attacks...). # # The "[-<>=*(]+" will be for ignoring accept & delivery lines. # What is the "SA"? SpamAssissin ? if ($flag !~ /^([-<>=*(]+|SA)$/ && / (rejected|refused|dropped|authenticator failed)/) { $flag = "Re"; - $extra -= 3; + } else { + # skip flag and space + $offset += 3; } # Rejects might have no MSGID... - # Note that $extra can go negative here. Really, a $offset would be - # much more clear. if ($flag eq "Re" && $id !~ /^[-0-9a-zA-Z]+$/) { - $extra -= length($id) + 1; + $offset -= length($id) + 1; $id = "reject:" . ++$rej_id; } '; @@ -1947,11 +1943,13 @@ sub generate_parser { } $parser .= ' - next unless ($flag =~ /<=|=>|->|==|\\*\\*|Co|SA|Re/); + next unless ($flag =~ /<=|\(=|=>|->|==|\\*\\*|Co|SA|Re/); + + # TODO: handling for fakereject [ flag (= ] - #Strip away the timestamp, ID and flag to speed up later pattern matches. - #The flags include Co (Completed), Re (Rejected), and SA (SpamAssassin). - $_ = substr($_, 40 + $extra); # PH + # Strip away the timestamp, ID and flag to speed up later pattern matches. + # The flags include Co (Completed), Re (Rejected), and SA (SpamAssassin). + $_ = substr($_, $offset); # PH # Alias @message to the array of information about the message. # This minimises the number of calls to hash functions. diff --git a/src/src/utils/exipick.src b/src/src/utils/exipick.src index c441936a2..788f7efae 100644 --- a/src/src/utils/exipick.src +++ b/src/src/utils/exipick.src @@ -941,8 +941,6 @@ sub _parse_header { } elsif ($tag eq '-spam_score_int') { $self->{_vars}{spam_score_int} = $arg; $self->{_vars}{spam_score} = $arg / 10; - } elsif ($tag eq '-bmi_verdicts') { - $self->{_vars}{bmi_verdicts} = $arg; } elsif ($tag eq '-host_lookup_deferred') { $self->{_vars}{host_lookup_deferred} = 1; } elsif ($tag eq '-host_lookup_failed') { @@ -1569,10 +1567,6 @@ The value of AUTH= param for smtp messages, or a generated value from the callin Value of the header(s) with the same name with any RFC2047 words decoded if present. See section 11.5 of Exim's spec.txt for full details. -=item S + B<$bmi_verdicts> - -The verdict string provided by a Brightmail content scan - =item N . B<$body_linecount> The number of lines in the message's body. diff --git a/src/src/verify.c b/src/src/verify.c index a12e74ce6..a3ade640b 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2779,162 +2779,6 @@ return yield; -/************************************************* -* Get RFC 1413 identification * -*************************************************/ - -/* Attempt to get an id from the sending machine via the RFC 1413 protocol. If -the timeout is set to zero, then the query is not done. There may also be lists -of hosts and nets which are exempt. To guard against malefactors sending -non-printing characters which could, for example, disrupt a message's headers, -make sure the string consists of printing characters only. - -Argument: - port the port to connect to; usually this is IDENT_PORT (113), but when - running in the test harness with -bh a different value is used. - -Returns: nothing - -Side effect: any received ident value is put in sender_ident (NULL otherwise) -*/ - -void -verify_get_ident(int port) -{ -client_conn_ctx ident_conn_ctx = {0}; -int host_af, qlen; -int received_sender_port, received_interface_port, n; -uschar *p; -blob early_data; -uschar buffer[2048]; - -/* Default is no ident. Check whether we want to do an ident check for this -host. */ - -sender_ident = NULL; -if (rfc1413_query_timeout <= 0 || verify_check_host(&rfc1413_hosts) != OK) - return; - -DEBUG(D_ident) debug_printf("doing ident callback\n"); - -/* Set up a connection to the ident port of the remote host. Bind the local end -to the incoming interface address. If the sender host address is an IPv6 -address, the incoming interface address will also be IPv6. */ - -host_af = Ustrchr(sender_host_address, ':') == NULL ? AF_INET : AF_INET6; -if ((ident_conn_ctx.sock = ip_socket(SOCK_STREAM, host_af)) < 0) return; - -if (ip_bind(ident_conn_ctx.sock, host_af, interface_address, 0) < 0) - { - DEBUG(D_ident) debug_printf("bind socket for ident failed: %s\n", - strerror(errno)); - goto END_OFF; - } - -/* Construct and send the query. */ - -qlen = snprintf(CS buffer, sizeof(buffer), "%d , %d\r\n", - sender_host_port, interface_port); -early_data.data = buffer; -early_data.len = qlen; - -/*XXX we trust that the query is idempotent */ -if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port, - rfc1413_query_timeout, &early_data) < 0) - { - if (errno == ETIMEDOUT && LOGGING(ident_timeout)) - log_write(0, LOG_MAIN, "ident connection to %s timed out", - sender_host_address); - else - DEBUG(D_ident) debug_printf("ident connection to %s failed: %s\n", - sender_host_address, strerror(errno)); - goto END_OFF; - } - -/* Read a response line. We put it into the rest of the buffer, using several -recv() calls if necessary. */ - -p = buffer + qlen; - -for (;;) - { - uschar *pp; - int count; - int size = sizeof(buffer) - (p - buffer); - - if (size <= 0) goto END_OFF; /* Buffer filled without seeing \n. */ - count = ip_recv(&ident_conn_ctx, p, size, time(NULL) + rfc1413_query_timeout); - if (count <= 0) goto END_OFF; /* Read error or EOF */ - - /* Scan what we just read, to see if we have reached the terminating \r\n. Be - generous, and accept a plain \n terminator as well. The only illegal - character is 0. */ - - for (pp = p; pp < p + count; pp++) - { - if (*pp == 0) goto END_OFF; /* Zero octet not allowed */ - if (*pp == '\n') - { - if (pp[-1] == '\r') pp--; - *pp = 0; - goto GOT_DATA; /* Break out of both loops */ - } - } - - /* Reached the end of the data without finding \n. Let the loop continue to - read some more, if there is room. */ - - p = pp; - } - -GOT_DATA: - -/* We have received a line of data. Check it carefully. It must start with the -same two port numbers that we sent, followed by data as defined by the RFC. For -example, - - 12345 , 25 : USERID : UNIX :root - -However, the amount of white space may be different to what we sent. In the -"osname" field there may be several sub-fields, comma separated. The data we -actually want to save follows the third colon. Some systems put leading spaces -in it - we discard those. */ - -if (sscanf(CS buffer + qlen, "%d , %d%n", &received_sender_port, - &received_interface_port, &n) != 2 || - received_sender_port != sender_host_port || - received_interface_port != interface_port) - goto END_OFF; - -p = buffer + qlen + n; -Uskip_whitespace(&p); -if (*p++ != ':') goto END_OFF; -Uskip_whitespace(&p); -if (Ustrncmp(p, "USERID", 6) != 0) goto END_OFF; -p += 6; -Uskip_whitespace(&p); -if (*p++ != ':') goto END_OFF; -while (*p && *p != ':') p++; -if (!*p++) goto END_OFF; -Uskip_whitespace(&p); -if (!*p) goto END_OFF; - -/* The rest of the line is the data we want. We turn it into printing -characters when we save it, so that it cannot mess up the format of any logging -or Received: lines into which it gets inserted. We keep a maximum of 127 -characters. The deconst cast is ok as we fed a nonconst to string_printing() */ - -sender_ident = US string_printing(string_copyn(p, 127)); -DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident); - -END_OFF: -(void)close(ident_conn_ctx.sock); -return; -} - - - - /************************************************* * Match host to a single host-list item * *************************************************/ commit 3858878623272c18ad8b4d3f856c3a3dbe22577c Author: Jeremy Harris Date: Thu Oct 30 09:42:01 2025 +0000 Fix taint status for dbm lookups. Bug 3169 Broken-by: c66a6edf7ba8 diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 7f6951ee3..30015fe73 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -386,13 +386,15 @@ Arguments: key the key of the record to be read klen length of key including a terminating NUL (if present) length a pointer to an int into which to return the length, if not NULL + hintsdb TRUE for hints DB use, FALSE for lookup dbm use Returns: a pointer to the retrieved record, or NULL if the record is not found */ void * -dbfn_read_klen(open_db * dbblock, const uschar * key, int klen, int * length) +dbfn_read_klen(open_db * dbblock, const uschar * key, int klen, int * length, + BOOL hintsdb) { void * yield; EXIM_DATUM key_datum, result_datum; @@ -423,7 +425,7 @@ store the taint status with the data. */ dlen = exim_datum_size_get(&result_datum); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); -yield = store_get(dlen+1, GET_TAINTED); +yield = store_get(dlen+1, hintsdb ? GET_TAINTED : GET_UNTAINTED); memcpy(yield, exim_datum_data_get(&result_datum), dlen); ((uschar *)yield)[dlen] = '\0'; if (length) *length = dlen; @@ -451,7 +453,7 @@ Returns: a pointer to the retrieved record, or void * dbfn_read_with_length(open_db * dbblock, const uschar * key, int * lenp) { -return dbfn_read_klen(dbblock, key, Ustrlen(key)+1, lenp); +return dbfn_read_klen(dbblock, key, Ustrlen(key)+1, lenp, TRUE); } diff --git a/src/src/dbfunctions.h b/src/src/dbfunctions.h index 1b0e446f7..a6fb2b51e 100644 --- a/src/src/dbfunctions.h +++ b/src/src/dbfunctions.h @@ -18,7 +18,7 @@ int dbfn_delete(open_db *, const uschar *); open_db *dbfn_open(const uschar *, int, open_db *, BOOL, BOOL); open_db * dbfn_open_path(const uschar *, open_db *); open_db *dbfn_open_multi(const uschar *, int, open_db *); -void *dbfn_read_klen(open_db *, const uschar *, int, int *); +void *dbfn_read_klen(open_db *, const uschar *, int, int *, BOOL); void *dbfn_read_with_length(open_db *, const uschar *, int *); void *dbfn_read_enforce_length(open_db *, const uschar *, size_t); uschar *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **); diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c index d3b26cf0a..58a839e84 100644 --- a/src/src/lookups/dbmdb.c +++ b/src/src/lookups/dbmdb.c @@ -91,7 +91,8 @@ dbmdb_find(void * handle, const uschar * filename, const uschar * keystring, const uschar * opts) { open_db * d = (open_db *)handle; -return (*result = dbfn_read_klen(d, keystring, length+1, NULL)) ? OK : FAIL; +return (*result = dbfn_read_klen(d, keystring, length+1, NULL, FALSE)) + ? OK : FAIL; } commit 50a6abf200c5116e9b86f12afbcc973ccd021261 Author: Jeremy Harris Date: Fri Oct 31 12:55:40 2025 +0000 Testsuite: expand store_free() checking diff --git a/src/src/deliver.c b/src/src/deliver.c index 497c62e81..94dc092a3 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -9088,6 +9088,38 @@ fail: #endif } + +/* When running with debug_store this is called on every store_reset(). Walk all +the address lists we maintain checking that none of the pointers are in the region +being freed. */ +/*XXX what about all the pointers contained in the addr? +If implemented, beware unbounded recursion. */ + +static void +check_addr_list(const uschar * name, const address_item * a, + void (*f)(const uschar*, const uschar*, void*), void * ctx) +{ +while (a) + { + f(name, CUS a, ctx); /* We lie about the data type */ + a = a->next; + } +} + +void +check_deliver_addrs_not_freed(void (*f)(const uschar*, const uschar*, void*), void * ctx) +{ +check_addr_list(US"(addr_defer)", addr_defer, f, ctx); +check_addr_list(US"(addr_failed)", addr_failed, f, ctx); +check_addr_list(US"(addr_fallback)", addr_fallback, f, ctx); +check_addr_list(US"(addr_local)", addr_local, f, ctx); +check_addr_list(US"(addr_new)", addr_new, f, ctx); +check_addr_list(US"(addr_remote)", addr_remote, f, ctx); +check_addr_list(US"(addr_route)", addr_route, f, ctx); +check_addr_list(US"(addr_succeed)", addr_succeed, f, ctx); +check_addr_list(US"(addr_duplicate)", addr_duplicate, f, ctx); +} + /* vi: aw ai sw=2 */ /* End of deliver.c */ diff --git a/src/src/expand.c b/src/src/expand.c index 554d68ba6..9bfa39fdc 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -9017,15 +9017,18 @@ typedef struct { const uschar *var_data; } err_ctx; -/* Called via tree_walk, which allows nonconst name/data. Our usage is const. */ +/* Called via tree_walk, which allows nonconst name/data. Our usage is const. */ +typedef void (*twalk_compat)(uschar *, uschar *, void *); + static void -assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx) +assert_variable_notin(const uschar * var_name, const uschar * var_data, + void * ctx) { err_ctx * e = ctx; if (var_data >= e->region_start && var_data < e->region_end) { - e->var_name = CUS var_name; - e->var_data = CUS var_data; + e->var_name = var_name; + e->var_data = var_data; } } @@ -9036,8 +9039,8 @@ err_ctx e = { .region_start = ptr, .region_end = US ptr + len, .var_name = NULL, .var_data = NULL }; /* check acl_ variables */ -tree_walk(acl_var_c, assert_variable_notin, &e); -tree_walk(acl_var_m, assert_variable_notin, &e); +tree_walk(acl_var_c, (twalk_compat) assert_variable_notin, &e); +tree_walk(acl_var_m, (twalk_compat) assert_variable_notin, &e); /* check auth variables. assert_variable_notin() treats as const, so deconst is safe. */ @@ -9056,10 +9059,13 @@ for (var_entry * v = var_table; v < var_table + nelem(var_table); v++) assert_variable_notin(US v->name, *(USS v->value), &e); /* check dns and address trees */ -tree_walk(tree_dns_fails, assert_variable_notin, &e); -tree_walk(tree_duplicates, assert_variable_notin, &e); -tree_walk(tree_nonrecipients, assert_variable_notin, &e); -tree_walk(tree_unusable, assert_variable_notin, &e); +tree_walk(tree_dns_fails, (twalk_compat) assert_variable_notin, &e); +tree_walk(tree_duplicates, (twalk_compat) assert_variable_notin, &e); +tree_walk(tree_nonrecipients, (twalk_compat) assert_variable_notin, &e); +tree_walk(tree_unusable, (twalk_compat) assert_variable_notin, &e); + +/* check address-lists */ +check_deliver_addrs_not_freed(assert_variable_notin, &e); if (e.var_name) log_write_die(0, LOG_MAIN, diff --git a/src/src/functions.h b/src/src/functions.h index a29dddbed..223723b81 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -144,6 +144,7 @@ extern void bits_set(unsigned int *, size_t, int *); extern void cancel_cutthrough_connection(BOOL, const uschar *); extern gstring *cat_file(FILE *, gstring *, const uschar *); extern gstring *cat_file_tls(void *, gstring *, const uschar *); +extern void check_deliver_addrs_not_freed(void (*)(const uschar*, const uschar*, void*), void *); extern int check_host(void *, const uschar *, const uschar **, uschar **); extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...); extern pid_t child_open_exim_function(int *, const uschar *); diff --git a/src/src/transport.c b/src/src/transport.c index d88653964..a59a5ae3d 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -705,10 +705,10 @@ Returns: FALSE if writing failed */ static BOOL -write_env_to(address_item *p, struct aci **pplist, struct aci **pdlist, - BOOL *first, transport_ctx * tctx) +write_env_to(address_item * p, struct aci ** pplist, struct aci ** pdlist, + BOOL * first, transport_ctx * tctx) { -address_item *pp; +address_item * pp; struct aci *ppp; /* Do nothing if we have already handled this address. If not, remember it @@ -725,8 +725,7 @@ ppp->ptr = p; for (pp = p;; pp = pp->parent) { - address_item *dup; - for (dup = addr_duplicate; dup; dup = dup->next) + for (address_item * dup = addr_duplicate; dup; dup = dup->next) if (dup->dupof == pp) /* a dup of our address */ if (!write_env_to(dup, pplist, pdlist, first, tctx)) return FALSE; commit baad2e56cdcffa83e2e5d138537dcef858bdf5b6 Author: Jeremy Harris Date: Fri Oct 31 12:59:39 2025 +0000 Fix duplicate address processing vs. continued-transport Broken-by: 79344067b96a diff --git a/src/src/deliver.c b/src/src/deliver.c index 94dc092a3..29c5dbfc6 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -8980,7 +8980,9 @@ report_time_since(×tamp_startup, US"delivery end"); /* testcase 0005 */ if (final_yield == DELIVER_ATTEMPTED_NORMAL && *continue_next_id) { addr_defer = addr_failed = addr_succeed = NULL; + tree_duplicates = NULL; /* discard dups info from old message */ + addr_duplicate = NULL; spool_clear_header_globals(); deliver_set_expansions(NULL); commit d021d9bddfbe66cfec7027999aa3ee501198e20a Author: Jeremy Harris Date: Sun Nov 2 10:12:55 2025 +0000 tidying diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 80fb419d0..154d3be38 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2163,10 +2163,7 @@ if (host) /* For client-side sessions we allocate a context. This lets us run several in parallel. */ - int old_pool = store_pool; - store_pool = POOL_PERM; - state = store_get(sizeof(exim_gnutls_state_st), GET_UNTAINTED); - store_pool = old_pool; + state = store_get_perm(sizeof(exim_gnutls_state_st), GET_UNTAINTED); memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init)); state->lib_state = ob->tls_preload; @@ -2806,7 +2803,7 @@ char sni_name[MAX_HOST_LEN]; size_t data_len = MAX_HOST_LEN; exim_gnutls_state_st *state = &state_server; unsigned int sni_type; -int rc, old_pool; +int rc; uschar * dummy_errstr; rc = gnutls_server_name_get(session, sni_name, &data_len, &sni_type, 0); @@ -2828,10 +2825,7 @@ if (sni_type != GNUTLS_NAME_DNS) } /* We now have a UTF-8 string in sni_name */ -old_pool = store_pool; -store_pool = POOL_PERM; -state->received_sni = string_copy_taint(US sni_name, GET_TAINTED); -store_pool = old_pool; +state->received_sni = string_copy_perm(US sni_name, TRUE); /* We set this one now so that variable expansions below will work */ state->tlsp->sni = state->received_sni; @@ -4386,8 +4380,9 @@ host_item * h; int old_pool = store_pool; store_pool = POOL_PERM; -state = store_get(sizeof(exim_gnutls_state_st), GET_UNTAINTED); -h = store_get(sizeof(host_item), GET_UNTAINTED); +state = store_get(sizeof(exim_gnutls_state_st) + sizeof(host_item), + GET_UNTAINTED); +h = ((host_item *)state) + 1; memset(h, 0, sizeof(host_item)); h->name = h->address = string_copy(ipaddr); @@ -4419,12 +4414,8 @@ store_pool = old_pool; void tls_state_out_to_in(int newfd, const uschar * ipaddr, int port) { -host_item * h; -int old_pool = store_pool; +host_item * h = store_get_perm(sizeof(host_item), GET_UNTAINTED); -store_pool = POOL_PERM; -h = store_get(sizeof(host_item), GET_UNTAINTED); -store_pool = old_pool; memset(h, 0, sizeof(host_item)); h->name = h->address = string_copy(ipaddr); h->port = port; diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index d5a6d368d..ddc72bfa2 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -2231,7 +2231,6 @@ tls_servername_cb(SSL * s, int * ad ARG_UNUSED, void * arg) const char * servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); exim_openssl_state_st * state = (exim_openssl_state_st *) arg; int rc; -int old_pool = store_pool; uschar * errstr; if (!servername) @@ -2241,9 +2240,7 @@ DEBUG(D_tls) debug_printf("Received TLS SNI %q%s\n", servername, reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)"); /* Make the extension value available for expansion */ -store_pool = POOL_PERM; -tls_in.sni = string_copy_taint(US servername, GET_TAINTED); -store_pool = old_pool; +tls_in.sni = string_copy_perm(US servername, TRUE); if (!reexpand_tls_files_for_sni) return SSL_TLSEXT_ERR_OK; @@ -3119,13 +3116,8 @@ return cipher_stdname(id >> 8, id & 0xff); static const uschar * tlsver_name(const SSL * ssl) { -const uschar * s; -uschar * p; -int pool = store_pool; +uschar * s = string_copy_perm(US SSL_get_version(ssl), FALSE), * p; -store_pool = POOL_PERM; -s = string_copy(US SSL_get_version(ssl)); -store_pool = pool; if ((p = Ustrchr(s, 'v'))) /* TLSv1.2 -> TLS1.2 */ for (;; p++) if (!(*p = p[1])) break; return CUS s; @@ -3151,12 +3143,8 @@ if (tlsp->peercert) { DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); } else { - int oldpool = store_pool; - peerdn[siz-1] = '\0'; /* paranoia */ - store_pool = POOL_PERM; - tlsp->peerdn = string_copy(peerdn); - store_pool = oldpool; + tlsp->peerdn = string_copy_perm(peerdn, TRUE); /* We used to set CV in the cert-verify callbacks (either plain or dane) but they don't get called on session-resumption. So use the official @@ -4237,11 +4225,9 @@ BOOL request_ocsp = FALSE; BOOL require_ocsp = FALSE; #endif -rc = store_pool; -store_pool = POOL_PERM; -exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), GET_UNTAINTED); +exim_client_ctx = store_get_perm(sizeof(exim_openssl_client_tls_ctx), + GET_UNTAINTED); exim_client_ctx->corked = NULL; -store_pool = rc; #ifdef SUPPORT_DANE tlsp->tlsa_usage = 0; @@ -5268,18 +5254,16 @@ void tls_state_in_to_out(int newfd, const uschar * ipaddr, int port) { exim_openssl_client_tls_ctx * exim_client_ctx; -int old_pool = store_pool; state_server.is_server = FALSE; state_server.tlsp = &tls_out; client_static_state = &state_server; -store_pool = POOL_PERM; -exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), GET_UNTAINTED); +exim_client_ctx = store_get_perm(sizeof(exim_openssl_client_tls_ctx), + GET_UNTAINTED); exim_client_ctx->ctx = client_static_state->lib_state.lib_ctx; exim_client_ctx->ssl = client_static_state->lib_state.lib_ssl; exim_client_ctx->corked = NULL; -store_pool = old_pool; SSL_set_fd(exim_client_ctx->ssl, newfd); commit 195bf3719bb6d673f6730b221cfcd0dfec0281b4 Author: Jeremy Harris Date: Sun Nov 2 14:31:22 2025 +0000 Revert "Retire identd support" This reverts commit 106c3eb8ee31297588d5ec0555195be966dfd7b2. diff --git a/src/src/configure.default b/src/src/configure.default index c05ed182e..633c6539e 100644 --- a/src/src/configure.default +++ b/src/src/configure.default @@ -260,6 +260,21 @@ host_lookup = * dns_dnssec_ok = 1 +# The settings below cause Exim to make RFC 1413 (ident) callbacks +# for all incoming SMTP calls. You can limit the hosts to which these +# calls are made, and/or change the timeout that is used. If you set +# the timeout to zero, all RFC 1413 calls are disabled. RFC 1413 calls +# are cheap and can provide useful information for tracing problem +# messages, but some hosts and firewalls have problems with them. +# This can result in a timeout instead of an immediate refused +# connection, leading to delays on starting up SMTP sessions. +# (The default was reduced from 30s to 5s for release 4.61. and to +# disabled for release 4.86) +# +#rfc1413_hosts = * +#rfc1413_query_timeout = 5s + + # Enable an efficiency feature. We advertise the feature; clients # may request to use it. For multi-recipient mails we then can # reject or accept per-user after the message is received. diff --git a/src/src/daemon.c b/src/src/daemon.c index 824fe0187..a31ef1eb5 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -479,9 +479,20 @@ if (pid == 0) signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); - /* Set up the fullhost information in case there is no HELO/EHLO. */ + /* Attempt to get an id from the sending machine via the RFC 1413 + protocol. We do this in the sub-process in order not to hold up the + main process if there is any delay. Then set up the fullhost information + in case there is no HELO/EHLO. + If debugging is enabled only for the daemon, we must turn if off while + finding the id, but turn it on again afterwards so that information about the + incoming connection is output. */ + + if (f.debug_daemon) debug_selector = 0; + verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); + debug_selector = save_debug_selector; + DEBUG(D_any) debug_printf("Process %d is handling incoming connection from %s\n", (int)getpid(), sender_fullhost); diff --git a/src/src/exim.c b/src/src/exim.c index 88ed33a8e..df343b5a1 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -5465,7 +5465,9 @@ if (raw_active_hostname) /* Handle host checking: this facility mocks up an incoming SMTP call from a given IP address so that the blocking and relay configuration can be tested. Unless a sender_ident was set by -oMt, we discard it (the default is the -caller's login name). */ +caller's login name). An RFC 1413 call is made only if we are running in the +test harness and an incoming interface and both ports are specified, because +there is no TCP/IP call to find the ident for. */ if (host_checking) { @@ -5473,7 +5475,12 @@ if (host_checking) int size; if (!sender_ident_set) + { sender_ident = NULL; + if (f.running_in_test_harness && sender_host_port + && interface_address && interface_port) + verify_get_ident(test_harness_identd_port); + } /* In case the given address is a non-canonical IPv6 address, canonicalize it. Use the compressed form for IPv6. */ @@ -5496,6 +5503,7 @@ if (host_checking) debug_file = stderr; debug_fd = fileno(debug_file); dprintf(smtp_out_fd, "\n**** SMTP testing session as if from host %s\n" + "**** but without any ident (RFC 1413) callback.\n" "**** This is not for real!\n\n", sender_host_address); @@ -5607,12 +5615,14 @@ sendmail error modes other than -oem ever actually used? Later: yes.) */ if (!smtp_input) error_handling = arg_error_handling; /* If this is an inetd call, ensure that stderr is closed to prevent panic -logging being sent down the socket. */ +logging being sent down the socket and make an identd call to get the +sender_ident. */ else if (f.is_inetd && !atrn_mode) { (void)fclose(stderr); exim_nullstd(); /* Re-open to /dev/null */ + verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); set_process_info("handling incoming connection from %s via inetd", sender_fullhost); diff --git a/src/src/exim.h b/src/src/exim.h index fa56f2c2c..5b931e9f4 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -156,6 +156,8 @@ configuration file. We also use this for some other short strings, such as queue names. Also TLS ciphersuite name (no real known limit since the protocols use integers, but max seen in reality is 45 octets). + +RFC 1413 gives us the 512 limit on IDENT protocol userids. */ #define EXIM_EMAILADDR_MAX 256 diff --git a/src/src/functions.h b/src/src/functions.h index 223723b81..98dc1a461 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -697,6 +697,7 @@ extern int verify_check_given_host(const uschar **, const host_item *); extern int verify_check_this_host(const uschar **, unsigned int *, const uschar*, const uschar *, const uschar **); extern address_item *verify_checked_sender(const uschar *); +extern void verify_get_ident(int); extern void verify_quota(uschar *); extern int verify_quota_call(const uschar *, int, int, uschar **); extern BOOL verify_sender(int *, uschar **); diff --git a/src/src/globals.c b/src/src/globals.c index be2b7ec13..c8636e191 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -707,6 +707,7 @@ bit_table debug_options[] = { /* must be in alphabetical order and use BIT_TABLE(D, filter), BIT_TABLE(D, hints_lookup), BIT_TABLE(D, host_lookup), + BIT_TABLE(D, ident), BIT_TABLE(D, interface), BIT_TABLE(D, lists), BIT_TABLE(D, load), @@ -989,6 +990,7 @@ bit_table log_options[] = { /* must be in alphabetical order, BIT_TABLE(L, dnssec), BIT_TABLE(L, etrn), BIT_TABLE(L, host_lookup_failed), + BIT_TABLE(L, ident_timeout), BIT_TABLE(L, incoming_interface), BIT_TABLE(L, incoming_port), BIT_TABLE(L, lost_incoming_connection), @@ -1238,6 +1240,8 @@ int retry_maximum_timeout = 0; /* set from retry config */ retry_config *retries = NULL; const uschar *return_path = NULL; int rewrite_existflags = 0; +uschar *rfc1413_hosts = US"@[]"; +int rfc1413_query_timeout = 0; uid_t root_gid = ROOT_GID; uid_t root_uid = ROOT_UID; @@ -1399,6 +1403,7 @@ uid_t system_filter_uid = (uid_t)-1; blob tcp_fastopen_nodata = { .data = NULL, .len = 0 }; tfo_state_t tcp_out_fastopen = TFO_NOT_USED; +int test_harness_identd_port = IDENT_PORT; int test_harness_load_avg = 0; int thismessage_size_limit = 0; int timeout_frozen_after = 0; diff --git a/src/src/globals.h b/src/src/globals.h index ccd790cc2..ddf78b4d8 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -919,6 +919,8 @@ extern int retry_maximum_timeout; /* The maximum timeout */ extern const uschar *return_path; /* Return path for a message */ extern BOOL return_path_remove; /* Remove return-path headers */ extern int rewrite_existflags; /* Indicate which headers have rewrites */ +extern uschar *rfc1413_hosts; /* RFC hosts */ +extern int rfc1413_query_timeout; /* Timeout on RFC 1413 calls */ /* extern BOOL rfc821_domains; */ /* If set, syntax is 821, not 822 => being abolished */ extern uid_t root_gid; /* The gid for root */ extern uid_t root_uid; /* The uid for root */ @@ -1059,6 +1061,7 @@ extern BOOL system_filter_uid_set; /* TRUE if uid set */ extern blob tcp_fastopen_nodata; /* for zero-data TFO connect requests */ extern BOOL tcp_nodelay; /* Controls TCP_NODELAY on daemon */ extern tfo_state_t tcp_out_fastopen; /* TCP fast open */ +extern int test_harness_identd_port; /* For use when testing */ extern int test_harness_load_avg; /* For use when testing */ extern int thismessage_size_limit; /* Limit for this message */ extern int timeout_frozen_after; /* Max time to keep frozen messages */ diff --git a/src/src/macros.h b/src/src/macros.h index 2e0efc9b8..75563d86b 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -90,6 +90,10 @@ don't make the file descriptors two-way. */ #define pipe_read 0 #define pipe_write 1 +/* The RFC 1413 ident port */ + +#define IDENT_PORT 113 + /* A macro to simplify testing bits in lookup types */ #define mac_islookup(li,b) ((li)->type & (b)) @@ -381,25 +385,26 @@ enum { DEBUG_BIT(filter), DEBUG_BIT(hints_lookup), DEBUG_BIT(host_lookup), + DEBUG_BIT(ident), DEBUG_BIT(interface), DEBUG_BIT(lists), - DEBUG_BIT(load), - DEBUG_BIT(lookup), /* 15 */ + DEBUG_BIT(load), /* 15 */ + DEBUG_BIT(lookup), DEBUG_BIT(memory), DEBUG_BIT(noutf8), DEBUG_BIT(pid), DEBUG_BIT(process_info), DEBUG_BIT(queue_run), DEBUG_BIT(receive), - DEBUG_BIT(resolver), - DEBUG_BIT(retry), /* 23 */ + DEBUG_BIT(resolver), /* 23 */ + DEBUG_BIT(retry), DEBUG_BIT(rewrite), DEBUG_BIT(route), DEBUG_BIT(timestamp), DEBUG_BIT(tls), DEBUG_BIT(transport), DEBUG_BIT(uid), - DEBUG_BIT(verify), /* 30 - one spare! */ + DEBUG_BIT(verify), /* 31 */ }; /* Multi-bit debug masks */ @@ -469,6 +474,7 @@ enum logbit { Li_dkim, Li_dkim_verbose, Li_dnssec, + Li_ident_timeout, Li_incoming_interface, Li_incoming_port, Li_millisec, diff --git a/src/src/readconf.c b/src/src/readconf.c index f4da20b6a..1fe2b2bfc 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -298,6 +298,9 @@ static optionlist optionlist_config[] = { { "retry_interval_max", opt_time, {&retry_interval_max} }, { "return_path_remove", opt_bool, {&return_path_remove} }, { "return_size_limit", opt_mkint|opt_hidden, {&bounce_return_size_limit} }, + { "rfc1413_hosts", opt_stringptr, {&rfc1413_hosts} }, + { "rfc1413_port", opt_int|opt_hidden, {&test_harness_identd_port} }, + { "rfc1413_query_timeout", opt_time, {&rfc1413_query_timeout} }, { "sender_unqualified_hosts", opt_stringptr, {&sender_unqualified_hosts} }, { "slow_lookup_log", opt_int, {&slow_lookup_log} }, { "smtp_accept_keepalive", opt_bool, {&smtp_accept_keepalive} }, diff --git a/src/src/verify.c b/src/src/verify.c index a3ade640b..a12e74ce6 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2779,6 +2779,162 @@ return yield; +/************************************************* +* Get RFC 1413 identification * +*************************************************/ + +/* Attempt to get an id from the sending machine via the RFC 1413 protocol. If +the timeout is set to zero, then the query is not done. There may also be lists +of hosts and nets which are exempt. To guard against malefactors sending +non-printing characters which could, for example, disrupt a message's headers, +make sure the string consists of printing characters only. + +Argument: + port the port to connect to; usually this is IDENT_PORT (113), but when + running in the test harness with -bh a different value is used. + +Returns: nothing + +Side effect: any received ident value is put in sender_ident (NULL otherwise) +*/ + +void +verify_get_ident(int port) +{ +client_conn_ctx ident_conn_ctx = {0}; +int host_af, qlen; +int received_sender_port, received_interface_port, n; +uschar *p; +blob early_data; +uschar buffer[2048]; + +/* Default is no ident. Check whether we want to do an ident check for this +host. */ + +sender_ident = NULL; +if (rfc1413_query_timeout <= 0 || verify_check_host(&rfc1413_hosts) != OK) + return; + +DEBUG(D_ident) debug_printf("doing ident callback\n"); + +/* Set up a connection to the ident port of the remote host. Bind the local end +to the incoming interface address. If the sender host address is an IPv6 +address, the incoming interface address will also be IPv6. */ + +host_af = Ustrchr(sender_host_address, ':') == NULL ? AF_INET : AF_INET6; +if ((ident_conn_ctx.sock = ip_socket(SOCK_STREAM, host_af)) < 0) return; + +if (ip_bind(ident_conn_ctx.sock, host_af, interface_address, 0) < 0) + { + DEBUG(D_ident) debug_printf("bind socket for ident failed: %s\n", + strerror(errno)); + goto END_OFF; + } + +/* Construct and send the query. */ + +qlen = snprintf(CS buffer, sizeof(buffer), "%d , %d\r\n", + sender_host_port, interface_port); +early_data.data = buffer; +early_data.len = qlen; + +/*XXX we trust that the query is idempotent */ +if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port, + rfc1413_query_timeout, &early_data) < 0) + { + if (errno == ETIMEDOUT && LOGGING(ident_timeout)) + log_write(0, LOG_MAIN, "ident connection to %s timed out", + sender_host_address); + else + DEBUG(D_ident) debug_printf("ident connection to %s failed: %s\n", + sender_host_address, strerror(errno)); + goto END_OFF; + } + +/* Read a response line. We put it into the rest of the buffer, using several +recv() calls if necessary. */ + +p = buffer + qlen; + +for (;;) + { + uschar *pp; + int count; + int size = sizeof(buffer) - (p - buffer); + + if (size <= 0) goto END_OFF; /* Buffer filled without seeing \n. */ + count = ip_recv(&ident_conn_ctx, p, size, time(NULL) + rfc1413_query_timeout); + if (count <= 0) goto END_OFF; /* Read error or EOF */ + + /* Scan what we just read, to see if we have reached the terminating \r\n. Be + generous, and accept a plain \n terminator as well. The only illegal + character is 0. */ + + for (pp = p; pp < p + count; pp++) + { + if (*pp == 0) goto END_OFF; /* Zero octet not allowed */ + if (*pp == '\n') + { + if (pp[-1] == '\r') pp--; + *pp = 0; + goto GOT_DATA; /* Break out of both loops */ + } + } + + /* Reached the end of the data without finding \n. Let the loop continue to + read some more, if there is room. */ + + p = pp; + } + +GOT_DATA: + +/* We have received a line of data. Check it carefully. It must start with the +same two port numbers that we sent, followed by data as defined by the RFC. For +example, + + 12345 , 25 : USERID : UNIX :root + +However, the amount of white space may be different to what we sent. In the +"osname" field there may be several sub-fields, comma separated. The data we +actually want to save follows the third colon. Some systems put leading spaces +in it - we discard those. */ + +if (sscanf(CS buffer + qlen, "%d , %d%n", &received_sender_port, + &received_interface_port, &n) != 2 || + received_sender_port != sender_host_port || + received_interface_port != interface_port) + goto END_OFF; + +p = buffer + qlen + n; +Uskip_whitespace(&p); +if (*p++ != ':') goto END_OFF; +Uskip_whitespace(&p); +if (Ustrncmp(p, "USERID", 6) != 0) goto END_OFF; +p += 6; +Uskip_whitespace(&p); +if (*p++ != ':') goto END_OFF; +while (*p && *p != ':') p++; +if (!*p++) goto END_OFF; +Uskip_whitespace(&p); +if (!*p) goto END_OFF; + +/* The rest of the line is the data we want. We turn it into printing +characters when we save it, so that it cannot mess up the format of any logging +or Received: lines into which it gets inserted. We keep a maximum of 127 +characters. The deconst cast is ok as we fed a nonconst to string_printing() */ + +sender_ident = US string_printing(string_copyn(p, 127)); +DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident); + +END_OFF: +(void)close(ident_conn_ctx.sock); +return; +} + + + + /************************************************* * Match host to a single host-list item * *************************************************/ commit e35ada6dc21d111ac30c30e8b9d792fbca55c9b4 Author: Jeremy Harris Date: Sun Nov 2 14:34:25 2025 +0000 TLS: log key-exchange group diff --git a/src/src/exim.h b/src/src/exim.h index 5b931e9f4..18d1b1f40 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -155,7 +155,8 @@ The driver name is a name of a router/transport/authenticator etc in the configuration file. We also use this for some other short strings, such as queue names. Also TLS ciphersuite name (no real known limit since the protocols use -integers, but max seen in reality is 45 octets). +integers, but max seen so far is 70 octets. Likely to increase further with +postquantum methods). RFC 1413 gives us the 512 limit on IDENT protocol userids. */ @@ -168,7 +169,7 @@ RFC 1413 gives us the 512 limit on IDENT protocol userids. #define EXIM_HUMANNAME_MAX 256 #define EXIM_DISPLAYMAIL_MAX 1024 #define EXIM_DRIVERNAME_MAX 64 -#define EXIM_CIPHERNAME_MAX 64 +#define EXIM_CIPHERNAME_MAX 128 #define EXIM_IDENTUSER_MAX 512 diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 154d3be38..f63d2ee12 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -57,11 +57,6 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x030000 # define SUPPORT_SELFSIGN /* Uncertain what version is first usable but 2.12.23 is not */ #endif -#if GNUTLS_VERSION_NUMBER >= 0x030306 -# define SUPPORT_CA_DIR -#else -# undef SUPPORT_CA_DIR -#endif #if GNUTLS_VERSION_NUMBER >= 0x030014 # define SUPPORT_SYSDEFAULT_CABUNDLE #endif @@ -78,6 +73,11 @@ require current GnuTLS, then we'll drop support for the ancient libraries). # define GNUTLS_AUTO_GLOBAL_INIT # define GNUTLS_AUTO_PKCS11_MANUAL #endif +#if GNUTLS_VERSION_NUMBER >= 0x030306 +# define SUPPORT_CA_DIR +#else +# undef SUPPORT_CA_DIR +#endif #if (GNUTLS_VERSION_NUMBER >= 0x030404) \ || (GNUTLS_VERSION_NUMBER >= 0x030311) && (GNUTLS_VERSION_NUMBER & 0xffff00 == 0x030300) # ifndef DISABLE_OCSP @@ -90,6 +90,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP) # define SUPPORT_SRV_OCSP_STACK #endif +#if GNUTLS_VERSION_NUMBER >= 0x030600 +# define EXIM_TLS_KEX_GROUP +#endif #if GNUTLS_VERSION_NUMBER >= 0x030603 # define EXIM_HAVE_TLS1_3 # define SUPPORT_GNUTLS_EXT_RAW_PARSE @@ -2385,11 +2388,15 @@ kx = old_pool = store_pool; { tls_support * tlsp = state->tlsp; + gstring * g = NULL; +#ifdef EXIM_TLS_KEX_GROUP + const char * kex_gp = gnutls_group_get_name(gnutls_group_get(session)); +#endif + store_pool = POOL_PERM; #ifdef SUPPORT_GNUTLS_SESS_DESC { - gstring * g = NULL; uschar * s = US gnutls_session_get_desc(session), c; if (!s) @@ -2424,15 +2431,25 @@ old_pool = store_pool; if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2); /* now on _ between groups */ } - g = string_catn(g, US":", 1); - g = string_cat(g, string_sprintf("%d", (int) gnutls_cipher_get_key_size(cipher) * 8)); + g = string_fmt_append(g, ":%d", + (int) gnutls_cipher_get_key_size(cipher) * 8); + +# ifdef EXIM_TLS_KEX_GROUP + if (kex_gp) + g = string_fmt_append(g, ":%s", kex_gp); +# endif state->ciphersuite = string_from_gstring(g); } #else - state->ciphersuite = string_sprintf("%s:%s:%d", - gnutls_protocol_get_name(protocol), - gnutls_cipher_suite_get_name(kx, cipher, mac), - (int) gnutls_cipher_get_key_size(cipher) * 8); + g = string_fmt_append(NULL, "%s:%s:%d", + gnutls_protocol_get_name(protocol), + gnutls_cipher_suite_get_name(kx, cipher, mac), + (int) gnutls_cipher_get_key_size(cipher) * 8); +# ifdef EXIM_TLS_KEX_GROUP + if (kex_gp) + g = string_fmt_append(g, ":%s", kex_gp); +# endif + state->ciphersuite = string_from_gstring(g); /* I don't see a way that spaces could occur, in the current GnuTLS code base, but it was a concern in the old code and perhaps older GnuTLS @@ -2441,7 +2458,7 @@ old_pool = store_pool; for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-'; tlsp->ver = string_copyn(state->ciphersuite, Ustrchr(state->ciphersuite, ':') - state->ciphersuite); -#endif +#endif /*SUPPORT_GNUTLS_SESS_DESC*/ /* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */ diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index ddc72bfa2..eea1f15d3 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -86,6 +86,9 @@ change this guard and punt the issue for a while longer. */ # if OPENSSL_VERSION_NUMBER >= 0x010101000L # define EXIM_TLS_EARLY_BANNER # endif +# if OPENSSL_VERSION_NUMBER >= 0x030200000L +# define EXIM_TLS_KEX_GROUP +# endif # if OPENSSL_VERSION_NUMBER < 0x030200020L # define EXIM_OPENSSL_BOGUS_SERVER_ALPN /*XXX when was this fixed? */ # endif @@ -3070,8 +3073,11 @@ return OK; *************************************************/ /* -Argument: pointer to an SSL structure for the connection - pointer to number of bits for cipher +Arguments: + ssl pointer to an SSL structure for the connection + ver TLS version string + bits pointer for return of number of bits for cipher + Returns: pointer to allocated string in perm-pool */ @@ -3089,7 +3095,15 @@ uschar * s; SSL_CIPHER_get_bits(c, bits); store_pool = POOL_PERM; -s = string_sprintf("%s:%s:%u", ver, SSL_CIPHER_get_name(c), *bits); + { +#ifdef EXIM_TLS_KEX_GROUP + const char * cs = SSL_get0_group_name(ssl); + if (cs) + s = string_sprintf("%s:%s:%u:%s", ver, SSL_CIPHER_get_name(c), *bits, cs); + else +#endif + s = string_sprintf("%s:%s:%u", ver, SSL_CIPHER_get_name(c), *bits); + } store_pool = pool; DEBUG(D_tls) debug_printf("Cipher: %s\n", s); return s; commit b93ee3883ef8a11c440c5519812f3cb6c074a02f Author: Jeremy Harris Date: Sun Nov 2 19:58:29 2025 +0000 Build: quieten sqlite-hints -Wunused-function build diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index 92cb91909..d2d30969b 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -74,8 +74,8 @@ extern void debug_printf_indent(const char *, ...) PRINTF_FUNCTION(1,2); # error USE_SQLITE conflict with alternate definition # endif # include "hintsdb/hints_sqlite.h" -#elif defined(USE_TDB) +#elif defined(USE_TDB) # if defined(USE_DB) || defined(USE_GDBM) || defined(USE_SQLITE) # error USE_TDB conflict with alternate definition # endif diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index 9e1e90322..9e4f65a51 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -354,17 +354,17 @@ exim_dbclose_multi__(dbp); /* Datum access */ -static uschar * +static inline uschar * exim_datum_data_get(EXIM_DATUM * dp) { return US dp->data; } -static void +static inline void exim_datum_data_set(EXIM_DATUM * dp, void * s) { dp->data = s; } -static unsigned +static inline unsigned exim_datum_size_get(EXIM_DATUM * dp) { return dp->len; } -static void +static inline void exim_datum_size_set(EXIM_DATUM * dp, unsigned n) { dp->len = n; } commit c7b6065cb9b945155491477297662bae458919d4 Author: Jeremy Harris Date: Sun Nov 2 21:06:43 2025 +0000 RFC 2047: fix encode operation. Bug 3168 diff --git a/src/src/parse.c b/src/src/parse.c index d840beb6d..cdb1e0c1e 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -882,13 +882,10 @@ const uschar * parse_quote_2047(const uschar * string, int len, const uschar * charset, BOOL fold) { -int hlen, line_off; -BOOL coded = FALSE; -BOOL first_byte = FALSE; -gstring * g = - string_fmt_append(NULL, "=?%s?Q?%n", charset ? charset : US"iso-8859-1", &hlen); - -line_off = hlen; +int line_off = 0, hlen; +BOOL coded = FALSE, first_byte = FALSE; +gstring * g = string_fmt_append(NULL, "=?%s?Q?%n", + charset ? charset : US"iso-8859-1", &hlen); for (const uschar * s = string; len > 0; s++, len--) { @@ -898,7 +895,7 @@ for (const uschar * s = string; len > 0; s++, len--) { g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3); line_off = g->ptr; - g = string_catn(g, g->s, hlen); + g = string_catn(g, g->s, hlen); /* dup the leader */ } if ( ch < 33 || ch > 126 commit dd081f9869df90ab7f7d7911c1bdd3ef976f1439 Author: Jeremy Harris Date: Wed Oct 29 12:13:09 2025 +0000 constify diff --git a/src/src/acl.c b/src/src/acl.c index 36fb850c8..7d07ab698 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3939,7 +3939,7 @@ for (; cb; cb = cb->next) /* See comment on ACLC_SPF wrt. coding issues */ { misc_module_info * mi = misc_mod_find(US"dmarc", &log_message); - typedef uschar * (*efn_t)(int); + typedef const uschar * (*efn_t)(void); const uschar * expanded_query; if (!mi) @@ -3956,8 +3956,7 @@ for (; cb; cb = cb->next) view into the process in the future. */ /*XXX is this call used with any other arg? */ - expanded_query = (((efn_t *) mi->functions)[DMARC_EXPAND_QUERY]) - (DMARC_VERIFY_STATUS); + expanded_query = (((efn_t *) mi->functions)[DMARC_EXPAND_QUERY]) (); rc = match_isinlist(expanded_query, &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); } diff --git a/src/src/functions.h b/src/src/functions.h index 98dc1a461..4801eb8b5 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -374,15 +374,17 @@ extern int misc_mod_msg_init(void); extern void misc_mod_smtp_reset(void); extern uschar *moan_check_errorcopy(const uschar *); -extern BOOL moan_skipped_syntax_errors(uschar *, error_block *, uschar *, - BOOL, uschar *); +extern BOOL moan_skipped_syntax_errors(const uschar *, const error_block *, + const uschar *, BOOL, const uschar *); extern void moan_smtp_batch(const uschar *, const char *, ...) PRINTF_FUNCTION(2,3); -extern BOOL moan_send_message(const uschar *, int, error_block *eblock, - header_line *, FILE *, const uschar *); -extern void moan_tell_someone(const uschar *, address_item *, - const uschar *, const char *, ...) PRINTF_FUNCTION(4,5); -extern BOOL moan_to_sender(int, error_block *, header_line *, FILE *, BOOL); +extern BOOL moan_send_message(const uschar *, int, + const error_block * eblock, const header_line *, + FILE *, const uschar *); +extern void moan_tell_someone(const uschar *, const address_item *, + const uschar *, const char *, ...) PRINTF_FUNCTION(4,5); +extern BOOL moan_to_sender(int, const error_block *, const header_line *, + FILE *, BOOL); extern void moan_write_from(FILE *); extern void moan_write_references(FILE *, uschar *); #ifdef LOOKUP_MODULE_DIR diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index bc96607e0..185ef9f4f 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -60,10 +60,10 @@ static dmarc_exim_p dmarc_policy_description[] = { /* $variables */ BOOL dmarc_alignment_dkim = FALSE; /* Subtest result */ BOOL dmarc_alignment_spf = FALSE; /* Subtest result */ -uschar * dmarc_domain_policy = NULL; /* Declared policy of used domain */ -uschar * dmarc_status = NULL; /* One word value */ -uschar * dmarc_status_text = NULL; /* Human readable value */ -uschar * dmarc_used_domain = NULL; /* Domain libopendmarc chose for DMARC policy lookup */ +const uschar * dmarc_domain_policy = NULL; /* Declared policy of used domain */ +const uschar * dmarc_status; /* One word value */ +const uschar * dmarc_status_text = NULL; /* Human readable value */ +uschar * dmarc_used_domain; /* Domain libopendmarc chose for DMARC policy lookup */ /* options */ uschar * dmarc_forensic_sender = NULL; /* Set sender address for forensic reports */ @@ -108,9 +108,9 @@ end, and append the two strings passed to it. Used for adding variable amounts of value:pair data to the forensic emails. */ static error_block * -add_to_eblock(error_block *eblock, uschar *t1, uschar *t2) +add_to_eblock(error_block * eblock, const uschar * t1, const uschar * t2) { -error_block *eb = store_malloc(sizeof(error_block)); +error_block * eb = store_malloc(sizeof(error_block)); if (!eblock) eblock = eb; else @@ -645,10 +645,7 @@ The EDITME provides a DMARC_API variable */ libdm_status = opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); for (c = 0; dmarc_policy_description[c].name; c++) if (tmp_ans == dmarc_policy_description[c].value) - { - dmarc_domain_policy = string_sprintf("%s",dmarc_policy_description[c].name); - break; - } + { dmarc_domain_policy = dmarc_policy_description[c].name; break; } /* Can't use exim's string manipulation functions so allocate memory for libopendmarc using its max hostname length definition. */ @@ -743,23 +740,19 @@ if (!f.dmarc_disable_verify) return OK; } -static uschar * -dmarc_exim_expand_defaults(int what) +static const uschar * +dmarc_exim_expand_defaults(void) { -if (what == DMARC_VERIFY_STATUS) - return f.dmarc_disable_verify ? US"off" : US"none"; -return US""; +return f.dmarc_disable_verify ? US"off" : US"none"; } -static uschar * -dmarc_exim_expand_query(int what) +static const uschar * +dmarc_exim_expand_query(void) { if (f.dmarc_disable_verify || !dmarc_pctx) - return dmarc_exim_expand_defaults(what); + return dmarc_exim_expand_defaults(); -if (what == DMARC_VERIFY_STATUS) - return dmarc_status; -return US""; +return dmarc_status; } diff --git a/src/src/moan.c b/src/src/moan.c index efac33681..5635f93e2 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -159,8 +159,9 @@ Returns: TRUE if message successfully sent */ BOOL -moan_send_message(const uschar * recipient, int ident, error_block * eblock, - header_line * headers, FILE * message_file, const uschar * firstline) +moan_send_message(const uschar * recipient, int ident, + const error_block * eblock, const header_line * headers, + FILE * message_file, const uschar * firstline) { int written = 0, fd, status, count = 0, size_limit = bounce_return_size_limit; FILE * fp; @@ -389,7 +390,7 @@ if (bounce_return_message) while (headers) { - if (headers->text != NULL) fprintf(fp, "%s", CS headers->text); + if (headers->text) fprintf(fp, "%s", CS headers->text); headers = headers->next; } @@ -494,8 +495,8 @@ Returns: FALSE if there is no sender_address to send to; */ BOOL -moan_to_sender(int ident, error_block *eblock, header_line *headers, - FILE *message_file, BOOL check_sender) +moan_to_sender(int ident, const error_block * eblock, + const header_line * headers, FILE * message_file, BOOL check_sender) { uschar *firstline = NULL; uschar *msg = US"Error while reading message with no usable sender address"; @@ -601,7 +602,7 @@ Returns: nothing */ void -moan_tell_someone(const uschar * who, address_item * addr, +moan_tell_someone(const uschar * who, const address_item * addr, const uschar * subject, const char * format, ...) { FILE * f; @@ -814,14 +815,14 @@ Returns: FALSE if string expansion failed; TRUE otherwise */ BOOL -moan_skipped_syntax_errors(uschar *rname, error_block *eblock, - uschar *syntax_errors_to, BOOL some, uschar *custom) +moan_skipped_syntax_errors(const uschar * rname, const error_block * eblock, + const uschar * syntax_errors_to, BOOL some, const uschar * custom) { int pid, fd; const uschar * s; FILE * f; -for (error_block * e = eblock; e; e = e->next) +for (const error_block * e = eblock; e; e = e->next) if (e->text2) log_write(0, LOG_MAIN, "%s router: skipped error: %s in %q", rname, e->text1, e->text2); @@ -870,11 +871,10 @@ if (custom) fprintf(f, "The %s router encountered the following error(s):\n\n", rname); -for (error_block * e = eblock; e; e = e->next) +for (const error_block * e = eblock; e; e = e->next) { fprintf(f, " %s", e->text1); - if (e->text2 != NULL) - fprintf(f, " in the address\n \"%s\"", e->text2); + if (e->text2) fprintf(f, " in the address\n \"%s\"", e->text2); fprintf(f, "\n\n"); } diff --git a/src/src/structs.h b/src/src/structs.h index 147819dd5..a6261afcb 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -680,8 +680,8 @@ typedef struct { typedef struct error_block { struct error_block *next; - const uschar *text1; - uschar *text2; + const uschar * text1; + const uschar * text2; } error_block; /* Chain of file names when processing the queue */ commit dea05068da8cbd8cb9c9707aa8c3e432bd967e55 Author: Jeremy Harris Date: Mon Nov 3 16:40:26 2025 +0000 fix constification Broken-by: 96f8f12e212b diff --git a/src/src/exim.c b/src/src/exim.c index df343b5a1..c6fa25fc7 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -5320,7 +5320,7 @@ if (verify_address_mode || f.address_test_mode) while (*s) { BOOL finished = FALSE; - uschar *ss = parse_find_address_end(s, FALSE); + uschar * ss = parse_find_address_end(s, FALSE); if (*ss == ',') *ss = 0; else finished = TRUE; test_address(s, flags, &exit_value); s = ss; @@ -5875,7 +5875,7 @@ for (BOOL more = TRUE; more; ) uschar * errmess; /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short. We'll still want to cap it to something, just in case. */ - const uschar * s = string_copy_taint( + uschar * s = string_copy_taint( exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"), GET_TAINTED); diff --git a/src/src/functions.h b/src/src/functions.h index 4801eb8b5..ef1c59dc3 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -398,7 +398,17 @@ extern uschar *parse_extract_address(const uschar *, uschar **, int *, int *, in BOOL); extern int parse_forward_list(const uschar *, int, address_item **, uschar **, const uschar *, const uschar *, error_block **); -extern uschar *parse_find_address_end(const uschar *, BOOL); + +extern const uschar * parse_find_address_end_gen(const uschar *, BOOL); +static inline uschar * parse_find_address_end_nc(uschar * s, BOOL b) +{ return US parse_find_address_end_gen(s, b); } +static inline const uschar * parse_find_address_end_c(const uschar * s, BOOL b) +{ return parse_find_address_end_gen(s, b); } +#define parse_find_address_end(X, B) _Generic((X), \ + uschar *: parse_find_address_end_nc, \ + const uschar *: parse_find_address_end_c \ + )(X, B) + extern const uschar *parse_find_at(const uschar *); extern const uschar *parse_fix_phrase(const uschar *, int); extern const uschar *parse_message_id(const uschar *, uschar **, uschar **); diff --git a/src/src/miscmods/exim_filter.c b/src/src/miscmods/exim_filter.c index 08124b3f7..21ede4ad5 100644 --- a/src/src/miscmods/exim_filter.c +++ b/src/src/miscmods/exim_filter.c @@ -2419,15 +2419,14 @@ while (commands) tt = to; while (*tt) { - uschar * ss = parse_find_address_end(tt, FALSE), * errmess; - const uschar * recipient; + const uschar * ss = parse_find_address_end(tt, FALSE); + const uschar * ttt, * recipient; + uschar * errmess; int start, end, domain; - int temp = *ss; - *ss = 0; - recipient = parse_extract_address(tt, &errmess, + ttt = *ss ? string_copyn(tt, ss - tt) : tt; + recipient = parse_extract_address(ttt, &errmess, &start, &end, &domain, FALSE); - *ss = temp; /* Ignore empty addresses and errors; an error will occur later if there's something really bad. */ diff --git a/src/src/miscmods/sieve_filter.c b/src/src/miscmods/sieve_filter.c index 38b408f1b..cb57fa11f 100644 --- a/src/src/miscmods/sieve_filter.c +++ b/src/src/miscmods/sieve_filter.c @@ -2036,7 +2036,7 @@ if (parse_identifier(filter, CUS "address")) for (gstring * h = hdr; h->ptr != -1 && !*cond; ++h) { const uschar * header_value = NULL; - uschar * extracted_addr, * end_addr; + uschar * extracted_addr; if ( !eq_asciicase(h, &str_from, FALSE) && !eq_asciicase(h, &str_to, FALSE) @@ -2061,15 +2061,15 @@ if (parse_identifier(filter, CUS "address")) f.parse_allow_group = TRUE; while (*header_value && !*cond) { - uschar *error; + uschar * part = NULL, * error; + const uschar * end_addr, * ss; int start, end, domain; - int saveend; - uschar *part = NULL; end_addr = parse_find_address_end(header_value, FALSE); - saveend = *end_addr; - *end_addr = 0; - extracted_addr = parse_extract_address(header_value, &error, &start, &end, &domain, FALSE); + ss = *end_addr + ? header_value : string_copyn(header_value, end_addr - header_value); + extracted_addr = parse_extract_address(ss, &error, + &start, &end, &domain, FALSE); if (extracted_addr) switch (addressPart) { @@ -2084,7 +2084,6 @@ if (parse_identifier(filter, CUS "address")) #endif } - *end_addr = saveend; if (part && extracted_addr) { gstring partStr = {.s = part, .ptr = Ustrlen(part), .size = Ustrlen(part)+1}; @@ -2096,7 +2095,7 @@ if (parse_identifier(filter, CUS "address")) } } - if (saveend == 0) break; + if (*end_addr) break; header_value = end_addr + 1; } f.parse_allow_group = FALSE; diff --git a/src/src/parse.c b/src/src/parse.c index cdb1e0c1e..1fe4f70f8 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -68,8 +68,8 @@ Returns: pointer past the end of the address (i.e. points to null or comma) */ -uschar * -parse_find_address_end(const uschar * s, BOOL nl_ends) +const uschar * +parse_find_address_end_gen(const uschar * s, BOOL nl_ends) { BOOL source_routing = *s == '@'; int no_term = source_routing ? 1 : 0; @@ -129,7 +129,7 @@ while (*s && (*s != ',' || no_term > 0) && (*s != '\n' || !nl_ends)) } } -return US s; +return s; } diff --git a/src/src/verify.c b/src/src/verify.c index a12e74ce6..1fee97150 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -2338,9 +2338,9 @@ Returns: OK */ int -verify_check_headers(uschar **msgptr) +verify_check_headers(uschar ** msgptr) { -uschar *colon, *s; +uschar * colon, * s; int yield = OK; for (header_line * h = header_list; h && yield == OK; h = h->next) @@ -2639,8 +2639,7 @@ int yield = FAIL; for (int i = 0; i < 3 && !done; i++) for (const header_line * h = header_list; h && !done; h = h->next) { - const uschar * endname, * s; - uschar * ss; + const uschar * endname, * s, * ss, * es; if (h->type != header_types[i]) continue; s = endname = Ustrchr(h->text, ':') + 1; @@ -2652,38 +2651,36 @@ for (int i = 0; i < 3 && !done; i++) while (*s) { - int terminator, new_ok; + int new_ok; address_item * vaddr; while (isspace(*s) || *s == ',') s++; if (!*s) break; /* End of header */ - ss = parse_find_address_end(s, FALSE); + es = parse_find_address_end(s, FALSE); /* The terminator is a comma or end of header, but there may be white space preceding it (including newline for the last address). Move back past any white space so we can check against any cached envelope sender address verifications. */ - while (isspace(ss[-1])) ss--; - terminator = *ss; - *ss = '\0'; + while (isspace(es[-1])) es--; + ss = *es ? string_copyn(s, es - s) : s; HDEBUG(D_verify) debug_printf("verifying %.*s header address %s\n", - (int)(endname - h->text), h->text, s); + (int)(endname - h->text), h->text, ss); /* See if we have already verified this address as an envelope sender, and if so, use the previous answer. */ - vaddr = verify_checked_sender(s); + vaddr = verify_checked_sender(ss); - if (vaddr != NULL && /* Previously checked */ - (callout <= 0 || /* No callout needed; OR */ - vaddr->special_action > 256)) /* Callout was done */ + if ( vaddr /* Previously checked */ + && ( callout <= 0 /* No callout needed; OR */ + || vaddr->special_action > 256)) /* Callout was done */ { new_ok = vaddr->special_action & 255; HDEBUG(D_verify) debug_printf("previously checked as envelope sender\n"); - *ss = terminator; /* Restore shortened string */ } /* Otherwise we run the verification now. We must restore the shortened @@ -2693,9 +2690,8 @@ for (int i = 0; i < 3 && !done; i++) else { int start, end, domain; - const uschar * address = parse_extract_address(s, log_msgptr, + const uschar * address = parse_extract_address(ss, log_msgptr, &start, &end, &domain, FALSE); - *ss = terminator; /* If we found an empty address, just carry on with the next one, but kill the message. */ @@ -2703,7 +2699,7 @@ for (int i = 0; i < 3 && !done; i++) if (!address && Ustrcmp(*log_msgptr, "empty address") == 0) { *log_msgptr = NULL; - s = ss; + s = es; continue; } @@ -2713,10 +2709,10 @@ for (int i = 0; i < 3 && !done; i++) if (!address) { - while (ss > s && isspace(ss[-1])) ss--; + while (es > s && isspace(es[-1])) es--; *log_msgptr = string_sprintf("syntax error in '%.*s' header when " "scanning for sender: %s in \"%.*s\"", - (int)(endname - h->text), h->text, *log_msgptr, (int)(ss - s), s); + (int)(endname - h->text), h->text, *log_msgptr, (int)(es - s), s); yield = FAIL; done = TRUE; break; @@ -2759,7 +2755,7 @@ for (int i = 0; i < 3 && !done; i++) /* Move on to any more addresses in the header */ - s = ss; + s = es; } /* Next address */ f.parse_allow_group = FALSE; commit e5dc9209cde969a66ac528c2d5fc5a244c5f5999 Author: Jeremy Harris Date: Tue Nov 4 09:58:43 2025 +0000 compiler quietening diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 2f6a56626..44b05465c 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -272,7 +272,6 @@ auth_cram_md5_options_block * ob = ablock->drinst.options_block; uschar *secret = expand_string(ob->client_secret); uschar *name = expand_string(ob->client_name); uschar *challenge, *p; -int i; uschar digest[16]; /* If expansion of either the secret or the user name failed, return CANCELLED diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index 9e4f65a51..01906f839 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -127,7 +127,6 @@ exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res) { # define FMT "SELECT dat FROM tbl WHERE ky = '%s';" uschar * encoded_key, * qry; -int i; BOOL ret; # ifdef COMPILE_UTILITY @@ -140,12 +139,14 @@ encoded_key = xtextencode(key->data, key->len); (int)key->len, encoded_key); */ # ifdef COMPILE_UTILITY -i = snprintf(NULL, 0, FMT, encoded_key) + 1; -if (!(qry = malloc(i))) - return FALSE; -snprintf(CS qry, i, FMT, encoded_key); -ret = exim_dbget__(dbp, qry, res); -free(qry); + { + int i = snprintf(NULL, 0, FMT, encoded_key) + 1; + if (!(qry = malloc(i))) + return FALSE; + snprintf(CS qry, i, FMT, encoded_key); + ret = exim_dbget__(dbp, qry, res); + free(qry); + } free(encoded_key); # else qry = string_sprintf(FMT, encoded_key); @@ -172,7 +173,7 @@ int hlen = data->len * 2, off = 0, res; # define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%s', X'%.*s');" uschar * encoded_key, * qry; # ifdef COMPILE_UTILITY -uschar * hex = malloc(hlen+1); +uschar * hex = malloc(hlen+1), dummy[1]; if (!hex) return EXIM_DBPUTB_DUP; /* best we can do */ # else uschar * hex = store_get(hlen+1, data->data); @@ -186,7 +187,7 @@ for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2) # ifdef COMPILE_UTILITY if (!(encoded_key = xtextencode(key->data, key->len))) return EXIM_DBPUTB_DUP; -res = snprintf(CS hex, 0, FMT, alt, encoded_key, hlen, hex) +1; +res = snprintf(CS dummy, 0, FMT, alt, encoded_key, hlen, hex) +1; if (!(qry = malloc(res))) return EXIM_DBPUTB_DUP; snprintf(CS qry, res, FMT, alt, encoded_key, hlen, hex); DEBUG(D_hints_lookup) debug_printf_indent("exim_s_dbp(%s)\n", qry); diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index f63d2ee12..b78c33fcb 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -393,7 +393,7 @@ Returns: DEFER/FAIL */ static int -tls_error(const uschar *prefix, const uschar *msg, const host_item *host, +tls_error(const uschar * prefix, const uschar * msg, const host_item * host, uschar ** errstr) { if (errstr) @@ -404,7 +404,7 @@ return host ? FAIL : DEFER; /* Returns: DEFER/FAIL */ static int -tls_error_gnu(exim_gnutls_state_st * state, const uschar *prefix, int err, +tls_error_gnu(exim_gnutls_state_st * state, const uschar * prefix, int err, uschar ** errstr) { return tls_error(prefix, @@ -461,7 +461,6 @@ return FALSE; static int tls_g_init(uschar ** errstr) { -int rc; DEBUG(D_tls) debug_printf("GnuTLS global init required\n"); #if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL) @@ -472,13 +471,19 @@ environment variables are used and so breaks for users calling mailq. To prevent this, we init PKCS11 first, which is the documented approach. */ if (!gnutls_allow_auto_pkcs11) + { + int rc; if ((rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL))) return tls_error_gnu(NULL, US"gnutls_pkcs11_init", rc, errstr); + } #endif #ifndef GNUTLS_AUTO_GLOBAL_INIT -if ((rc = gnutls_global_init())) - return tls_error_gnu(NULL, US"gnutls_global_init", rc, errstr); + { + int rc; + if ((rc = gnutls_global_init())) + return tls_error_gnu(NULL, US"gnutls_global_init", rc, errstr); + } #endif #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 @@ -833,7 +838,6 @@ const uschar * filename = NULL; size_t sz; uschar * exp_tls_dhparam; BOOL use_file_in_spool = FALSE; -const host_item * host = NULL; /* dummy for macros */ DEBUG(D_tls) debug_printf("Initialising GnuTLS server params\n"); @@ -1380,12 +1384,14 @@ creds_load_server_certs(exim_gnutls_state_st * state, const uschar * cert, const uschar * pkey, const uschar * ocsp, uschar ** errstr) { const uschar * clist = cert, * klist = pkey, * kfile, * cfile; -int csep = 0, ksep = 0, cnt = 0, rc; +int csep = 0, ksep = 0, rc; #ifndef DISABLE_OCSP uschar * ofile; const uschar * olist; # ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE gnutls_x509_crt_fmt_t ocsp_fmt = GNUTLS_X509_FMT_DER; +# else +int ocsp_file_cnt = 0; # endif if (!expand_check(ocsp, US"tls_ocsp_file", &ofile, errstr)) @@ -1460,7 +1466,7 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) else # endif { - if (cnt++ > 0) + if (ocsp_file_cnt++ > 0) { DEBUG(D_tls) debug_printf("oops; multiple OCSP files not supported\n"); commit 2486cac31dc0ce68d3705695c6fe61d68db51d31 Author: Jeremy Harris Date: Tue Nov 4 11:12:11 2025 +0000 Unbreak Solaris build Broken-by: dea05068da8c diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index caa6bf7c3..e7070f554 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -20,9 +20,12 @@ unsigned mp_index = 0; void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {} uschar * syslog_facility_str; -/* Solaris needs this one for the macro expand_string() */ +/* Solaris needs these for the macros expand_string, parse_find_address_end */ const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) {return NULL; } +const uschar * parse_find_address_end_gen(const uschar *, BOOL) +{return NULL; } + /******************************************************************************/ commit acfcde05f2800db3bf24ba521c62599d95713a08 Author: Jeremy Harris Date: Tue Nov 4 11:48:08 2025 +0000 Unbreak Solaris build Broken-by: dea05068da8c diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index e7070f554..79cbd5290 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -23,7 +23,7 @@ uschar * syslog_facility_str; /* Solaris needs these for the macros expand_string, parse_find_address_end */ const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) {return NULL; } -const uschar * parse_find_address_end_gen(const uschar *, BOOL) +const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } commit 826a1788778a6655a25b7d157ff4000531b9a215 Author: Jeremy Harris Date: Tue Nov 4 12:46:33 2025 +0000 Unbreak Solaris build Broken-by: dea05068da8c diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 02754d0ee..99ea5c826 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -71,6 +71,9 @@ string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, void log_write(unsigned int selector, int flags, const char *format, ...) { } +const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) +{return NULL; } + struct global_flags f; diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 339d022bb..cd98ff053 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -77,6 +77,8 @@ BOOL string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, const char * fmt, ...) { return FALSE; } +const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) +{return NULL; } struct global_flags f; unsigned int log_selector[1]; commit e5c1a2ba01a0bd00615ec1bfd05b47c6127bec38 Author: Jeremy Harris Date: Tue Nov 4 14:52:05 2025 +0000 Fix local delivery defers Broken-by: 3cee6033bae8 diff --git a/src/src/deliver.c b/src/src/deliver.c index 29c5dbfc6..445b9dacb 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2903,65 +2903,57 @@ while (addr_local) { BOOL ok = TRUE; /* to deliver this address */ - if (f.queue_2stage) - { - DEBUG(D_deliver) - debug_printf_indent("no router retry check (ph1 qrun)\n"); - } - else + /* Set up the retry key to include the domain or not, and change its + leading character from "R" to "T". Must make a copy before doing this, + because the old key may be pointed to from a "delete" retry item after + a routing delay. */ + uschar * retry_key = string_copy(tp->retry_use_local_part + ? addr2->address_retry_key : addr2->domain_retry_key); + *retry_key = 'T'; + + /* Inspect the retry data. If there is no hints file, delivery happens. */ + + if (dbm_file) { - /* Set up the retry key to include the domain or not, and change its - leading character from "R" to "T". Must make a copy before doing this, - because the old key may be pointed to from a "delete" retry item after - a routing delay. */ - uschar * retry_key = string_copy(tp->retry_use_local_part - ? addr2->address_retry_key : addr2->domain_retry_key); - *retry_key = 'T'; + dbdata_retry * retry_record = dbfn_read(dbm_file, retry_key); - /* Inspect the retry data. If there is no hints file, delivery happens. */ + /* If there is no retry record, delivery happens. If there is, + remember it exists so it can be deleted after a successful delivery. */ - if (dbm_file) + if (retry_record) { - dbdata_retry * retry_record = dbfn_read(dbm_file, retry_key); + setflag(addr2, af_lt_retry_exists); - /* If there is no retry record, delivery happens. If there is, - remember it exists so it can be deleted after a successful delivery. */ + /* A retry record exists for this address. If queue running and not + forcing, inspect its contents. If the record is too old, or if its + retry time has come, or if it has passed its cutoff time, delivery + will go ahead. */ - if (retry_record) + DEBUG(D_retry) { - setflag(addr2, af_lt_retry_exists); - - /* A retry record exists for this address. If queue running and not - forcing, inspect its contents. If the record is too old, or if its - retry time has come, or if it has passed its cutoff time, delivery - will go ahead. */ - - DEBUG(D_retry) - { - debug_printf("retry record exists: age=%s ", - readconf_printtime(now - retry_record->time_stamp)); - debug_printf("(max %s)\n", readconf_printtime(retry_data_expire)); - debug_printf(" time to retry = %s expired = %d\n", - readconf_printtime(retry_record->next_try - now), - retry_record->expired); - } + debug_printf("retry record exists: age=%s ", + readconf_printtime(now - retry_record->time_stamp)); + debug_printf("(max %s)\n", readconf_printtime(retry_data_expire)); + debug_printf(" time to retry = %s expired = %d\n", + readconf_printtime(retry_record->next_try - now), + retry_record->expired); + } - if (f.queue_running && !f.deliver_force) - { - ok = (now - retry_record->time_stamp > retry_data_expire) - || (now >= retry_record->next_try) - || retry_record->expired; + if (f.queue_running && !f.deliver_force) + { + ok = (now - retry_record->time_stamp > retry_data_expire) + || (now >= retry_record->next_try) + || retry_record->expired; - /* If we haven't reached the retry time, there is one more check - to do, which is for the ultimate address timeout. */ + /* If we haven't reached the retry time, there is one more check + to do, which is for the ultimate address timeout. */ - if (!ok) - ok = retry_ultimate_address_timeout(retry_key, addr2->domain, - retry_record, now); - } + if (!ok) + ok = retry_ultimate_address_timeout(retry_key, addr2->domain, + retry_record, now); } - else DEBUG(D_retry) debug_printf("no retry record exists\n"); } + else DEBUG(D_retry) debug_printf("no retry record exists\n"); } /* This address is to be delivered. Leave it on the chain. */ @@ -7821,82 +7813,74 @@ while (addr_new) /* Loop until all addresses dealt with */ continue; } - if (f.queue_2stage) + /* Get the routing retry status, saving the two retry keys (with and + without the local part) for subsequent use. If there is no retry record + for the standard address routing retry key, we look for the same key with + the sender attached, because this form is used by the smtp transport after + a 4xx response to RCPT when address_retry_include_sender is true. */ + + DEBUG(D_deliver|D_retry) { - DEBUG(D_deliver) - debug_printf_indent("no router retry check (ph1 qrun)\n"); + debug_printf_indent("checking router retry status\n"); + acl_level++; } - else - { - /* Get the routing retry status, saving the two retry keys (with and - without the local part) for subsequent use. If there is no retry record - for the standard address routing retry key, we look for the same key with - the sender attached, because this form is used by the smtp transport after - a 4xx response to RCPT when address_retry_include_sender is true. */ + addr->domain_retry_key = string_sprintf("R:%s", addr->domain); + addr->address_retry_key = string_sprintf("R:%s@%s", addr->local_part, + addr->domain); - DEBUG(D_deliver|D_retry) + if (dbm_file) + { + domain_retry_record = dbfn_read(dbm_file, addr->domain_retry_key); + if ( domain_retry_record + && now - domain_retry_record->time_stamp > retry_data_expire + ) { - debug_printf_indent("checking router retry status\n"); - acl_level++; + DEBUG(D_deliver|D_retry) + debug_printf_indent("domain retry record present but expired\n"); + domain_retry_record = NULL; /* Ignore if too old */ } - addr->domain_retry_key = string_sprintf("R:%s", addr->domain); - addr->address_retry_key = string_sprintf("R:%s@%s", addr->local_part, - addr->domain); - if (dbm_file) + address_retry_record = dbfn_read(dbm_file, addr->address_retry_key); + if ( address_retry_record + && now - address_retry_record->time_stamp > retry_data_expire + ) { - domain_retry_record = dbfn_read(dbm_file, addr->domain_retry_key); - if ( domain_retry_record - && now - domain_retry_record->time_stamp > retry_data_expire - ) - { - DEBUG(D_deliver|D_retry) - debug_printf_indent("domain retry record present but expired\n"); - domain_retry_record = NULL; /* Ignore if too old */ - } + DEBUG(D_deliver|D_retry) + debug_printf_indent("address retry record present but expired\n"); + address_retry_record = NULL; /* Ignore if too old */ + } - address_retry_record = dbfn_read(dbm_file, addr->address_retry_key); + if (!address_retry_record) + { + const uschar * altkey = string_sprintf("%s:<%s>", + addr->address_retry_key, sender_address); + address_retry_record = dbfn_read(dbm_file, altkey); if ( address_retry_record - && now - address_retry_record->time_stamp > retry_data_expire - ) + && now - address_retry_record->time_stamp > retry_data_expire) { DEBUG(D_deliver|D_retry) - debug_printf_indent("address retry record present but expired\n"); + debug_printf_indent("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ } - - if (!address_retry_record) - { - const uschar * altkey = string_sprintf("%s:<%s>", - addr->address_retry_key, sender_address); - address_retry_record = dbfn_read(dbm_file, altkey); - if ( address_retry_record - && now - address_retry_record->time_stamp > retry_data_expire) - { - DEBUG(D_deliver|D_retry) - debug_printf_indent("address retry record present but expired\n"); - address_retry_record = NULL; /* Ignore if too old */ - } - } } + } - DEBUG(D_deliver|D_retry) - { - if (!domain_retry_record) - debug_printf_indent("no domain retry record\n"); - else - debug_printf_indent("have domain retry record; next_try = now%+d\n", - f.running_in_test_harness ? 0 : - (int)(domain_retry_record->next_try - now)); + DEBUG(D_deliver|D_retry) + { + if (!domain_retry_record) + debug_printf_indent("no domain retry record\n"); + else + debug_printf_indent("have domain retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(domain_retry_record->next_try - now)); - if (!address_retry_record) - debug_printf_indent("no address retry record\n"); - else - debug_printf_indent("have address retry record; next_try = now%+d\n", - f.running_in_test_harness ? 0 : - (int)(address_retry_record->next_try - now)); - acl_level--; - } + if (!address_retry_record) + debug_printf_indent("no address retry record\n"); + else + debug_printf_indent("have address retry record; next_try = now%+d\n", + f.running_in_test_harness ? 0 : + (int)(address_retry_record->next_try - now)); + acl_level--; } /* If we are sending a message down an existing SMTP connection, we must commit 140c289d1170334e29ee3fd4e2c385cdb7bd837c Author: Jeremy Harris Date: Tue Nov 4 18:44:53 2025 +0000 Fix remote-delivery DNS defers. Bug 3172 Broken-by: 6748707c6446 diff --git a/src/src/deliver.c b/src/src/deliver.c index 445b9dacb..3dc1aef73 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -7540,42 +7540,37 @@ while (addr_new) /* Loop until all addresses dealt with */ address_item * addr, * parent; /* Failure to open the retry database is treated the same as if it does - not exist. In both cases, dbm_file is NULL. For the first stage of a 2-phase - queue run don't bother checking domain- or address-retry info; they will take - effect on the second stage. */ - - if (!f.queue_2stage) - { - /* If we have transaction-capable hintsdbs, open the retry db without - locking, and leave open for the transport process and for subsequent - deliveries. Use a writeable open as we can keep it open all the way through - to writing retry records if needed due to message fails. - If the open fails, tag that explicitly for the transport but retry the open - next time around, in case it was created in the interim. - If non-transaction, we are only reading records at this stage and - we close the db before running the transport. - Either way we do a non-creating open. */ - - if (continue_retry_db == (open_db *)-1) - continue_retry_db = NULL; - - if (continue_retry_db) - { - DEBUG(D_hints_lookup) debug_printf("using cached retry hintsdb handle\n"); - dbm_file = continue_retry_db; - } - else if (!exim_lockfile_needed()) - { - dbm_file = dbfn_open_multi(US"retry", O_RDWR, &dbblock); - continue_retry_db = dbm_file ? dbm_file : (open_db *)-1; - } - else - dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE); + not exist. In both cases, dbm_file is NULL. */ + + /* If we have transaction-capable hintsdbs, open the retry db without + locking, and leave open for the transport process and for subsequent + deliveries. Use a writeable open as we can keep it open all the way through + to writing retry records if needed due to message fails. + If the open fails, tag that explicitly for the transport but retry the open + next time around, in case it was created in the interim. + If non-transaction, we are only reading records at this stage and + we close the db before running the transport. + Either way we do a non-creating open. */ - if (!dbm_file) - DEBUG(D_deliver|D_retry|D_route|D_hints_lookup) - debug_printf("no retry data available\n"); + if (continue_retry_db == (open_db *)-1) + continue_retry_db = NULL; + + if (continue_retry_db) + { + DEBUG(D_hints_lookup) debug_printf("using cached retry hintsdb handle\n"); + dbm_file = continue_retry_db; + } + else if (!exim_lockfile_needed()) + { + dbm_file = dbfn_open_multi(US"retry", O_RDWR, &dbblock); + continue_retry_db = dbm_file ? dbm_file : (open_db *)-1; } + else + dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE); + + if (!dbm_file) + DEBUG(D_deliver|D_retry|D_route|D_hints_lookup) + debug_printf("no retry data available\n"); /* Scan the current batch of new addresses, to handle pipes, files and autoreplies, and determine which others are ready for routing. */ commit ea41f8373bd699697585193862afab334a62ec1a Author: Jeremy Harris Date: Wed Nov 5 10:17:04 2025 +0000 Build: more files for cscope diff --git a/src/Makefile b/src/Makefile index 9c08915ef..45711a05b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -121,10 +121,15 @@ cscope.files: FRC echo "-p3" >> $@ -bd=build-$(buildname); [ -d $$bd ] && echo -e "$$bd/config.h\n$$bd/Makefile" >> $@ find src Local OS exim_monitor -name "*.[cshyl]" -print \ + -o -name "*.src" -print \ -o -name "os.[ch]*" -print \ -o -name "*akefile*" -print \ -o -name config.h.defaults -print \ -o -name EDITME -print >> $@ + echo scripts/* >> $@ + +cscope: cscope.files + cscope -b -p 3 FRC: commit d3dd48e449dcd329126c4365c8f92335c8afa350 Author: Jeremy Harris Date: Thu Nov 6 10:55:05 2025 +0000 fix radius expansion condition diff --git a/src/src/miscmods/pam.c b/src/src/miscmods/pam.c index 842282ba5..f39e09208 100644 --- a/src/src/miscmods/pam.c +++ b/src/src/miscmods/pam.c @@ -68,7 +68,7 @@ static int pam_converse (int num_msg, PAM_CONVERSE_ARG2_TYPE **msg, struct pam_response **resp, void *appdata_ptr) { -int sep = 0; +int sep = ':'; struct pam_response *reply; /* It seems that PAM frees reply[] */ @@ -131,7 +131,7 @@ Returns: OK if authentication succeeded static int auth_call_pam(const uschar * s, uschar ** errptr) { -pam_handle_t *pamh = NULL; +pam_handle_t * pamh = NULL; struct pam_conv pamc; int pam_error; int sep = ':'; /* Do not permit change-of-separator */ diff --git a/src/src/miscmods/radius.c b/src/src/miscmods/radius.c index 3f8232756..fd75b3ae4 100644 --- a/src/src/miscmods/radius.c +++ b/src/src/miscmods/radius.c @@ -59,8 +59,8 @@ using its original API. At release 0.4.0 the API changed. */ more data strings. Arguments: - s a colon-separated list of strings - errptr where to point an error message + radius_args a colon-separated list of strings + errptr where to point an error message Returns: OK if authentication succeeded FAIL if authentication failed @@ -68,12 +68,10 @@ Returns: OK if authentication succeeded */ static int -auth_call_radius(const uschar *s, uschar **errptr) +auth_call_radius(const uschar * radius_args, uschar ** errptr) { -uschar *user; -const uschar *radius_args = s; -int result; -int sep = ':'; +uschar * user, * pwd; +int sep = ':', result; #ifdef RADIUS_LIB_RADLIB struct rad_handle *h; @@ -89,9 +87,10 @@ int sep = ':'; if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) user = US""; +pwd = string_nextinlist(&radius_args, &sep, NULL, 0); DEBUG(D_auth) debug_printf("Running RADIUS authentication for user %q " - "and %q\n", user, radius_args); + "and %q\n", user, pwd); *errptr = NULL; @@ -112,7 +111,7 @@ else if (rc_read_dictionary(rc_conf_str("dictionary")) != 0) else if (!rc_avpair_add(&send, PW_USER_NAME, user, 0)) *errptr = US"RADIUS: add user name failed"; -else if (!rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0)) +else if (!rc_avpair_add(&send, PW_USER_PASSWORD, pwd, 0)) *errptr = US"RADIUS: add password failed"); else if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0)) commit eaf7eae8474ded19ec64022f71d1b9e610013d5c Author: Samuel Thibault Date: Fri Nov 7 09:37:04 2025 +0000 Fix file open modes for Gnu/Hurd. Bug 3175 diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index cd98ff053..5065b6e9b 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -335,7 +335,7 @@ if ( asprintf(CSS &dirname, "%s/db", spool_directory) < 0 || asprintf(CSS &filename, "%s/%s.lockfile", dirname, name) < 0) return NULL; -dbblock->readonly = (flags & (O_WRONLY|O_RDWR)) == O_RDONLY; +dbblock->readonly = (flags & O_ACCMODE) == O_RDONLY; dbblock->lockfd = -1; if (exim_lockfile_needed()) { diff --git a/src/src/hintsdb/hints_bdb.h b/src/src/hintsdb/hints_bdb.h index 7285e85f9..85e8984ec 100644 --- a/src/src/hintsdb/hints_bdb.h +++ b/src/src/hintsdb/hints_bdb.h @@ -115,7 +115,7 @@ if (db_create(&b, dbp, 0) == 0) if (b->open(b, NULL, CS name, NULL, flags & O_CREAT ? DB_HASH : DB_UNKNOWN, flags & O_CREAT ? DB_CREATE - : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY, + : (flags & O_ACCMODE) == O_RDONLY ? DB_RDONLY : 0, mode) == 0 ) return dbp; @@ -266,7 +266,7 @@ return db_create(&dbp, NULL, 0) == 0 dbp->open(dbp, CS name, NULL, flags & O_CREAT ? DB_HASH : DB_UNKNOWN, flags & O_CREAT ? DB_CREATE - : flags & (O_WRONLY|O_RDWR) ? 0 : DB_RDONLY, + : (flags & O_ACCMODE) == O_RDONLY ? DB_RDONLY : 0, mode) ) == 0 ? dbp : NULL; diff --git a/src/src/hintsdb/hints_gdbm.h b/src/src/hintsdb/hints_gdbm.h index 00c94a777..34df8c84f 100644 --- a/src/src/hintsdb/hints_gdbm.h +++ b/src/src/hintsdb/hints_gdbm.h @@ -58,7 +58,7 @@ if (dbp) dbp->lkey.dptr = NULL; dbp->gdbm = gdbm_open(CS name, 0, flags & O_CREAT ? GDBM_WRCREAT - : flags & (O_RDWR|O_WRONLY) ? GDBM_WRITER : GDBM_READER, + : (flags & O_ACCMODE) == O_RDONLY ? GDBM_READER : GDBM_WRITER, mode, 0); if (dbp->gdbm) return dbp; diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index 01906f839..40d50b8c0 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -45,7 +45,8 @@ exim_dbopen_multi__(const uschar * name, const uschar * dirname, int flags, unsigned mode) { EXIM_DB * dbp; -int ret, sflags = flags & O_RDWR ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; +int ret, sflags = (flags & O_ACCMODE) == O_RDONLY + ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE; if (flags & O_CREAT) sflags |= SQLITE_OPEN_CREATE; if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK) commit 0cf5f1656eff31bcc1131ca047030f4866b4224b Author: Jeremy Harris Date: Fri Nov 7 17:50:28 2025 +0000 Retire "pwcheck" expansion condition diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index e24ef95f2..25a8e82a7 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -552,8 +552,7 @@ OBJ_LOOKUPS = lf_quote.o lf_check_file.o lf_sqlperform.o OBJ_ROUTERS = rf_change_domain.o rf_expand_data.o rf_get_errors_address.o \ rf_get_munge_headers.o rf_get_transport.o rf_get_ugid.o \ rf_lookup_hostlist.o rf_queue_add.o rf_self_action.o rf_set_ugid.o -OBJ_AUTHS = call_pwcheck.o check_serv_cond.o \ - get_data.o get_no64_data.o pwcheck.o +OBJ_AUTHS = check_serv_cond.o get_data.o get_no64_data.o pwcheck.o OBJ_EXIM = acl.o atrn.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o \ deliver.o directory.o dns.o drtables.o enq.o exim.o expand.o \ @@ -1003,9 +1002,6 @@ rf_set_ugid.o: routers/rf_set_ugid.c auth-spa.o: auths/auth-spa.c @echo "$(CC) $<" $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< -call_pwcheck.o: auths/call_pwcheck.c auths/pwcheck.h - @echo "$(CC) $<" - $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< check_serv_cond.o: auths/check_serv_cond.c @echo "$(CC) $<" $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 8f55be0b5..765472195 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -78,7 +78,7 @@ d="auths" mkdir $d cd $d # Makefile is generated -for f in README call_pwcheck.c \ +for f in README \ check_serv_cond.c cyrus_sasl.c cyrus_sasl.h gsasl.c \ gsasl.h get_data.c get_no64_data.c heimdal_gssapi.c heimdal_gssapi.h \ cram_md5.c cram_md5.h plaintext.c plaintext.h \ diff --git a/src/src/EDITME b/src/src/EDITME index 998406359..d38ac98e5 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1205,23 +1205,6 @@ ZCAT_COMMAND=/usr/bin/zcat # using the original API. -#------------------------------------------------------------------------------ -# Support for authentication via the Cyrus SASL pwcheck daemon is available. -# Note, however, that pwcheck is now deprecated in favour of saslauthd (see -# next item). The Exim support for pwcheck, which is intented for use in -# conjunction with the SMTP AUTH facilities, is included only when requested by -# setting the following parameter to the location of the pwcheck daemon's -# socket. -# -# There is no need to install all of SASL on your system. You just need to run -# ./configure --with-pwcheck, cd to the pwcheck directory within the sources, -# make and make install. You must create the socket directory (default -# /var/pwcheck) and chown it to Exim's user and group. Once you have installed -# pwcheck, you should arrange for it to be started by root at boot time. - -# CYRUS_PWCHECK_SOCKET=/var/pwcheck/pwcheck - - #------------------------------------------------------------------------------ # Support for authentication via the Cyrus SASL saslauthd daemon is available. # The Exim support, which is intended for use in conjunction with the SMTP AUTH diff --git a/src/src/auths/call_pwcheck.c b/src/src/auths/call_pwcheck.c deleted file mode 100644 index 9e0d5d41f..000000000 --- a/src/src/auths/call_pwcheck.c +++ /dev/null @@ -1,120 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ -/* Copyright (c) University of Cambridge 1995 - 2015 */ -/* See the file NOTICE for conditions of use and distribution. */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* This module contains interface functions to the two Cyrus authentication -daemons. The original one was "pwcheck", which gives its name to the source -file. This is now deprecated in favour of "saslauthd". */ - - -#include "../exim.h" -#include "pwcheck.h" - - -/************************************************* -* External entry point for pwcheck * -*************************************************/ - -/* This function calls the now-deprecated "pwcheck" Cyrus-SASL authentication -daemon, passing over a colon-separated user name and password. As this is -called from the string expander, the string will always be in dynamic store and -can be overwritten. - -Arguments: - s a colon-separated username:password string - errptr where to point an error message - -Returns: OK if authentication succeeded - FAIL if authentication failed - ERROR some other error condition -*/ - -int -auth_call_pwcheck(uschar *s, uschar **errptr) -{ -uschar * reply = NULL, * pw = Ustrrchr(s, ':'); - -if (!pw) - { - *errptr = US"pwcheck: malformed input - missing colon"; - return ERROR; - } - -*pw++ = 0; /* Separate user and password */ - -DEBUG(D_auth) debug_printf("Running pwcheck authentication for user %q\n", s); - -switch (pwcheck_verify_password(CS s, CS pw, CCSS &reply)) - { - case PWCHECK_OK: - DEBUG(D_auth) debug_printf("pwcheck: success (%s)\n", reply); - return OK; - - case PWCHECK_NO: - DEBUG(D_auth) debug_printf("pwcheck: access denied (%s)\n", reply); - return FAIL; - - default: - DEBUG(D_auth) debug_printf("pwcheck: query failed (%s)\n", reply); - *errptr = reply; - return ERROR; - } -} - - -/************************************************* -* External entry point for pwauthd * -*************************************************/ - -/* This function calls the "saslauthd" Cyrus-SASL authentication daemon, -saslauthd, As this is called from the string expander, all the strings will -always be in dynamic store and can be overwritten. - -Arguments: - username username - password password - service optional service - realm optional realm - errptr where to point an error message - -Returns: OK if authentication succeeded - FAIL if authentication failed - ERROR some other error condition -*/ - -int -auth_call_saslauthd(const uschar *username, const uschar *password, - const uschar *service, const uschar *realm, uschar **errptr) -{ -uschar *reply = NULL; - -if (service == NULL) service = US""; -if (realm == NULL) realm = US""; - -DEBUG(D_auth) - debug_printf("Running saslauthd authentication for user %q \n", username); - -switch (saslauthd_verify_password(username, password, service, - realm, (const uschar **)(&reply))) - { - case PWCHECK_OK: - DEBUG(D_auth) debug_printf("saslauthd: success (%s)\n", reply); - return OK; - - case PWCHECK_NO: - DEBUG(D_auth) debug_printf("saslauthd: access denied (%s)\n", reply); - return FAIL; - - default: - DEBUG(D_auth) debug_printf("saslauthd: query failed (%s)\n", reply); - *errptr = reply; - return ERROR; - } -} - -/* End of call_pwcheck.c */ diff --git a/src/src/auths/pwcheck.c b/src/src/auths/pwcheck.c index bf305832f..cd8ed1e10 100644 --- a/src/src/auths/pwcheck.c +++ b/src/src/auths/pwcheck.c @@ -59,16 +59,16 @@ */ /* Originally this module supported only the pwcheck daemon, which is where its -name comes from. Nowadays it supports saslauthd as well; pwcheck is in fact -deprecated. The definitions of CYRUS_PWCHECK_SOCKET and CYRUS_SASLAUTHD_SOCKET -determine whether the facilities are actually supported or not. */ +name comes from. Nowadays it supports saslauthd instead; pwcheck is in fact +deprecated. The definition of CYRUS_SASLAUTHD_SOCKET +determines whether the facilities are actually supported or not. */ #include "../exim.h" #include "pwcheck.h" -#if defined(CYRUS_PWCHECK_SOCKET) || defined(CYRUS_SASLAUTHD_SOCKET) +#if defined(CYRUS_SASLAUTHD_SOCKET) #include @@ -80,79 +80,6 @@ static int write_string(int, const uschar *, int); #endif -/* A dummy function that always fails if pwcheck support is not -wanted. */ - -#ifndef CYRUS_PWCHECK_SOCKET -int pwcheck_verify_password(const char *userid, - const char *passwd, - const char **reply) -{ -*reply = "pwcheck support is not included in this Exim binary"; -return PWCHECK_FAIL; -} - - -/* This is the real function */ - -#else - - /* taken from cyrus-sasl file checkpw.c */ - /* pwcheck daemon-authenticated login */ - int pwcheck_verify_password(const char *userid, - const char *passwd, - const char **reply) - { - int s, start, r, n; - struct sockaddr_un srvaddr; - struct iovec iov[2]; - static char response[1024]; - - *reply = NULL; - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s == -1) { return PWCHECK_FAIL; } - - memset(CS &srvaddr, 0, sizeof(srvaddr)); - srvaddr.sun_family = AF_UNIX; - strncpy(srvaddr.sun_path, CYRUS_PWCHECK_SOCKET, sizeof(srvaddr.sun_path)); - r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); - if (r == -1) { - DEBUG(D_auth) - debug_printf("Cannot connect to pwcheck daemon (at '%s')\n",CYRUS_PWCHECK_SOCKET); - *reply = "cannot connect to pwcheck daemon"; - return PWCHECK_FAIL; - } - - iov[0].iov_base = CS userid; - iov[0].iov_len = strlen(userid)+1; - iov[1].iov_base = CS passwd; - iov[1].iov_len = strlen(passwd)+1; - - retry_writev(s, iov, 2); - - start = 0; - while (start < sizeof(response) - 1) { - n = read(s, response+start, sizeof(response) - 1 - start); - if (n < 1) break; - start += n; - } - - (void)close(s); - - if (start > 1 && !strncmp(response, "OK", 2)) { - return PWCHECK_OK; - } - - response[start] = '\0'; - *reply = response; - return PWCHECK_NO; - } - -#endif - - - /* A dummy function that always fails if saslauthd support is not wanted. */ @@ -268,7 +195,7 @@ int saslauthd_verify_password(const uschar *userid, /* helper functions */ -#if defined(CYRUS_PWCHECK_SOCKET) || defined(CYRUS_SASLAUTHD_SOCKET) +#if defined(CYRUS_SASLAUTHD_SOCKET) #define MAX_REQ_LEN 1024 diff --git a/src/src/auths/pwcheck.h b/src/src/auths/pwcheck.h index 4c1d71d92..0c20292ce 100644 --- a/src/src/auths/pwcheck.h +++ b/src/src/auths/pwcheck.h @@ -6,8 +6,8 @@ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* This file provides support for authentication via the Cyrus SASL pwcheck -daemon (whence its name) and the newer saslauthd daemon. */ +/* This file originally provided support for authentication via the Cyrus +SASL pwcheck daemon (whence its name), but now the newer saslauthd daemon. */ /* Error codes used internally within the authentication functions */ @@ -21,7 +21,6 @@ daemon (whence its name) and the newer saslauthd daemon. */ /* Cyrus functions for doing the business. */ -extern int pwcheck_verify_password(const char *, const char *, const char **); extern int saslauthd_verify_password(const uschar *, const uschar *, const uschar *, const uschar *, const uschar **); diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 05bdcd6d3..f331ad0d5 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -40,7 +40,6 @@ Do not put spaces between # and the 'define'. #define CONFIGURE_FILE_USE_NODE #define CONFIGURE_GROUP #define CONFIGURE_OWNER -#define CYRUS_PWCHECK_SOCKET #define CYRUS_SASLAUTHD_SOCKET #define DEFAULT_CRYPT crypt diff --git a/src/src/exim.c b/src/src/exim.c index c6fa25fc7..9d6f858bd 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1158,9 +1158,6 @@ g = string_cat(g, US"Support for:"); #ifdef USE_OPENSSL g = string_cat(g, US" OpenSSL"); #endif -#if defined(CYRUS_PWCHECK_SOCKET) - g = string_cat(g, US" pwcheck"); -#endif #if defined(RADIUS_CONFIG_FILE) g = string_cat(g, US" radius"); #endif diff --git a/src/src/expand.c b/src/src/expand.c index 9bfa39fdc..fb32ce985 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -362,7 +362,6 @@ static uschar *cond_table[] = { US"match_local_part", US"or", US"pam", - US"pwcheck", US"queue_running", US"radius", US"saslauthd" @@ -415,7 +414,6 @@ enum { ECOND_MATCH_LOCAL_PART, ECOND_OR, ECOND_PAM, - ECOND_PWCHECK, ECOND_QUEUE_RUNNING, ECOND_RADIUS, ECOND_SASLAUTHD @@ -2740,7 +2738,6 @@ switch(cond_type = identify_operator(&s, &opname)) case ECOND_PAM: case ECOND_RADIUS: case ECOND_LDAPAUTH: - case ECOND_PWCHECK: if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */ @@ -2835,16 +2832,8 @@ switch(cond_type = identify_operator(&s, &opname)) goto COND_FAILED_NOT_COMPILED; #endif /* LOOKUP_LDAP */ - case ECOND_PWCHECK: - #ifdef CYRUS_PWCHECK_SOCKET - rc = auth_call_pwcheck(sub[0], &expand_string_message); - goto END_AUTH; - #else - goto COND_FAILED_NOT_COMPILED; - #endif /* CYRUS_PWCHECK_SOCKET */ - #if defined(SUPPORT_PAM) || defined(RADIUS_CONFIG_FILE) || \ - defined(LOOKUP_LDAP) || defined(CYRUS_PWCHECK_SOCKET) + defined(LOOKUP_LDAP) END_AUTH: if (rc == ERROR || rc == DEFER) goto failout; *yield = (rc == OK) == testfor; @@ -3724,7 +3713,7 @@ goto failout; /* A condition requires code that is not compiled */ #if !defined(SUPPORT_PAM) || !defined(RADIUS_CONFIG_FILE) || \ - !defined(LOOKUP_LDAP) || !defined(CYRUS_PWCHECK_SOCKET) || \ + !defined(LOOKUP_LDAP) || \ !defined(SUPPORT_CRYPTEQ) || !defined(CYRUS_SASLAUTHD_SOCKET) COND_FAILED_NOT_COMPILED: expand_string_message = string_sprintf("support for %q not compiled", diff --git a/src/src/functions.h b/src/src/functions.h index ef1c59dc3..bd390cce6 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -112,7 +112,6 @@ extern void assert_no_variables(void *, int, const char *, int); extern void atrn_handle_customer(void); extern int atrn_handle_provider(uschar **, uschar **); -extern int auth_call_pwcheck(uschar *, uschar **); extern int auth_call_saslauthd(const uschar *, const uschar *, const uschar *, const uschar *, uschar **); extern int auth_check_serv_cond(auth_instance *); commit 3bac7a1bac4fbccea548b3f8ed9a788b8b41d943 Author: Jeremy Harris Date: Mon Nov 10 10:09:49 2025 +0000 Fix CYRUS_SASLAUTHD_SOCKET build. Bug 3176 Broken-by: 0cf5f1656eff diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 25a8e82a7..40befe325 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -552,7 +552,8 @@ OBJ_LOOKUPS = lf_quote.o lf_check_file.o lf_sqlperform.o OBJ_ROUTERS = rf_change_domain.o rf_expand_data.o rf_get_errors_address.o \ rf_get_munge_headers.o rf_get_transport.o rf_get_ugid.o \ rf_lookup_hostlist.o rf_queue_add.o rf_self_action.o rf_set_ugid.o -OBJ_AUTHS = check_serv_cond.o get_data.o get_no64_data.o pwcheck.o +OBJ_AUTHS = call_saslauthd.o check_serv_cond.o \ + get_data.o get_no64_data.o pwcheck.o OBJ_EXIM = acl.o atrn.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o \ deliver.o directory.o dns.o drtables.o enq.o exim.o expand.o \ @@ -1002,6 +1003,9 @@ rf_set_ugid.o: routers/rf_set_ugid.c auth-spa.o: auths/auth-spa.c @echo "$(CC) $<" $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< +call_saslauthd.o: auths/call_saslauthd.c auths/pwcheck.h + @echo "$(CC) $<" + $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< check_serv_cond.o: auths/check_serv_cond.c @echo "$(CC) $<" $(FE)$(CC) -c $(CFLAGS) -I. $(INCLUDE) $< diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 765472195..4e4a638c7 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -78,7 +78,7 @@ d="auths" mkdir $d cd $d # Makefile is generated -for f in README \ +for f in README call_saslauthd.c \ check_serv_cond.c cyrus_sasl.c cyrus_sasl.h gsasl.c \ gsasl.h get_data.c get_no64_data.c heimdal_gssapi.c heimdal_gssapi.h \ cram_md5.c cram_md5.h plaintext.c plaintext.h \ diff --git a/src/src/auths/call_saslauthd.c b/src/src/auths/call_saslauthd.c new file mode 100644 index 000000000..b5735fc6c --- /dev/null +++ b/src/src/auths/call_saslauthd.c @@ -0,0 +1,69 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2020 - 2025 */ +/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* This module contains interface functions to the two Cyrus authentication +daemons. The original one was "pwcheck", which gives its name to the source +file. This is now deprecated in favour of "saslauthd". */ + + +#include "../exim.h" +#include "pwcheck.h" + + +/************************************************* +* External entry point for saslauthd * +*************************************************/ + +/* This function calls the "saslauthd" Cyrus-SASL authentication daemon, +saslauthd, As this is called from the string expander, all the strings will +always be in dynamic store and can be overwritten. + +Arguments: + username username + password password + service optional service + realm optional realm + errptr where to point an error message + +Returns: OK if authentication succeeded + FAIL if authentication failed + ERROR some other error condition +*/ + +int +auth_call_saslauthd(const uschar *username, const uschar *password, + const uschar *service, const uschar *realm, uschar **errptr) +{ +uschar *reply = NULL; + +if (service == NULL) service = US""; +if (realm == NULL) realm = US""; + +DEBUG(D_auth) + debug_printf("Running saslauthd authentication for user %q \n", username); + +switch (saslauthd_verify_password(username, password, service, + realm, (const uschar **)(&reply))) + { + case PWCHECK_OK: + DEBUG(D_auth) debug_printf("saslauthd: success (%s)\n", reply); + return OK; + + case PWCHECK_NO: + DEBUG(D_auth) debug_printf("saslauthd: access denied (%s)\n", reply); + return FAIL; + + default: + DEBUG(D_auth) debug_printf("saslauthd: query failed (%s)\n", reply); + *errptr = reply; + return ERROR; + } +} + +/* End of call_pwcheck.c */ diff --git a/src/src/expand.c b/src/src/expand.c index fb32ce985..fcf699d2e 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -3712,14 +3712,10 @@ goto failout; /* A condition requires code that is not compiled */ -#if !defined(SUPPORT_PAM) || !defined(RADIUS_CONFIG_FILE) || \ - !defined(LOOKUP_LDAP) || \ - !defined(SUPPORT_CRYPTEQ) || !defined(CYRUS_SASLAUTHD_SOCKET) COND_FAILED_NOT_COMPILED: expand_string_message = string_sprintf("support for %q not compiled", opname); goto failout; -#endif failout: next = NULL; commit 1cb819c5032dc7797999c60c023f65c842dcf5d4 Author: Jeremy Harris Date: Sun Nov 9 12:15:07 2025 +0000 Build: quietening diff --git a/src/Makefile b/src/Makefile index 45711a05b..a19c6928a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,6 +29,9 @@ RM_COMMAND=/bin/rm buildname=$${build:-`$(SHELL) scripts/os-type`-`$(SHELL) scripts/arch-type`}$${EXIM_BUILD_SUFFIX:+.$$EXIM_BUILD_SUFFIX} +# Quieten gnumake wrt. sub-make directories +GNUMAKEFLAGS=--no-print-directory + # The default target checks for the existence of Local/Makefile, that the main # makefile is built and up-to-date, and then it runs it. # If Local/Makefile- exists, it is read too. @@ -63,12 +66,14 @@ build-directory: (mkdir $$builddir; cd $$builddir; $(SHELL) ../scripts/MakeLinks)"; checks: - $(SHELL) scripts/source_checks + @$(SHELL) scripts/source_checks # The "configure" target ensures that the build directory exists, then arranges # to build the main makefile from inside the build directory, by calling the # Configure-Makefile script. This does its own dependency checking because of # the optional files. +# We always run the script (as there is no actual"configure" file) +# but it quietly dooes nothing if nothing is needed. configure: checks build-directory \ scripts/lookups-Makefile scripts/drivers-Makefile diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 40befe325..80f1f1f97 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -36,8 +36,9 @@ FE = $(FULLECHO) # up-to-date. Then the os-specific source files and the C configuration file # are set up, and finally it goes to the main Exim target. -all: utils exim dynmodules -config: $(EDITME) checklocalmake Makefile os.c config.h version.h version.sh macro.c +CONFIG_DEPS = Makefile os.c config.h version.h version.sh macro.c + +all: $(EDITME) checklocalmake $(CONFIG_DEPS) utils exim dynmodules exim_openssl exim_gnutls: clean exim cp exim $@ @@ -243,9 +244,7 @@ macro.c: macro_predef # therefore always be run, even if the files exist. This shouldn't in fact be a # problem, but it does no harm. Other make programs will just ignore this. -.PHONY: all config utils \ - buildauths buildlookups buildrouters \ - buildtransports buildmisc dynmodules checklocalmake clean +.PHONY: all config utils dynmodules clean utils: $(EXIM_MONITOR) exicyclog exinext exiwhat \ @@ -261,12 +260,12 @@ buildconfig: buildconfig.c $(FE)$(CC) $(CFLAGS) $(INCLUDE) -o buildconfig buildconfig.c $(LIBS) -util_deps: config ../src/utils/msgid.frag +UTIL_DEPS = $(CONFIG_DEPS) ../src/utils/msgid.frag # Target for the exicyclog utility script -exicyclog: util_deps ../src/utils/exicyclog.src - @rm -f exicyclog - @. ./version.sh && sed \ +exicyclog: $(UTIL_DEPS) ../src/utils/exicyclog.src + $(FE)rm -f exicyclog + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -292,15 +291,15 @@ exicyclog: util_deps ../src/utils/exicyclog.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exicyclog.src > exicyclog-t - @mv exicyclog-t exicyclog - @chmod a+x exicyclog - @./exicyclog -v 2>&1 >/dev/null - @echo ">>> exicyclog script built" + $(FE)mv exicyclog-t exicyclog + $(FE)chmod a+x exicyclog + $(FE)./exicyclog -v 2>&1 >/dev/null +# $(FE)echo ">>> exicyclog script built" # Target for the exinext utility script -exinext: util_deps ../src/utils/exinext.src - @rm -f exinext - @. ./version.sh && sed \ +exinext: $(UTIL_DEPS) ../src/utils/exinext.src + $(FE)rm -f exinext + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -316,15 +315,15 @@ exinext: util_deps ../src/utils/exinext.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exinext.src > exinext-t - @mv exinext-t exinext - @chmod a+x exinext - @./exinext -v 2>&1 >/dev/null - @echo ">>> exinext script built" + $(FE)mv exinext-t exinext + $(FE)chmod a+x exinext + $(FE)./exinext -v 2>&1 >/dev/null +# $(FE)echo ">>> exinext script built" # Target for the exiwhat utility script -exiwhat: config ../src/utils/exiwhat.src - @rm -f exiwhat - @. ./version.sh && sed \ +exiwhat: $(CONFIG_DEPS) ../src/utils/exiwhat.src + $(FE)rm -f exiwhat + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -341,15 +340,15 @@ exiwhat: config ../src/utils/exiwhat.src -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ -e "s?RM_COMMAND?$(RM_COMMAND)?" \ ../src/utils/exiwhat.src > exiwhat-t - @mv exiwhat-t exiwhat - @chmod a+x exiwhat - @./exiwhat -v 2>&1 >/dev/null - @echo ">>> exiwhat script built" + $(FE)mv exiwhat-t exiwhat + $(FE)chmod a+x exiwhat + $(FE)./exiwhat -v 2>&1 >/dev/null +# $(FE)echo ">>> exiwhat script built" # Target for the exim_checkaccess utility script -exim_checkaccess: config ../src/utils/exim_checkaccess.src - @rm -f exim_checkaccess - @. ./version.sh && sed \ +exim_checkaccess: $(CONFIG_DEPS) ../src/utils/exim_checkaccess.src + $(FE)rm -f exim_checkaccess + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -360,17 +359,17 @@ exim_checkaccess: config ../src/utils/exim_checkaccess.src -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ ../src/utils/exim_checkaccess.src > exim_checkaccess-t - @mv exim_checkaccess-t exim_checkaccess - @chmod a+x exim_checkaccess - # @./exim_checkaccess -v 2>&1 >/dev/null - @echo ">>> exim_checkaccess script built"; echo "" + $(FE)mv exim_checkaccess-t exim_checkaccess + $(FE)chmod a+x exim_checkaccess +# @./exim_checkaccess -v 2>&1 >/dev/null +# $(FE)echo ">>> exim_checkaccess script built"; echo "" # Target for the Exim monitor start-up script -eximon: config ../src/utils/eximon.src ../OS/eximon.conf-Default \ +eximon: $(CONFIG_DEPS) ../src/utils/eximon.src ../OS/eximon.conf-Default \ ../Local/eximon.conf - @rm -f eximon + $(FE)rm -f eximon $(SHELL) $(SCRIPTS)/Configure-eximon - @. ./version.sh && sed \ + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -383,15 +382,15 @@ eximon: config ../src/utils/eximon.src ../OS/eximon.conf-Default \ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ ../src/utils/eximon.src >> eximon - @./eximon -v 2>&1 >/dev/null - @echo ">>> eximon script built"; echo "" + $(FE)./eximon -v 2>&1 >/dev/null +# $(FE)echo ">>> eximon script built"; echo "" # Targets for utilities; these are all Perl scripts that have to get the # location of Perl put in them. A few need other things as well. -exigrep: util_deps ../src/utils/exigrep.src - @rm -f exigrep - @. ./version.sh && sed \ +exigrep: $(UTIL_DEPS) ../src/utils/exigrep.src + $(FE)rm -f exigrep + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -407,14 +406,14 @@ exigrep: util_deps ../src/utils/exigrep.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exigrep.src > exigrep-t - @mv exigrep-t exigrep - @chmod a+x exigrep - @./exigrep --version 2>&1 >/dev/null - @echo ">>> exigrep script built" - -exim_msgdate: util_deps ../src/utils/exim_msgdate.src - @rm -f exim_msgdate - @. ./version.sh && sed \ + $(FE)mv exigrep-t exigrep + $(FE)chmod a+x exigrep + $(FE)./exigrep --version 2>&1 >/dev/null +# $(FE)echo ">>> exigrep script built" + +exim_msgdate: $(UTIL_DEPS) ../src/utils/exim_msgdate.src + $(FE)rm -f exim_msgdate + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^[ \t]*# /p" \ -e "/^[ \t]*# /d" \ @@ -431,26 +430,26 @@ exim_msgdate: util_deps ../src/utils/exim_msgdate.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exim_msgdate.src > exim_msgdate-t - @mv exim_msgdate-t exim_msgdate - @chmod a+x exim_msgdate - @./exim_msgdate -v 2>&1 >/dev/null - @echo ">>> exim_msgdate script built" - -eximstats: config ../src/utils/eximstats.src - @rm -f eximstats - @. ./version.sh && sed \ + $(FE)mv exim_msgdate-t exim_msgdate + $(FE)chmod a+x exim_msgdate + $(FE)./exim_msgdate -v 2>&1 >/dev/null +# $(FE)echo ">>> exim_msgdate script built" + +eximstats: $(CONFIG_DEPS) ../src/utils/eximstats.src + $(FE)rm -f eximstats + $(FE). ./version.sh && sed \ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ ../src/utils/eximstats.src > eximstats-t - @mv eximstats-t eximstats - @chmod a+x eximstats - @./eximstats -v 2>&1 >/dev/null - @echo ">>> eximstats script built" - -exiqgrep: util_deps ../src/utils/exiqgrep.src - @rm -f exiqgrep - @. ./version.sh && sed \ + $(FE)mv eximstats-t eximstats + $(FE)chmod a+x eximstats + $(FE)./eximstats -v 2>&1 >/dev/null +# $(FE)echo ">>> eximstats script built" + +exiqgrep: $(UTIL_DEPS) ../src/utils/exiqgrep.src + $(FE)rm -f exiqgrep + $(FE). ./version.sh && sed \ -e "s?PROCESSED_FLAG?This file has been so processed.?"\ -e "/^# /p" \ -e "/^# /d" \ @@ -465,14 +464,14 @@ exiqgrep: util_deps ../src/utils/exiqgrep.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exiqgrep.src > exiqgrep-t - @mv exiqgrep-t exiqgrep - @chmod a+x exiqgrep - @./exiqgrep -v 2>&1 >/dev/null - @echo ">>> exiqgrep script built" - -exiqsumm: util_deps ../src/utils/exiqsumm.src - @rm -f exiqsumm - @. ./version.sh && sed \ + $(FE)mv exiqgrep-t exiqgrep + $(FE)chmod a+x exiqgrep + $(FE)./exiqgrep -v 2>&1 >/dev/null +# $(FE)echo ">>> exiqgrep script built" + +exiqsumm: $(UTIL_DEPS) ../src/utils/exiqsumm.src + $(FE)rm -f exiqsumm + $(FE). ./version.sh && sed \ -e "/^MSGID_RE/b mi" \ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ @@ -483,28 +482,28 @@ exiqsumm: util_deps ../src/utils/exiqsumm.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exiqsumm.src > exiqsumm-t - @mv exiqsumm-t exiqsumm - @chmod a+x exiqsumm - @./exiqsumm -v 2>&1 >/dev/null - @echo ">>> exiqsumm script built" - -exipick: config ../src/utils/exipick.src - @rm -f exipick - @. ./version.sh && sed \ + $(FE)mv exiqsumm-t exiqsumm + $(FE)chmod a+x exiqsumm + $(FE)./exiqsumm -v 2>&1 >/dev/null +# $(FE)echo ">>> exiqsumm script built" + +exipick: $(CONFIG_DEPS) ../src/utils/exipick.src + $(FE)rm -f exipick + $(FE). ./version.sh && sed \ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ -e "s?SPOOL_DIRECTORY?$(SPOOL_DIRECTORY)?" \ -e "s?BIN_DIRECTORY?$(BIN_DIRECTORY)?" \ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ ../src/utils/exipick.src > exipick-t - @mv exipick-t exipick - @chmod a+x exipick - @./exipick -v 2>&1 >/dev/null - @echo ">>> exipick script built" - -exim_id_update: util_deps ../src/utils/exim_id_update.src - @rm -f exim_id_update - @. ./version.sh && sed \ + $(FE)mv exipick-t exipick + $(FE)chmod a+x exipick + $(FE)./exipick -v 2>&1 >/dev/null +# $(FE)echo ">>> exipick script built" + +exim_id_update: $(UTIL_DEPS) ../src/utils/exim_id_update.src + $(FE)rm -f exim_id_update + $(FE). ./version.sh && sed \ -e "/^MSGID_RE/b mi" \ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ -e "s?SPOOL_DIRECTORY?$(SPOOL_DIRECTORY)?" \ @@ -517,21 +516,21 @@ exim_id_update: util_deps ../src/utils/exim_id_update.src -e "s?^?# Insert ?" \ -e "r ../src/utils/msgid.frag" \ ../src/utils/exim_id_update.src > exim_id_update-t - @mv exim_id_update-t exim_id_update - @chmod a+x exim_id_update - @./exim_id_update -v 2>&1 >/dev/null - @echo ">>> exim_id_update script built" - -transport-filter.pl: config ../src/transport-filter.src - @rm -f transport-filter.pl - @. ./version.sh && sed \ + $(FE)mv exim_id_update-t exim_id_update + $(FE)chmod a+x exim_id_update + $(FE)./exim_id_update -v 2>&1 >/dev/null +# $(FE)echo ">>> exim_id_update script built" + +transport-filter.pl: $(CONFIG_DEPS) ../src/transport-filter.src + $(FE)rm -f transport-filter.pl + $(FE). ./version.sh && sed \ -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \ -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \ -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \ ../src/transport-filter.src > transport-filter.pl-t - @mv transport-filter.pl-t transport-filter.pl - @chmod a+x transport-filter.pl - @echo ">>> transport-filter.pl script built" + $(FE)mv transport-filter.pl-t transport-filter.pl + $(FE)chmod a+x transport-filter.pl +# $(FE)echo ">>> transport-filter.pl script built" # These are objects of optional features. They are always compiled, but @@ -568,9 +567,8 @@ OBJ_EXIM = acl.o atrn.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o \ local_scan.o $(OBJ_WITH_CONTENT_SCAN) \ $(OBJ_EXPERIMENTAL) -exim: buildlookups buildauths \ - buildrouters buildtransports buildmisc \ - $(OBJ_EXIM) version.o +exim: buildlookups buildauths buildrouters buildtransports buildmisc \ + $(OBJ_EXIM) version.o @echo "$(LNCC) -o exim" $(FE)$(PURIFY) $(LNCC) -o exim $(LFLAGS) $(OBJ_EXIM) version.o \ routers/routers.a transports/transports.a lookups/lookups.a \ @@ -583,9 +581,9 @@ exim: buildlookups buildauths \ $(STRIP_COMMAND) exim; \ fi $(EXIM_CHMOD) - @echo " " - @echo ">>> exim binary built" - @echo " " +# @echo " " +# @echo ">>> exim binary built" +# @echo " " # The utility for dumping the contents of an exim database @@ -599,8 +597,8 @@ exim_dumpdb: $(OBJ_DUMPDB) echo $(STRIP_COMMAND) exim_dumpdb; \ $(STRIP_COMMAND) exim_dumpdb; \ fi - @echo ">>> exim_dumpdb utility built" - @echo " " +# @echo ">>> exim_dumpdb utility built" +# @echo " " # The utility for interrogating/fixing the contents of an exim database @@ -614,8 +612,8 @@ exim_fixdb: $(OBJ_FIXDB) echo $(STRIP_COMMAND) exim_fixdb; \ $(STRIP_COMMAND) exim_fixdb; \ fi - @echo ">>> exim_fixdb utility built" - @echo " " +# @echo ">>> exim_fixdb utility built" +# @echo " " # The utility for tidying the contents of an exim database @@ -630,8 +628,8 @@ exim_tidydb: $(OBJ_TIDYDB) echo $(STRIP_COMMAND) exim_tidydb; \ $(STRIP_COMMAND) exim_tidydb; \ fi - @echo ">>> exim_tidydb utility built" - @echo " " +# @echo ">>> exim_tidydb utility built" +# @echo " " # The utility for building dbm files @@ -646,8 +644,8 @@ exim_dbmbuild: $(OBJ_DBMBUILD) echo $(STRIP_COMMAND) exim_dbmbuild; \ $(STRIP_COMMAND) exim_dbmbuild; \ fi - @echo ">>> exim_dbmbuild utility built" - @echo " " +# @echo ">>> exim_dbmbuild utility built" +# @echo " " # The utility for locking a mailbox while messing around with it @@ -661,8 +659,8 @@ exim_lock: exim_lock.c os.h echo $(STRIP_COMMAND) exim_lock; \ $(STRIP_COMMAND) exim_lock; \ fi - @echo ">>> exim_lock utility built" - @echo " " +# @echo ">>> exim_lock utility built" +# @echo " " # The X-based Exim monitor program's binary part. There's a macro for cutting # out the modified TextPop module, because some antique link editors cannot @@ -701,8 +699,8 @@ eximon.bin: $(EXIMON_EDITME) eximon $(OBJ_MONBIN) ../exim_monitor/em_version.c \ echo $(STRIP_COMMAND) eximon.bin; \ $(STRIP_COMMAND) eximon.bin; \ fi - @echo ">>> exim monitor binary built" - @echo " " +# @echo ">>> exim monitor binary built" +# @echo " " # Compile step for most of the exim modules. HDRS is a list of headers @@ -861,7 +859,7 @@ util-os.o: $(HDRS) os.c # The local scan module depends only on its own special header, and is compiled # from a source whose location is set by configuration. -local_scan.o: config local_scan.h ../$(LOCAL_SCAN_SOURCE) +local_scan.o: $(CONFIG_DEPS) local_scan.h ../$(LOCAL_SCAN_SOURCE) @echo "$(CC) local_scan.c" $(FE)$(CC) -DLOCAL_SCAN -c $(CFLAGS) -I. $(INCLUDE) -o local_scan.o ../$(LOCAL_SCAN_SOURCE) @@ -1047,11 +1045,10 @@ $(MONBIN): $(HDRS) # Copies of modules built as dynamic-load libraries -dynmodules: buildlookups buildrouters buildtransports buildauths \ - buildmisc - rm -fr dynmodules - mkdir dynmodules - for d in lookup router transport auth miscmod; do \ +dynmodules: buildlookups buildrouters buildtransports buildauths buildmisc + $(FE)rm -fr dynmodules + $(FE)mkdir dynmodules + $(FE)for d in lookup router transport auth miscmod; do \ for f in $${d}s/*.so; do \ [ -e $$f ] && ln $$f dynmodules/`basename $$f .so`_$$d.so; \ done; \ @@ -1060,42 +1057,46 @@ dynmodules: buildlookups buildrouters buildtransports buildauths \ # The lookups library. -buildlookups: config - @cd lookups && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ +buildlookups: $(CONFIG_DEPS) + @cd lookups && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" HDRS="../version.h $(PHDRS)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE) $(LOOKUP_INCLUDE)" - @echo " " + $(FE)touch $@ +# @echo " " # The routers library. -buildrouters: config - @cd routers && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ +buildrouters: $(CONFIG_DEPS) + @cd routers && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - @echo " " + $(FE)touch $@ +# @echo " " # The transports library. -buildtransports: config - @cd transports && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ +buildtransports: $(CONFIG_DEPS) + @cd transports && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - @echo " " + $(FE)touch $@ +# @echo " " # The library of authorization modules -buildauths: config - @cd auths && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ +buildauths: $(CONFIG_DEPS) + @cd auths && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - @echo " " + $(FE)touch $@ +# @echo " " -buildmisc: config - @cd miscmods && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) \ +buildmisc: $(CONFIG_DEPS) + @cd miscmods && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) \ CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ LDFLAGS_PARTIAL="$(LDFLAGS_PARTIAL)" HDRS="../version.h $(PHDRS)" \ @@ -1103,7 +1104,8 @@ buildmisc: config PERL_CC="$(PERL_CC)" PERL_CCOPTS="$(PERL_CCOPTS)" \ PERL_CFLAGS="$(PERL_CFLAGS)" PERL_LFLAGS="$(PERL_LFLAGS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE)" TLS_INCLUDE="$(TLS_INCLUDE)" - @echo " " + $(FE)touch $@ +# @echo " " # The "clean", "install", and "makefile" targets just pass themselves back to # the main Exim makefile. These targets will be obeyed only if "make" is obeyed diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 73737274e..cf85d6306 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -38,15 +38,20 @@ rebuild=yes if [ -f Makefile ] ; then rebuild=no - if ../scripts/newer $editme Makefile || \ - ../scripts/newer $editme-$ostype Makefile || \ - ../scripts/newer $editme-$archtype Makefile || \ - ../scripts/newer $editme-$ostype-$archtype Makefile || \ - ../scripts/newer ../scripts/Configure-Makefile Makefile || \ - ../scripts/newer ../scripts/lookups-Makefile Makefile || \ - ../scripts/newer ../scripts/drivers-Makefile Makefile || \ - ../scripts/newer ../OS/Makefile-Base Makefile || \ - ../scripts/newer ../OS/Makefile-Default Makefile + if ../scripts/newer $editme Makefile \ + || ../scripts/newer $editme-$ostype Makefile \ + || ../scripts/newer $editme-$archtype Makefile \ + || ../scripts/newer $editme-$ostype-$archtype Makefile \ + || ../scripts/newer ../scripts/Configure-Makefile Makefile \ + || ../scripts/newer ../scripts/lookups-Makefile Makefile \ + || ../scripts/newer ../scripts/drivers-Makefile Makefile \ + || ../scripts/newer ../OS/Makefile-Base Makefile \ + || ../scripts/newer ../OS/Makefile-Default Makefile \ + || ../scripts/newer ../src/auths/Makefile Makefile \ + || ../scripts/newer ../src/lookups/Makefile Makefile \ + || ../scripts/newer ../src/miscmods/Makefile Makefile \ + || ../scripts/newer ../src/routers/Makefile Makefile \ + || ../scripts/newer ../src/transports/Makefile Makefile then rebuild=yes fi @@ -78,8 +83,8 @@ fi # If Makefile is up-to-date, no need to rebuild it. if [ $rebuild = no ] ; then - echo "\`Makefile' is up to date." - echo " " +# echo "\`Makefile' is up to date." +# echo " " exit fi diff --git a/src/src/auths/Makefile b/src/src/auths/Makefile index b929f6742..6eab96a66 100644 --- a/src/src/auths/Makefile +++ b/src/src/auths/Makefile @@ -17,6 +17,7 @@ OBJ += auth-spa.o all: auths.a $(MODS) + $(FE): auths.a: $(OBJ) @$(RM_COMMAND) -f auths.a diff --git a/src/src/lookups/Makefile b/src/src/lookups/Makefile index d794fe895..23347e83b 100644 --- a/src/src/lookups/Makefile +++ b/src/src/lookups/Makefile @@ -18,7 +18,8 @@ OBJS = $(OBJ) $(OBJ_ALWAYS) # This assumes that the driver and object-file names match AVAIL= $(OBJS:.o=) -all: Makefile lookups.a $(MODS) +all: Makefile lookups.a $(MODS) + $(FE): # We assume here that the driver name is used as the prefix for # its module_info struct. diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index 1e46d4456..cac4bd316 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -14,6 +14,7 @@ OBJ += dummy.o all: miscmods.a $(MODS) + $(FE): miscmods.a: $(OBJ) @$(RM_COMMAND) -f miscmods.a diff --git a/src/src/routers/Makefile b/src/src/routers/Makefile index 6c1dc6e9a..1b2953d40 100644 --- a/src/src/routers/Makefile +++ b/src/src/routers/Makefile @@ -12,7 +12,8 @@ # MAGIC-TAG-MODS-OBJ-RULES-GO-HERE -all: routers.a $(MODS) +all: routers.a $(MODS) + $(FE): routers.a: $(OBJ) @$(RM_COMMAND) -f routers.a diff --git a/src/src/transports/Makefile b/src/src/transports/Makefile index 454d36347..89cadc568 100644 --- a/src/src/transports/Makefile +++ b/src/src/transports/Makefile @@ -13,7 +13,8 @@ OBJ += smtp_socks.o tf_maildir.o -all: transports.a $(MODS) +all: transports.a $(MODS) + $(FE): transports.a: $(OBJ) smtp_socks.o tf_maildir.o @$(RM_COMMAND) -f transports.a commit 998636a4f8493855a351bb1080fc7687269cb9f9 Author: Jeremy Harris Date: Wed Nov 12 11:20:42 2025 +0000 library versions diff --git a/src/scripts/reversion b/src/scripts/reversion index 6fd0782a4..00b4058d3 100755 --- a/src/scripts/reversion +++ b/src/scripts/reversion @@ -122,9 +122,9 @@ then test -n "$EXIM_VARIANT_VERSION" && \ echo '#define EXIM_VARIANT_VERSION "'"$EXIM_VARIANT_VERSION"'"' echo '#ifdef EXIM_VARIANT_VERSION' - echo '#define EXIM_VERSION_STR EXIM_RELEASE_VERSION "-" EXIM_VARIANT_VERSION' + echo '# define EXIM_VERSION_STR EXIM_RELEASE_VERSION "-" EXIM_VARIANT_VERSION' echo '#else' - echo '#define EXIM_VERSION_STR EXIM_RELEASE_VERSION' + echo '# define EXIM_VERSION_STR EXIM_RELEASE_VERSION' echo '#endif' if [ ".${exim_build_date_override:-}" != "." ]; then echo '#define EXIM_BUILD_DATE_OVERRIDE "'"${exim_build_date_override}"'"' diff --git a/src/src/exim.c b/src/src/exim.c index 9d6f858bd..13cc4ff2c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1316,19 +1316,15 @@ Currently they are output in misc_mod_add() */ #ifndef PCRE_PRERELEASE # define PCRE_PRERELEASE #endif -#define QUOTE(X) #X -#define EXPAND_AND_QUOTE(X) QUOTE(X) { uschar buf[24]; pcre2_config(PCRE2_CONFIG_VERSION, buf); g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n" " Runtime: %s\n", PCRE2_MAJOR, PCRE2_MINOR, - EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "", + mac_expanded_string(PCRE2_PRERELEASE) "", buf); } -#undef QUOTE -#undef EXPAND_AND_QUOTE show_string(is_stdout, g); g = NULL; diff --git a/src/src/lookups/cdb.c b/src/src/lookups/cdb.c index b56306a7f..98ff462a3 100644 --- a/src/src/lookups/cdb.c +++ b/src/src/lookups/cdb.c @@ -462,10 +462,8 @@ if (cdbp->cdb_map) gstring * cdb_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: CDB: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: CDB: Exim %s builtin\n", + EXIM_VERSION_STR); } diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index d08f6122e..6e2be8ae1 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -591,10 +591,8 @@ return rc; gstring * dnsdb_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: DNSDB: Exim %s builtin\n", + EXIM_VERSION_STR); } diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c index 99e1c8648..4fb8f0c27 100644 --- a/src/src/lookups/dsearch.c +++ b/src/src/lookups/dsearch.c @@ -172,10 +172,8 @@ handle = handle; /* Avoid compiler warning */ gstring * dsearch_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: dsearch: Exim %s builtin\n", + EXIM_VERSION_STR); } diff --git a/src/src/lookups/json.c b/src/src/lookups/json.c index 43575cacf..3e5f9609e 100644 --- a/src/src/lookups/json.c +++ b/src/src/lookups/json.c @@ -162,7 +162,8 @@ json_close(void *handle) gstring * json_version_report(gstring * g) { -return string_fmt_append(g, "Library version: json: Jansonn version %s\n", JANSSON_VERSION); +return string_fmt_append(g, "Library version: json: Jansonn version %s\n", + JANSSON_VERSION); } diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index a6e99f567..c657797d9 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1563,11 +1563,29 @@ return quoted; gstring * ldap_version_report(gstring * g) { -#ifdef DYNLOOKUP -/*XXX it would be nice to haul a version string for the underlying ldap library */ -g = string_fmt_append(g, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR); -#endif +#ifdef LDAP_LIB_OPENLDAP2 +LDAP * ld = ldap_init("", 0); +LDAPAPIInfo info = {.ldapai_info_version = LDAP_API_INFO_VERSION}; + +g = string_fmt_append(g, "Library version: LDAP: Compile %s %u.%u.%u\n", + LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION_MAJOR, + LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH); + +if (ldap_get_option(ld, LDAP_OPT_API_INFO, &info) == LDAP_OPT_SUCCESS) + { + g = string_fmt_append(g, " Runtime %s %d\n", + info.ldapai_vendor_name, info.ldapai_vendor_version); + + for (char ** sp = info.ldapai_extensions; *sp; *sp++) + ldap_memfree(*sp); + ldap_memfree(info.ldapai_extensions); + ldap_memfree(info.ldapai_vendor_name); + } return g; + +#else +return string_fmt_append(g, "Library version: LDAP: (unknown)\n"); +#endif } diff --git a/src/src/lookups/lmdb.c b/src/src/lookups/lmdb.c index 3a3eebcba..c90632cee 100644 --- a/src/src/lookups/lmdb.c +++ b/src/src/lookups/lmdb.c @@ -134,10 +134,9 @@ gstring * lmdb_version_report(gstring * g) { g = string_fmt_append(g, "Library version: LMDB: Compile: %d.%d.%d\n", - MDB_VERSION_MAJOR, MDB_VERSION_MINOR, MDB_VERSION_PATCH); -#ifdef DYNLOOKUP -g = string_fmt_append(g, " Exim version %s\n", EXIM_VERSION_STR); -#endif + MDB_VERSION_MAJOR, MDB_VERSION_MINOR, MDB_VERSION_PATCH); +g = string_fmt_append(g, " Runtime: %s\n", + mdb_version(NULL, NULL, NULL)); return g; } diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c index 89a9e6c80..fc7ebaf62 100644 --- a/src/src/lookups/lsearch.c +++ b/src/src/lookups/lsearch.c @@ -418,10 +418,8 @@ lsearch_close(void *handle) gstring * lsearch_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: lsearch: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: lsearch: Exim %s builtin\n", + EXIM_VERSION_STR); } diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c index bbf98cb0c..76954ca43 100644 --- a/src/src/lookups/mysql.c +++ b/src/src/lookups/mysql.c @@ -475,12 +475,8 @@ mysql_version_report(gstring * g) g = string_fmt_append(g, "Library version: MySQL: Compile: %lu %s [%s]\n" " Runtime: %lu %s\n", - (long)EXIM_MxSQL_VERSION_ID, EXIM_MxSQL_VERSION_STR, EXIM_MxSQL_BASE_STR, - mysql_get_client_version(), mysql_get_client_info()); -#ifdef DYNLOOKUP -g = string_fmt_append(g, - " Exim version %s\n", EXIM_VERSION_STR); -#endif + (long)EXIM_MxSQL_VERSION_ID, EXIM_MxSQL_VERSION_STR, EXIM_MxSQL_BASE_STR, + mysql_get_client_version(), mysql_get_client_info()); return g; } diff --git a/src/src/lookups/nis.c b/src/src/lookups/nis.c index aa12f4742..77f6b0f68 100644 --- a/src/src/lookups/nis.c +++ b/src/src/lookups/nis.c @@ -101,6 +101,7 @@ return (rc == YPERR_KEY || rc == YPERR_MAP)? FAIL : DEFER; gstring * nis_version_report(gstring * g) { +/* maybe part of glibc? */ #ifdef DYNLOOKUP g = string_fmt_append(g, "Library version: NIS: Exim version %s\n", EXIM_VERSION_STR); #endif diff --git a/src/src/lookups/nmh.c b/src/src/lookups/nmh.c index c2fd0e61c..0e93186c1 100644 --- a/src/src/lookups/nmh.c +++ b/src/src/lookups/nmh.c @@ -347,6 +347,7 @@ while ((cn = nmh_connections)) gstring * nmh_version_report(gstring * g) { +/* NMH has no version api! */ #ifdef DYNLOOKUP g = string_fmt_append(g, "Library version: NMH: Exim version %s\n", EXIM_VERSION_STR); #endif diff --git a/src/src/lookups/passwd.c b/src/src/lookups/passwd.c index 7bf499920..c22c2d4cc 100644 --- a/src/src/lookups/passwd.c +++ b/src/src/lookups/passwd.c @@ -58,10 +58,8 @@ return OK; gstring * passwd_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: passwd: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: passwd: Exim %s builtin\n", + EXIM_VERSION_STR); } static lookup_info _lookup_info = { diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c index a578645ff..8ddf0e058 100644 --- a/src/src/lookups/pgsql.c +++ b/src/src/lookups/pgsql.c @@ -477,9 +477,7 @@ return quoted; gstring * pgsql_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: PostgreSQL: Exim version %s\n", EXIM_VERSION_STR); -#endif +int ver = PQlibVersion(); /* Version reporting: there appears to be no available information about the client library in libpq-fe.h; once you have a connection object, you @@ -487,6 +485,9 @@ can access the server version and the chosen protocol version, but those aren't really what we want. It might make sense to debug_printf those when the connection is established though? */ +/* version 9.1 onwards */ +g = string_fmt_append(g, "Library version: PostgreSQL: Runtime: %d.%d\n", + ver/10000, ver%10000); return g; } diff --git a/src/src/lookups/psl.c b/src/src/lookups/psl.c index 1592fe32d..9171192a3 100644 --- a/src/src/lookups/psl.c +++ b/src/src/lookups/psl.c @@ -212,10 +212,8 @@ return psl_gen_find(handle, keystring, length, result, errmsg, TRUE); gstring * psl_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: psl: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: psl: Exim %s builtin\n", + EXIM_VERSION_STR); } static lookup_info psl_lookup_info = { diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index 4b11475d0..a721d0605 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -433,13 +433,8 @@ return quoted; gstring * redis_version_report(gstring * g) { -g = string_fmt_append(g, - "Library version: REDIS: Compile: %d [%d]\n", HIREDIS_MAJOR, HIREDIS_MINOR); -#ifdef DYNLOOKUP -g = string_fmt_append(g, - " Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: REDIS: Compile: %d.%d.%d\n", + HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH); } diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index e1931ca0f..ce314f7e5 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -86,10 +86,11 @@ return FAIL; gstring * spf_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: SPF: Exim version %s\n", EXIM_VERSION_STR)); -#endif -return g; +int maj, min, patch; + +SPF_get_lib_version(&maj, &min, &patch); +return string_fmt_append(g, "Library version: SPF: Runtime: %d.%d.%d\n", + maj, min, patch); } diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index 722916cf3..e358c9f84 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -172,10 +172,6 @@ g = string_fmt_append(g, "Library version: SQLite: Compile: %s\n" " Runtime: %s\n", SQLITE_VERSION, sqlite3_libversion()); -#ifdef DYNLOOKUP -g = string_fmt_append(g, - " Exim version %s\n", EXIM_VERSION_STR); -#endif return g; } diff --git a/src/src/lookups/testdb.c b/src/src/lookups/testdb.c index 44d77b8c8..2e3ed36c2 100644 --- a/src/src/lookups/testdb.c +++ b/src/src/lookups/testdb.c @@ -83,10 +83,8 @@ return quoted; gstring * testdb_version_report(gstring * g) { -#ifdef DYNLOOKUP -g = string_fmt_append(g, "Library version: TestDB: Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; +return string_fmt_append(g, "Library version: TestDB: Exim version %s\n", + EXIM_VERSION_STR); } diff --git a/src/src/lookups/whoson.c b/src/src/lookups/whoson.c index cd6c7e85c..f783a905a 100644 --- a/src/src/lookups/whoson.c +++ b/src/src/lookups/whoson.c @@ -68,13 +68,8 @@ switch (wso_query(CS query, CS buffer, sizeof(buffer))) gstring * whoson_version_report(gstring * g) { -g = string_fmt_append(g, +return string_fmt_append(g, "Library version: Whoson: Runtime: %s\n", wso_version()); -#ifdef DYNLOOKUP -g = string_fmt_append(g, - " Exim version %s\n", EXIM_VERSION_STR); -#endif -return g; } static lookup_info _lookup_info = { diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index d491ae64e..e7bc1e331 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -121,16 +121,14 @@ return g; /******************************************************************************/ -#ifdef notdef /*API*/ static gstring * spf_lib_version_report(gstring * g) { /*XXX Does Mail::SPF have a version? MetaCPAN says yes, but does not document a method that returns it. */ -return g; +return string_fmt_append(g, "Library_version: SPF: perl Mail::SPF\n"); } -#endif @@ -389,7 +387,7 @@ misc_module_info spf_module_info = # ifdef DYNLOOKUP .dyn_magic = MISC_MODULE_MAGIC, # endif - /* .lib_vers_report = spf_lib_version_report, */ + .lib_vers_report = spf_lib_version_report, .conn_init = spf_conn_init, .smtp_reset = spf_smtp_reset, .authres = authres_spf, commit ed97fea3e920289ac87f1736146c68f4ce3050a8 Author: Jeremy Harris Date: Wed Nov 12 14:37:42 2025 +0000 Fix non-openldap2 build Broken-by: 998636a4f849 diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index c657797d9..7d240309c 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1584,7 +1584,7 @@ if (ldap_get_option(ld, LDAP_OPT_API_INFO, &info) == LDAP_OPT_SUCCESS) return g; #else -return string_fmt_append(g, "Library version: LDAP: (unknown)\n"); +return string_cat(g, "Library version: LDAP: (unknown)\n"); #endif } commit 86161af9d94e2beeb7ad630e80247ef791c22313 Author: Jeremy Harris Date: Wed Nov 12 21:40:04 2025 +0000 Experimental native DMARC Bug 3140 diff --git a/src/Makefile b/src/Makefile index a19c6928a..eac96323e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -124,7 +124,7 @@ distclean: clean_doc cscope.files: FRC echo "-q" > $@ echo "-p3" >> $@ - -bd=build-$(buildname); [ -d $$bd ] && echo -e "$$bd/config.h\n$$bd/Makefile" >> $@ + -bd=build-$(buildname); [ -d $$bd ] && echo -e "$$bd/config.h\n$$bd/version.h\n$$bd/Makefile" >> $@ find src Local OS exim_monitor -name "*.[cshyl]" -print \ -o -name "*.src" -print \ -o -name "os.[ch]*" -print \ diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 80f1f1f97..f713ad3ca 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -1062,7 +1062,6 @@ buildlookups: $(CONFIG_DEPS) CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" HDRS="../version.h $(PHDRS)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE) $(LOOKUP_INCLUDE)" - $(FE)touch $@ # @echo " " # The routers library. @@ -1072,7 +1071,6 @@ buildrouters: $(CONFIG_DEPS) CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - $(FE)touch $@ # @echo " " # The transports library. @@ -1082,17 +1080,15 @@ buildtransports: $(CONFIG_DEPS) CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - $(FE)touch $@ # @echo " " -# The library of authorization modules +# The library of authentication modules buildauths: $(CONFIG_DEPS) @cd auths && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \ FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)" - $(FE)touch $@ # @echo " " buildmisc: $(CONFIG_DEPS) @@ -1104,7 +1100,6 @@ buildmisc: $(CONFIG_DEPS) PERL_CC="$(PERL_CC)" PERL_CCOPTS="$(PERL_CCOPTS)" \ PERL_CFLAGS="$(PERL_CFLAGS)" PERL_LFLAGS="$(PERL_LFLAGS)" \ INCLUDE="$(INCLUDE) $(IPV6_INCLUDE)" TLS_INCLUDE="$(TLS_INCLUDE)" - $(FE)touch $@ # @echo " " # The "clean", "install", and "makefile" targets just pass themselves back to diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index cf85d6306..70dc886ab 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -326,7 +326,7 @@ done <<-END routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS - miscmods SUPPORT ARC _DKIM DMARC _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SPF SPF_PERL + miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SPF SPF_PERL END # See if there is a definition of EXIM_PERL in what we have built so far. diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 4e4a638c7..517310c8a 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -101,7 +101,7 @@ for f in dummy.c \ dkim.c dkim_transport.c dkim.h dkim_api.h \ pdkim/crypt_ver.h pdkim/pdkim.c pdkim/pdkim.h \ pdkim/pdkim_hash.h pdkim/signing.c pdkim/signing.h \ - dmarc.c dmarc.h dmarc_api.h \ + dmarc.c dmarc_common.c dmarc.h dmarc_api.h dmarc_native.c \ exim_filter.c exim_filter_api.h \ pam.c pam_api.h \ perl.c perl_api.h \ diff --git a/src/src/acl.c b/src/src/acl.c index 7d07ab698..be61fc953 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -77,7 +77,7 @@ enum { ACLC_ACL, ACLC_DKIM_SIGNER, ACLC_DKIM_STATUS, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC ACLC_DMARC_STATUS, #endif ACLC_DNSLISTS, @@ -206,9 +206,9 @@ static condition_def conditions[] = { ), }, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC [ACLC_DMARC_STATUS] = { US"dmarc_status", -# if SUPPORT_DMARC==2 +# if EXIM_HAVE_DMARC==2 ACD_LOAD | # endif ACD_EXP, @@ -390,7 +390,7 @@ static int spf_condx[] = { ACLC_SPF, ACLC_SPF_GUESS, -1 }; # if SUPPORT_DKIM==2 static int dkim_condx[] = { ACLC_DKIM_SIGNER, ACLC_DKIM_STATUS, -1 }; # endif -# if SUPPORT_DMARC==2 +# if EXIM_HAVE_DMARC==2 static int dmarc_condx[] = { ACLC_DMARC_STATUS, -1 }; # endif @@ -404,7 +404,7 @@ static condition_module condition_modules[] = { # if SUPPORT_DKIM==2 {.mod_name = US"dkim", .conditions = dkim_condx}, # endif -# if SUPPORT_DMARC==2 +# if EXIM_HAVE_DMARC==2 {.mod_name = US"dmarc", .conditions = dmarc_condx}, # endif }; @@ -424,7 +424,7 @@ enum { #ifndef DISABLE_DKIM CONTROL_DKIM_VERIFY, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC CONTROL_DMARC_VERIFY, CONTROL_DMARC_FORENSIC, #endif @@ -492,7 +492,7 @@ static control_def controls_list[] = { }, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC [CONTROL_DMARC_VERIFY] = { US"dmarc_disable_verify", FALSE, ACL_BIT_DATA | ACL_BIT_NOTSMTP | ACL_BIT_NOTSMTP_START @@ -3481,7 +3481,7 @@ for (; cb; cb = cb->next) #ifndef DISABLE_DKIM case CONTROL_DKIM_VERIFY: f.dkim_disable_verify = TRUE; -# ifdef SUPPORT_DMARC +# ifdef EXIM_HAVE_DMARC /* Since DKIM was blocked, skip DMARC too */ f.dmarc_disable_verify = TRUE; f.dmarc_enable_forensic = FALSE; @@ -3489,7 +3489,7 @@ for (; cb; cb = cb->next) break; #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC case CONTROL_DMARC_VERIFY: f.dmarc_disable_verify = TRUE; break; @@ -3934,7 +3934,7 @@ for (; cb; cb = cb->next) } #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC case ACLC_DMARC_STATUS: /* See comment on ACLC_SPF wrt. coding issues */ { @@ -3945,7 +3945,7 @@ for (; cb; cb = cb->next) if (!mi) { rc = DEFER; break; } /* shouldn't happen */ - if (!f.dmarc_has_been_checked) + if (!f.dmarc_has_been_checked) /* only once per message */ { typedef int (*pfn_t)(void); (void) (((pfn_t *) mi->functions)[DMARC_PROCESS]) (); @@ -3955,7 +3955,6 @@ for (; cb; cb = cb->next) /* used long way of dmarc_exim_expand_query() in case we need more view into the process in the future. */ - /*XXX is this call used with any other arg? */ expanded_query = (((efn_t *) mi->functions)[DMARC_EXPAND_QUERY]) (); rc = match_isinlist(expanded_query, &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index f331ad0d5..71146ae3b 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -217,6 +217,7 @@ Do not put spaces between # and the 'define'. /* EXPERIMENTAL features */ #define EXPERIMENTAL_ARC #define EXPERIMENTAL_DCC +#define EXPERIMENTAL_DMARC_NATIVE #define EXPERIMENTAL_DSN_INFO #define EXPERIMENTAL_NMH #define EXPERIMENTAL_QUEUEFILE diff --git a/src/src/drtables.c b/src/src/drtables.c index 5993b5c29..9e25472d3 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -481,7 +481,7 @@ built as static */ #if !defined(DISABLE_DKIM) && (!defined(SUPPORT_DKIM) || SUPPORT_DKIM!=2) extern misc_module_info dkim_module_info; #endif -#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2 +#if defined(EXIM_HAVE_DMARC) && EXIM_HAVE_DMARC!=2 extern misc_module_info dmarc_module_info; #endif #if defined(EXIM_HAVE_SPF) && EXIM_HAVE_SPF!=2 @@ -519,13 +519,13 @@ onetime = TRUE; #if defined(EXIM_HAVE_SPF) && EXIM_HAVE_SPF!=2 misc_mod_add(&spf_module_info); #endif -#if defined(SUPPORT_DMARC) && SUPPORT_DMARC!=2 -/* dmarc depends on spf so this add must go after, for the both-static case */ - misc_mod_add(&dmarc_module_info); -#endif #if defined(EXPERIMENTAL_ARC) && (!defined(SUPPORT_ARC) || SUPPORT_ARC!=2) misc_mod_add(&arc_module_info); #endif +#if defined(EXIM_HAVE_DMARC) && EXIM_HAVE_DMARC!=2 +/* dmarc depends on spf/dkim/arc so this add must go after, for the both-static case */ + misc_mod_add(&dmarc_module_info); +#endif #if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) misc_mod_add(&radius_module_info); #endif diff --git a/src/src/exim.c b/src/src/exim.c index 13cc4ff2c..c23eb868c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1176,7 +1176,7 @@ g = string_cat(g, US"Support for:"); #ifndef DISABLE_DKIM g = string_cat(g, US" DKIM"); #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC g = string_cat(g, US" DMARC"); #endif #ifndef DISABLE_DNSSEC diff --git a/src/src/exim.h b/src/src/exim.h index 18d1b1f40..538f354e2 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -535,8 +535,6 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY) # include "hash.h" #endif -#include "globals.h" -#include "functions.h" #if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY) # include "dbfunctions.h" #endif @@ -550,10 +548,12 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. # include "miscmods/dkim.h" # include "miscmods/dkim_api.h" #endif -#ifdef SUPPORT_DMARC +#if defined(SUPPORT_DMARC) || defined(EXPERIMENTAL_DMARC_NATIVE) # include "miscmods/dmarc.h" # include "miscmods/dmarc_api.h" -# include +# ifdef SUPPORT_DMARC +# include +# endif #endif #ifdef EXPERIMENTAL_ARC # include "miscmods/arc_api.h" @@ -570,6 +570,9 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #include "miscmods/exim_filter_api.h" #include "miscmods/sieve_filter_api.h" +#include "globals.h" +#include "functions.h" + /* The following stuff must follow the inclusion of config.h because it requires various things that are set therein. */ diff --git a/src/src/expand.c b/src/src/expand.c index fcf699d2e..1b5980f5b 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -514,7 +514,7 @@ static var_entry var_table[] = { { "dkim_verify_signers", vtype_module, US"dkim" }, { "dkim_verify_status", vtype_module, US"dkim" }, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC { "dmarc_alignment_dkim",vtype_module, US"dmarc" }, { "dmarc_alignment_spf", vtype_module, US"dmarc" }, { "dmarc_domain_policy", vtype_module, US"dmarc" }, diff --git a/src/src/globals.c b/src/src/globals.c index c8636e191..36f364996 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -251,7 +251,7 @@ struct global_flags f = .dkim_disable_verify = FALSE, .dkim_init_done = FALSE, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC .dmarc_has_been_checked = FALSE, .dmarc_disable_verify = FALSE, .dmarc_enable_forensic = FALSE, diff --git a/src/src/globals.h b/src/src/globals.h index ddf78b4d8..9f4d04a2d 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -221,7 +221,7 @@ extern struct global_flags { BOOL dkim_disable_verify :1; /* Set via ACL control statement. When set, DKIM verification is disabled for the current message */ BOOL dkim_init_done :1; /* lazy-init status */ #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC BOOL dmarc_has_been_checked :1; /* Global variable to check if test has been called yet */ BOOL dmarc_disable_verify :1; /* Set via ACL control statement. When set, DMARC verification is disabled for the current message */ BOOL dmarc_enable_forensic :1; /* Set via ACL control statement. When set, DMARC forensic reports are enabled for the current message */ diff --git a/src/src/log.c b/src/src/log.c index c485fc285..41f91a1ad 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -260,9 +260,6 @@ subprocess when the original process is root. Arguments: name the file name -The file name has been build in a working buffer, so it is permissible to -overwrite it temporarily if it is necessary to create the directory. - Returns: a file descriptor, or < 0 on failure (errno set) */ @@ -286,15 +283,14 @@ problem. */ if (fd < 0 && errno == ENOENT) { BOOL created; - uschar *lastslash = Ustrrchr(name, '/'); - *lastslash = 0; - created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE); + const uschar * lastslash = Ustrrchr(name, '/'); + uschar * dirname = string_copyn(name, lastslash - name); + created = directory_make(NULL, dirname, LOG_DIRECTORY_MODE, FALSE); DEBUG(D_any) if (created) - debug_printf("created log directory %s\n", name); + debug_printf("created log directory %s\n", dirname); else - debug_printf("failed to create log directory %s: %s\n", name, strerror(errno)); - *lastslash = '/'; + debug_printf("failed to create log directory %s: %s\n", dirname, strerror(errno)); if (created) fd = Uopen(name, flags, LOG_MODE); } diff --git a/src/src/lookups/testdb.c b/src/src/lookups/testdb.c index 2e3ed36c2..7745bd193 100644 --- a/src/src/lookups/testdb.c +++ b/src/src/lookups/testdb.c @@ -109,7 +109,7 @@ static lookup_info testdb2_lookup_info = { .close = NULL, /* no close function */ .tidy = NULL, /* no tidy function */ .quote = testdb_quote, /* same quoting function */ - .version_report = testdb_version_report /* version reporting */ + .version_report = NULL /* version reporting */ }; static lookup_info testdb3_lookup_info = { @@ -121,7 +121,7 @@ static lookup_info testdb3_lookup_info = { .close = NULL, /* no close function */ .tidy = NULL, /* no tidy function */ .quote = NULL, /* NO quoting function */ - .version_report = testdb_version_report /* version reporting */ + .version_report = NULL /* version reporting */ }; #ifdef DYNLOOKUP diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index 79cbd5290..a8ebc40d4 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -158,7 +158,7 @@ due to conflicts with other common macros. */ #ifndef DISABLE_DKIM builtin_macro_create(US"_HAVE_DKIM"); #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC builtin_macro_create(US"_HAVE_DMARC"); #endif #ifndef DISABLE_DNSSEC diff --git a/src/src/macros.h b/src/src/macros.h index 75563d86b..c0900eee9 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -240,10 +240,8 @@ enum { ERRMESS_TOOBIG, /* Message too big */ ERRMESS_TOOMANYRECIP, /* Too many recipients */ ERRMESS_LOCAL_SCAN, /* Rejected by local scan */ - ERRMESS_LOCAL_ACL /* Rejected by non-SMTP ACL */ -#ifdef SUPPORT_DMARC - ,ERRMESS_DMARC_FORENSIC /* DMARC Forensic Report */ -#endif + ERRMESS_LOCAL_ACL, /* Rejected by non-SMTP ACL */ + ERRMESS_DMARC_FORENSIC /* DMARC Forensic Report */ }; /* Error handling styles - set by option, and apply only when receiving diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index cac4bd316..e92c34941 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -37,7 +37,10 @@ arc.o arc.so: $(HDRS) pdkim.h arc.c dkim.o dkim.so: $(HDRS) dkim.h dkim.c dkim_transport.c \ crypt_ver.h pdkim.h pdkim_hash.h pdkim.c \ signing.h signing.c -dmarc.o dmarc.so: $(HDRS) spf.h pdkim.h dmarc.h dmarc.c +dmarc.o dmarc.so: $(HDRS) spf.h pdkim.h dmarc.h \ + dmarc.c dmarc_common.c +dmarc_native.o dmarc_native.so: $(HDRS) spf.h pdkim.h dmarc.h \ + dmarc_native.c dmarc_common.c dummy.o: dummy.c exim_filter.o exim_filter.so: $(HDRS) exim_filter.c pam.o pam.so: $(HDRS) pam.c @@ -52,10 +55,6 @@ spf_perl.o spf_perl.so: $(HDRS) spf.h spf_perl.c # We need a single .o because that's what scripts/Configure-Makefile # understands and fills in to $(OBJ). # Try desparately to get the Solaris cc/ld to build one. -#dkim.o: -# @echo "$(CC) dkim.c dkim_transport.c pdkim.c signing.c" -# $(FE)$(CC) -r $(LDFLAGS_PARTIAL) -o $@ $(CFLAGS) $(INCLUDE) \ -# dkim.c dkim_transport.c pdkim.c signing.c dkim.o: @echo "$(CC) dkim.c dkim_transport.c pdkim.c signing.c" $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) dkim.c @@ -86,6 +85,22 @@ spf_perl.so: -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) \ $(DLFLAGS) spf_perl.c -o spf.so +# DMARC +dmarc.o dmarc_native.o: + @echo "$(CC) $*.c dmarc_common.c" + $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c + $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) dmarc_common.c + $(FE)mv $@ dmarc_tmp.o + $(FE)ld -r -o $@ $(LDFLAGS_PARTIAL) dmarc_tmp.o dmarc_common.o + +# dmarc_native is special in the same way as spf_perl +dmarc.so dmarc_native.so: + @echo "$(CC) -shared $*.c dmarc_common.c" + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) -o dmarc.so \ + $(SUPPORT_$*_INCLUDE) $(SUPPORT_$*_LIBS) \ + $(CFLAGS) $(INCLUDE) $(TLS_INCLUDE) $(DLFLAGS) \ + $*.c dmarc_common.c + # Compile instructions for static perl.o for when EXIM_PERL is set # Dynamic is managed all via scripts/Configure-Makefile diff --git a/src/src/miscmods/arc.c b/src/src/miscmods/arc.c index 4767d45bf..cdd746547 100644 --- a/src/src/miscmods/arc.c +++ b/src/src/miscmods/arc.c @@ -2090,7 +2090,7 @@ return g; } -# ifdef SUPPORT_DMARC +# ifdef EXIM_HAVE_DMARC /* Module API: obtain ARC info for DMARC history. Arguments: @@ -2144,7 +2144,7 @@ static void * arc_functions[] = { [ARC_STATE_IS_PASS] = (void *) arc_is_pass, [ARC_SIGN_INIT] = (void *) arc_sign_init, [ARC_SIGN] = (void *) arc_sign, -# ifdef SUPPORT_DMARC +# ifdef EXIM_HAVE_DMARC [ARC_ARCSET_INFO] = (void *) arc_arcset_string, # endif }; diff --git a/src/src/miscmods/dkim.c b/src/src/miscmods/dkim.c index 4a2c50516..ccb649ca1 100644 --- a/src/src/miscmods/dkim.c +++ b/src/src/miscmods/dkim.c @@ -1137,7 +1137,7 @@ expand_bad: -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC /* Module API */ @@ -1331,7 +1331,7 @@ static void * dkim_functions[] = { [DKIM_TRANSPORT_INIT] = (void *) dkim_exim_sign_init, [DKIM_TRANSPORT_WRITE] = (void *) dkim_transport_write_message, -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC [DKIM_SIGS_LIST] = (void *) dkim_sigs_list, #endif #ifdef EXPERIMENTAL_ARC diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index 185ef9f4f..be5d68c3a 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -26,21 +26,13 @@ # include "dmarc.h" # include "pdkim.h" +extern void dmarc_send_forensic_report(const uschar **); +extern uschar * dmarc_dns_lookup(const uschar *); +extern void dmarc_write_history_file(const gstring *); + OPENDMARC_LIB_T dmarc_ctx; -DMARC_POLICY_T *dmarc_pctx = NULL; -OPENDMARC_STATUS_T libdm_status, action, dmarc_policy; -OPENDMARC_STATUS_T da, sa, action; -BOOL dmarc_abort = FALSE; -uschar *dmarc_pass_fail = US"skipped"; -header_line *from_header = NULL; - -static misc_module_info * dmarc_dkim_mod_info; -static misc_module_info * dmarc_spf_mod_info; -int dmarc_spf_ares_result = ARES_RESULT_UNDEFINED; -uschar *spf_sender_domain = NULL; -uschar *spf_human_readable = NULL; -u_char *header_from_sender = NULL; -int history_file_status = DMARC_HIST_OK; +DMARC_POLICY_T *dmarc_pctx; +OPENDMARC_STATUS_T libdm_status; typedef struct dmarc_exim_p { uschar *name; @@ -58,41 +50,24 @@ static dmarc_exim_p dmarc_policy_description[] = { /* $variables */ -BOOL dmarc_alignment_dkim = FALSE; /* Subtest result */ -BOOL dmarc_alignment_spf = FALSE; /* Subtest result */ -const uschar * dmarc_domain_policy = NULL; /* Declared policy of used domain */ -const uschar * dmarc_status; /* One word value */ -const uschar * dmarc_status_text = NULL; /* Human readable value */ -uschar * dmarc_used_domain; /* Domain libopendmarc chose for DMARC policy lookup */ +extern BOOL dmarc_alignment_dkim; /* Subtest result */ +extern BOOL dmarc_alignment_spf; /* Subtest result */ +extern const uschar * dmarc_domain_policy; /* Declared policy of used domain */ +extern const uschar * dmarc_status; /* One word value */ +extern const uschar * dmarc_status_text; /* Human readable value */ +extern uschar * dmarc_used_domain; /* options */ -uschar * dmarc_forensic_sender = NULL; /* Set sender address for forensic reports */ -uschar * dmarc_history_file = NULL; /* File to store dmarc results */ -uschar * dmarc_tld_file = NULL; /* Mozilla TLDs text file */ - +extern uschar * dmarc_forensic_sender; /* Set sender address for forensic reports */ +extern uschar * dmarc_history_file; /* File to store dmarc results */ +extern uschar * dmarc_tld_file; /* Mozilla TLDs text file */ -/* One-time initialisation for dmarc. Ensure the spf module is available. */ - -static BOOL -dmarc_init(void * dummy) -{ -uschar * errstr; -if (!(dmarc_spf_mod_info = misc_mod_find(US"spf", &errstr))) - { - log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); - return FALSE; - } -if (!(dmarc_dkim_mod_info = misc_mod_find(US"dkim", &errstr))) - { - log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); - return FALSE; - } +void +dmarc_local_init(void) +{} -return TRUE; -} - -static gstring * +gstring * dmarc_version_report(gstring * g) { return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n", @@ -103,58 +78,10 @@ return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n", } -/* Accept an error_block struct, initialize if empty, parse to the -end, and append the two strings passed to it. Used for adding -variable amounts of value:pair data to the forensic emails. */ - -static error_block * -add_to_eblock(error_block * eblock, const uschar * t1, const uschar * t2) +void +dmarc_local_msg_init(void) { -error_block * eb = store_malloc(sizeof(error_block)); -if (!eblock) - eblock = eb; -else - { - /* Find the end of the eblock struct and point it at eb */ - error_block *tmp = eblock; - while(tmp->next) - tmp = tmp->next; - tmp->next = eb; - } -eb->text1 = t1; -eb->text2 = t2; -eb->next = NULL; -return eblock; -} - -/* dmarc_msg_init sets up a context that can be re-used for several -messages on the same SMTP connection (that come from the -same host with the same HELO string). -However, we seem to only use it for one; we destroy some sort of context -at the tail end of dmarc_process(). */ - -static int -dmarc_msg_init() -{ -int *netmask = NULL; /* Ignored */ -uschar * s; - -/* Set some sane defaults. Also clears previous results when -multiple messages in one connection. */ - dmarc_pctx = NULL; -dmarc_status = US"none"; -dmarc_abort = FALSE; -dmarc_pass_fail = US"skipped"; -dmarc_used_domain = US""; -f.dmarc_has_been_checked = FALSE; -header_from_sender = NULL; -spf_sender_domain = NULL; -spf_human_readable = NULL; - -/* ACLs have "control=dmarc_disable_verify" */ -if (f.dmarc_disable_verify) - return OK; (void) memset(&dmarc_ctx, '\0', sizeof dmarc_ctx); dmarc_ctx.nscount = 0; @@ -165,27 +92,17 @@ if (libdm_status != DMARC_PARSE_OKAY) opendmarc_policy_status_to_str(libdm_status)); dmarc_abort = TRUE; } -GET_OPTION("dmarc_tld_file"); -if (!(s = dmarc_tld_file) || !(s = expand_string(s)) || !*s) - { - DEBUG(D_receive) debug_printf_indent("DMARC: no dmarc_tld_file\n"); - dmarc_abort = TRUE; - } else if (opendmarc_tld_read_file(CS dmarc_tld_file, NULL, NULL, NULL)) { log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to load tld list '%s': %s", dmarc_tld_file, strerror(errno)); dmarc_abort = TRUE; } -if (!sender_host_address) - { - DEBUG(D_receive) debug_printf_indent("DMARC: no sender_host_address\n"); - dmarc_abort = TRUE; - } + /* This catches locally originated email and startup errors above. */ if (!dmarc_abort) { - int is_ipv6 = string_is_ip_address(sender_host_address, netmask) == 6; + int is_ipv6 = string_is_ip_address(sender_host_address, NULL) == 6; if (!(dmarc_pctx = opendmarc_policy_connect_init(sender_host_address, is_ipv6))) { log_write(0, LOG_MAIN|LOG_PANIC, @@ -193,244 +110,39 @@ if (!dmarc_abort) dmarc_abort = TRUE; } } - -return OK; -} - - -static void -dmarc_smtp_reset(void) -{ -f.dmarc_has_been_checked = f.dmarc_disable_verify = -f.dmarc_enable_forensic = FALSE; -dmarc_domain_policy = dmarc_status = dmarc_status_text = -dmarc_used_domain = NULL; -} - - -/* dmarc_store_data stores the header data so that subsequent dmarc_process can -access the data. -Called after the entire message has been received, with the From: header. */ - -static int -dmarc_store_data(header_line * hdr) -{ -/* No debug output because would change every test debug output */ -if (!f.dmarc_disable_verify) - from_header = hdr; -return OK; } static void -dmarc_send_forensic_report(u_char ** ruf) +dmarc_local_send_forensic_report(u_char ** ruf) { -uschar * recipient; -error_block * eblock = NULL; -FILE *message_file = NULL; - /* Earlier ACL does not have *required* control=dmarc_enable_forensic */ if (!f.dmarc_enable_forensic) return; -if ( dmarc_policy == DMARC_POLICY_REJECT && action == DMARC_RESULT_REJECT - || dmarc_policy == DMARC_POLICY_QUARANTINE && action == DMARC_RESULT_QUARANTINE - || dmarc_policy == DMARC_POLICY_NONE && action == DMARC_RESULT_REJECT - || dmarc_policy == DMARC_POLICY_NONE && action == DMARC_RESULT_QUARANTINE +if ( dmarc_policy == DMARC_POLICY_REJECT + && dmarc_action == DMARC_RESULT_REJECT + || dmarc_policy == DMARC_POLICY_QUARANTINE + && dmarc_action == DMARC_RESULT_QUARANTINE + || dmarc_policy == DMARC_POLICY_NONE + && dmarc_action == DMARC_RESULT_REJECT + || dmarc_policy == DMARC_POLICY_NONE + && dmarc_action == DMARC_RESULT_QUARANTINE ) if (ruf) - { - eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_used_domain); - eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address); - eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full)); - eblock = add_to_eblock(eblock, US"SPF Alignment", - sa == DMARC_POLICY_SPF_ALIGNMENT_PASS ? US"yes" : US"no"); - eblock = add_to_eblock(eblock, US"DKIM Alignment", - da == DMARC_POLICY_DKIM_ALIGNMENT_PASS ? US"yes" : US"no"); - eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text); - - for (int c = 0; ruf[c]; c++) - { - recipient = string_copylc(ruf[c]); - if (Ustrncmp(recipient, "mailto:",7)) - continue; - /* Move to first character past the colon */ - recipient += 7; - DEBUG(D_receive) - debug_printf_indent("DMARC forensic report to %s%s\n", recipient, - (host_checking || f.running_in_test_harness) ? " (not really)" : ""); - if (host_checking || f.running_in_test_harness) - continue; - - if (!moan_send_message(recipient, ERRMESS_DMARC_FORENSIC, eblock, - header_list, message_file, NULL)) - log_write(0, LOG_MAIN|LOG_PANIC, - "failure to send DMARC forensic report to %s", recipient); - } - } -} - - -/* Look up a DNS dmarc record for the given domain. Return it or NULL */ - -static uschar * -dmarc_dns_lookup(uschar * dom) -{ -dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; -uschar * res = NULL; - -expand_level++; - -if (dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL) - == DNS_SUCCEED) - for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) - if (rr->type == T_TXT && rr->size > 3) - res = string_copyn_taint(US rr->data, rr->size, GET_TAINTED); - -expand_level--; -store_free_dns_answer(dnsa); -return res; + dmarc_send_forensic_report(CUSS ruf); } -static int -dmarc_write_history_file(const gstring * dkim_history_buffer) -{ -int history_file_fd = 0, tmp_ans; -u_char ** rua; /* aggregate report addressees */ -uschar * s; -gstring * g; -GET_OPTION("dmarc_history_file"); -if (!(s = dmarc_history_file) || !(s = expand_string(s)) || !*s) - { - DEBUG(D_receive) debug_printf_indent("DMARC history file not set\n"); - return DMARC_HIST_DISABLED; - } -if (!host_checking) - /* Ensure we use a modifiiable copy for the filename */ - if ((history_file_fd = - log_open_as_exim(s == dmarc_history_file ? string_copy(s) : s)) < 0) - { - log_write(0, LOG_MAIN|LOG_PANIC, - "failure to create DMARC history file: %s: %s", - s, strerror(errno)); - return DMARC_HIST_FILE_ERR; - } - -/* Generate the contents of the history file entry */ - -g = string_fmt_append(NULL, - "job %s\nreporter %s\nreceived %ld\nipaddr %s\nfrom %s\nmfrom %s\n", - message_id, primary_hostname, time(NULL), sender_host_address, - header_from_sender, expand_string(US"$sender_address_domain")); - -if (dmarc_spf_ares_result != ARES_RESULT_UNDEFINED) - g = string_fmt_append(g, "spf %d\n", dmarc_spf_ares_result); - -if (dkim_history_buffer) - g = string_fmt_append(g, "%Y", dkim_history_buffer); - -g = string_fmt_append(g, "pdomain %s\npolicy %d\n", - dmarc_used_domain, dmarc_policy); - -if ((rua = opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1))) - for (tmp_ans = 0; rua[tmp_ans]; tmp_ans++) - g = string_fmt_append(g, "rua %s\n", rua[tmp_ans]); -else - g = string_catn(g, US"rua -\n", 6); - -opendmarc_policy_fetch_pct(dmarc_pctx, &tmp_ans); -g = string_fmt_append(g, "pct %d\n", tmp_ans); - -opendmarc_policy_fetch_adkim(dmarc_pctx, &tmp_ans); -g = string_fmt_append(g, "adkim %d\n", tmp_ans); - -opendmarc_policy_fetch_aspf(dmarc_pctx, &tmp_ans); -g = string_fmt_append(g, "aspf %d\n", tmp_ans); - -opendmarc_policy_fetch_p(dmarc_pctx, &tmp_ans); -g = string_fmt_append(g, "p %d\n", tmp_ans); - -opendmarc_policy_fetch_sp(dmarc_pctx, &tmp_ans); -g = string_fmt_append(g, "sp %d\n", tmp_ans); - -g = string_fmt_append(g, "align_dkim %d\nalign_spf %d\naction %d\n", - da, sa, action); - -#if DMARC_API >= 100400 -# ifdef EXPERIMENTAL_ARC - { - const misc_module_info * mi = misc_mod_findonly(US"arc"); - const uschar * t; - gstring * g2 = NULL; - typedef const uschar * (*fn_t)(gstring **); - - if (mi && (t = (((fn_t *) mi->functions)[ARC_ARCSET_INFO]) (&g2))) - { - int i = Ustrcmp(t, "pass") == 0 ? ARES_RESULT_PASS - : Ustrcmp(t, "fail") == 0 ? ARES_RESULT_FAIL - : ARES_RESULT_UNKNOWN; - - g = string_fmt_append(g, "arc %d\n" - "arc_policy %d json[%#Y ]\n", - i, - i == ARES_RESULT_PASS ? DMARC_ARC_POLICY_RESULT_PASS - : i == ARES_RESULT_FAIL ? DMARC_ARC_POLICY_RESULT_FAIL - : DMARC_ARC_POLICY_RESULT_UNUSED, - g2 - ); - } - else - string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", - ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); - } - -# else -g = string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", - ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); -# endif -#endif - -/* Write the contents to the history file */ -DEBUG(D_receive) - { - debug_printf_indent("DMARC logging history data for opendmarc reporting%s\n", - host_checking ? " (not really)" : ""); - debug_printf_indent("DMARC history data for debugging:\n"); - expand_level++; - debug_printf_indent("%Y", g); - expand_level--; - } - -if (!host_checking) - { - ssize_t written_len = write_to_fd_buf(history_file_fd, - g->s, - gstring_length(g)); - if (written_len == 0) - { - log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s", - dmarc_history_file); - return DMARC_HIST_WRITE_ERR; - } - (void)close(history_file_fd); - } -return DMARC_HIST_OK; -} - - -/* dmarc_process adds the envelope sender address to the existing +/*API: dmarc_process adds the envelope sender address to the existing context (if any), retrieves the result, sets up expansion strings and evaluates the condition outcome. Called for the first ACL dmarc= condition. */ -static int +int dmarc_process(void) { -int sr = SPF_RESULT_INVALID, origin; /* used in SPF section */ int dmarc_spf_result; /* stores spf into dmarc conn ctx */ int tmp_ans, c; uschar * rr; @@ -444,44 +156,44 @@ if (f.dmarc_disable_verify) return OK; /* Store the header From: sender domain for this part of DMARC. -If there is no from_header struct, then it's likely this message +If there is no from_header string, then it's likely this message is locally generated and relying on fixups to add it. Just skip the entire DMARC system if we can't find a From: header....or if there was a previous error. */ -if (!from_header) +if (!dmarc_from_header) { DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); dmarc_abort = TRUE; } else if (!dmarc_abort) { + const uschar * end_addr, * s; uschar * errormsg; int dummy, domain; - uschar * p; - uschar saveend; f.parse_allow_group = TRUE; - p = parse_find_address_end(from_header->text, FALSE); - saveend = *p; *p = '\0'; - if ((header_from_sender = parse_extract_address(from_header->text, &errormsg, + end_addr = parse_find_address_end(dmarc_from_header, FALSE); + s = *end_addr + ? string_copyn(dmarc_from_header, end_addr - dmarc_from_header) + : dmarc_from_header; + if ((dmarc_header_from_sender = parse_extract_address(s, &errormsg, &dummy, &dummy, &domain, FALSE))) - header_from_sender += domain; - *p = saveend; + dmarc_header_from_sender += domain; /* The opendmarc library extracts the domain from the email address, but only try to store it if it's not empty. Otherwise, skip out of DMARC. */ - if (!header_from_sender || (strcmp( CCS header_from_sender, "") == 0)) + if (!dmarc_header_from_sender || !*dmarc_header_from_sender) dmarc_abort = TRUE; libdm_status = dmarc_abort ? DMARC_PARSE_OKAY - : opendmarc_policy_store_from_domain(dmarc_pctx, header_from_sender); + : opendmarc_policy_store_from_domain(dmarc_pctx, dmarc_header_from_sender); if (libdm_status != DMARC_PARSE_OKAY) { log_write(0, LOG_MAIN|LOG_PANIC, "failure to store header From: in DMARC: %s, header was '%s'", - opendmarc_policy_status_to_str(libdm_status), from_header->text); + opendmarc_policy_status_to_str(libdm_status), dmarc_from_header); dmarc_abort = TRUE; } } @@ -491,7 +203,8 @@ instead do this in the ACLs. */ if (!dmarc_abort && !sender_host_authenticated) { - uschar * dmarc_domain; + int sr = SPF_RESULT_INVALID, origin; + uschar * spf_human_readable = NULL, * spf_sender_domain; gstring * dkim_history_buffer = NULL; typedef const pdkim_signature * (*sigs_fn_t)(void); @@ -511,14 +224,11 @@ if (!dmarc_abort && !sender_host_authenticated) /* No spf data means null envelope sender so generate a domain name from the sender_helo_name */ - if (!spf_sender_domain) + if (!spf_sender_domain || !*spf_sender_domain) { spf_sender_domain = sender_helo_name; log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", spf_sender_domain); - DEBUG(D_receive) - debug_printf_indent("DMARC using synthesized SPF sender domain = %s\n", - spf_sender_domain); } dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; @@ -544,7 +254,7 @@ if (!dmarc_abort && !sender_host_authenticated) DEBUG(D_receive) debug_printf_indent("DMARC using SPF sender domain = %s\n", spf_sender_domain); } - if (strcmp( CCS spf_sender_domain, "") == 0) + if (!*spf_sender_domain) dmarc_abort = TRUE; if (!dmarc_abort) { @@ -610,24 +320,24 @@ The EDITME provides a DMARC_API variable */ our dns access path is used for debug tracing and for the testsuite diversion. */ - libdm_status = (rr = dmarc_dns_lookup(header_from_sender)) - ? opendmarc_policy_store_dmarc(dmarc_pctx, rr, header_from_sender, NULL) + libdm_status = (rr = dmarc_dns_lookup(dmarc_header_from_sender)) + ? opendmarc_policy_store_dmarc(dmarc_pctx, rr, dmarc_header_from_sender, NULL) : DMARC_DNS_ERROR_NO_RECORD; switch (libdm_status) { case DMARC_DNS_ERROR_NXDOMAIN: case DMARC_DNS_ERROR_NO_RECORD: DEBUG(D_receive) - debug_printf_indent("DMARC no record found for %s\n", header_from_sender); + debug_printf_indent("DMARC no record found for %s\n", dmarc_header_from_sender); has_dmarc_record = FALSE; break; case DMARC_PARSE_OKAY: DEBUG(D_receive) - debug_printf_indent("DMARC record found for %s\n", header_from_sender); + debug_printf_indent("DMARC record found for %s\n", dmarc_header_from_sender); break; case DMARC_PARSE_ERROR_BAD_VALUE: DEBUG(D_receive) - debug_printf_indent("DMARC record parse error for %s\n", header_from_sender); + debug_printf_indent("DMARC record parse error for %s\n", dmarc_header_from_sender); has_dmarc_record = FALSE; break; default: @@ -635,7 +345,7 @@ The EDITME provides a DMARC_API variable */ DEBUG(D_receive) debug_printf_indent("DMARC skipping (%s), unsure what to do with %s", opendmarc_policy_status_to_str(libdm_status), - from_header->text); + dmarc_from_header); has_dmarc_record = FALSE; break; } @@ -650,11 +360,10 @@ The EDITME provides a DMARC_API variable */ /* Can't use exim's string manipulation functions so allocate memory for libopendmarc using its max hostname length definition. */ - dmarc_domain = store_get(DMARC_MAXHOSTNAMELEN, GET_TAINTED); + dmarc_used_domain = store_get(DMARC_MAXHOSTNAMELEN, GET_TAINTED); libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx, - dmarc_domain, DMARC_MAXHOSTNAMELEN-1); - store_release_above(dmarc_domain + Ustrlen(dmarc_domain)+1); - dmarc_used_domain = dmarc_domain; + dmarc_used_domain, DMARC_MAXHOSTNAMELEN-1); + store_release_above(dmarc_used_domain + Ustrlen(dmarc_used_domain)+1); if (libdm_status != DMARC_PARSE_OKAY) log_write(0, LOG_MAIN|LOG_PANIC, @@ -662,61 +371,65 @@ The EDITME provides a DMARC_API variable */ opendmarc_policy_status_to_str(libdm_status)); dmarc_policy = libdm_status = opendmarc_get_policy_to_enforce(dmarc_pctx); + switch(libdm_status) { - case DMARC_POLICY_ABSENT: /* No DMARC record found */ + case DMARC_POLICY_ABSENT: /* No DMARC record found */ dmarc_status = US"norecord"; dmarc_pass_fail = US"none"; dmarc_status_text = US"No DMARC record"; - action = DMARC_RESULT_ACCEPT; + dmarc_action = DMARC_RESULT_ACCEPT; break; - case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ + case DMARC_FROM_DOMAIN_ABSENT: /* No From: domain */ dmarc_status = US"nofrom"; dmarc_pass_fail = US"temperror"; dmarc_status_text = US"No From: domain found"; - action = DMARC_RESULT_ACCEPT; + dmarc_action = DMARC_RESULT_ACCEPT; break; - case DMARC_POLICY_NONE: /* Accept and report */ + case DMARC_POLICY_NONE: /* Accept and report */ dmarc_status = US"none"; dmarc_pass_fail = US"none"; dmarc_status_text = US"None, Accept"; - action = DMARC_RESULT_ACCEPT; + dmarc_action = DMARC_RESULT_ACCEPT; break; - case DMARC_POLICY_PASS: /* Explicit accept */ + case DMARC_POLICY_PASS: /* Explicit accept */ dmarc_status = US"accept"; dmarc_pass_fail = US"pass"; dmarc_status_text = US"Accept"; - action = DMARC_RESULT_ACCEPT; + dmarc_action = DMARC_RESULT_ACCEPT; break; - case DMARC_POLICY_REJECT: /* Explicit reject */ + case DMARC_POLICY_REJECT: /* Explicit reject */ dmarc_status = US"reject"; dmarc_pass_fail = US"fail"; dmarc_status_text = US"Reject"; - action = DMARC_RESULT_REJECT; + dmarc_action = DMARC_RESULT_REJECT; break; - case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ + case DMARC_POLICY_QUARANTINE: /* Explicit quarantine */ dmarc_status = US"quarantine"; dmarc_pass_fail = US"fail"; dmarc_status_text = US"Quarantine"; - action = DMARC_RESULT_QUARANTINE; + dmarc_action = DMARC_RESULT_QUARANTINE; break; default: dmarc_status = US"temperror"; dmarc_pass_fail = US"temperror"; dmarc_status_text = US"Internal Policy Error"; - action = DMARC_RESULT_TEMPFAIL; + dmarc_action = DMARC_RESULT_TEMPFAIL; break; } - libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &da, &sa); + libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, + &dmarc_dkim_alignment, &dmarc_spf_alignment); if (libdm_status != DMARC_PARSE_OKAY) log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s", opendmarc_policy_status_to_str(libdm_status)); if (has_dmarc_record) { - dmarc_alignment_spf = sa == DMARC_POLICY_SPF_ALIGNMENT_PASS; - dmarc_alignment_dkim = da == DMARC_POLICY_DKIM_ALIGNMENT_PASS; + dmarc_alignment_spf = + dmarc_spf_alignment == DMARC_POLICY_SPF_ALIGNMENT_PASS; + dmarc_alignment_dkim = + dmarc_dkim_alignment == DMARC_POLICY_DKIM_ALIGNMENT_PASS; log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", @@ -724,10 +437,18 @@ The EDITME provides a DMARC_API variable */ dmarc_alignment_spf ? "yes" : "no", dmarc_alignment_dkim ? "yes" : "no", dmarc_status_text); - history_file_status = dmarc_write_history_file(dkim_history_buffer); + + dmarc_rua = USS opendmarc_policy_fetch_rua(dmarc_pctx, NULL, 0, 1); + opendmarc_policy_fetch_pct(dmarc_pctx, &dmarc_pct); + opendmarc_policy_fetch_adkim(dmarc_pctx, &dmarc_adkim); + opendmarc_policy_fetch_aspf(dmarc_pctx, &dmarc_aspf); + opendmarc_policy_fetch_p(dmarc_pctx, &dmarc_dom_policy); + opendmarc_policy_fetch_sp(dmarc_pctx, &dmarc_subdom_policy); + dmarc_write_history_file(dkim_history_buffer); + /* Now get the forensic reporting addresses, if any */ ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1); - dmarc_send_forensic_report(ruf); + dmarc_local_send_forensic_report(ruf); } } @@ -746,7 +467,8 @@ dmarc_exim_expand_defaults(void) return f.dmarc_disable_verify ? US"off" : US"none"; } -static const uschar * +/*API*/ +const uschar * dmarc_exim_expand_query(void) { if (f.dmarc_disable_verify || !dmarc_pctx) @@ -756,75 +478,6 @@ return dmarc_status; } -static gstring * -authres_dmarc(gstring * g) -{ -if (f.dmarc_has_been_checked) - { - int start = 0; /* Compiler quietening */ - DEBUG(D_acl) start = gstring_length(g); - g = string_append(g, 2, US";\n\tdmarc=", dmarc_pass_fail); - if (header_from_sender) - g = string_append(g, 2, US" header.from=", header_from_sender); - DEBUG(D_acl) debug_printf_indent("DMARC:\tauthres '%.*s'\n", - gstring_length(g) - start - 3, g->s + start + 3); - } -else - DEBUG(D_acl) debug_printf_indent("DMARC:\tno authres\n"); -return g; -} - -/******************************************************************************/ -/* Module API */ - -static optionlist dmarc_options[] = { - { "dmarc_forensic_sender", opt_stringptr, {&dmarc_forensic_sender} }, - { "dmarc_history_file", opt_stringptr, {&dmarc_history_file} }, - { "dmarc_tld_file", opt_stringptr, {&dmarc_tld_file} }, -}; - -static void * dmarc_functions[] = { - [DMARC_PROCESS] = (void *) dmarc_process, - [DMARC_EXPAND_QUERY] = (void *) dmarc_exim_expand_query, - [DMARC_STORE_DATA] = (void *) dmarc_store_data, -}; - -/* dmarc_forensic_sender is provided for visibility of the the option setting -by moan_send_message. We do not document it as a config-visible $variable. -We could provide it via a function but there's little advantage. */ - -static var_entry dmarc_variables[] = { - { "dmarc_alignment_dkim", vtype_bool, &dmarc_alignment_dkim }, - { "dmarc_alignment_spf", vtype_bool, &dmarc_alignment_spf }, - { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy }, - { "dmarc_forensic_sender", vtype_stringptr, &dmarc_forensic_sender}, - { "dmarc_status", vtype_stringptr, &dmarc_status }, - { "dmarc_status_text", vtype_stringptr, &dmarc_status_text }, - { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain }, -}; - -misc_module_info dmarc_module_info = -{ - .name = US"dmarc", -# ifdef DYNLOOKUP - .dyn_magic = MISC_MODULE_MAGIC, -# endif - .init = dmarc_init, - .lib_vers_report = dmarc_version_report, - .smtp_reset = dmarc_smtp_reset, - .msg_init = dmarc_msg_init, - .authres = authres_dmarc, - - .options = dmarc_options, - .options_count = nelem(dmarc_options), - - .functions = dmarc_functions, - .functions_count = nelem(dmarc_functions), - - .variables = dmarc_variables, - .variables_count = nelem(dmarc_variables), -}; - # endif /* SUPPORT_SPF */ #endif /* SUPPORT_DMARC */ /* vi: aw ai sw=2 diff --git a/src/src/miscmods/dmarc.h b/src/src/miscmods/dmarc.h index c1cafd0d1..6f8c456dd 100644 --- a/src/src/miscmods/dmarc.h +++ b/src/src/miscmods/dmarc.h @@ -2,8 +2,8 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Experimental DMARC support. - Copyright (c) The Exim Maintainers 2021 - 2023 +/* DMARC support. + Copyright (c) The Exim Maintainers 2021 - 2025 Copyright (c) Todd Lyons 2012 - 2014 License: GPL */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -11,14 +11,54 @@ /* Portions Copyright (c) 2012, 2013, The Trusted Domain Project; All rights reserved, licensed for use per LICENSE.opendmarc. */ -#ifdef SUPPORT_DMARC +#ifdef EXPERIMENTAL_DMARC_NATIVE +# define EXIM_HAVE_DMARC EXPERIMENTAL_DMARC_NATIVE +# define DMARC_SUPPORTS_ARC + +/* from opendmarc/dmarc.h */ +# define DMARC_MAXHOSTNAMELEN 256 + +# define DMARC_POLICY_ABSENT 14 +# define DMARC_POLICY_PASS 15 +# define DMARC_POLICY_REJECT 16 +# define DMARC_POLICY_QUARANTINE 17 +# define DMARC_POLICY_NONE 18 +# define DMARC_USED_POLICY_IS_P 19 +# define DMARC_USED_POLICY_IS_SP 20 + +# define DMARC_POLICY_SPF_ORIGIN_MAILFROM 1 +# define DMARC_POLICY_SPF_ORIGIN_HELO 2 + +# define DMARC_POLICY_SPF_OUTCOME_NONE 0 +# define DMARC_POLICY_SPF_OUTCOME_PASS 1 +# define DMARC_POLICY_SPF_OUTCOME_FAIL 2 +# define DMARC_POLICY_SPF_OUTCOME_TMPFAIL 3 +# define DMARC_POLICY_SPF_ALIGNMENT_PASS 4 +# define DMARC_POLICY_SPF_ALIGNMENT_FAIL 5 + +# define DMARC_POLICY_DKIM_OUTCOME_NONE 0 +# define DMARC_POLICY_DKIM_OUTCOME_PASS 1 +# define DMARC_POLICY_DKIM_OUTCOME_FAIL 2 +# define DMARC_POLICY_DKIM_OUTCOME_TMPFAIL 3 +# define DMARC_POLICY_DKIM_ALIGNMENT_PASS 4 +# define DMARC_POLICY_DKIM_ALIGNMENT_FAIL 5 + + + +#elif defined(SUPPORT_DMARC) +# define EXIM_HAVE_DMARC SUPPORT_DMARC +# if DMARC_API >= 100400 +# define DMARC_SUPPORTS_ARC +# endif # include # ifdef SUPPORT_SPF # include # endif /* SUPPORT_SPF */ -#define DMARC_VERIFY_STATUS 1 +#endif /* SUPPORT_DMARC */ + + #define DMARC_HIST_OK 1 #define DMARC_HIST_DISABLED 2 @@ -50,8 +90,55 @@ #define ARES_RESULT_UNKNOWN 11 #define ARES_RESULT_DISCARD 12 +# define DMARC_RECORD_A_UNSPECIFIED ('\0') /* adkim and aspf */ +# define DMARC_RECORD_A_STRICT ('s') /* adkim and aspf */ +# define DMARC_RECORD_A_RELAXED ('r') /* adkim and aspf */ +# define DMARC_RECORD_P_UNSPECIFIED ('\0') /* p and sp */ +# define DMARC_RECORD_P_NONE ('n') /* p and sp */ +# define DMARC_RECORD_P_QUARANTINE ('q') /* p and sp */ +# define DMARC_RECORD_P_REJECT ('r') /* p and sp */ + +#ifndef DMARC_POLICY_SPF_ALIGNMENT_PASS +/* From opendmarc/dmarc.h */ +# define DMARC_POLICY_SPF_ALIGNMENT_PASS 4 +# define DMARC_POLICY_SPF_ALIGNMENT_FAIL 5 +#endif + +#ifndef DMARC_POLICY_DKIM_ALIGNMENT_PASS +/* From opendmarc/dmarc.h */ +# define DMARC_POLICY_DKIM_ALIGNMENT_PASS 4 +# define DMARC_POLICY_DKIM_ALIGNMENT_FAIL 5 +#endif + #define DMARC_ARC_POLICY_RESULT_PASS 0 #define DMARC_ARC_POLICY_RESULT_UNUSED 1 #define DMARC_ARC_POLICY_RESULT_FAIL 2 -#endif /* SUPPORT_DMARC */ + + +/* These live in dmarc_common.c */ +extern BOOL dmarc_abort; +extern uschar * dmarc_header_from_sender; +extern uschar * dmarc_pass_fail; +extern const uschar * dmarc_from_header; +extern const misc_module_info * dmarc_dkim_mod_info; +extern const misc_module_info * dmarc_spf_mod_info; +extern int dmarc_spf_ares_result; +extern uschar ** dmarc_rua; /* aggregate report addressees */ +extern int dmarc_pct; +extern int dmarc_adkim; +extern int dmarc_aspf; +extern int dmarc_policy; +extern int dmarc_dom_policy; +extern int dmarc_subdom_policy; +extern int dmarc_spf_alignment; +extern int dmarc_dkim_alignment; +extern int dmarc_action; +extern uschar * dmarc_used_domain; +extern const uschar * dmarc_domain_policy; +extern BOOL dmarc_alignment_spf; +extern BOOL dmarc_alignment_dkim; + +extern const uschar * dmarc_status; +extern const uschar * dmarc_status_text; + diff --git a/src/src/miscmods/dmarc_api.h b/src/src/miscmods/dmarc_api.h index 2f10463fc..54b1630a6 100644 --- a/src/src/miscmods/dmarc_api.h +++ b/src/src/miscmods/dmarc_api.h @@ -13,4 +13,4 @@ #define DMARC_PROCESS 0 #define DMARC_EXPAND_QUERY 1 -#define DMARC_STORE_DATA 2 +#define DMARC_STORE_FROMHDR 2 diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c new file mode 100644 index 000000000..168e7da8e --- /dev/null +++ b/src/src/miscmods/dmarc_common.c @@ -0,0 +1,546 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* DMARC support. + Copyright (c) The Exim Maintainers 2025 + License: GPL */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../exim.h" + +#ifdef EXIM_HAVE_DMARC + +// # include "dmarc.h" +// # include "pdkim.h" + +extern BOOL dmarc_local_init(void); +extern void dmarc_local_msg_init(void); +extern gstring * dmarc_version_report(gstring *); +extern int dmarc_process(void); +extern const uschar * dmarc_exim_expand_query(void); + + +/* Other modules needed for services */ +const misc_module_info * dmarc_spf_mod_info; +const misc_module_info * dmarc_dkim_mod_info; +const misc_module_info * dmarc_arc_mod_info; + +/* Working data */ +BOOL dmarc_abort; +uschar * dmarc_pass_fail; /* for authres */ +const uschar * dmarc_from_header; +uschar * dmarc_header_from_sender; + +/* results */ +int dmarc_spf_ares_result; +uschar ** dmarc_rua; /* aggregate report addressees */ +int dmarc_pct; /* percentage */ +int dmarc_adkim; /* dkim policy */ +int dmarc_aspf; /* spf policy */ +int dmarc_policy; /* policy to enforce */ +int dmarc_dom_policy; /* (the p tag, as numeric) */ +int dmarc_subdom_policy; /* (the sp tag, as numeric) */ +int dmarc_spf_alignment; +int dmarc_dkim_alignment; +int dmarc_action; + + +/* $variables */ +BOOL dmarc_alignment_dkim = FALSE; /* Subtest result */ +BOOL dmarc_alignment_spf = FALSE; /* Subtest result */ +const uschar * dmarc_domain_policy = NULL; /* Declared policy of used domain */ +const uschar * dmarc_status; /* One word value */ +const uschar * dmarc_status_text = NULL; /* Human readable value */ +uschar * dmarc_used_domain; /* Domain libopendmarc chose for DMARC policy lookup */ + +/* options */ +uschar * dmarc_forensic_sender = NULL; /* Set sender address for forensic reports */ +uschar * dmarc_history_file = NULL; /* File to store dmarc results */ +uschar * dmarc_tld_file = NULL; /* Mozilla TLDs text file */ + + +/*API: +One-time initialisation for dmarc. Ensure the spf module is available. +*/ + +static BOOL +dmarc_init(void * dummy) +{ +uschar * errstr; +if (!(dmarc_spf_mod_info = misc_mod_find(US"spf", &errstr))) + { + log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); + return FALSE; + } + +if (!(dmarc_dkim_mod_info = misc_mod_find(US"dkim", &errstr))) + { + log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); + return FALSE; + } + +dmarc_arc_mod_info = misc_mod_findonly(US"arc"); +return dmarc_local_init(); +} + + + +/*API: dmarc_msg_init could set up a context that can be re-used for several +messages on the same SMTP connection +(that come from the same host with the same HELO string). +However, we seem to only use it for one; we destroy some sort of context +at the tail end of dmarc_process(). */ + +static int +dmarc_msg_init(void) +{ +/* Set some sane defaults. Also clears previous results when +multiple messages in one connection. */ + +f.dmarc_has_been_checked = FALSE; +dmarc_from_header = NULL; +dmarc_header_from_sender = NULL; +dmarc_spf_ares_result = ARES_RESULT_UNDEFINED; +dmarc_status = US"none"; +dmarc_abort = FALSE; +dmarc_pass_fail = US"skipped"; +dmarc_used_domain = US""; + +/* ACLs have "control=dmarc_disable_verify" */ +if (f.dmarc_disable_verify) + return OK; + +GET_OPTION("dmarc_tld_file"); +if ( !dmarc_tld_file + || !(dmarc_tld_file = expand_string(dmarc_tld_file)) + || !*dmarc_tld_file) + { + DEBUG(D_receive) debug_printf_indent("DMARC: no dmarc_tld_file\n"); + dmarc_abort = TRUE; + } +else if (!sender_host_address) + { + DEBUG(D_receive) debug_printf_indent("DMARC: no sender_host_address\n"); + dmarc_abort = TRUE; + } +else + dmarc_local_msg_init(); + +return OK; +} + + +/*API*/ + +static void +dmarc_smtp_reset(void) +{ +f.dmarc_has_been_checked = f.dmarc_disable_verify = + f.dmarc_enable_forensic = FALSE; +dmarc_domain_policy = dmarc_status = dmarc_status_text = + dmarc_used_domain = NULL; +} + + +/* API: dmarc_store_data stores the header data so that subsequent dmarc_process +can access the data. Cleared by msg_init. +Called after the entire message has been received, with the From: header. */ + +static void +dmarc_store_fromhdr(const uschar * hdr) +{ +/* No debug output because would change every test debug output */ +dmarc_from_header = hdr; +} + + +/* Accept an error_block struct, initialize if empty, parse to the +end, and append the two strings passed to it. Used for adding +variable amounts of value:pair data to the forensic emails. */ + +static error_block * +add_to_eblock(error_block * eblock, const uschar * t1, const uschar * t2) +{ +error_block * eb = store_malloc(sizeof(error_block)); +if (!eblock) + eblock = eb; +else + { + /* Find the end of the eblock struct and point it at eb */ + error_block * tmp = eblock; + while(tmp->next) + tmp = tmp->next; + tmp->next = eb; + } +eb->text1 = t1; +eb->text2 = t2; +eb->next = NULL; +return eblock; +} + +void +dmarc_send_forensic_report(const uschar ** ruf) +{ +error_block * eblock; + +/* Earlier ACL does not have *required* control=dmarc_enable_forensic */ +if (!f.dmarc_enable_forensic || !ruf) + return; + +eblock = add_to_eblock(NULL, + string_sprintf("Subject: DMARC Forensic Report for %s from IP %s\n\n", + dmarc_used_domain, sender_host_address), NULL); +eblock = add_to_eblock(eblock, + US"A message claiming to be from you has failed the published DMARC\n" + "policy for your domain.\n\n", NULL); + +eblock = add_to_eblock(eblock, US"Sender Domain", dmarc_header_from_sender); +eblock = add_to_eblock(eblock, US"Sender IP Address", sender_host_address); +eblock = add_to_eblock(eblock, US"Received Date", tod_stamp(tod_full)); +eblock = add_to_eblock(eblock, US"SPF Alignment", + dmarc_alignment_spf ? US"yes" : US"no"); +eblock = add_to_eblock(eblock, US"DKIM Alignment", + dmarc_alignment_dkim ? US"yes" : US"no"); +eblock = add_to_eblock(eblock, US"DMARC Results", dmarc_status_text); + +for (int c = 0; ruf[c]; c++) + { + uschar * recipient = string_copylc(ruf[c]); + if (Ustrncmp(recipient, "mailto:",7)) + continue; + /* Move to first character past the colon */ + recipient += 7; + DEBUG(D_receive) + debug_printf_indent("DMARC forensic report to %s%s\n", recipient, + host_checking || f.running_in_test_harness ? " (not really)" : ""); + if (host_checking || f.running_in_test_harness) + continue; + + if (!moan_send_message(recipient, ERRMESS_DMARC_FORENSIC, eblock, + header_list, NULL, NULL)) + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to send DMARC forensic report to %s", recipient); + } +} + + +/* Look up a DNS dmarc record for the given domain. Return it or NULL */ + +const uschar * +dmarc_dns_lookup(const uschar * dom) +{ +dns_answer * dnsa = store_get_dns_answer(); +dns_scan dnss; +const uschar * res = NULL; + +expand_level++; + +/* RFC 7489 6.6.1 :- policy record is at a "_dmarc" sub of the domain */ + +if (dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL) + == DNS_SUCCEED) + { +/*XXX we lose track of temporary DNS failures */ + + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) + { + const uschar * rdata = rr->data; + int len = rdata[0]; + + if (len > 511) len = 127; + rdata++; + +/* RFC 7489 6.6.1 :- policy record is a TXT record */ +/* RFC 7489 6.6.3 step 2: ignore records not starting "v=DMARC1;" + (also noted in 6.3 for the v tag) */ + + if ( rr->type == T_TXT && len > 9 + && Ustrncmp(rdata, "v=DMARC1;", 9) == 0) + if (!res) + res = string_copyn_taint(rdata, len, GET_TAINTED); + else +/* RFC 7489 6.6.3 step 5: multiple records are treated as no record */ + { + DEBUG(D_receive) debug_printf_indent("DMARC: multiple rr\n"); + res = NULL; + break; + } + } + } +else + DEBUG(D_receive) debug_printf_indent("DMARC: no ret\n"); + +expand_level--; +store_free_dns_answer(dnsa); +DEBUG(D_receive) debug_printf_indent("DMARC: rr %q\n", res); +return res; +} + + + +const uschar * +dmarc_lookup_regdom(const uschar * dom) +{ +int expand_setup = -1, partial, affixlen, starflags; +const uschar * affix, * opts, * res; +const lookup_info * li; +void * handle; +static const uschar * cached_key = NULL, * cached_res = NULL; + +DEBUG(D_receive) debug_printf_indent("DMARC: lookup regdom for %q\n", dom); + +if (cached_key && Ustrcmp(dom, cached_key) == 0) + { + res = cached_res; + DEBUG(D_receive) debug_printf_indent(" DMARC: cached value %q\n", res); + return res; + } + +expand_level++; +res = NULL; +if (!(li = search_findtype_partial(US"regdom", &partial, &affix, &affixlen, + &starflags, &opts))) + { + DEBUG(D_receive) debug_printf_indent("DMARC: missing regdom lookup\n"); + goto out; + } + +if (!(handle = search_open(dmarc_tld_file, li, 0, NULL, NULL))) + goto out; + +/*XXX should we handle a defer return? cf. f.search_find_defer */ + +res = search_find(handle, dmarc_tld_file, dom, partial, affix, + affixlen, starflags, &expand_setup, opts); + +out: + cached_key = dom; cached_res = res; + expand_level--; + return res; +} + +const uschar * +dmarc_get_dns_policy_record(const uschar ** used_dom_p) +{ +const uschar * s; + +DEBUG(D_receive) debug_printf_indent("DMARC: lookup policy record for %s\n", + dmarc_header_from_sender); + +/* RFC 7489 6.6.3 step 1: DNS domain matching the 5322.From */ + +if ((s= dmarc_dns_lookup(*used_dom_p = dmarc_header_from_sender))) + return s; + +/* RFC 7489 6.6.3 step 3: if no record, use the Organizational Domain */ + +if (!(s = dmarc_lookup_regdom(dmarc_header_from_sender))) + return NULL; + +/* RFC 7489 6.6.3 step 3: if the Organizational Domain differs */ + +if (Ustrcmp(s, dmarc_header_from_sender) == 0) + return NULL; + +return dmarc_dns_lookup(*used_dom_p = s); +} + + +void +dmarc_write_history_file(const gstring * dkim_history_buffer) +{ +int history_file_fd = -1; +uschar * s; +gstring * g; + +GET_OPTION("dmarc_history_file"); +if (!(s = dmarc_history_file) || !(s = expand_string(s)) || !*s) + { + DEBUG(D_receive) debug_printf_indent("DMARC history file not set\n"); + return; + } +if (!host_checking) /* -bh mode: nothing written except debug */ + if ((history_file_fd = log_open_as_exim(s)) < 0) + { + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to create DMARC history file: %s: %s", + s, strerror(errno)); + return; + } + +/* Generate the contents of the history file entry */ + +g = string_fmt_append(NULL, + "job %s\n" + "reporter %s\n" + "received %ld\n" + "ipaddr %s\n" + "from %s\n" + "mfrom %s\n", + message_id, primary_hostname, time(NULL), sender_host_address, + dmarc_header_from_sender, expand_string(US"$sender_address_domain")); + +if (dmarc_spf_ares_result != ARES_RESULT_UNDEFINED) + g = string_fmt_append(g, "spf %d\n", dmarc_spf_ares_result); + +if (dkim_history_buffer) + g = string_fmt_append(g, "%Y", dkim_history_buffer); + +g = string_fmt_append(g, "pdomain %s\n" + "policy %d\n", + dmarc_used_domain, dmarc_policy); + +if (dmarc_rua) + for (uschar ** ss = dmarc_rua; *ss; ss++) + g = string_fmt_append(g, "rua %s\n", *ss); +else + g = string_catn(g, US"rua -\n", 6); + +/* policy tag values */ +g = string_fmt_append(g, "pct %d\n" + "adkim %d\n" + "aspf %d\n" + "p %d\n" + "sp %d\n", + dmarc_pct, dmarc_adkim, dmarc_aspf, dmarc_dom_policy, dmarc_subdom_policy); + +g = string_fmt_append(g, "align_dkim %d\n" + "align_spf %d\n" + "action %d\n", + dmarc_dkim_alignment, dmarc_spf_alignment, dmarc_action); + +#ifdef DMARC_SUPPORTS_ARC + { +# ifdef EXPERIMENTAL_ARC + const uschar * s; + gstring * g2 = NULL; + typedef const uschar * (*fn_t)(gstring **); + + if ( dmarc_arc_mod_info + && (s = (((fn_t *) dmarc_arc_mod_info->functions)[ARC_ARCSET_INFO]) (&g2))) + { + int i = Ustrcmp(s, "pass") == 0 ? ARES_RESULT_PASS + : Ustrcmp(s, "fail") == 0 ? ARES_RESULT_FAIL + : ARES_RESULT_UNKNOWN; + + g = string_fmt_append(g, "arc %d\n" + "arc_policy %d json[%#Y ]\n", + i, + i == ARES_RESULT_PASS ? DMARC_ARC_POLICY_RESULT_PASS + : i == ARES_RESULT_FAIL ? DMARC_ARC_POLICY_RESULT_FAIL + : DMARC_ARC_POLICY_RESULT_UNUSED, + g2 + ); + } + else + +# endif + g = string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", + ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); + } +#endif + +/* Write the contents to the history file */ +DEBUG(D_receive) + { + debug_printf_indent("DMARC history data for debugging:\n"); + expand_level++; + debug_printf_indent("%Y", g); + expand_level--; + debug_printf_indent("DMARC logging history data for opendmarc reporting%s\n", + host_checking ? " (not really)" : ""); + } + +if (!host_checking) + { + ssize_t written_len = write_to_fd_buf(history_file_fd, + string_from_gstring(g), gstring_length(g)); + if (written_len == 0) + { + log_write(0, LOG_MAIN|LOG_PANIC, + "failure to write to DMARC history file: %s", dmarc_history_file); + (void)close(history_file_fd); + return; + } + (void)close(history_file_fd); + } +return; +} + + + +/*API*/ +static gstring * +authres_dmarc(gstring * g) +{ +if (f.dmarc_has_been_checked) + { + int start = 0; /* Compiler quietening */ + DEBUG(D_acl) start = gstring_length(g); + g = string_append(g, 2, US";\n\tdmarc=", dmarc_pass_fail); + if (dmarc_header_from_sender) + g = string_append(g, 2, US" header.from=", dmarc_header_from_sender); + DEBUG(D_acl) debug_printf_indent("DMARC:\tauthres '%.*s'\n", + gstring_length(g) - start - 3, g->s + start + 3); + } +else + DEBUG(D_acl) debug_printf_indent("DMARC:\tno authres\n"); +return g; +} + +/******************************************************************************/ +/* Module API */ + +static optionlist dmarc_options[] = { + { "dmarc_forensic_sender", opt_stringptr, {&dmarc_forensic_sender} }, + { "dmarc_history_file", opt_stringptr, {&dmarc_history_file} }, + { "dmarc_tld_file", opt_stringptr, {&dmarc_tld_file} }, +}; + +static void * dmarc_functions[] = { + [DMARC_PROCESS] = (void *) dmarc_process, + [DMARC_EXPAND_QUERY] = (void *) dmarc_exim_expand_query, + [DMARC_STORE_FROMHDR] = (void *) dmarc_store_fromhdr, +}; + +/* dmarc_forensic_sender is provided for visibility of the the option setting +by moan_send_message. We do not document it as a config-visible $variable. +We could provide it via a function but there's little advantage. */ + +static var_entry dmarc_variables[] = { + { "dmarc_alignment_dkim", vtype_bool, &dmarc_alignment_dkim }, + { "dmarc_alignment_spf", vtype_bool, &dmarc_alignment_spf }, + { "dmarc_domain_policy", vtype_stringptr, &dmarc_domain_policy }, + { "dmarc_forensic_sender", vtype_stringptr, &dmarc_forensic_sender}, + { "dmarc_status", vtype_stringptr, &dmarc_status }, + { "dmarc_status_text", vtype_stringptr, &dmarc_status_text }, + { "dmarc_used_domain", vtype_stringptr, &dmarc_used_domain }, +}; + +misc_module_info dmarc_module_info = +{ + .name = US"dmarc", +# ifdef DYNLOOKUP + .dyn_magic = MISC_MODULE_MAGIC, +# endif + .init = dmarc_init, + .lib_vers_report = dmarc_version_report, + .smtp_reset = dmarc_smtp_reset, + .msg_init = dmarc_msg_init, + .authres = authres_dmarc, + + .options = dmarc_options, + .options_count = nelem(dmarc_options), + + .functions = dmarc_functions, + .functions_count = nelem(dmarc_functions), + + .variables = dmarc_variables, + .variables_count = nelem(dmarc_variables), +}; + +#endif /*EXIM_HAVE_DMARC*/ +/* vi: aw ai sw=2 + */ diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c new file mode 100644 index 000000000..ce4aaee4f --- /dev/null +++ b/src/src/miscmods/dmarc_native.c @@ -0,0 +1,707 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* DMARC support. + Copyright (c) The Exim Maintainers 2025 + License: GPL */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../exim.h" + +#ifdef SUPPORT_DMARC +# error Build cannot support both libopendmarc and native DMARC modules +#endif + +#ifdef EXPERIMENTAL_DMARC_NATIVE +# ifndef EXIM_HAVE_SPF +# error SPF must also be enabled for DMARC +# elif defined DISABLE_DKIM +# error DKIM must also be enabled for DMARC +# elif !defined LOOKUP_PSL +# error PSL lookups must be enabled for DMARC +# else + +# include "../functions.h" +# include "pdkim.h" + +extern void dmarc_send_forensic_report(const uschar **); +extern const uschar * dmarc_get_dns_policy_record(uschar **); +extern void dmarc_write_history_file(const gstring *); +extern const uschar * dmarc_lookup_regdom(const uschar *); + + +static const pcre2_code * dmarc_regex_uri = NULL; +static const pcre2_code * dmarc_regex_pct = NULL; +static const pcre2_code * dmarc_regex_ri = NULL; +static const pcre2_code * dmarc_regex_fo = NULL; + +BOOL +dmarc_local_init(void) +{ +if (!dmarc_regex_uri) + dmarc_regex_uri = regex_must_compile(US "^mailto:[^@]+@[^ !]+(?:[ !]|$)", + MCS_CACHEABLE, FALSE); +if (!dmarc_regex_pct) + dmarc_regex_uri = regex_must_compile(US "^\\d{1,3}$", MCS_CACHEABLE, FALSE); +if (!dmarc_regex_ri) + dmarc_regex_ri = regex_must_compile(US "^\\d{1,10}$", MCS_CACHEABLE, FALSE); +if (!dmarc_regex_fo) + dmarc_regex_fo = regex_must_compile(US "^[01ds]$", MCS_CACHEABLE, FALSE); +} + + +#include "../version.h" + +gstring * +dmarc_version_report(gstring * g) +{ +/* +return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n", + (OPENDMARC_LIB_VERSION & 0xff000000) >> 24, + (OPENDMARC_LIB_VERSION & 0x00ff0000) >> 16, + (OPENDMARC_LIB_VERSION & 0x0000ff00) >> 8, + (OPENDMARC_LIB_VERSION & 0x000000ff)); +*/ +return string_fmt_append(g, "Library version: dmarc: Exim %s builtin\n", + EXIM_VERSION_STR); +} + + +int +dmarc_local_msg_init() +{ +return OK; +} + + +/* Convert to comma-sep list to NULL-terminated array of pointers */ +static uschar ** +dmarc_clist_to_array(const uschar * list) +{ +int cnt = 0, sep = ','; +const uschar * s = list; +uschar * buf = store_get(2, list), ** rarray; + +while (string_nextinlist(&s, &sep, buf, 1)) cnt++; /* count the elements */ +rarray = store_get((cnt+1) * sizeof(*rarray), list); +for (cnt = 0; rarray[cnt] = string_nextinlist(&list, &sep, NULL, 0); ) cnt++; +return rarray; +} + + +static void +dmarc_maybe_send_forensic(const uschar * ruf) +{ +/* Earlier ACL does not have *required* control=dmarc_enable_forensic */ +if (!f.dmarc_enable_forensic) + return; + +/* RFC 7489 6.3 - ruf is optional */ +if (!ruf) + return; + +if ( dmarc_policy == DMARC_POLICY_REJECT + && dmarc_action == DMARC_RESULT_REJECT + || dmarc_policy == DMARC_POLICY_QUARANTINE + && dmarc_action == DMARC_RESULT_QUARANTINE + || dmarc_policy == DMARC_POLICY_NONE + && dmarc_action == DMARC_RESULT_REJECT + || dmarc_policy == DMARC_POLICY_NONE + && dmarc_action == DMARC_RESULT_QUARANTINE + ) + { +/* RFC 7489 6.3 - ruf is a comma-sep list */ + /* Convert to NULL-terminated array of pointers */ + const uschar ** rarray = CUSS dmarc_clist_to_array(ruf); + dmarc_send_forensic_report(rarray); + } +} + + +/******************************************************************************/ +/* Policy record parsing */ + +/* Value verification routines: return boolean "good" */ + +static BOOL dmarc_vfy_vmode(const uschar * val) +{ return (*val == 's' || *val == 'r') && val[1] == '\0'; } +static BOOL dmarc_vfy_policy(const uschar * val) +{ return Ustrcmp(val, "none") == 0 + || Ustrcmp(val, "quarantine") == 0 + || Ustrcmp(val, "reject") == 0; } +static BOOL dmarc_vfy_fbl(const uschar * val) +{ +/* For now, permit a list starting with (a plausible) mailto URI */ +return regex_match(dmarc_regex_uri, val, -1, NULL); +} + +static BOOL dmarc_tag_vfy_adkim(const uschar * val) +{ return dmarc_vfy_vmode(val); } +static BOOL dmarc_tag_vfy_aspf(const uschar * val) +{ return dmarc_vfy_vmode(val); } +static BOOL dmarc_tag_vfy_fo(const uschar * val) +{ return regex_match(dmarc_regex_fo, val, -1, NULL); } +static BOOL dmarc_tag_vfy_p(const uschar * val) +{ return dmarc_vfy_policy(val); } +static BOOL dmarc_tag_vfy_pct(const uschar * val) +{ return regex_match(dmarc_regex_pct, val, -1, NULL); } +static BOOL dmarc_tag_vfy_rf(const uschar * val) +{ return Ustrcmp(val, "afrf") == 0; } +static BOOL dmarc_tag_vfy_ri(const uschar * val) +{ return regex_match(dmarc_regex_ri, val, -1, NULL); } +static BOOL dmarc_tag_vfy_rua(const uschar * val) +{ return dmarc_vfy_fbl(val); } +static BOOL dmarc_tag_vfy_ruf(const uschar * val) +{ return dmarc_vfy_fbl(val); } +static BOOL dmarc_tag_vfy_sp(const uschar * val) +{ return dmarc_vfy_policy(val); } +static BOOL dmarc_tag_vfy_v(const uschar * val) +{ return Ustrcmp(val, "DMARC1") == 0; } + +typedef struct dmarc_policy_record { + const uschar * adkim; + const uschar * aspf; + const uschar * fo; + const uschar * p; + const uschar * pct; + const uschar * rf; + const uschar * ri; + const uschar * rua; + const uschar * ruf; + const uschar * sp; + const uschar * v; +} dmarc_policy_record; + +typedef struct tag { + const uschar * name; + unsigned offset; + BOOL (*verify)(const uschar *); +} tag; +#define TAG(field) {.name = US mac_expanded_string(field), \ + .offset = offsetof(dmarc_policy_record, field), \ + .verify = dmarc_tag_vfy_ ## field } +tag policy_tags[] = { + TAG(adkim), + TAG(aspf), + TAG(fo), + TAG(p), + TAG(pct), + TAG(rf), + TAG(ri), + TAG(rua), + TAG(ruf), + TAG(sp), + TAG(v), +}; +#undef TAG + +/* Handle one potential tag +Return: boolean success; else parsing error + +RFC 7489 6.3 :- unknown tags are ignored +*/ +static int +parse_tag(const uschar * tagrecord, dmarc_policy_record * prp) +{ +const uschar * e = Ustrchr(tagrecord, '='), * s; + +/* RFC 6736 3.2 tagspec must have = */ +if (!*e) + return FALSE; + +/* RFC 6736 3.2 ignore whitespace between tag name and = */ +for (s = e; s > tagrecord && isspace(s[-1]); ) s--; + +/* RFC 6736 3.2 tag name at least 1 char */ +if (s == tagrecord) + return FALSE; + +/* search for tag name in our table of known ones */ +for (tag * ptp = policy_tags; ptp < policy_tags + nelem(policy_tags); ptp++) + { + if ( Ustrncmp(ptp->name, tagrecord, s - tagrecord) == 0 + && Ustrlen(ptp->name) == s - tagrecord) + + { /* match; copy tag value to policy record struct */ + const uschar ** vp = CUSS (US prp + ptp->offset); + +// debug_printf_indent("matched %q, off %u\n", tagrecord, ptp->offset); + +/* RFC 6736 3.2 ignore whitespace between = and value */ + s = e + 1; + Uskip_whitespace(&s); + + if (!ptp->verify(s)) DEBUG(D_receive) + debug_printf_indent("DMARC: bad value for tag %q: %q\n", ptp->name, s); + *vp = string_copy(s); + break; + } + } +return TRUE; +} + +static BOOL +dmarc_local_parse_policy(const uschar * rr, dmarc_policy_record * prp) +{ +/* RFC 6376 3.2 :- a taglist is a ;-sep list of tagspec */ +int sep = ';'; + +/* RFC 6736 3.2 :- ignore whitespace preceding tag-name and after value */ + +for (uschar * tagspec; tagspec = string_nextinlist(&rr, &sep, NULL, 0); ) + if (!parse_tag(tagspec, prp)) + return FALSE; + +return TRUE; +} + +/******************************************************************************/ + +static BOOL +identifier_aligned(const uschar * a, const uschar * b, const uschar * mode) +{ +BOOL res; + +/* RFC 7489 3.3.1 - In strict mode, only an exact match */ + +if (*mode == 's') + res = Ustrcmp(a, b) == 0; + +/* RFC 7489 3.3.1 - In relaxed mode, the Organizational Domains of both */ +else + { + /* - if there is an exact match, the ODs will also match - + so check that first to save on regdom lookups. */ + + if (Ustrcmp(a, b) == 0) + res = TRUE; + else + { + a = dmarc_lookup_regdom(a); + b = dmarc_lookup_regdom(b); + res = a && b && Ustrcmp(a, b) == 0; + } + } +DEBUG(D_receive) + if (res) debug_printf_indent("DMARC aligned(%s) %s %s\n", mode, a, b); +return res; +} + + +/* API: dmarc_process adds the envelope sender address to the existing +context (if any), retrieves the result, sets up expansion +strings and evaluates the condition outcome. +Called for the first ACL dmarc= condition. */ + +int +dmarc_process(void) +{ +const uschar * rr; +BOOL has_dmarc_record = TRUE; +u_char ** ruf; /* forensic report addressees, if called for */ + +dmarc_alignment_spf = dmarc_alignment_dkim = FALSE; +dmarc_dkim_alignment = DMARC_POLICY_DKIM_ALIGNMENT_FAIL; +dmarc_spf_alignment = DMARC_POLICY_SPF_ALIGNMENT_FAIL; + +/* ACLs have "control=dmarc_disable_verify" */ +if (f.dmarc_disable_verify || dmarc_abort) + return OK; + +DEBUG(D_receive) { debug_printf_indent("DMARC: process\n"); expand_level++; } + +/* Store the header From: sender domain for this part of DMARC. +If there is no from_header string, then it's likely this message +is locally generated and relying on fixups to add it. Just skip +the entire DMARC system if we can't find a From: header....or if +there was a previous error. */ + +if (!dmarc_from_header) + { + DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); + dmarc_abort = TRUE; + } +else + { +/* RFC 7489 6.6.1 :- extract the domain from the 5322.From */ + const uschar * end_addr, * s; + uschar * errormsg; + int dummy, domain; + + f.parse_allow_group = TRUE; + end_addr = parse_find_address_end(dmarc_from_header, FALSE); + s = *end_addr + ? string_copyn(dmarc_from_header, end_addr - dmarc_from_header) + : dmarc_from_header; + if ((dmarc_header_from_sender = parse_extract_address(s, &errormsg, + &dummy, &dummy, &domain, FALSE))) + dmarc_header_from_sender += domain; + + /* Only use the domain if not empty. Otherwise, skip out of DMARC. */ + + if (!dmarc_header_from_sender || !*dmarc_header_from_sender) + { + dmarc_status = US"nofrom"; + dmarc_pass_fail = US"temperror"; + dmarc_status_text = US"No From: domain found"; + dmarc_action = DMARC_RESULT_ACCEPT; + + dmarc_abort = TRUE; + } + } + +/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should +instead do this in the ACLs. */ + +if (!dmarc_abort && !sender_host_authenticated) + { +/* RFC 7489 6.3 :- defaults for policy record tags */ + dmarc_policy_record dmarc_parsed = { + .adkim = US"r", + .aspf = US"r", + .fo = US"0", + .pct = US"100", + .rf = US"afrf", + .ri = US"86400", + }; + + int sr = SPF_RESULT_INVALID, spf_origin; + uschar * spf_human_readable = NULL, * spf_sender_domain = NULL; + unsigned dkim_sig_count = 0; + gstring * dkim_history_buffer = NULL; + typedef const pdkim_signature * (*sigs_fn_t)(void); + +/* RFC 7489 6.6.2 step 2: DMARC policy record from DNS */ + DEBUG(D_receive) + { + debug_printf_indent("DMARC: get policy record\n"); + expand_level++; + } + + /* uses $dmarc_header_from_sender */ + if (!(rr = dmarc_get_dns_policy_record(&dmarc_used_domain))) + /*XXX want to handle nxdomain,temprror etc. here */ + { + DEBUG(D_receive) debug_printf_indent("DMARC: no record found for %s\n", + dmarc_header_from_sender); + dmarc_policy = DMARC_POLICY_ABSENT; + dmarc_status = US"norecord"; + dmarc_pass_fail = US"none"; + dmarc_status_text = US"No DMARC record"; + dmarc_action = DMARC_RESULT_ACCEPT; + + has_dmarc_record = FALSE; + } + + else if (!dmarc_local_parse_policy(rr, &dmarc_parsed)) + { + DEBUG(D_receive) debug_printf_indent("DMARC: invalid record found for %s\n", + dmarc_header_from_sender); + dmarc_policy = DMARC_POLICY_ABSENT; + dmarc_status = US"norecord"; + dmarc_pass_fail = US"none"; + dmarc_status_text = US"No DMARC record"; + dmarc_action = DMARC_RESULT_ACCEPT; + + has_dmarc_record = FALSE; + goto out; + } + +/* RFC 7489 6.6.3 step 6: p/sp checks */ + if ( !dmarc_parsed.p + || !dmarc_tag_vfy_p(dmarc_parsed.p) + || dmarc_parsed.sp && !dmarc_tag_vfy_sp(dmarc_parsed.sp) + ) + +/* RFC 7489 6.6.3 step 6: if a valid rua, continue with p=none */ +/*XXX "at least one syntactically valid reporting URI" */ + if (dmarc_parsed.rua && dmarc_tag_vfy_rua(dmarc_parsed.rua)) + { + DEBUG(D_receive) + debug_printf_indent("DMARC: invalid p or sp; continue for rua\n"); + dmarc_parsed.p = US"none"; + } + else + { + DEBUG(D_receive) + debug_printf_indent("DMARC: invalid p or sp, and no rua. Abort.\n"); + dmarc_abort = TRUE; + goto out; + } + +/* RFC 7489 6.6.2 step 3: Perform DKIM signature verification checks */ + DEBUG(D_receive) + { + expand_level--; + debug_printf_indent("DMARC: process dkim results\n"); + expand_level++; + } + + /* Now we cycle through the dkim signature results and put into + the opendmarc context, further building the DMARC reply. */ + + if (has_dmarc_record) + for(const pdkim_signature * sig = + (((sigs_fn_t *)dmarc_dkim_mod_info->functions)[DKIM_SIGS_LIST])(); + sig; sig = sig->next) + { + int dkim_result, dkim_ares_result, vs, ves; + + dkim_sig_count++; + vs = sig->verify_status & ~PDKIM_VERIFY_POLICY; + ves = sig->verify_ext_status; + dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS : + vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL : + vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : + DMARC_POLICY_DKIM_OUTCOME_NONE; + + DEBUG(D_receive) + debug_printf_indent("DMARC: adding DKIM sender domain = %s\n", + sig->domain); + + /* Update the history buffer */ + + dkim_ares_result = + vs == PDKIM_VERIFY_PASS ? ARES_RESULT_PASS : + vs == PDKIM_VERIFY_FAIL ? ARES_RESULT_FAIL : + vs == PDKIM_VERIFY_NONE ? ARES_RESULT_NONE : + vs == PDKIM_VERIFY_INVALID ? + ves == PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE ? ARES_RESULT_PERMERROR : + ves == PDKIM_VERIFY_INVALID_BUFFER_SIZE ? ARES_RESULT_PERMERROR : + ves == PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD ? ARES_RESULT_PERMERROR : + ves == PDKIM_VERIFY_INVALID_PUBKEY_IMPORT ? ARES_RESULT_PERMERROR : + ARES_RESULT_UNKNOWN : + ARES_RESULT_UNKNOWN; + + dkim_history_buffer = string_fmt_append(dkim_history_buffer, + "dkim %s %s %d\n", sig->domain, sig->selector, dkim_ares_result); + + /* Evaluate the sig vs. dmarc requirements */ + +/* RFC 7489 3.1.1 if any DKIM signature ... verifies. */ + if ( !dmarc_alignment_dkim + && dkim_result == DMARC_POLICY_DKIM_OUTCOME_PASS + +/* RFC 7489 3.1.1 dkim alignment: d= tag in dkim sig */ +/* RFC 7489 3.1.1 dkim alignment: 5322.From domain */ +/* RFC 7489 6.3 adkim: DKIM Identifier Alignment mode */ + + && (dmarc_alignment_dkim = identifier_aligned(sig->domain, + dmarc_header_from_sender, dmarc_parsed.adkim)) + ) + dmarc_dkim_alignment = DMARC_POLICY_DKIM_ALIGNMENT_PASS; + } + DEBUG(D_receive) debug_printf_indent("DMARC: %u dkim sig%s\n", + dkim_sig_count, dkim_sig_count == 1 ? "" : "s"); + + DEBUG(D_receive) + { + expand_level--; + debug_printf_indent("DMARC: process spf results\n"); + expand_level++; + } + +/* RFC 7489 6.6.2 step 4: Perform SPF validation checks */ + + if (has_dmarc_record) + { + int spf_result; + typedef int (*fn_t)(uschar **); + + /* Use the envelope sender domain for this part of DMARC */ + + spf_sender_domain = expand_string(US"$sender_address_domain"); + + if (dmarc_spf_mod_info) + sr = ((fn_t *) dmarc_spf_mod_info->functions)[SPF_GET_RESULTS] + (&spf_human_readable); + + if (sr == SPF_RESULT_INVALID) + { + /* No spf data means null envelope sender so generate a domain name + from the sender_helo_name */ + + DEBUG(D_receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); + + if (!spf_sender_domain || !*spf_sender_domain) + { + spf_sender_domain = sender_helo_name; + log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", + spf_sender_domain); + } + spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; + dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; + spf_origin = DMARC_POLICY_SPF_ORIGIN_HELO; + spf_human_readable = US""; + } + else + { + spf_result = sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE : + sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS : + sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL : + sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL : + DMARC_POLICY_SPF_OUTCOME_NONE; + dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL ? ARES_RESULT_NEUTRAL : + sr == SPF_RESULT_PASS ? ARES_RESULT_PASS : + sr == SPF_RESULT_FAIL ? ARES_RESULT_FAIL : + sr == SPF_RESULT_SOFTFAIL ? ARES_RESULT_SOFTFAIL : + sr == SPF_RESULT_NONE ? ARES_RESULT_NONE : + sr == SPF_RESULT_TEMPERROR ? ARES_RESULT_TEMPERROR : + sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR : + ARES_RESULT_UNKNOWN; + /*XXX hmm, spf_origin never used? */ + spf_origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; + DEBUG(D_receive) + debug_printf_indent("DMARC: using SPF sender domain = %s\n", + spf_sender_domain); + } + if (!spf_sender_domain || !*spf_sender_domain) + dmarc_abort = TRUE; + if (!dmarc_abort) + { + /* RFC 7489 3.1.1 spf alignment: the SPF-authenticated domain */ + /* RFC 7489 3.1.1 spf alignment: 5322.From domain */ + /* RFC 7489 6.3 aspf: SPF Identifier Alignment mode */ + + if ( spf_result == DMARC_POLICY_SPF_OUTCOME_PASS + && (dmarc_alignment_spf = identifier_aligned(spf_sender_domain, + dmarc_header_from_sender, dmarc_parsed.aspf)) + ) + dmarc_spf_alignment = DMARC_POLICY_SPF_ALIGNMENT_PASS; + } + } + + DEBUG(D_receive) + { + expand_level--; + debug_printf_indent("DMARC: finished spf\n"); + } + + /* Store the policy string in an expandable variable. */ + +/* RFC 7489 is unclear how to obtain the policy-string that is to be used. +The decription of tags p & sp in 6.3 uses the term "domain queried". I assume +that is the portion of the DNS lookup key *after* the prepended "_dmarc." +which returned the DMARC RR being used (so it could be the Organizational +Domain, per 6.6.3 bullet 3, rather than the 5322.From domain). + +Given that assumption: if dom-used != 5322.From.dom and there is an sp, +use the sp. Otherwise use the p. */ + + dmarc_domain_policy = dmarc_parsed.sp + && dmarc_used_domain != dmarc_header_from_sender + ? dmarc_parsed.sp : dmarc_parsed.p; + +/* RFC 7489 6.6.2 step 5 - if either the spf or dkim shows alignment, pass */ + if (dmarc_alignment_spf || dmarc_alignment_dkim) + { /* Explicit accept */ + dmarc_policy = DMARC_POLICY_PASS; + dmarc_status = US"accept"; + dmarc_pass_fail = US"pass"; + dmarc_status_text = US"Accept"; + dmarc_action = DMARC_RESULT_ACCEPT; + } + +/* RFC 7489 6.6.2 step 6 - dispose of no-alignment per discovered policy */ + else + { + dmarc_status = dmarc_domain_policy; + if (Ustrcmp(dmarc_domain_policy, "none") == 0) + { /* Accept and report */ + dmarc_policy = DMARC_POLICY_NONE; + dmarc_pass_fail = US"none"; + dmarc_status_text = US"None, Accept"; + dmarc_action = DMARC_RESULT_ACCEPT; + } + else if (Ustrcmp(dmarc_domain_policy, "quarantine") == 0) + { /* Explicit quarantine*/ + dmarc_policy = DMARC_POLICY_QUARANTINE; + dmarc_pass_fail = US"fail"; + dmarc_status_text = US"Quarantine"; + dmarc_action = DMARC_RESULT_QUARANTINE; + } + else if (Ustrcmp(dmarc_domain_policy, "reject") == 0) + { /* Explicit reject */ + dmarc_policy = DMARC_POLICY_REJECT; + dmarc_pass_fail = US"fail"; + dmarc_status_text = US"Reject"; + dmarc_action = DMARC_RESULT_REJECT; + } + else /* should never happen; tag values were validated */ + { /* could use similar for dns tmpfail */ + dmarc_status = dmarc_pass_fail = US"temperror"; + dmarc_status_text = US"Internal Policy Error"; + dmarc_action = DMARC_RESULT_TEMPFAIL; + } + } + + // the alignments would be results of the DMARC evaluation + // - we have them already, from the dkim & spf processing + + if (has_dmarc_record && !dmarc_abort) + { + /* Log results. Robably should have a log_selector to reduce noise. */ + + log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + "spf_align=%s dkim_align=%s enforcement='%s'", + spf_sender_domain, dmarc_used_domain, + dmarc_alignment_spf ? "yes" : "no", + dmarc_alignment_dkim ? "yes" : "no", + dmarc_status_text); + + + /* History file, for later aggregate reporting. */ + + dmarc_pct = atoi(CCS dmarc_parsed.pct); + + dmarc_adkim = dmarc_parsed.adkim + ? *dmarc_parsed.adkim : DMARC_RECORD_A_UNSPECIFIED; + dmarc_aspf = dmarc_parsed.aspf + ? *dmarc_parsed.aspf : DMARC_RECORD_A_UNSPECIFIED; + dmarc_dom_policy = dmarc_parsed.p + ? *dmarc_parsed.p : DMARC_RECORD_P_UNSPECIFIED; + dmarc_subdom_policy = dmarc_parsed.sp + ? *dmarc_parsed.sp : DMARC_RECORD_P_UNSPECIFIED; + +/* RFC 7489 6.3 - rua is a comma-sep list */ + dmarc_rua = dmarc_clist_to_array(dmarc_parsed.rua); + + dmarc_write_history_file(dkim_history_buffer); + + /* Forensic reporting */ + + dmarc_maybe_send_forensic(dmarc_parsed.ruf); + } + } + +out: + DEBUG(D_receive) + { + expand_level--; + debug_printf_indent("DMARC: finished process, status %q\n", dmarc_status); + } + return OK; +} + +static const uschar * +dmarc_exim_expand_defaults(void) +{ +return f.dmarc_disable_verify ? US"off" : US"none"; +} + +/*API*/ +const uschar * +dmarc_exim_expand_query(void) +{ +if (f.dmarc_disable_verify ) // || !dmarc_pctx) + return dmarc_exim_expand_defaults(); + +return dmarc_status; +} + + +# endif /* have SPF & DKIM */ +#endif /* EXPERIMENTAL_DMARC_NATIVE */ +/* vi: aw ai sw=2 + */ diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index 9d215f516..f73a8776b 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -84,18 +84,18 @@ SPF_dns_rr_t srr = { .source = spf_dns_server }; -DEBUG(D_receive) debug_printf("SPF_dns_exim_lookup '%s'\n", domain); +DEBUG(D_receive) + { debug_printf_indent("SPF_dns_exim_lookup '%s'\n", domain); expand_level++; } /* Shortcircuit SPF RR lookups by returning NO_DATA. They were obsoleted by RFC 6686/7208 years ago. see bug #1294 */ if (rr_type == T_SPF) { - HDEBUG(D_host_lookup) debug_printf("faking NO_DATA for SPF RR(99) lookup\n"); + HDEBUG(D_host_lookup) + debug_printf_indent("faking NO_DATA for SPF RR(99) lookup\n"); srr.herrno = NO_DATA; - SPF_dns_rr_dup(&spfrr, &srr); - store_free_dns_answer(dnsa); - return spfrr; + goto out; } switch (dns_lookup(dnsa, US domain, rr_type, NULL)) @@ -115,11 +115,7 @@ switch (dns_lookup(dnsa, US domain, rr_type, NULL)) } if (found == 0) - { - SPF_dns_rr_dup(&spfrr, &srr); - store_free_dns_answer(dnsa); - return spfrr; - } + goto out; srr.rr = store_malloc(sizeof(SPF_dns_rr_data_t) * found); @@ -153,8 +149,8 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; if (rr->size < 1+6) continue; /* min for version str */ if (strncmpic(rr->data+1, US SPF_VER_STR, 6) != 0) { - HDEBUG(D_host_lookup) debug_printf("not an spf record: %.*s\n", - (int) s[0], s+1); + HDEBUG(D_host_lookup) debug_printf_indent("not an spf record: %.*s\n", + (int) s[0], s+1); continue; } @@ -170,7 +166,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; continue; gstring_release_unused(g); s = string_copy_malloc(string_from_gstring(g)); - DEBUG(D_receive) debug_printf("SPF_dns_exim_lookup '%s'\n", s); + DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_lookup '%s'\n", s); break; } @@ -192,10 +188,13 @@ empty ANSWER section. */ if (!(srr.num_rr = found)) srr.herrno = NO_DATA; -/* spfrr->rr must have been malloc()d for this */ -SPF_dns_rr_dup(&spfrr, &srr); -store_free_dns_answer(dnsa); -return spfrr; +out: + /* spfrr->rr must have been malloc()d for this */ + SPF_dns_rr_dup(&spfrr, &srr); + + DEBUG(D_receive) expand_level--; + store_free_dns_answer(dnsa); + return spfrr; } @@ -205,7 +204,7 @@ SPF_dns_exim_new(int debug) { SPF_dns_server_t * spf_dns_server = store_malloc(sizeof(SPF_dns_server_t)); -/* DEBUG(D_receive) debug_printf("SPF_dns_exim_new\n"); */ +/* DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_new\n"); */ memset(spf_dns_server, 0, sizeof(SPF_dns_server_t)); spf_dns_server->destroy = NULL; @@ -252,17 +251,17 @@ testsuite. */ if (!(dc = SPF_dns_exim_new(debug))) { - DEBUG(D_receive) debug_printf("spf: SPF_dns_exim_new() failed\n"); + DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_new() failed\n"); return FALSE; } if (!(dc = SPF_dns_cache_new(dc, NULL, debug, 8))) { - DEBUG(D_receive) debug_printf("spf: SPF_dns_cache_new() failed\n"); + DEBUG(D_receive) debug_printf_indent("SPF_dns_cache_new() failed\n"); return FALSE; } if (!(spf_server = SPF_server_new_dns(dc, debug))) { - DEBUG(D_receive) debug_printf("spf: SPF_server_new() failed.\n"); + DEBUG(D_receive) debug_printf_indent("SPF_server_new() failed.\n"); return FALSE; } @@ -294,8 +293,8 @@ static int spf_conn_init(const uschar * spf_helo_domain, const uschar * spf_remote_addr, const uschar ** errstr) { -DEBUG(D_receive) - debug_printf("spf_conn_init: %s %s\n", spf_helo_domain, spf_remote_addr); +DEBUG(D_receive) debug_printf_indent("spf_conn_init: %s %s\n", + spf_helo_domain, spf_remote_addr); if (!spf_server && !spf_init(NULL)) { @@ -305,8 +304,8 @@ if (!spf_server && !spf_init(NULL)) if (SPF_server_set_rec_dom(spf_server, CS primary_hostname)) { - DEBUG(D_receive) debug_printf("spf: SPF_server_set_rec_dom(%q) failed.\n", - primary_hostname); + DEBUG(D_receive) debug_printf_indent("SPF_server_set_rec_dom(%q) failed.\n", + primary_hostname); spf_server = NULL; *errstr = US"spf: setting host name"; return FAIL; @@ -319,7 +318,7 @@ if ( SPF_request_set_ipv4_str(spf_request, CCS spf_remote_addr) ) { DEBUG(D_receive) - debug_printf("spf: SPF_request_set_ipv4_str() and " + debug_printf_indent("SPF_request_set_ipv4_str() and " "SPF_request_set_ipv6_str() failed [%s]\n", spf_remote_addr); spf_server = NULL; spf_request = NULL; @@ -329,8 +328,8 @@ if ( SPF_request_set_ipv4_str(spf_request, CCS spf_remote_addr) if (SPF_request_set_helo_dom(spf_request, CCS spf_helo_domain)) { - DEBUG(D_receive) debug_printf("spf: SPF_set_helo_dom(%q) failed.\n", - spf_helo_domain); + DEBUG(D_receive) debug_printf_indent("SPF_set_helo_dom(%q) failed.\n", + spf_helo_domain); spf_server = NULL; spf_request = NULL; *errstr = US"spf: setting helo string"; @@ -352,14 +351,14 @@ static void spf_response_debug(SPF_response_t * spf_response) { if (SPF_response_messages(spf_response) == 0) - debug_printf(" (no errors)\n"); + debug_printf_indent(" (no errors)\n"); else for (int i = 0; i < SPF_response_messages(spf_response); i++) { SPF_error_t * err = SPF_response_message(spf_response, i); - debug_printf( "%s_msg = (%d) %s\n", - (SPF_error_errorp(err) ? "warn" : "err"), - SPF_error_code(err), - SPF_error_message(err)); + debug_printf_indent("%s_msg = (%d) %s\n", + SPF_error_errorp(err) ? "warn" : "err", + SPF_error_code(err), + SPF_error_message(err)); } } @@ -375,11 +374,11 @@ spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, int action) { int sep = 0; -const uschar *list = *listptr; -uschar *spf_result_id; -int rc = SPF_RESULT_PERMERROR; +const uschar * list = * listptr; +uschar * spf_result_id; +int rc = SPF_RESULT_PERMERROR, ret = OK; -DEBUG(D_receive) debug_printf("spf_process\n"); +DEBUG(D_receive) { debug_printf_indent("SPF: process\n"); expand_level++; } if (!(spf_server && spf_request)) /* no global context, assume temp error and skip to evaluation */ @@ -412,24 +411,32 @@ else } /* We got a result. Now see if we should return OK or FAIL for it */ -DEBUG(D_acl) debug_printf("SPF result is %s (%d)\n", SPF_strresult(rc), rc); +DEBUG(D_acl) + debug_printf_indent("SPF: result is %s (%d)\n", SPF_strresult(rc), rc); if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none"))) - return spf_process(listptr, spf_envelope_sender, SPF_PROCESS_FALLBACK); + ret = spf_process(listptr, spf_envelope_sender, SPF_PROCESS_FALLBACK); -while ((spf_result_id = string_nextinlist(&list, &sep, NULL, 0))) +else { - BOOL negate, result; + while ((spf_result_id = string_nextinlist(&list, &sep, NULL, 0))) + { + BOOL negate, result; - if ((negate = spf_result_id[0] == '!')) - spf_result_id++; + if ((negate = spf_result_id[0] == '!')) + spf_result_id++; + + result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name) == 0; + if (negate != result) goto out; + } - result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name) == 0; - if (negate != result) return OK; + /* no match */ + ret = FAIL; } -/* no match */ -return FAIL; +out: + DEBUG(D_receive) expand_level--; + return ret; } @@ -457,11 +464,11 @@ if (spf_result) ? string_append(g, 2, US" smtp.helo=", s) : string_cat(g, US" smtp.mailfrom=<>"); } - DEBUG(D_acl) debug_printf("SPF:\tauthres '%.*s'\n", + DEBUG(D_acl) debug_printf_indent("SPF:\tauthres '%.*s'\n", gstring_length(g) - start - 3, g->s + start + 3); } else - DEBUG(D_acl) debug_printf("SPF:\tno authres\n"); + DEBUG(D_acl) debug_printf_indent("SPF:\tno authres\n"); return g; } @@ -478,7 +485,7 @@ if (spf_response) s = US spf_response->header_comment; } *human_readable_p = s ? string_copy(s) : US""; -DEBUG(D_acl) debug_printf("SPF: %d '%s'\n", res, s); +DEBUG(D_acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); return res; } diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index e7bc1e331..33871c9aa 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -298,7 +298,7 @@ if (spf_result) } *human_readable_p = s ? string_copy(s) : US""; -DEBUG(D_acl) debug_printf_indent("SPF: %d '%s'\n", res, s); +DEBUG(D_acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); return res; } diff --git a/src/src/moan.c b/src/src/moan.c index 5635f93e2..01bf4f578 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -167,7 +167,7 @@ int written = 0, fd, status, count = 0, size_limit = bounce_return_size_limit; FILE * fp; int pid; -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC uschar * s, * s2; /* For DMARC if there is a specific sender set, expand the variable for the @@ -206,7 +206,7 @@ fp = fdopen(fd, "wb"); if (errors_reply_to) fprintf(fp, "Reply-To: %s\n", errors_reply_to); fprintf(fp, "Auto-Submitted: auto-replied\n"); -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC if (s) fprintf(fp, "From: %s\n", s); else @@ -324,23 +324,16 @@ switch(ident) fprintf(fp, "\n"); break; -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC case ERRMESS_DMARC_FORENSIC: bounce_return_message = TRUE; bounce_return_body = FALSE; - fprintf(fp, "Subject: DMARC Forensic Report for %s from IP %s\n\n", - eblock ? eblock->text2 : US"Unknown", - sender_host_address); - fprintf(fp, - "A message claiming to be from you has failed the published DMARC\n" - "policy for your domain.\n\n"); - while (eblock) - { - fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2); - count++; - eblock = eblock->next; - } - break; + for (; eblock; eblock = eblock->next) + if (eblock->text2) + fprintf(fp, " %s: %s\n", eblock->text1, eblock->text2); + else + fprintf(fp, "%s", eblock->text1); + break; #endif default: @@ -435,13 +428,13 @@ if (bounce_return_message) fputs(CS buf, fp); } } -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC /* Overkill, but use exact test in case future code gets inserted */ - else if (bounce_return_body && message_file == NULL) + else if (bounce_return_body && !message_file) { /*XXX limit line length here? */ /* This doesn't print newlines, disable until can parse and fix - * output to be legible. */ + output to be legible. */ fprintf(fp, "%s", expand_string(US"$message_body")); } #endif diff --git a/src/src/readconf.c b/src/src/readconf.c index 1fe2b2bfc..04cd5e68a 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -124,7 +124,7 @@ static optionlist optionlist_config[] = { { "dkim_verify_minimal", opt_module, {US"dkim"} }, { "dkim_verify_signers", opt_module, {US"dkim"} }, #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC { "dmarc_forensic_sender", opt_module, {US"dmarc"} }, { "dmarc_history_file", opt_module, {US"dmarc"} }, { "dmarc_tld_file", opt_module, {US"dmarc"} }, diff --git a/src/src/receive.c b/src/src/receive.c index cde09c40a..0f407ce93 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -16,7 +16,7 @@ extern int dcc_ok; #endif -#ifdef SUPPORT_DMARC +#ifdef EXIM_HAVE_DMARC # include "miscmods/dmarc.h" #endif @@ -1754,9 +1754,6 @@ BOOL date_header_exists = FALSE; /* Pointers to receive the addresses of headers whose contents we need. */ header_line * from_header = NULL; -#ifdef SUPPORT_DMARC -header_line * dmarc_from_header = NULL; -#endif header_line * subject_header = NULL, * msgid_header = NULL, * received_header; BOOL msgid_header_newly_created = FALSE; @@ -2454,8 +2451,16 @@ for (header_line * h = header_list->next; h; h = h->next) case htype_from: h->type = htype_from; -#ifdef SUPPORT_DMARC - if (!is_resent) dmarc_from_header = h; +#ifdef EXIM_HAVE_DMARC + if (!is_resent && !f.dmarc_disable_verify) + { + misc_module_info * mi = misc_mod_findonly(US"dmarc"); + if (mi) + { + typedef void (*fn_t)(const uschar *); + (((fn_t *) mi->functions)[DMARC_STORE_FROMHDR]) (h->text); + } + } #endif if (!resents_exist || is_resent) { @@ -3584,17 +3589,6 @@ else } #endif /* WITH_CONTENT_SCAN */ -#ifdef SUPPORT_DMARC - { - misc_module_info * mi = misc_mod_findonly(US"dmarc"); - if (mi) - { - typedef int (*fn_t)(header_line *); - (((fn_t *) mi->functions)[DMARC_STORE_DATA]) (dmarc_from_header); - } - } -#endif - #ifndef DISABLE_PRDR if (prdr_requested && recipients_count > 1) { diff --git a/src/src/regex_cache.c b/src/src/regex_cache.c index b92556d92..713da90d5 100644 --- a/src/src/regex_cache.c +++ b/src/src/regex_cache.c @@ -142,7 +142,7 @@ size_t offset; const pcre2_code * yield; int old_pool = store_pool, err; -/* Optionall, check the cache and return if found */ +/* Optionally, check the cache and return if found */ if ( flags & MCS_CACHEABLE && (yield = regex_from_cache(pattern, caseless))) commit 726e6f798bc2a18b019a23ba48ee6ddbf68ebf7f Author: Jeremy Harris Date: Fri Nov 14 11:58:10 2025 +0000 Build: fix spf dynamic-module build Broken-by: 998636a4f849 diff --git a/src/src/EDITME b/src/src/EDITME index d38ac98e5..a2dddd780 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -406,7 +406,8 @@ TRANSPORT_SMTP=yes # for the specialist case of using the DNS as a general database facility (not # common). # If set to "2" instead of "yes" then the corresponding lookup will be -# built as a module and must be installed into LOOKUP_MODULE_DIR. You need to +# built as a module and left in the "dynlibs" directory under the build +# directory. They must be installed into LOOKUP_MODULE_DIR. You need to # add -export-dynamic -rdynamic to EXTRALIBS. You may also need to add -ldl to # EXTRALIBS so that dlopen() is available to Exim. You need to define # LOOKUP_MODULE_DIR above so the exim binary actually loads dynamic lookup diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index ce314f7e5..bfce04fa7 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -86,11 +86,15 @@ return FAIL; gstring * spf_version_report(gstring * g) { +#if EXIM_HAVE_SPF == 2 +return g; +#else int maj, min, patch; SPF_get_lib_version(&maj, &min, &patch); return string_fmt_append(g, "Library version: SPF: Runtime: %d.%d.%d\n", maj, min, patch); +#endif } commit 03c4dd24276bfb43f5f803fa7c8cc83076f1c485 Author: Jeremy Harris Date: Fri Nov 14 12:11:10 2025 +0000 LDAP: fix version report under dynamic build diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 7d240309c..b73413a39 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1576,7 +1576,7 @@ if (ldap_get_option(ld, LDAP_OPT_API_INFO, &info) == LDAP_OPT_SUCCESS) g = string_fmt_append(g, " Runtime %s %d\n", info.ldapai_vendor_name, info.ldapai_vendor_version); - for (char ** sp = info.ldapai_extensions; *sp; *sp++) + for (char ** sp = info.ldapai_extensions; *sp; sp++) ldap_memfree(*sp); ldap_memfree(info.ldapai_extensions); ldap_memfree(info.ldapai_vendor_name); commit 11f6b4c7d34582a3b046345dd67d576b3fef920f Author: Jeremy Harris Date: Fri Nov 14 14:17:14 2025 +0000 DMARC: fix history-file ARC reporting, under dynamic build diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index 168e7da8e..059b31167 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -418,6 +418,9 @@ g = string_fmt_append(g, "align_dkim %d\n" gstring * g2 = NULL; typedef const uschar * (*fn_t)(gstring **); + if (!dmarc_arc_mod_info) + dmarc_arc_mod_info = misc_mod_findonly(US"arc"); + if ( dmarc_arc_mod_info && (s = (((fn_t *) dmarc_arc_mod_info->functions)[ARC_ARCSET_INFO]) (&g2))) { @@ -437,7 +440,7 @@ g = string_fmt_append(g, "align_dkim %d\n" else # endif - g = string_fmt_append(g, "arc %d\narc_policy %d json:[]\n", + g = string_fmt_append(g, "arc %d\narc_policy %d json[ ]\n", ARES_RESULT_UNKNOWN, DMARC_ARC_POLICY_RESULT_UNUSED); } #endif commit 68841125d8ba6168ae38de296273bdcd4df592c8 Author: Jeremy Harris Date: Sun Nov 16 15:16:53 2025 +0000 tidying diff --git a/src/src/functions.h b/src/src/functions.h index bd390cce6..73371cc7b 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1080,7 +1080,7 @@ if (gstring_last_char(g) == c) gstring_trim(g, 1); static inline void gstring_reset(gstring * g) { -g->ptr = 0; +g->s[g->ptr = 0] = '\0'; } diff --git a/src/src/host.c b/src/src/host.c index cfa2620df..28e08ee23 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -836,6 +836,7 @@ Returns: pointer to character string uschar * host_ntoa(int type, const void * arg, uschar * buffer, int * portptr) { +#define NTOA_BSIZE 46 uschar * yield; /* The new world. It is annoying that we have to fish out the address from @@ -845,7 +846,7 @@ function inet_ntoa() returns just uschar *, and some picky compilers insist on warning if one assigns a const uschar * to a uschar *. Hence the casts. */ #if HAVE_IPV6 -uschar addr_buffer[46]; +uschar addr_buffer[NTOA_BSIZE]; if (type < 0) { int family = ((struct sockaddr *)arg)->sa_family; @@ -888,7 +889,7 @@ else /* If there is no buffer, put the string into some new store. */ -if (!buffer) buffer = store_get(46, GET_UNTAINTED); +if (!buffer) buffer = store_get(NTOA_BSIZE, GET_UNTAINTED); /* Callers of this function with a non-NULL buffer must ensure that it is large enough to hold an IPv6 address, namely, at least 46 bytes. That's what @@ -896,9 +897,10 @@ makes this use of strcpy() OK. If the library returned apparently an apparently tainted string, clean it; we trust IP addresses. */ -string_format_nt(buffer, 46, "%s", yield); +string_format_nt(buffer, NTOA_BSIZE, "%s", yield); return buffer; } +#undef NTOA_BSIZE diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index ce4aaee4f..617517d84 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -299,7 +299,6 @@ dmarc_process(void) { const uschar * rr; BOOL has_dmarc_record = TRUE; -u_char ** ruf; /* forensic report addressees, if called for */ dmarc_alignment_spf = dmarc_alignment_dkim = FALSE; dmarc_dkim_alignment = DMARC_POLICY_DKIM_ALIGNMENT_FAIL; diff --git a/src/src/miscmods/pdkim/pdkim.c b/src/src/miscmods/pdkim/pdkim.c index a43ea9bfb..a7ec5f511 100644 --- a/src/src/miscmods/pdkim/pdkim.c +++ b/src/src/miscmods/pdkim/pdkim.c @@ -1000,10 +1000,12 @@ else last_sig->next = sig; } + /* Check for too many signatures */ + if (dkim_collect_input && --dkim_collect_input == 0) { ctx->headers = pdkim_prepend_stringlist(ctx->headers, g->s); - g->s[g->ptr = 0] = '\0'; + gstring_reset(g); return PDKIM_ERR_EXCESS_SIGS; } } @@ -1013,7 +1015,7 @@ else } BAIL: -g->s[g->ptr = 0] = '\0'; /* leave buffer for reuse */ +gstring_reset(g); /* leave buffer for reuse */ return PDKIM_OK; } commit 3c24de41ada52816d2890033b99eda0543a06b06 Author: Jeremy Harris Date: Fri Nov 21 11:54:08 2025 +0000 debug: indents diff --git a/src/OS/os.c-Linux b/src/OS/os.c-Linux index 34dd7c190..b7cd4e53a 100644 --- a/src/OS/os.c-Linux +++ b/src/OS/os.c-Linux @@ -140,7 +140,7 @@ while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", } DEBUG(D_interface) - debug_printf("Actual local interface address is %s (%s)\n", last->address, + debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, devname); } fclose(f); diff --git a/src/OS/unsupported/os.c-IRIX b/src/OS/unsupported/os.c-IRIX index 6f043d044..67725322b 100644 --- a/src/OS/unsupported/os.c-IRIX +++ b/src/OS/unsupported/os.c-IRIX @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX6 b/src/OS/unsupported/os.c-IRIX6 index 6f043d044..67725322b 100644 --- a/src/OS/unsupported/os.c-IRIX6 +++ b/src/OS/unsupported/os.c-IRIX6 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX632 b/src/OS/unsupported/os.c-IRIX632 index 6f043d044..67725322b 100644 --- a/src/OS/unsupported/os.c-IRIX632 +++ b/src/OS/unsupported/os.c-IRIX632 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX65 b/src/OS/unsupported/os.c-IRIX65 index 6f043d044..67725322b 100644 --- a/src/OS/unsupported/os.c-IRIX65 +++ b/src/OS/unsupported/os.c-IRIX65 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/src/host.c b/src/src/host.c index 28e08ee23..4c513e28c 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -413,7 +413,7 @@ else if (Ustrchr(h->name, ':') == p) h->name = string_copyn(h->name, p - h->name); else return PORT_NONE; -DEBUG(D_route|D_host_lookup) debug_printf("host=%s port=%d\n", h->name, port); +DEBUG(D_route|D_host_lookup) debug_printf_indent("host=%s port=%d\n", h->name, port); return port; } @@ -792,7 +792,7 @@ if (!local_interface_data) local_interface_data = add_unique_interface(local_interface_data, ipa); DEBUG(D_interface) { - debug_printf("Configured local interface: address=%s", ipa->address); + debug_printf_indent("Configured local interface: address=%s", ipa->address); if (ipa->port != 0) debug_printf(" port=%d", ipa->port); debug_printf("\n"); } @@ -1408,7 +1408,7 @@ while (host != *lastptr) if (h->next->address != NULL && Ustrcmp(h->next->address, host->address) == 0) { - DEBUG(D_host_lookup) debug_printf("duplicate IP address %s (MX=%d) " + DEBUG(D_host_lookup) debug_printf_indent("duplicate IP address %s (MX=%d) " "removed\n", host->address, h->next->mx); if (h->next == *lastptr) *lastptr = h; h->next = h->next->next; @@ -1490,7 +1490,7 @@ if ( slow_lookup_log if (!hosts) { - HDEBUG(D_host_lookup) debug_printf("IP address lookup failed: h_errno=%d\n", + HDEBUG(D_host_lookup) debug_printf_indent("IP address lookup failed: h_errno=%d\n", h_errno); return (h_errno == TRY_AGAIN || h_errno == NO_RECOVERY) ? DEFER : FAIL; } @@ -1602,7 +1602,7 @@ if (f.running_in_test_harness && Ustrcmp(sender_host_address, "99.99.99.99") == 0) { HDEBUG(D_host_lookup) - debug_printf("Test harness: host name lookup returns DEFER\n"); + debug_printf_indent("Test harness: host name lookup returns DEFER\n"); host_lookup_deferred = TRUE; yield = DEFER; goto out; @@ -1701,7 +1701,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) if (rc == DNS_AGAIN) { HDEBUG(D_host_lookup) - debug_printf("IP address PTR lookup gave temporary error\n"); + debug_printf_indent("IP address PTR lookup gave temporary error\n"); host_lookup_deferred = TRUE; yield = DEFER; goto out; @@ -1713,7 +1713,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) else if (strcmpic(ordername, US"byaddr") == 0) { HDEBUG(D_host_lookup) - debug_printf("IP address lookup using gethostbyaddr()\n"); + debug_printf_indent("IP address lookup using gethostbyaddr()\n"); rc = host_name_lookup_byaddr(); if (rc == DEFER) { @@ -1786,27 +1786,27 @@ for (uschar * hname = sender_host_name; hname; hname = *aliases++) for (host_item * hh = &h; hh; hh = hh->next) if (host_is_in_net(hh->address, sender_host_address, 0)) { - HDEBUG(D_host_lookup) debug_printf(" %s OK\n", hh->address); + HDEBUG(D_host_lookup) debug_printf_indent(" %s OK\n", hh->address); ok = TRUE; break; } else - HDEBUG(D_host_lookup) debug_printf(" %s\n", hh->address); + HDEBUG(D_host_lookup) debug_printf_indent(" %s\n", hh->address); if (!ok) HDEBUG(D_host_lookup) - debug_printf("no IP address for %s matched %s\n", hname, + debug_printf_indent("no IP address for %s matched %s\n", hname, sender_host_address); } else if (rc == HOST_FIND_AGAIN) { - HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n"); + HDEBUG(D_host_lookup) debug_printf_indent("temporary error for host name lookup\n"); host_lookup_deferred = TRUE; sender_host_name = NULL; yield = DEFER; goto out; } else - HDEBUG(D_host_lookup) debug_printf("no IP addresses found for %s\n", hname); + HDEBUG(D_host_lookup) debug_printf_indent("no IP addresses found for %s\n", hname); /* If this name is no good, and it's the sender name, set it null pro tem; if it's an alias, just remove it from the list. */ @@ -1835,7 +1835,7 @@ if (sender_host_name) { yield = OK; goto out; } /* We have failed to find an address that matches. */ HDEBUG(D_host_lookup) - debug_printf("%s does not match any IP address for %s\n", + debug_printf_indent("%s does not match any IP address for %s\n", sender_host_address, save_hostname); /* This message must be in permanent store */ @@ -2051,7 +2051,7 @@ for (int i = 1; i <= times; text_address, NULL) == OK) { DEBUG(D_host_lookup) - debug_printf("ignored host %s [%s]\n", host->name, text_address); + debug_printf_indent("ignored host %s [%s]\n", host->name, text_address); continue; } #endif @@ -2130,8 +2130,8 @@ yield = local_host_check? HDEBUG(D_host_lookup) { if (fully_qualified_name) - debug_printf("fully qualified name = %s\n", *fully_qualified_name); - debug_printf("%s looked up these IP addresses:\n", + debug_printf_indent("fully qualified name = %s\n", *fully_qualified_name); + debug_printf_indent("%s looked up these IP addresses:\n", #if HAVE_IPV6 #if HAVE_GETIPNODEBYNAME "getipnodebyname" @@ -2143,7 +2143,7 @@ HDEBUG(D_host_lookup) #endif ); for (const host_item * h = host; h != last->next; h = h->next) - debug_printf(" name=%s address=%s\n", h->name, + debug_printf_indent(" name=%s address=%s\n", h->name, h->address ? h->address : US""); } @@ -2165,7 +2165,7 @@ RETURN_AGAIN: deliver_domain = save; if (rc == OK) { - DEBUG(D_host_lookup) debug_printf("%s is in dns_again_means_nonexist: " + DEBUG(D_host_lookup) debug_printf_indent("%s is in dns_again_means_nonexist: " "returning HOST_FIND_FAILED\n", host->name); return HOST_FIND_FAILED; } @@ -2297,7 +2297,7 @@ for (; i >= 0; i--) && !dns_is_secure(dnsa) && dns_is_aa(dnsa) ) - debug_printf("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name); + debug_printf_indent("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name); /* We want to return HOST_FIND_AGAIN if one of the A or AAAA lookups fails or times out, but not if another one succeeds. (In the early @@ -2328,7 +2328,7 @@ for (; i >= 0; i--) { if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf("%s A DNSSEC\n", host->name); + DEBUG(D_host_lookup) debug_printf_indent("%s A DNSSEC\n", host->name); if (host->dnssec_used == DS_UNK) /* set in host_find_bydns() */ host->dnssec_used = DS_YES; } @@ -2337,13 +2337,13 @@ for (; i >= 0; i--) if (dnssec_require) { dnssec_fail = TRUE; - DEBUG(D_host_lookup) debug_printf("dnssec fail on %s for %.256s", + DEBUG(D_host_lookup) debug_printf_indent("dnssec fail on %s for %.256s", i>0 ? "AAAA" : "A", host->name); continue; } if (host->dnssec_used == DS_YES) /* set in host_find_bydns() */ { - DEBUG(D_host_lookup) debug_printf("%s A cancel DNSSEC\n", host->name); + DEBUG(D_host_lookup) debug_printf_indent("%s A cancel DNSSEC\n", host->name); host->dnssec_used = DS_NO; lookup_dnssec_authenticated = US"no"; } @@ -2364,7 +2364,7 @@ for (; i >= 0; i--) dns_address * da = dns_address_from_rr(dnsa, rr); DEBUG(D_host_lookup) - if (!da) debug_printf("no addresses extracted from A6 RR for %s\n", + if (!da) debug_printf_indent("no addresses extracted from A6 RR for %s\n", host->name); /* This loop runs only once for A and AAAA records, but may run @@ -2378,7 +2378,7 @@ for (; i >= 0; i--) host->name, da->address, NULL) == OK) { DEBUG(D_host_lookup) - debug_printf("ignored host %s [%s]\n", host->name, da->address); + debug_printf_indent("ignored host %s [%s]\n", host->name, da->address); continue; } #endif @@ -3198,7 +3198,7 @@ BOOL sec; rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname); sec = dns_is_secure(dnsa); DEBUG(D_transport) - debug_printf("TLSA lookup ret %s %sDNSSEC\n", dns_rc_names[rc], sec ? "" : "not "); + debug_printf_indent("TLSA lookup ret %s %sDNSSEC\n", dns_rc_names[rc], sec ? "" : "not "); switch (rc) { @@ -3221,7 +3221,7 @@ switch (rc) if (payload_length > MAX_TLSA_EXPANDED_SIZE) payload_length = MAX_TLSA_EXPANDED_SIZE; - debug_printf(" %d %d %d %.*H\n", + debug_printf_indent(" %d %d %d %.*H\n", usage, selector, matching_type, payload_length, p); } } diff --git a/src/src/os.c b/src/src/os.c index 4a054ac50..4b9d2d1d5 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -528,7 +528,7 @@ for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s (%s)\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, ifa->ifa_name); } @@ -761,7 +761,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len) last = next; } - DEBUG(D_interface) debug_printf("Actual local interface address is %s (%s)\n", + DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, ifreq.V_ifr_name); } diff --git a/src/src/routers/rf_lookup_hostlist.c b/src/src/routers/rf_lookup_hostlist.c index 0a3a71ba9..59e0761ea 100644 --- a/src/src/routers/rf_lookup_hostlist.c +++ b/src/src/routers/rf_lookup_hostlist.c @@ -73,6 +73,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) DEBUG(D_route|D_host_lookup) debug_printf_indent("finding IP address for %s\n", h->name); + expand_level++; /* Handle any port setting that may be on the name; it will be removed from the end of the name. */ @@ -164,12 +165,14 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) if (rc == HOST_FIND_SECURITY) { + expand_level--; addr->message = string_sprintf("host lookup for %s done insecurely" , h->name); addr->basic_errno = ERRNO_DNSDEFER; return DEFER; } if (rc == HOST_FIND_AGAIN) { + expand_level--; if (rblock->pass_on_timeout) { DEBUG(D_route) @@ -187,6 +190,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) if (rc == HOST_FIND_FAILED) { + expand_level--; if (hff_code == hff_ignore) { if (prev == NULL) addr->host_list = next_h; else prev->next = next_h; @@ -238,6 +242,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) } prev->next = NULL; setflag(addr, af_local_host_removed); + expand_level--; break; } rc = rf_self_action(addr, h, rblock->self_code, rblock->self_rewrite, @@ -245,6 +250,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) if (rc != OK) { addr->host_list = NULL; /* Kill the host list for */ + expand_level--; return rc; /* anything other than "send" */ } self_send = TRUE; @@ -255,6 +261,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) prev = h; while (prev->next != next_h) prev = prev->next; + expand_level--; } return OK; diff --git a/src/src/routers/rf_self_action.c b/src/src/routers/rf_self_action.c index 75fbaa400..dba0774f8 100644 --- a/src/src/routers/rf_self_action.c +++ b/src/src/routers/rf_self_action.c @@ -95,25 +95,25 @@ switch (code) case self_reroute: DEBUG(D_route) - debug_printf("%s: %s: domain changed to %s\n", msg, addr->domain, new); + debug_printf_indent("%s: %s: domain changed to %s\n", msg, addr->domain, new); rf_change_domain(addr, new, rewrite, addr_new); return REROUTED; case self_send: DEBUG(D_route) - debug_printf("%s: %s: configured to try delivery anyway\n", msg, addr->domain); + debug_printf_indent("%s: %s: configured to try delivery anyway\n", msg, addr->domain); return OK; case self_pass: /* This is soft failure; pass to next router */ DEBUG(D_route) - debug_printf("%s: %s: passed to next router (self = pass)\n", msg, addr->domain); + debug_printf_indent("%s: %s: passed to next router (self = pass)\n", msg, addr->domain); addr->message = msg; addr->self_hostname = string_copy(host->name); return PASS; case self_fail: DEBUG(D_route) - debug_printf("%s: %s: address failed (self = fail)\n", msg, addr->domain); + debug_printf_indent("%s: %s: address failed (self = fail)\n", msg, addr->domain); addr->message = msg; setflag(addr, af_pass_message); return FAIL; commit d2353fcd8f602a1f4fdeb31ae006e6b7bc46b349 Author: Jeremy Harris Date: Fri Nov 21 14:17:39 2025 +0000 fix TLS held-open verify to delivery diff --git a/src/src/daemon.c b/src/src/daemon.c index a31ef1eb5..056bf6311 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -709,11 +709,8 @@ if (pid == 0) signal(SIGINT, SIG_DFL); if (geteuid() != root_uid && !deliver_drop_privilege) - { - signal(SIGALRM, SIG_DFL); delivery_re_exec(CEE_EXEC_PANIC); /* Control does not return here. */ - } /* No need to re-exec; SIGALRM remains set to the default handler */ diff --git a/src/src/deliver.c b/src/src/deliver.c index 3dc1aef73..c978e67b5 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -9011,7 +9011,6 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) { int channel_fd = cutthrough.cctx.sock; - smtp_peer_options = cutthrough.peer_options; continue_sequence = 0; #ifndef DISABLE_TLS @@ -9019,9 +9018,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) { int pfd[2], pid; - smtp_peer_options |= OPTION_TLS; - sending_ip_address = cutthrough.snd_ip; - sending_port = cutthrough.snd_port; + cutthrough.peer_options |= OPTION_TLS; where = US"socketpair"; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0) @@ -9034,7 +9031,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) if (pid == 0) /* child: will fork again to totally disconnect */ { - smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size, + smtp_proxy_tls(&cutthrough.cctx, big_buffer, big_buffer_size, pfd, 5*60, cutthrough.host.name); /* does not return */ } @@ -9046,8 +9043,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) } #endif - transport_do_pass_socket(cutthrough.transport, cutthrough.host.name, - cutthrough.host.address, cutthrough.host.port, message_id, channel_fd); + transport_do_pass_socket(message_id, channel_fd); } else { diff --git a/src/src/exim.c b/src/src/exim.c index c23eb868c..a50303049 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -405,13 +405,13 @@ Returns: nothing */ static void -milliwait(struct itimerval *itval) +milliwait(struct itimerval * itval) { sigset_t sigmask; sigset_t old_sigmask; int save_errno = errno; -if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec == 0) +if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec <= 0) return; (void)sigemptyset(&sigmask); /* Empty mask */ (void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */ @@ -3000,7 +3000,16 @@ on the second character (the one after '-'), to save some effort. */ if (!continue_proxy_cipher) if (getsockname(0, (struct sockaddr *)(&tmp_sock), &size) == 0) - sending_ip_address = host_ntoa(-1, &tmp_sock, NULL, &sending_port); + switch (tmp_sock.v0.sa_family) + { + case AF_INET: + case AF_INET6: + sending_ip_address = + host_ntoa(-1, &tmp_sock, NULL, &sending_port); + break; + default: + exim_fail("non-INET socket on stdin for -MC option"); + } else exim_fail("getsockname() failed after -MC option: %s", strerror(errno)); diff --git a/src/src/functions.h b/src/src/functions.h index 73371cc7b..937259334 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -551,7 +551,7 @@ extern void smtp_log_no_mail(void); extern void smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL); extern void smtp_notquit_exit(const uschar *, uschar *, const uschar *, ...); extern void smtp_port_for_connect(host_item *, int); -extern void smtp_proxy_tls(void *, uschar *, size_t, int *, int, const uschar *) NORETURN; +extern void smtp_proxy_tls(client_conn_ctx *, uschar *, size_t, int *, int, const uschar *) NORETURN; extern BOOL smtp_read_response(void *, uschar *, int, int, int); rmark smtp_reset(rmark); extern void smtp_respond(uschar *, int, BOOL, uschar *); @@ -662,8 +662,7 @@ extern uschar *tod_stamp(int); extern BOOL transport_check_waiting(const uschar *, const uschar *, int, uschar *, oicf, void*); extern uschar *transport_current_name(void); -extern void transport_do_pass_socket(const uschar *, const uschar *, - const uschar *, int, uschar *, int); +extern void transport_do_pass_socket(uschar *, int); extern void transport_init(void); extern const uschar *transport_rcpt_address(address_item *, BOOL); extern BOOL transport_set_up_command(const uschar ***, const uschar *, diff --git a/src/src/globals.c b/src/src/globals.c index 36f364996..38fdbc7a3 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -665,14 +665,8 @@ open_db *continue_wait_db = NULL; #endif uschar *csa_status = NULL; -cut_t cutthrough = { - .callout_hold_only = FALSE, /* verify-only: normal delivery */ - .delivery = FALSE, /* when to attempt */ - .tpt_sender = FALSE, /* use tpt's sender */ - .defer_pass = FALSE, /* on defer: spool locally */ - .is_tls = FALSE, /* not a TLS conn yet */ +cut_t cutthrough = { /* All remaining items 0/FALSE/NULL */ .cctx = {.sock = -1}, /* open connection */ - .nrcpt = 0, /* number of addresses */ }; int daemon_notifier_fd = -1; diff --git a/src/src/globals.h b/src/src/globals.h index 9f4d04a2d..1c133f5ea 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -474,11 +474,14 @@ extern open_db *continue_wait_db; /* Hintsdb for wait-transport */ extern uschar *csa_status; /* Client SMTP Authorization result */ typedef struct { - unsigned callout_hold_only:1; /* Conn is only for verify callout */ - unsigned delivery:1; /* When to attempt */ - unsigned tpt_sender:1; /* Use tpt-defined sender */ - unsigned defer_pass:1; /* Pass 4xx to caller rather than spooling */ - unsigned is_tls:1; /* Conn has TLS active */ + BOOL callout_hold_only:1; /* Conn is only for verify callout */ + BOOL delivery:1; /* When to attempt */ + BOOL tpt_sender:1; /* Use tpt-defined sender */ + BOOL defer_pass:1; /* Pass 4xx to caller rather than spooling */ + BOOL is_tls:1; /* Conn has TLS active */ + BOOL is_dane:1; + uschar * sni; + uschar * cipher; client_conn_ctx cctx; /* Open connection */ int nrcpt; /* Count of addresses */ uschar * transport; /* Name of transport */ diff --git a/src/src/transport.c b/src/src/transport.c index a59a5ae3d..5d3b8a732 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -2025,16 +2025,17 @@ retfalse: * Deliver waiting message down same socket * *************************************************/ -/* Just the regain-root-privilege exec portion */ +/* Just the regain-root-privilege exec portion. +The sole caller is delivery_re_exec(). */ + void -transport_do_pass_socket(const uschar * transport_name, const uschar * hostname, - const uschar * hostaddress, int hostport, uschar * id, int socket_fd) +transport_do_pass_socket(uschar * id, int socket_fd) { int i = 14; const uschar **argv; #ifndef DISABLE_TLS -if (smtp_peer_options & OPTION_TLS) i += 6; +if (cutthrough.peer_options & OPTION_TLS) i += 6; #endif #ifndef DISABLE_ESMTP_LIMITS if (continue_limit_mail || continue_limit_rcpt || continue_limit_rcptdom) @@ -2051,27 +2052,27 @@ but we have a number of extras that may be added. */ argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); if (f.smtp_authenticated) argv[i++] = US"-MCA"; -if (smtp_peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK"; -if (smtp_peer_options & OPTION_DSN) argv[i++] = US"-MCD"; -if (smtp_peer_options & OPTION_PIPE) argv[i++] = US"-MCP"; -if (smtp_peer_options & OPTION_SIZE) argv[i++] = US"-MCS"; +if (cutthrough.peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK"; +if (cutthrough.peer_options & OPTION_DSN) argv[i++] = US"-MCD"; +if (cutthrough.peer_options & OPTION_PIPE) argv[i++] = US"-MCP"; +if (cutthrough.peer_options & OPTION_SIZE) argv[i++] = US"-MCS"; #ifndef DISABLE_TLS -if (smtp_peer_options & OPTION_TLS) - if (tls_out.active.sock >= 0 || continue_proxy_cipher) +if (cutthrough.peer_options & OPTION_TLS) + if (cutthrough.is_tls) { argv[i++] = US"-MCt"; - argv[i++] = sending_ip_address; - argv[i++] = string_sprintf("%d", sending_port); - argv[i++] = tls_out.active.sock >= 0 ? tls_out.cipher : continue_proxy_cipher; + argv[i++] = cutthrough.snd_ip; + argv[i++] = string_sprintf("%d", cutthrough.snd_port); + argv[i++] = cutthrough.cipher; - if (tls_out.sni) + if (cutthrough.sni) { argv[i++] = #ifdef SUPPORT_DANE - tls_out.dane_verified ? US"-MCr" : + cutthrough.is_dane ? US"-MCr" : #endif US"-MCs"; - argv[i++] = tls_out.sni; + argv[i++] = cutthrough.sni; } } else @@ -2107,11 +2108,11 @@ if (proxy_session) #endif argv[i++] = US"-MC"; -argv[i++] = US transport_name; -argv[i++] = US hostname; -argv[i++] = US hostaddress; -argv[i++] = string_sprintf("%d", hostport); -argv[i++] = string_sprintf("%d", continue_sequence + 1); +argv[i++] = US cutthrough.transport; +argv[i++] = US cutthrough.host.name; +argv[i++] = US cutthrough.host.address; +argv[i++] = string_sprintf("%d", cutthrough.host.port); +argv[i++] = string_sprintf("%d", continue_sequence + 1); /*XXX always 0+1 */ argv[i++] = id; argv[i++] = NULL; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 36b6370fd..7160f0616 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -3881,7 +3881,7 @@ Do blocking full-size writes, and reads under a timeout. Once both input channels are closed, exit the process. Arguments: - ct_ctx tls context + ctx client context buf space to use for buffering bufsiz size of buffer pfd pipe filedescriptor array; [0] is comms to proxied process @@ -3892,11 +3892,12 @@ Does not return. */ void -smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd, +smtp_proxy_tls(client_conn_ctx * ctx, uschar * buf, size_t bsize, int * pfd, int timeout, const uschar * host) { -struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN}, +struct pollfd p[2] = {{.fd = ctx->sock, .events = POLLIN}, {.fd = pfd[0], .events = POLLIN}}; +void * tls_ctx = ctx->tls_ctx; int rc, i; BOOL send_tls_shutdown = TRUE; @@ -3930,7 +3931,7 @@ do if (p[0].revents & POLLERR || p[1].revents & POLLERR) { - DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n", + DEBUG(D_transport) debug_printf("poll: err cond on %s fd\n", p[0].revents & POLLERR ? "tls" : "proxy"); if (!(p[0].revents & POLLIN || p[1].events & POLLIN)) goto done; @@ -3941,7 +3942,7 @@ do /* handle inbound data */ if (p[0].revents & POLLIN) - if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0) /* Expect -1 for EOF; */ + if ((rc = tls_read(tls_ctx, buf, bsize)) <= 0) /* Expect -1 for EOF; */ { /* that reaps the TLS Close Notify record */ p[0].fd = -1; shutdown(pfd[0], SHUT_WR); @@ -3965,19 +3966,19 @@ do # ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */ (void) setsockopt(tls_out.active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); # endif - tls_shutdown_wr(ct_ctx); + tls_shutdown_wr(tls_ctx); send_tls_shutdown = FALSE; shutdown(tls_out.active.sock, SHUT_WR); } else for (int nbytes = 0; rc - nbytes > 0; nbytes += i) - if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0) + if ((i = tls_write(tls_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0) goto done; } while (p[0].fd >= 0 || p[1].fd >= 0); done: - if (send_tls_shutdown) tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT); + if (send_tls_shutdown) tls_close(tls_ctx, TLS_SHUTDOWN_NOWAIT); testharness_pause_ms(100); /* let logging complete */ exim_exit(EXIT_SUCCESS); } @@ -5108,7 +5109,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) if (pid == 0) /* child; fork again to disconnect totally */ { /* does not return */ - smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), + smtp_proxy_tls(&sx->cctx, sx->buffer, sizeof(sx->buffer), pfd, ob->command_timeout, host->name); } diff --git a/src/src/verify.c b/src/src/verify.c index 1fee97150..84134e49c 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1157,7 +1157,12 @@ no_conn: ? "cutthrough delivery" : "potential further verifies and delivery"); cutthrough.callout_hold_only = !cutthrough.delivery; - cutthrough.is_tls = tls_out.active.sock >= 0; + if ((cutthrough.is_tls = tls_out.active.sock >= 0)) + { + cutthrough.is_dane = tls_out.sni && tls_out.dane_verified; + cutthrough.sni = tls_out.sni; + cutthrough.cipher = tls_out.cipher; + } /* We assume no buffer in use in the outblock */ cutthrough.cctx = sx->cctx; cutthrough.nrcpt = 1; commit 1fd121860e713f4d2783be54939b92a297a82dd4 Author: Jeremy Harris Date: Fri Nov 21 14:37:12 2025 +0000 fix non-DANE build Broken-by: d2353fcd8f60 diff --git a/src/src/verify.c b/src/src/verify.c index 84134e49c..18c53c1e8 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1159,7 +1159,9 @@ no_conn: cutthrough.callout_hold_only = !cutthrough.delivery; if ((cutthrough.is_tls = tls_out.active.sock >= 0)) { +#ifdef SUPPORT_DANE cutthrough.is_dane = tls_out.sni && tls_out.dane_verified; +#endif cutthrough.sni = tls_out.sni; cutthrough.cipher = tls_out.cipher; } commit 9ecbb33982299a8d83a72d4dcd951949e5cfb81e Author: Jeremy Harris Date: Sun Nov 23 10:35:12 2025 +0000 Local-scan: bump API minor version Things like constification and ifdeffed-feature removal have, strictly, affected the API definition diff --git a/src/src/exim.c b/src/src/exim.c index a50303049..32ca1e1d2 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1125,6 +1125,9 @@ g = string_cat(g, US"Support for:"); #ifdef WITH_CONTENT_SCAN g = string_cat(g, US" Content_Scanning"); #endif +#ifdef HAVE_LOCAL_SCAN + g = string_cat(g, US" Local_Scan"); +#endif #ifndef DISABLE_EXIM_FILTER g = string_cat(g, US" Exim_filter"); #endif @@ -1282,6 +1285,7 @@ DEBUG(D_any) #else g = string_cat(g, US"Compiler: \n"); #endif +/*XXX Sun Studio compiler? */ #if defined(__GLIBC__) && !defined(__UCLIBC__) g = string_fmt_append(g, "Library version: Glibc: Compile: %d.%d\n", @@ -1344,6 +1348,10 @@ Currently they are output in misc_mod_add() */ g = string_fmt_append(g, "TRUSTED_CONFIG_LIST: %q\n", TRUSTED_CONFIG_LIST); #else g = string_cat(g, US"TRUSTED_CONFIG_LIST unset\n"); +#endif +#ifdef HAVE_LOCAL_SCAN + g = string_cat(g, US"Local-Scan API: " + mac_expanded_string(LOCAL_SCAN_ABI_VERSION) "\n"); #endif } diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 355487b0d..915b12007 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -44,7 +44,7 @@ each time a new feature is added (in a way that doesn't break backward compatibility). */ #define LOCAL_SCAN_ABI_VERSION_MAJOR 6 -#define LOCAL_SCAN_ABI_VERSION_MINOR 0 +#define LOCAL_SCAN_ABI_VERSION_MINOR 1 #define LOCAL_SCAN_ABI_VERSION \ LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR commit 66a452cb6128ddc0805eac37230afd77d6fb168c Author: Jeremy Harris Date: Sun Nov 23 14:18:54 2025 +0000 Local-scan: fix API Broken-by: 7b4e2a15a529 diff --git a/src/src/functions.h b/src/src/functions.h index 937259334..76bc24c1b 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -238,19 +238,6 @@ extern int exp_bool(address_item *, extern BOOL expand_check_condition(const uschar *, const uschar *, const uschar *); extern uschar *expand_file_big_buffer(const uschar *); -extern const uschar *expand_string_2(const uschar *, BOOL *); - -static inline uschar * expand_nc_string(uschar * s) -{ return US expand_string_2(s, NULL); } -static inline const uschar * expand_c_string(const uschar * s) -{ return expand_string_2(s, NULL); } - -/* A macro that picks which function to use depending on the type of the arg */ -#define expand_string(X) _Generic((X), \ - uschar *: expand_nc_string, \ - const uschar *: expand_c_string \ - )(X) - extern BOOL expand_string_nonempty(const uschar *); extern uschar *expand_getkeyed(const uschar *, const uschar *); diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 915b12007..5aff615e7 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -193,7 +193,19 @@ extern BOOL smtp_input; /* TRUE if input is via SMTP */ extern int child_close(pid_t, int); extern void debug_printf(const char *, ...) PRINTF_FUNCTION(1,2); -extern uschar *expand_string(uschar *); + +extern const uschar * expand_string_2(const uschar *, BOOL *); +static inline uschar * expand_nc_string(uschar * s) +{ return US expand_string_2(s, NULL); } +static inline const uschar * expand_c_string(const uschar * s) +{ return expand_string_2(s, NULL); } + +/* A macro that picks which function to use depending on the type of the arg */ +#define expand_string(X) _Generic((X), \ + uschar *: expand_nc_string, \ + const uschar *: expand_c_string \ + )(X) + extern void header_add(int, const char *, ...); extern void header_add_at_position(BOOL, uschar *, BOOL, int, const char *, ...); extern void header_remove(int, const uschar *); diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index e6c9dbacc..674bdd785 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1798,6 +1798,9 @@ deliver_host = deliver_host_address = NULL; /* Can be set by ACL */ #ifdef SUPPORT_SRS srs_recipient = NULL; #endif +#ifdef HAVE_LOCAL_SCAN +local_scan_data = NULL; +#endif #ifdef WITH_CONTENT_SCAN regex_vars_clear(); malware_name = NULL; commit 5921ece54a48e3d773293b280722fb0e34a66539 Author: Jeremy Harris Date: Mon Nov 24 12:27:09 2025 +0000 Testsuite: add testcases for dbmjz/dbmnz under sqlite diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 30015fe73..7c2dbcce3 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -403,10 +403,7 @@ unsigned dlen; memcpy(key_copy, key, klen); -/*XXX the %.*s will terminate early on a key with embedded NUL (legit for -lookup dbmjz). We do not have a convenient function; maybe extend -string_printing2() ? */ -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%.*s\n", klen, key); +DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%.*W\n", klen, key); exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ exim_datum_init(&result_datum); /* to be cleared before use. */ commit 89c878362b94d35fa662e02a8834238b699762d7 Author: Jeremy Harris Date: Sat Nov 29 12:51:38 2025 +0000 extend string-formatting facility diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 99ea5c826..e3ef848d3 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -44,7 +44,7 @@ uschar * readconf_printtime(int t) { return NULL; } const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) -{return NULL; } +{ return NULL; } void * store_get_3(int size, const void * proto_mem, const char *filename, int linenumber) { return NULL; } @@ -55,9 +55,6 @@ void store_release_above_3(void *ptr, const char *func, int linenumber) { } gstring * -string_catn(gstring * g, const uschar * s, int count) -{ return NULL; } -gstring * string_vformat_trc(gstring * g, const uschar * func, unsigned line, unsigned size_limit, unsigned flags, const char *format, va_list ap) { return NULL; } diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 5065b6e9b..30d446bad 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -62,9 +62,6 @@ uschar * readconf_printtime(int t) { return NULL; } const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) -{return NULL; } -gstring * -string_catn(gstring * g, const uschar * s, int count) { return NULL; } gstring * string_vformat_trc(gstring * g, const uschar * func, unsigned line, diff --git a/src/src/string.c b/src/src/string.c index 474f4a1bb..472008382 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -15,6 +15,11 @@ utilities and tests, and are cut out by the COMPILE_UTILITY macro. */ #include +#ifdef COMPILE_UTILITY +BOOL print_topbitchars = FALSE; /* referenced by string_printing3() */ +#endif + + #ifndef COMPILE_UTILITY /************************************************* * Test for IP address * @@ -310,7 +315,6 @@ return ch; -#ifndef COMPILE_UTILITY /************************************************* * Ensure string is printable * *************************************************/ @@ -325,19 +329,20 @@ Arguments: flags Bit 0: convert tabs. Bit 1: convert spaces. Bit 2: convert doublequotes. + len if >= 0, max size of string + otherwise, NUL-terminated Returns: string with non-printers encoded as printing sequences */ const uschar * -string_printing2(const uschar * s, int flags) +string_printing3(const uschar * s, int flags, int len) { -int nonprintcount = 0; -int length = 0; -const uschar *t = s; -uschar *ss, *tt; +int nonprintcount = 0, olen = 0; +const uschar * t = s; +uschar * ss, * tt; -while (*t) +for (int n = len; n != 0 && *t; n--) { int c = *t++; if ( !mac_isprint(c) @@ -345,7 +350,7 @@ while (*t) || flags & SP_SPACE && c == ' ' || flags & SP_DQUOTES && c == '"' ) nonprintcount++; - length++; + olen++; } if (nonprintcount == 0) return s; @@ -353,13 +358,15 @@ if (nonprintcount == 0) return s; /* Get a new block of store guaranteed big enough to hold the expanded string. */ -tt = ss = store_get(length + nonprintcount * 3 + 1, s); +tt = ss = store_get(olen + nonprintcount * 3 + 1, s); /* Copy everything, escaping non printers. */ for (t = s; *t; ) { int c = *t; + /*XXX does \ go through unchanged here? Since we use it for escaping, + surely it should be doubled? */ if ( mac_isprint(c) && (!(flags & SP_TAB) || c != '\t') && (!(flags & SP_SPACE) || c != ' ') @@ -386,7 +393,12 @@ for (t = s; *t; ) *tt = 0; return ss; } -#endif /* COMPILE_UTILITY */ + +const uschar * +string_printing2(const uschar * s, int flags) +{ +return string_printing3(s, flags, -1); +} /************************************************* * Undo printing escapes in string * @@ -1215,6 +1227,7 @@ if (!store_extend(g->s, oldsize, g->size)) g->s = store_newblock(g->s, g->size, p); } +#endif /*!COMPILE_UTILITY*/ /************************************************* @@ -1290,6 +1303,7 @@ return g; +#ifndef COMPILE_UTILITY /************************************************* * Append strings to another string * *************************************************/ @@ -1410,15 +1424,15 @@ enum ltypes { L_NORMAL=1, L_SHORT=2, L_LONG=3, L_LONGLONG=4, L_LONGDOUBLE=5, L_S int width, precision, initial_off, lim, need; const char * fp = format; /* Deliberately not unsigned */ -string_datestamp_offset = -1; /* Datestamp not inserted */ -string_datestamp_length = 0; /* Datestamp not inserted */ -string_datestamp_type = 0; /* Datestamp not inserted */ - #ifdef COMPILE_UTILITY assert(!(flags & SVFMT_EXTEND)); assert(g); #else +string_datestamp_offset = -1; /* Datestamp not inserted */ +string_datestamp_length = 0; /* Datestamp not inserted */ +string_datestamp_type = 0; /* Datestamp not inserted */ + /* Ensure we have a string, to save on checking later */ if (!g) g = string_get(16); @@ -1532,7 +1546,7 @@ while (*fp) gp = CS g->s + g->ptr; } strncpy(newformat, item_start, fp - item_start); - newformat[fp - item_start] = 0; + newformat[fp - item_start] = '\0'; /* Short int is promoted to int when passing through ..., so we must use int for va_arg(). */ @@ -1566,7 +1580,7 @@ while (*fp) if ((ptr = va_arg(ap, void *))) { strncpy(newformat, item_start, fp - item_start); - newformat[fp - item_start] = 0; + newformat[fp - item_start] = '\0'; g->ptr += sprintf(gp, newformat, ptr); } else @@ -1595,7 +1609,7 @@ while (*fp) gp = CS g->s + g->ptr; } strncpy(newformat, item_start, fp - item_start); - newformat[fp-item_start] = 0; + newformat[fp-item_start] = '\0'; if (length == L_LONGDOUBLE) g->ptr += sprintf(gp, newformat, va_arg(ap, long double)); else @@ -1624,6 +1638,7 @@ while (*fp) g->s[g->ptr++] = (uschar) va_arg(ap, int); break; +#ifndef COMPILE_UTILITY case 'D': /* Insert daily datestamp for log file names */ s = CS tod_stamp(tod_log_datestamp_daily); string_datestamp_offset = g->ptr; /* Passed back via global */ @@ -1639,6 +1654,7 @@ while (*fp) string_datestamp_type = tod_log_datestamp_monthly; slen = string_datestamp_length; goto INSERT_STRING; +#endif case 'Y': /* gstring pointer */ { @@ -1782,12 +1798,14 @@ while (*fp) { s = ""; precision = slen = 6; } } goto INSERT_GSTRING; +#endif case 'q': /* string, to be wrapped in "" and with tab & " escaped */ if ((s = va_arg(ap, char *))) { gstring * zg = string_catn(NULL, US"\"", 1); - zg = string_cat(zg, string_printing2(US s, SP_TAB | SP_DQUOTES)); + zg = string_cat(zg, + string_printing3(US s, SP_TAB | SP_DQUOTES, precision)); zg = string_catn(zg, US"\"", 1); s = CS zg->s; precision = slen = gstring_length(zg); } @@ -1795,7 +1813,6 @@ while (*fp) { s = ""; precision = slen = 6; } goto INSERT_GSTRING; -#endif case 's': case 'S': /* Forces *lower* case */ case 'T': /* Forces *upper* case */ @@ -1876,7 +1893,7 @@ while (*fp) default: strncpy(newformat, item_start, fp - item_start); - newformat[fp-item_start] = 0; + newformat[fp-item_start] = '\0'; log_write_die(0, LOG_MAIN, "string_format: unsupported type " "in %q in %q", newformat, format); break; commit e4e66eda1683cfd3a6658b39c21be91a7ca99df0 Author: Jeremy Harris Date: Sat Nov 29 14:01:04 2025 +0000 local_scan: bump API version, for smtp_fflush() Broken-by: 9682a4923d1d diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 5aff615e7..c9d179375 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -43,8 +43,8 @@ ABI is changed in a non backward compatible way. The minor number is increased each time a new feature is added (in a way that doesn't break backward compatibility). */ -#define LOCAL_SCAN_ABI_VERSION_MAJOR 6 -#define LOCAL_SCAN_ABI_VERSION_MINOR 1 +#define LOCAL_SCAN_ABI_VERSION_MAJOR 7 +#define LOCAL_SCAN_ABI_VERSION_MINOR 0 #define LOCAL_SCAN_ABI_VERSION \ LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR commit 34b791b30d336dd78db0ded8c9b9790fdfa8f3c9 Author: Jeremy Harris Date: Sun Nov 16 15:23:56 2025 +0000 fix build with perl-spf diff --git a/src/scripts/lookups-Makefile b/src/scripts/lookups-Makefile index 6555e820c..7aa186e2e 100755 --- a/src/scripts/lookups-Makefile +++ b/src/scripts/lookups-Makefile @@ -158,7 +158,7 @@ sed -n "1,/$tag_marker/p" < "$input" for name_mod in \ CDB DBM:dbmdb DNSDB DSEARCH JSON LMDB LDAP LSEARCH MYSQL NIS NISPLUS \ - NMH ORACLE PASSWD PGSQL PSL REDIS SQLITE SPF TESTDB WHOSON + NMH ORACLE PASSWD PGSQL PSL REDIS SQLITE SPF SPF_PERL:spf TESTDB WHOSON do emit_module_rule $name_mod done diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index 33871c9aa..3008facc8 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -127,7 +127,7 @@ spf_lib_version_report(gstring * g) { /*XXX Does Mail::SPF have a version? MetaCPAN says yes, but does not document a method that returns it. */ -return string_fmt_append(g, "Library_version: SPF: perl Mail::SPF\n"); +return string_cat(g, US"Library_version: SPF: perl Mail::SPF\n"); } commit 21811ff3fd95a5325c665cb28b1d65e612a179dc Author: Jeremy Harris Date: Tue Nov 18 18:03:39 2025 +0000 Testsuite: fix for perl-spf dynamic build diff --git a/src/src/EDITME b/src/src/EDITME index a2dddd780..1c9d834dd 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -412,6 +412,7 @@ TRANSPORT_SMTP=yes # EXTRALIBS so that dlopen() is available to Exim. You need to define # LOOKUP_MODULE_DIR above so the exim binary actually loads dynamic lookup # modules. +# # Also, instead of adding all the libraries/includes to LOOKUP_INCLUDE and # LOOKUP_LIBS, add them to the respective LOOKUP_*_INCLUDE and LOOKUP_*_LIBS # (where * is the name as given here in this list). That ensures that only @@ -1170,6 +1171,7 @@ ZCAT_COMMAND=/usr/bin/zcat # SUPPORT_SPF=yes # CFLAGS += -I/usr/local/include # LDFLAGS += -lspf2 +# SUPPORT_SPF_LIBS= -lspf2 #------------------------------------------------------------------------------ diff --git a/src/src/drtables.c b/src/src/drtables.c index 9e25472d3..87ff8da61 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -185,9 +185,13 @@ if (info->magic != LOOKUP_MODULE_INFO_MAGIC) } addlookupmodule(info); -EARLY_DEBUG(D_lookup, "Loaded %q (%d lookup type%s)\n", +if (debug_startup) + { EARLY_DEBUG(D_lookup, "Loaded %q (%d lookup type%s)\n", name, info->lookupcount, - info->lookupcount > 1 ? "s" : ""); + info->lookupcount > 1 ? "s" : ""); } +else + DEBUG(D_lookup) debug_printf_indent("Loaded module %q\n", name); + return TRUE; } @@ -341,7 +345,8 @@ if ((mi = misc_mod_findonly(name))) return mi; #ifdef LOOKUP_MODULE_DIR return misc_mod_load(name, errstr); #else -*errstr = string_sprintf("module '%s' not found", name); +*errstr = string_sprintf("module %q not built-in, and" + "no setting for LOOKUP_MODULE_DIR", name); return NULL; #endif /*LOOKUP_MODULE_DIR*/ } @@ -470,7 +475,7 @@ else closedir(dd); } -EARLY_DEBUG(D_lookup, "Loaded %d lookup modules\n", countmodules); +EARLY_DEBUG(D_lookup, "Loaded %d dynamic lookup modules\n", countmodules); #endif } diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index e3ef848d3..8cb06fefe 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -55,6 +55,9 @@ void store_release_above_3(void *ptr, const char *func, int linenumber) { } gstring * +string_catn(gstring * g, const uschar * s, int count) +{ return NULL; } +gstring * string_vformat_trc(gstring * g, const uschar * func, unsigned line, unsigned size_limit, unsigned flags, const char *format, va_list ap) { return NULL; } diff --git a/src/src/lookups/json.c b/src/src/lookups/json.c index 3e5f9609e..92da9b9cb 100644 --- a/src/src/lookups/json.c +++ b/src/src/lookups/json.c @@ -157,8 +157,6 @@ json_close(void *handle) /* See local README for interface description. */ -#include "../version.h" - gstring * json_version_report(gstring * g) { diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index b73413a39..0a00633ab 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -1558,8 +1558,6 @@ return quoted; /* See local README for interface description. */ -#include "../version.h" - gstring * ldap_version_report(gstring * g) { diff --git a/src/src/lookups/lmdb.c b/src/src/lookups/lmdb.c index c90632cee..dc8bec3ba 100644 --- a/src/src/lookups/lmdb.c +++ b/src/src/lookups/lmdb.c @@ -128,8 +128,6 @@ mdb_env_close(db_env); * Version reporting entry point * *************************************************/ -#include "../version.h" - gstring * lmdb_version_report(gstring * g) { diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c index 76954ca43..f28e9154f 100644 --- a/src/src/lookups/mysql.c +++ b/src/src/lookups/mysql.c @@ -467,8 +467,6 @@ return quoted; /* See local README for interface description. */ -#include "../version.h" - gstring * mysql_version_report(gstring * g) { diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c index 8ddf0e058..7071cb4ab 100644 --- a/src/src/lookups/pgsql.c +++ b/src/src/lookups/pgsql.c @@ -472,8 +472,6 @@ return quoted; /* See local README for interface description. */ -#include "../version.h" - gstring * pgsql_version_report(gstring * g) { diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index a721d0605..61c264a73 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -428,7 +428,6 @@ return quoted; /************************************************* * Version reporting entry point * *************************************************/ -#include "../version.h" gstring * redis_version_report(gstring * g) diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index bfce04fa7..a8404d9bf 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -81,39 +81,33 @@ return FAIL; /* See local README for interface description. */ -#include "../version.h" - gstring * spf_version_report(gstring * g) { -#if EXIM_HAVE_SPF == 2 -return g; -#else -int maj, min, patch; - -SPF_get_lib_version(&maj, &min, &patch); -return string_fmt_append(g, "Library version: SPF: Runtime: %d.%d.%d\n", - maj, min, patch); -#endif +uschar * dummy_errmsg; +misc_module_info * mi = misc_mod_find(US"spf", &dummy_errmsg); +return mi && mi->lib_vers_report ? mi->lib_vers_report(g) : g; } + static lookup_info spf_lookup_info = { - .name = US"spf", /* lookup name */ - .type = 0, /* not absfile, not query style */ - .open = spf_open, /* open function */ - .check = NULL, /* no check function */ - .find = spf_find, /* find function */ - .close = spf_close, /* close function */ - .tidy = NULL, /* no tidy function */ - .quote = NULL, /* no quoting function */ - .version_report = spf_version_report /* version reporting */ + .name = US"spf", /* lookup name */ + .type = 0, /* not absfile, not query style */ + .open = spf_open, /* open function */ + .check = NULL, /* no check function */ + .find = spf_find, /* find function */ + .close = spf_close, /* close function */ + .tidy = NULL, /* no tidy function */ + .quote = NULL, /* no quoting function */ + .version_report = spf_version_report /* version reporting */ }; -#ifdef notdef_DYNLOOKUP -#define spf_lookup_module_info _lookup_module_info +#ifdef DYNLOOKUP +# define spf_lookup_module_info _lookup_module_info #endif static lookup_info *_lookup_list[] = { &spf_lookup_info }; -lookup_module_info spf_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; +lookup_module_info spf_lookup_module_info = + { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 }; diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index e358c9f84..eb23b8631 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -163,8 +163,6 @@ return quoted; /* See local README for interface description. */ -#include "../version.h" - gstring * sqlite_version_report(gstring * g) { diff --git a/src/src/lookups/whoson.c b/src/src/lookups/whoson.c index f783a905a..dcd48db2d 100644 --- a/src/src/lookups/whoson.c +++ b/src/src/lookups/whoson.c @@ -63,8 +63,6 @@ switch (wso_query(CS query, CS buffer, sizeof(buffer))) /* See local README for interface description. */ -#include "../version.h" - gstring * whoson_version_report(gstring * g) { diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index 2220c7dc9..41d946735 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -131,7 +131,8 @@ s = US SvPV(ST(0), len); log_write(0, LOG_MAIN, "%.*s", (int)len, s); } -/* Do a DNS lookup using Exim's facilities. Returns a scalar with the response packet. */ +/* Do a DNS lookup using Exim's facilities. +Returns a scalar with the response packet; undef for DNS_FAIL or DNS_AGAIN. */ XS(xs_dns_lookup) { @@ -154,8 +155,10 @@ debug_printf_indent(" dnsa answer %p len %d\n", dnsa->answer, dnsa->answerlen); */ ST(0) = sv_newmortal(); -sv_setpvn(ST(0), CCS dnsa->answer, - (STRLEN) (dns_res == DNS_NODATA ? 0 : dnsa->answerlen)); +if (dns_res == DNS_AGAIN || dns_res == DNS_FAIL) + sv_setsv(ST(0), &PL_sv_undef); +else + sv_setpvn(ST(0), CCS dnsa->answer, (STRLEN) dnsa->answerlen); XSRETURN(1); /* ? needed because there are 2 arg, but 1 res? */ store_free_dns_answer(dnsa); @@ -222,9 +225,11 @@ errstr = exim_perl_add_codeblock(US "\"TLSA\" => 52," "\"SPF\" => 99," "};" - "my $rrtype = $rr->{$rrtype_str};" /*XXX only one rrtype per query...*/ + /*XXX only one rrtype per query...*/ + "my $rrtype = $rr->{$rrtype_str};" "my $dnsa = Exim::dns_lookup($dom, $rrtype);" - "my $res = Net::DNS::Packet->decode( \\$dnsa );" + "my $res;" + "my $res = Net::DNS::Packet->decode(\\$dnsa) unless (!defined($dnsa));" /* "Exim::debug_write( $res->string . '\n' );" */ "return $res;" "}" diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index 3008facc8..17eb3ce35 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -212,7 +212,7 @@ else sep = '\n'; spf_result = string_nextinlist(CUSS &res_list, &sep, NULL, 0); - DEBUG(D_acl) debug_printf_indent("SPF result is %s\n", spf_received); + DEBUG(D_acl) debug_printf_indent("MAIL::SPF result is %q\n", spf_received); spf_received = res_list; /* remainder of the returned string */ @@ -329,9 +329,9 @@ spf_lookup_find(void * handle, const uschar * filename, { int res = FAIL; -expand_level++; DEBUG(D_acl) debug_printf_indent("%s: mfrom:<%s> ip %q\n", __FUNCTION__, keystring, filename); +expand_level++; if (setup_spf_perl_mi()) if (!filename) @@ -346,11 +346,12 @@ if (setup_spf_perl_mi()) uschar * res_list = US string_from_gstring(g); int sep = '\n'; *result = string_nextinlist(CUSS &res_list, &sep, NULL, 0); - DEBUG(D_acl) debug_printf_indent("SPF result is %s\n", *result); + DEBUG(D_acl) debug_printf_indent("MAIL::SPF result is %q\n", *result); res = OK; } } +expand_level--; return res; } commit 6096b50a869de851b710262dcc479f61e68c1bc7 Author: Jeremy Harris Date: Tue Nov 18 18:11:10 2025 +0000 dmarc-native: fix rua/ruf verify diff --git a/src/src/drtables.c b/src/src/drtables.c index 87ff8da61..45b1ade16 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -346,7 +346,7 @@ if ((mi = misc_mod_findonly(name))) return mi; return misc_mod_load(name, errstr); #else *errstr = string_sprintf("module %q not built-in, and" - "no setting for LOOKUP_MODULE_DIR", name); + " no setting for LOOKUP_MODULE_DIR", name); return NULL; #endif /*LOOKUP_MODULE_DIR*/ } diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index 059b31167..d6e27c892 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -11,9 +11,6 @@ #ifdef EXIM_HAVE_DMARC -// # include "dmarc.h" -// # include "pdkim.h" - extern BOOL dmarc_local_init(void); extern void dmarc_local_msg_init(void); extern gstring * dmarc_version_report(gstring *); diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index 617517d84..d073e4274 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -43,7 +43,7 @@ if (!dmarc_regex_uri) dmarc_regex_uri = regex_must_compile(US "^mailto:[^@]+@[^ !]+(?:[ !]|$)", MCS_CACHEABLE, FALSE); if (!dmarc_regex_pct) - dmarc_regex_uri = regex_must_compile(US "^\\d{1,3}$", MCS_CACHEABLE, FALSE); + dmarc_regex_pct = regex_must_compile(US "^\\d{1,3}$", MCS_CACHEABLE, FALSE); if (!dmarc_regex_ri) dmarc_regex_ri = regex_must_compile(US "^\\d{1,10}$", MCS_CACHEABLE, FALSE); if (!dmarc_regex_fo) @@ -56,13 +56,6 @@ if (!dmarc_regex_fo) gstring * dmarc_version_report(gstring * g) { -/* -return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n", - (OPENDMARC_LIB_VERSION & 0xff000000) >> 24, - (OPENDMARC_LIB_VERSION & 0x00ff0000) >> 16, - (OPENDMARC_LIB_VERSION & 0x0000ff00) >> 8, - (OPENDMARC_LIB_VERSION & 0x000000ff)); -*/ return string_fmt_append(g, "Library version: dmarc: Exim %s builtin\n", EXIM_VERSION_STR); } commit 2a87c1fb9d76cd00cc1815c9b56b8bea47e409e1 Author: Jeremy Harris Date: Sun Nov 30 19:41:43 2025 +0000 perl-spf: fix undef whine diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index 41d946735..1b111e711 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -77,6 +77,7 @@ if (SvTRUE(ERRSV)) STRLEN len; s = US SvPV(ERRSV, len); s = string_copyn(s, (unsigned)len); + debug_printf_indent("adding perl codeblock: %s\n", s); } setlocale(LC_ALL, "C"); /* In case it got changed */ @@ -228,9 +229,13 @@ errstr = exim_perl_add_codeblock(US /*XXX only one rrtype per query...*/ "my $rrtype = $rr->{$rrtype_str};" "my $dnsa = Exim::dns_lookup($dom, $rrtype);" + "my $res;" - "my $res = Net::DNS::Packet->decode(\\$dnsa) unless (!defined($dnsa));" - /* "Exim::debug_write( $res->string . '\n' );" */ + "$res = new Net::DNS::Packet(\\$dnsa) if (defined($dnsa));" + + /*XXX dumb, but at least clears the undef on errorstring */ + "$self->errorstring(defined($dnsa) ? 'ok' : 'timeout');" + "return $res;" "}" "package MAIN;" diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index 17eb3ce35..4e854d7af 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -61,9 +61,10 @@ static const uschar spf_pl[] = "use Mail::SPF;" "sub my_spf_req {" "my ($mfrom, $conn_addr, $conn_helo) = @_;" + "my ($id, $sc) = ($mfrom ne '') ? ($mfrom, 'mfrom') : ($conn_helo, 'helo');" "my $request = Mail::SPF::Request->new(" - "scope => 'mfrom'," - "identity => $mfrom," + "scope => $sc," + "identity => $id," "ip_address => $conn_addr," "helo_identity => $conn_helo" ");" @@ -80,21 +81,19 @@ spf lookup routine to it. Safely does nothing if called again. */ static const misc_module_info * -setup_spf_perl_mi(void) +setup_spf_perl_mi(uschar ** errstr) { typedef uschar * (*fn_t)(const uschar *); if (!spf_perl_mi) { if (!(spf_perl_mi = perl_startup(opt_perl_startup ? opt_perl_startup : US""))) - /* errstr = string_sprintf("spf: %s", expand_string_message); */ + { + *errstr = string_sprintf("spf: %s", expand_string_message); return NULL; + } - /*XXX could return an error string here: - if ((errstr = (((fn_t *) spf_perl_mi->functions)[PERL_ADDBLOCK]) (spf_pl))) - */ - - if ((((fn_t *) spf_perl_mi->functions)[PERL_ADDBLOCK]) (spf_pl)) + if ((*errstr = (((fn_t *) spf_perl_mi->functions)[PERL_ADDBLOCK]) (spf_pl))) return spf_perl_mi = NULL; } return spf_perl_mi; @@ -187,14 +186,18 @@ spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, int action) { int res = FAIL, sep; +uschar * errstr; const uschar * arglist = *listptr; expand_level++; DEBUG(D_acl) debug_printf_indent("%s: mfrom:<%s>\n", __FUNCTION__, spf_envelope_sender); -if (!setup_spf_perl_mi()) +if (!setup_spf_perl_mi(&errstr)) + { + expand_level--; return FAIL; + } if (!(conn_helo && conn_addr)) spf_result = US"permerror"; @@ -327,13 +330,14 @@ spf_lookup_find(void * handle, const uschar * filename, const uschar * keystring, int key_len, uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts) { +uschar * errstr; int res = FAIL; DEBUG(D_acl) debug_printf_indent("%s: mfrom:<%s> ip %q\n", __FUNCTION__, keystring, filename); expand_level++; -if (setup_spf_perl_mi()) +if (setup_spf_perl_mi(&errstr)) if (!filename) *result = US"permerror"; else commit 1b88acb34288b0858d0f26c1ab2ebc752d046595 Author: Jeremy Harris Date: Mon Dec 1 18:17:46 2025 +0000 Fix nonstandard DNS server port number use from perl. Bug 3177 Broken-by: 040f2adb9003 diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index 1b111e711..cee920c77 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -200,19 +200,26 @@ perl_parse(interp_perl, xs_init, argc, argv, 0); perl_run(interp_perl); /*********************************************************************/ +errstr = exim_perl_add_codeblock(US + /* These lines by PH added to make "warn" output go to the Exim log; I hope this doesn't break anything. */ -errstr = exim_perl_add_codeblock(US "$SIG{__WARN__} = sub { my($s) = $_[0];" "$s =~ s/\\n$//;" "Exim::log_write($s) };" -/* These lines added by JGH to route DNS queries via Exim's facilities */ +/* These lines added by JGH to route DNS queries via Exim's facilities. +If a port was specified, we punt. +*/ "package Net::DNS::Resolver;" "sub send {" - "my ( $self, $dom, $rrtype_str ) = @_;" + "my $self = shift;" + + "return $self->SUPER::send(@_) if ($self->{'port'} != 53);" + + "my ( $dom, $rrtype_str ) = @_;" "my $rr = {" "\"A\" => 1," "\"NS\" => 2," commit 5f52bd307cccd1a840ab4e0b761add7b3d1946cd Author: Jeremy Harris Date: Mon Dec 1 22:43:53 2025 +0000 Build: Solaris compilers diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 30d446bad..42396fe8b 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -64,6 +64,9 @@ readconf_printtime(int t) const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) { return NULL; } gstring * +string_catn(gstring * g, const uschar * s, int count) +{ return NULL; } +gstring * string_vformat_trc(gstring * g, const uschar * func, unsigned line, unsigned size_limit, unsigned flags, const char *format, va_list ap) { return NULL; } commit 29b229ef956c08381bb5514a4da3fecf89148441 Author: Jeremy Harris Date: Tue Dec 2 11:19:49 2025 +0000 Build: GCC on Solaris diff --git a/src/OS/os.h-SunOS5 b/src/OS/os.h-SunOS5 index f7ad50421..389b3403b 100644 --- a/src/OS/os.h-SunOS5 +++ b/src/OS/os.h-SunOS5 @@ -2,6 +2,13 @@ /* Copyright (c) The Exim Maintainers 2021 - 2025 */ /* SPDX-License-Identifier: GPL-2.0-or-later */ +/* The Sun Studio compilers define these, but GCC does not. +Adjust if needed. */ +#if !defined(__SunOS_5_10) && !defined(__SunOS_5_11) +# define __SunOS_5_11 +#endif + + #define CRYPT_H #define HAVE_MMAP #define HAVE_SYS_STATVFS_H @@ -35,6 +42,11 @@ it seems. */ /* default is non-const */ #define ICONV_ARG2_TYPE const char ** +/* A GCC user reported that the following was needed. Possibly using +Glibc iconv? + #define ICONV_ARG2_TYPE char ** restrict +A way of spotting the difference would be useful. +*/ #if _POSIX_C_SOURCE + 0 < 200112L # define MISSING_UNSETENV_3 commit 9536defc5cb25beeb00491f6b00c454aadfdb7a5 Author: Jeremy Harris Date: Tue Dec 2 22:59:04 2025 +0000 SPF: logging diff --git a/src/src/functions.h b/src/src/functions.h index 76bc24c1b..873b8c8be 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -107,6 +107,7 @@ extern uschar *acl_standalone_setvar(const uschar *, BOOL); extern tree_node *acl_var_create(const uschar *); extern void acl_var_write(uschar *, uschar *, void *); extern void add_driver_info(driver_info **, const driver_info *, size_t); +extern gstring * add_spf_info_for_log(gstring *); extern void assert_no_variables(void *, int, const char *, int); extern void atrn_handle_customer(void); diff --git a/src/src/globals.c b/src/src/globals.c index 38fdbc7a3..be5afe736 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1021,6 +1021,10 @@ bit_table log_options[] = { /* must be in alphabetical order, BIT_TABLE(L, smtp_no_mail), BIT_TABLE(L, smtp_protocol_error), BIT_TABLE(L, smtp_syntax_error), +#ifdef EXIM_HAVE_SPF + BIT_TABLE(L, spf), + BIT_TABLE(L, spf_verbose), +#endif BIT_TABLE(L, subject), BIT_TABLE(L, tls_certificate_verified), BIT_TABLE(L, tls_cipher), diff --git a/src/src/macros.h b/src/src/macros.h index c0900eee9..ad5d73267 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -453,7 +453,7 @@ enum logbit { LOG_BIT(dnslist_defer), LOG_BIT(etrn), LOG_BIT(host_lookup_failed), - LOG_BIT(lost_incoming_connection), + LOG_BIT(lost_incoming_connection), /* 7 */ LOG_BIT(queue_run), LOG_BIT(retry_defer), LOG_BIT(size_reject), @@ -461,7 +461,7 @@ enum logbit { LOG_BIT(smtp_connection), LOG_BIT(smtp_incomplete_transaction), LOG_BIT(smtp_protocol_error), - LOG_BIT(smtp_syntax_error), + LOG_BIT(smtp_syntax_error), /* 15 */ Li_8bitmime = BITWORDSIZE, Li_acl_warn_skipped, @@ -497,6 +497,8 @@ enum logbit { Li_smtp_confirmation, Li_smtp_mailauth, Li_smtp_no_mail, + Li_spf, + Li_spf_verbose, Li_subject, Li_tls_certificate_verified, Li_tls_cipher, diff --git a/src/src/receive.c b/src/src/receive.c index 0f407ce93..a0fcffd06 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1361,6 +1361,21 @@ DEBUG(D_receive|D_acl) debug_printf_indent(">>\n"); * Add host information for log line * *************************************************/ +gstring * +add_spf_info_for_log(gstring * g) +{ +#ifdef EXIM_HAVE_SPF +if (LOGGING(spf_verbose)) + { + const uschar * s = expand_string(CUS"$spf_result"); + if (*s) g = string_append(g, 2, US" SPF=", s); + } +else if (LOGGING(spf) && Ustrcmp(expand_string(CUS"$spf_result"), "pass") == 0) + g = string_catn(g, US" SPF", 4); +#endif +return g; +} + /* Called for acceptance and rejecting log lines. This adds information about the calling host to a string that is being built dynamically. @@ -1407,6 +1422,8 @@ if (LOGGING(pipelining) && f.smtp_in_pipelining_advertised) if (!f.smtp_in_pipelining_used) g = string_catn(g, US"-", 1); } + +g = add_spf_info_for_log(g); return g; } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 674bdd785..6cfc36f7a 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -3166,7 +3166,7 @@ switch (where) #ifdef WITH_CONTENT_SCAN case ACL_WHERE_MIME: #endif - sender_info = string_sprintf("F=<%s>%s%s%s%s ", + sender_info = string_sprintf(" F=<%s>%s%s%s%s", sender_address_unrewritten ? sender_address_unrewritten : sender_address, sender_host_authenticated ? US" A=" : US"", sender_host_authenticated ? sender_host_authenticated : US"", @@ -3266,18 +3266,23 @@ is closing if required and return 2. */ if (log_reject_target) { #ifndef DISABLE_TLS - gstring * g = add_tls_info_for_log(NULL); - uschar * tls = string_from_gstring(g); - if (!tls) tls = US""; + gstring * tls = add_tls_info_for_log(NULL); #else - uschar * tls = US""; + gstring * tls = NULL; #endif +#ifdef EXIM_HAVE_SPF + gstring * spf= add_spf_info_for_log(NULL); +#else + gstring * spf = NULL; +#endif + log_write(where == ACL_WHERE_CONNECT ? L_connection_reject : 0, - log_reject_target, "%s%s%s %s%srejected %s%s", + log_reject_target, "%s%s%#Y%s%#Y %srejected %s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), tls, sender_info, + spf, rc == FAIL ? US"" : US"temporarily ", what, log_msg); } commit b8d16e2a4e8e2016e8cd03402705a6f47f1e2b5b Author: Jeremy Harris Date: Wed Dec 3 12:16:59 2025 +0000 SPF: support * in ACL condition diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index f73a8776b..4febe7f4e 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -373,10 +373,7 @@ static int spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, int action) { -int sep = 0; -const uschar * list = * listptr; -uschar * spf_result_id; -int rc = SPF_RESULT_PERMERROR, ret = OK; +int rc = SPF_RESULT_PERMERROR, ret; DEBUG(D_receive) { debug_printf_indent("SPF: process\n"); expand_level++; } @@ -419,24 +416,13 @@ if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none"))) else { - while ((spf_result_id = string_nextinlist(&list, &sep, NULL, 0))) - { - BOOL negate, result; - - if ((negate = spf_result_id[0] == '!')) - spf_result_id++; - - result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name) == 0; - if (negate != result) goto out; - } - - /* no match */ - ret = FAIL; + const uschar * list = *listptr; + ret = match_isinlist(spf_result_id_list[rc].name, &list, + 0, NULL, NULL, MCL_STRING, TRUE, NULL); } -out: - DEBUG(D_receive) expand_level--; - return ret; +DEBUG(D_receive) expand_level--; +return ret; } diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index 4e854d7af..55741eef0 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -35,9 +35,6 @@ static spf_result_id spf_result_id_list[] = { { US"permerror", 7 } /* RFC 4408 defined */ }; -const uschar * conn_helo = NULL; -const uschar * conn_addr = NULL; - uschar * spf_guess = US"v=spf1 a/24 mx/24 ptr ?all"; uschar * spf_header_comment = NULL; uschar * spf_received = NULL; @@ -131,34 +128,6 @@ return string_cat(g, US"Library_version: SPF: perl Mail::SPF\n"); -/*API*/ -/* Set up a context that can be re-used for several - messages on the same SMTP connection (that come from the - same host with the same HELO string). - -We delay doing perl startup until spf processing time, as ACL might -never need us on any given connection. - -Return: OK/FAIL -*/ - -static int -spf_conn_init(const uschar * spf_helo_domain, const uschar * spf_remote_addr, - const uschar ** errstr) -{ -DEBUG(D_receive) debug_printf_indent("spf_conn_init: helo:%s addr:%s\n", - spf_helo_domain, spf_remote_addr); - -/* Copy the args to globals */ - -conn_helo = spf_helo_domain; -conn_addr = spf_remote_addr; - -return OK; -} - - - /*API*/ static void spf_smtp_reset(void) @@ -185,7 +154,7 @@ static int spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, int action) { -int res = FAIL, sep; +int res, sep; uschar * errstr; const uschar * arglist = *listptr; @@ -199,17 +168,18 @@ if (!setup_spf_perl_mi(&errstr)) return FAIL; } -if (!(conn_helo && conn_addr)) +if (!(sender_helo_name && sender_host_address)) spf_result = US"permerror"; else { - const uschar * argv[4] = {spf_envelope_sender, conn_addr, conn_helo, NULL}; + const uschar * argv[4] = {spf_envelope_sender, sender_host_address, + sender_helo_name, NULL}; gstring * g; uschar * res_list, * s; if (!(g = call_my_spf_req(argv))) - goto out; + { res = FAIL; goto out; } res_list = US string_from_gstring(g); sep = '\n'; @@ -228,18 +198,8 @@ else } } -sep = 0; -for (uschar * ele; ele = string_nextinlist(&arglist, &sep, NULL, 0); ) - { - BOOL negate, result; - - if ((negate = *ele == '!')) - ele++; - - result = Ustrcmp(ele, spf_result) == 0; - if (negate != result) { res = OK; break; } - } -/* if the loop ran out of list, no match */ +res = match_isinlist(spf_result, &arglist, + 0, NULL, NULL, MCL_STRING, TRUE, NULL); out: expand_level--; @@ -342,7 +302,7 @@ if (setup_spf_perl_mi(&errstr)) *result = US"permerror"; else { - const uschar * argv[4] = {keystring, filename, conn_helo, NULL}; + const uschar * argv[4] = {keystring, filename, sender_helo_name, NULL}; gstring * g; if ((g = call_my_spf_req(argv))) @@ -393,7 +353,7 @@ misc_module_info spf_module_info = .dyn_magic = MISC_MODULE_MAGIC, # endif .lib_vers_report = spf_lib_version_report, - .conn_init = spf_conn_init, + .conn_init = NULL, .smtp_reset = spf_smtp_reset, .authres = authres_spf, commit 266b6e714cf4a95d412a81197516e6dcb1454214 Author: Jeremy Harris Date: Wed Dec 3 14:10:50 2025 +0000 Debug: redefine the early-debug macro to be also active after main-debug init diff --git a/src/src/macros.h b/src/src/macros.h index ad5d73267..0b69bb83f 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -106,11 +106,10 @@ don't make the file descriptors two-way. */ #define HDEBUG(x) if (host_checking || IS_DEBUG(x)) #define EARLY_DEBUG(x, fmt, ...) \ - if (debug_startup) \ - if (debug_fd < 0) \ - fprintf(stderr, "%s", string_sprintf(fmt, __VA_ARGS__)); \ - else DEBUG(x) \ - debug_printf_indent(fmt, __VA_ARGS__); + if (debug_fd >= 0) \ + { DEBUG(x) debug_printf_indent(fmt, __VA_ARGS__); } \ + else if (debug_startup) \ + fprintf(stderr, "%s", string_sprintf(fmt, __VA_ARGS__)); /* The default From: text for DSNs */ diff --git a/src/src/readconf.c b/src/src/readconf.c index 04cd5e68a..37d9c6b85 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -4592,7 +4592,7 @@ readconf_rest(void) { int had = 0; -while(next_section[0] != 0) +while(*next_section) { int bit; int first = 0; @@ -4601,6 +4601,7 @@ while(next_section[0] != 0) int n = Ustrlen(next_section); EARLY_DEBUG(D_any, "%s: %s\n", __FUNCTION__, next_section); + expand_level++; if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, US"s"); for (;;) @@ -4630,6 +4631,7 @@ while(next_section[0] != 0) case 5: route_init(); break; case 6: transport_init(); break; } + expand_level--; } (void)fclose(config_file); commit c5d27945075095ee56c92eee36a81aa239a53494 Author: Jeremy Harris Date: Wed Dec 3 15:06:10 2025 +0000 DMARC: logging diff --git a/src/src/functions.h b/src/src/functions.h index 873b8c8be..a15369af9 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -20,7 +20,6 @@ are in in fact in separate headers. */ #ifndef DISABLE_TLS -extern gstring * add_tls_info_for_log(gstring *); extern const char * std_dh_prime_default(void); extern const char * std_dh_prime_named(const uschar *); @@ -106,8 +105,10 @@ extern uschar *acl_standalone_setvar(const uschar *, BOOL); extern tree_node *acl_var_create(const uschar *); extern void acl_var_write(uschar *, uschar *, void *); +extern gstring * add_dmarc_info_for_log(gstring *); extern void add_driver_info(driver_info **, const driver_info *, size_t); extern gstring * add_spf_info_for_log(gstring *); +extern gstring * add_tls_info_for_log(gstring *); extern void assert_no_variables(void *, int, const char *, int); extern void atrn_handle_customer(void); diff --git a/src/src/globals.c b/src/src/globals.c index be5afe736..610c72909 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -979,6 +979,10 @@ bit_table log_options[] = { /* must be in alphabetical order, #ifndef DISABLE_DKIM BIT_TABLE(L, dkim), BIT_TABLE(L, dkim_verbose), +#endif +#ifdef EXIM_HAVE_DMARC + BIT_TABLE(L, dmarc), + BIT_TABLE(L, dmarc_verbose), #endif BIT_TABLE(L, dnslist_defer), BIT_TABLE(L, dnssec), diff --git a/src/src/macros.h b/src/src/macros.h index 0b69bb83f..6c7d8b085 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -470,6 +470,8 @@ enum logbit { Li_delivery_size, Li_dkim, Li_dkim_verbose, + Li_dmarc, + Li_dmarc_verbose, Li_dnssec, Li_ident_timeout, Li_incoming_interface, diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index be5d68c3a..8d840ae84 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -431,7 +431,8 @@ The EDITME provides a DMARC_API variable */ dmarc_alignment_dkim = dmarc_dkim_alignment == DMARC_POLICY_DKIM_ALIGNMENT_PASS; - log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + if (LOGGING(dmarc_verbose)) + log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, dmarc_alignment_spf ? "yes" : "no", diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index d073e4274..02eb5dbd3 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -628,14 +628,12 @@ use the sp. Otherwise use the p. */ } } - // the alignments would be results of the DMARC evaluation - // - we have them already, from the dkim & spf processing - if (has_dmarc_record && !dmarc_abort) { - /* Log results. Robably should have a log_selector to reduce noise. */ + /* Log results. */ - log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + if (LOGGING(dmarc_verbose)) + log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, dmarc_alignment_spf ? "yes" : "no", diff --git a/src/src/receive.c b/src/src/receive.c index a0fcffd06..7827d0288 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1376,6 +1376,21 @@ else if (LOGGING(spf) && Ustrcmp(expand_string(CUS"$spf_result"), "pass") == 0) return g; } +gstring * +add_dmarc_info_for_log(gstring * g) +{ +#ifdef EXIM_HAVE_DMARC +if (LOGGING(dmarc_verbose)) + { + const uschar * s = expand_string(CUS"$dmarc_status"); + if (*s) g = string_append(g, 2, US" DMARC=", s); + } +else if (LOGGING(dmarc) && Ustrcmp(expand_string(CUS"$dmarc_status"), "accept") == 0) + g = string_catn(g, US" DMARC", 6); +#endif +return g; +} + /* Called for acceptance and rejecting log lines. This adds information about the calling host to a string that is being built dynamically. @@ -4099,10 +4114,7 @@ if (message_reference) g = string_append(g, 2, US" R=", message_reference); g = add_host_info_for_log(g); - -#ifndef DISABLE_TLS g = add_tls_info_for_log(g); -#endif if (sender_host_authenticated) { @@ -4156,6 +4168,8 @@ if (LOGGING(dkim)) } #endif +g = add_dmarc_info_for_log(g); + if (LOGGING(receive_time)) { struct timeval diff = received_time_complete; diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 6cfc36f7a..d694c8d7a 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1483,7 +1483,6 @@ return string_from_gstring(g); -#ifndef DISABLE_TLS /* Append TLS-related information to a log line Arguments: @@ -1494,13 +1493,14 @@ Returns: Allocated string or NULL gstring * add_tls_info_for_log(gstring * g) { +#ifndef DISABLE_TLS if (LOGGING(tls_cipher) && tls_in.cipher) { g = string_append(g, 2, US" X=", tls_in.cipher); -#ifndef DISABLE_TLS_RESUME +# ifndef DISABLE_TLS_RESUME if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED) g = string_catn(g, US"*", 1); -#endif +# endif } if (LOGGING(tls_certificate_verified) && tls_in.peercert) g = string_append(g, 2, US" CV=", tls_in.certificate_verified? "yes":"no"); @@ -1509,8 +1509,8 @@ if (LOGGING(tls_peerdn) && tls_in.peerdn) if (LOGGING(tls_sni) && tls_in.sni) g = string_append(g, 2, US" SNI=", string_printing2(tls_in.sni, SP_TAB|SP_SPACE)); return g; -} #endif +} @@ -1547,7 +1547,6 @@ Returns: nothing void smtp_log_no_mail(void) { -uschar * s; gstring * g = NULL; if (smtp_mailcmd_count > 0 || !LOGGING(smtp_no_mail)) @@ -1559,17 +1558,12 @@ if (sender_host_authenticated) if (authenticated_id) g = string_append(g, 2, US":", authenticated_id); } -#ifndef DISABLE_TLS g = add_tls_info_for_log(g); -#endif - g = s_connhad_log(g); -if (!(s = string_from_gstring(g))) s = US""; - -log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s", +log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%#Y", f.tcp_in_fastopen ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " : US"", - host_and_ident(FALSE), string_timesince(&smtp_connection_start), s); + host_and_ident(FALSE), string_timesince(&smtp_connection_start), g); } @@ -2178,21 +2172,13 @@ static void log_connect_tls_drop(const uschar * what, const uschar * log_msg) { if (log_reject_target) - { -#ifdef DISABLE_TLS - uschar * tls = NULL; -#else - gstring * g = add_tls_info_for_log(NULL); - uschar * tls = string_from_gstring(g); -#endif log_write(L_connection_reject, - log_reject_target, "%s%s%s dropped by %s%s%s", + log_reject_target, "%s%s%#Y dropped by %s%s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), - tls ? tls : US"", + add_tls_info_for_log(NULL), what, log_msg ? US": " : US"", log_msg); - } } @@ -3264,28 +3250,16 @@ the connection is not forcibly to be dropped, return 0. Otherwise, log why it is closing if required and return 2. */ if (log_reject_target) - { -#ifndef DISABLE_TLS - gstring * tls = add_tls_info_for_log(NULL); -#else - gstring * tls = NULL; -#endif -#ifdef EXIM_HAVE_SPF - gstring * spf= add_spf_info_for_log(NULL); -#else - gstring * spf = NULL; -#endif - log_write(where == ACL_WHERE_CONNECT ? L_connection_reject : 0, - log_reject_target, "%s%s%#Y%s%#Y %srejected %s%s", + log_reject_target, "%s%s%#Y%s%#Y%#Y %srejected %s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), - tls, + add_tls_info_for_log(NULL), sender_info, - spf, + add_spf_info_for_log(NULL), + add_dmarc_info_for_log(NULL), rc == FAIL ? US"" : US"temporarily ", what, log_msg); - } if (!drop) return 0; commit c5007722d5f5e86953912ea75b13575577e4f98a Author: Jeremy Harris Date: Thu Dec 4 22:22:17 2025 +0000 Perl: tweak dns lookup fail cases diff --git a/src/src/dns.c b/src/src/dns.c index dd754f6c9..5ed896b38 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -717,7 +717,7 @@ the packet length if the packet header looks plausible. Return TRUE iff it seemed ok */ -static BOOL +BOOL fake_dnsa_len_for_fail(dns_answer * dnsa, int type) { const HEADER * h = (const HEADER *)dnsa->answer; diff --git a/src/src/functions.h b/src/src/functions.h index a15369af9..49ed1064d 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -248,6 +248,7 @@ extern uschar *expand_string_copy(const uschar *); extern int_eximarith_t expand_string_integer(uschar *, BOOL); extern void modify_variable(uschar *, void *); +extern BOOL fake_dnsa_len_for_fail(dns_answer *, int); extern BOOL fd_ready(int, time_t); extern BOOL filter_runtest(int, const uschar *, BOOL, BOOL); diff --git a/src/src/lookups/Makefile b/src/src/lookups/Makefile index 23347e83b..27ae3fe1e 100644 --- a/src/src/lookups/Makefile +++ b/src/src/lookups/Makefile @@ -40,7 +40,7 @@ avail_static_lookups.o: $(HDRS) avail_static_lookups.c lookups.a: avail_static_lookups.o $(OBJS) @$(RM_COMMAND) -f lookups.a @echo "$(AR) lookups.a" - @$(AR) lookups.a avail_static_lookups.o $(OBJS) + $(FE)$(AR) lookups.a avail_static_lookups.o $(OBJS) $(RANLIB) $@ .SUFFIXES: .o .c .so diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index cee920c77..5877d3dea 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -158,6 +158,8 @@ debug_printf_indent(" dnsa answer %p len %d\n", dnsa->answer, dnsa->answerlen); ST(0) = sv_newmortal(); if (dns_res == DNS_AGAIN || dns_res == DNS_FAIL) sv_setsv(ST(0), &PL_sv_undef); +else if (dnsa->answerlen == -1 && !fake_dnsa_len_for_fail(dnsa, rrtype_int)) + sv_setsv(ST(0), &PL_sv_undef); else sv_setpvn(ST(0), CCS dnsa->answer, (STRLEN) dnsa->answerlen); XSRETURN(1); /* ? needed because there are 2 arg, but 1 res? */ commit 46846fc1f6254cb6a1ef14babc40fcae9f5baea1 Author: Jeremy Harris Date: Fri Dec 5 12:18:39 2025 +0000 taint: better tracking for dns lookup results diff --git a/src/src/acl.c b/src/src/acl.c index be61fc953..b3c45668a 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1435,7 +1435,7 @@ tree_node *t; const uschar *found; int priority, weight, port; dns_answer * dnsa; -dns_scan dnss; +dns_scan dnss = {0}; dns_record *rr; int rc, type, yield; #define TARGET_SIZE 256 @@ -1584,7 +1584,7 @@ be authorized. (This is an odd configuration because weight=2 target=. is equivalent to weight=1, but we check for it in order to keep load off the root name servers.) Note that dn_expand() turns "." into "". */ -if (Ustrcmp(target, "") == 0) +if (!*target) { yield = CSA_FAIL_NOADDR; goto out; diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index 118e95f29..c9fdc0ea9 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -298,7 +298,10 @@ if (ob->server_tls) { union sockaddr_46 interface_sock; EXIM_SOCKLEN_T size = sizeof(interface_sock); + + /* Large (64k if DANE supported) */ smtp_connect_args conn_args = { .host = &host }; + tls_support tls_dummy = { .sni = NULL }; uschar * errstr; diff --git a/src/src/dns.c b/src/src/dns.c index 5ed896b38..6b527ef00 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -318,6 +318,20 @@ dnss_inc_aptr(const dns_answer * dnsa, dns_scan * dnss, unsigned delta) return dnsa_bad_ptr(dnsa, dnss->aptr += delta); } +static int +dns_rr_expand_taint(const uschar * msg, const uschar * eom, + const uschar * comp_dn, dns_scan * dnss) +{ +uschar buf[DNS_MAXNAME]; +int ret; + +if ((ret = dn_expand(msg, eom, comp_dn, + (DN_EXPAND_ARG4_TYPE) buf, sizeof(buf))) < 0) + return ret; +dnss->srr.name = string_copy_taint(buf, GET_TAINTED); +return ret; +} + /************************************************* * Get next DNS record from answer block * *************************************************/ @@ -339,6 +353,7 @@ dns_record * dns_next_rr(const dns_answer * dnsa, dns_scan * dnss, int reset) { const HEADER * h = (const HEADER *)dnsa->answer; +const uschar * eom = dnsa->answer + dnsa->answerlen; int namelen; char * trace = NULL; @@ -361,9 +376,9 @@ if (reset != RESET_NEXT) while (dnss->rrcount-- > 0) { TRACE trace = "Q-namelen"; - namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, - dnss->aptr, (DN_EXPAND_ARG4_TYPE) &dnss->srr.name, DNS_MAXNAME); - if (namelen < 0) goto null_return; + /*TTT*/ + if ((namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) <0) + goto null_return; /* skip name & type & class */ TRACE trace = "Q-skip"; if (dnss_inc_aptr(dnsa, dnss, namelen+4)) goto null_return; @@ -392,9 +407,10 @@ if (reset != RESET_NEXT) while (dnss->rrcount-- > 0) { TRACE trace = "A-namelen"; - namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, - dnss->aptr, (DN_EXPAND_ARG4_TYPE) &dnss->srr.name, DNS_MAXNAME); - if (namelen < 0) goto null_return; + /*TTT*/ + if ( (namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) + < 0) + goto null_return; /* skip name, type, class & TTL */ TRACE trace = "A-hdr"; @@ -426,9 +442,9 @@ if (dnss->rrcount-- <= 0) return NULL; (something safe). */ TRACE trace = "R-namelen"; -namelen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, dnss->aptr, - (DN_EXPAND_ARG4_TYPE) &dnss->srr.name, DNS_MAXNAME); -if (namelen < 0) goto null_return; +/*TTT*/ +if ((namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) < 0) + goto null_return; /* Move the pointer past the name and fill in the rest of the data structure from the following bytes. We seem to be assuming here that the RR blob passed @@ -482,16 +498,16 @@ Scan the whole AUTHORITY section, since it may contain other records Return: name for the authority, in an allocated string, or NULL if none found */ static const uschar * -dns_extract_auth_name(const dns_answer * dnsa) /* FIXME: const dns_answer */ +dns_extract_auth_name(const dns_answer * dnsa) { -dns_scan dnss; +dns_scan dnss = {0}; const HEADER * h = (const HEADER *) dnsa->answer; if (h->nscount && h->aa) for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == (h->ancount ? T_NS : T_SOA)) - return string_copy(rr->name); + return string_copy(rr->name); /*TTT*/ return NULL; } @@ -750,7 +766,7 @@ bother doing a separate lookup; if not found return a forever TTL. time_t dns_expire_from_soa(dns_answer * dnsa, int type) { -dns_scan dnss; +dns_scan dnss = {0}; if (fake_dnsa_len_for_fail(dnsa, type)) for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); @@ -1046,7 +1062,7 @@ for (int i = 0; i <= dns_cname_loops; i++) { uschar * data; dns_record cname_rr, type_rr; - dns_scan dnss; + dns_scan dnss = {0}; /* DNS lookup failures get passed straight back. */ @@ -1087,7 +1103,7 @@ for (int i = 0; i <= dns_cname_loops; i++) ) #endif ) - *fully_qualified_name = string_copy_dnsdomain(rr_name); + *fully_qualified_name = string_copy_dnsdomain(rr_name); /*TTT*/ } /* If any data records of the correct type were found, we are done. */ @@ -1111,7 +1127,7 @@ for (int i = 0; i <= dns_cname_loops; i++) } /* DNS data comes from the outside, hence tainted */ - data = store_get(256, GET_TAINTED); + data = store_get(256, GET_TAINTED); /*TTT alloc*/ if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0) { @@ -1120,6 +1136,13 @@ for (int i = 0; i <= dns_cname_loops; i++) } name = data; + for (int i = 256-50; i > 0; i--) /* Usually much smaller, so find end */ + if (!*data++) + { + store_release_above(data); /* and release excess allocation */ + break; + } + if (!dns_is_secure(dnsa)) secure_so_far = FALSE; @@ -1239,8 +1262,8 @@ switch (type) uschar * namesuff, * tld; int priority, dummy_weight, port, limit, rc, i; BOOL ipv6; - dns_record *rr; - dns_scan dnss; + dns_record * rr; + dns_scan dnss = {0}; DEBUG(D_dns) debug_printf_indent("CSA lookup of %s\n", name); @@ -1336,7 +1359,7 @@ switch (type) /* If it's making an interesting assertion, return this response. */ if (port & 1) { - *fully_qualified_name = namesuff + 1; + *fully_qualified_name = namesuff + 1; /*TTT*/ return DNS_SUCCEED; } } diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c index dc4a0bea0..ac3e017e9 100644 --- a/src/src/dnsbl.c +++ b/src/src/dnsbl.c @@ -70,7 +70,7 @@ one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain, int defer_return) { dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; tree_node *t; dnsbl_cache_block *cb; int old_pool = store_pool; @@ -363,6 +363,7 @@ if (cb->rc == DNS_SUCCEED) int len = (rr->data)[0]; if (len > 511) len = 127; store_pool = POOL_PERM; + /*TTT*/ cb->text = string_copyn_taint(CUS (rr->data+1), len, GET_TAINTED); store_pool = old_pool; break; diff --git a/src/src/functions.h b/src/src/functions.h index 49ed1064d..ec13c544e 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -590,7 +590,7 @@ extern uschar *string_base62_32(unsigned long int); extern uschar *string_base62_64(unsigned long int); extern gstring *string_catn(gstring *, const uschar *, int) WARN_UNUSED_RESULT; extern int string_compare_by_pointer(const void *, const void *); -extern uschar *string_copy_dnsdomain(uschar *); +extern uschar *string_copy_dnsdomain(const uschar *); extern uschar *string_copy_malloc(const uschar *); extern uschar *string_dequote(const uschar **); extern uschar *string_format_size(int, uschar *); @@ -1145,8 +1145,9 @@ return item /* Use store_malloc for DNSA structs, and explicit frees. Using the same pool for them as the strings we proceed to copy from them meant they could not be released, hence blowing 64k for every DNS lookup. That mounted up. With malloc -we do have to take care over marking tainted all copied strings. A separate pool -could be used and would handle that implicitly. */ +we do have to take care over marking tainted all copied strings. +A separate pool could be used and could handle taint implicitly - but we would +want to support independent free ops, not limited to stacked alloc/release */ #define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__) diff --git a/src/src/host.c b/src/src/host.c index 4c513e28c..95694635a 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -180,7 +180,7 @@ uschar *adds; uschar **alist; struct hostent *yield; dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; DEBUG(D_host_lookup) debug_printf_indent("using host_fake_gethostbyname for %s (%s)\n", name, @@ -1587,7 +1587,7 @@ uschar **aliases; uschar *ordername; const uschar *list = host_lookup_order; dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; @@ -1662,6 +1662,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ + /*TTT*/ if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, US rr->data, (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { @@ -2286,7 +2287,7 @@ for (; i >= 0; i--) int type = types[i]; int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0) ? 500 : 0; /* Ensures v6/4 sort order */ - dns_scan dnss; + dns_scan dnss = {0}; int rc = dns_lookup_timerwrap(dnsa, host->name, type, fully_qualified_name); lookup_dnssec_authenticated = !dnssec_request ? NULL @@ -2389,7 +2390,7 @@ for (; i >= 0; i--) if (thishostlast == NULL) { if (strcmpic(host->name, rr->name) != 0) - host->name = string_copy_dnsdomain(rr->name); + host->name = string_copy_dnsdomain(rr->name); /*TTT*/ host->address = da->address; host->sort_key = host->mx * 1000 + random_number(500) + randoffset; host->status = hstatus_unknown; @@ -2530,7 +2531,7 @@ BOOL srv_smtps = FALSE; #endif int rc = DNS_FAIL, ind_type = 0, yield; dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; BOOL dnssec_require, dnssec_request; dnssec_status_t dnssec; @@ -2784,7 +2785,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); int port = PORT_NONE; /* MX lookups get PORT_NONE */ const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */ host_item * next; - uschar data[256]; + uschar data[256]; /*TTT*/ if (rr_bad_size(rr, sizeof(uint16_t))) continue; GETSHORT(precedence, s); /* Pointer s is advanced */ @@ -2811,8 +2812,10 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); /* Get the name of the host pointed to. */ - (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, - (DN_EXPAND_ARG4_TYPE)data, sizeof(data)); + /*TTT*/ + if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, + (DN_EXPAND_ARG4_TYPE)data, sizeof(data)) < 0) + continue; /* Check that we haven't already got this host on the chain; if we have, keep only the lower precedence. This situation shouldn't occur, but you @@ -2851,7 +2854,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); before the first block, copy the first block's data to a new second block. */ next = last ? store_get(sizeof(host_item), GET_UNTAINTED) : host; - next->name = string_copy_dnsdomain(data); + next->name = string_copy_dnsdomain(data); /*TTT*/ next->address = NULL; next->port = port; next->mx = precedence; @@ -3210,7 +3213,7 @@ switch (rc) { DEBUG(D_transport) { - dns_scan dnss; + dns_scan dnss = {0}; for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_TLSA && rr->size > 3) diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 6e2be8ae1..80cf2e62a 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -134,22 +134,19 @@ dnsdb_find(void * handle, const uschar * filename, const uschar * keystring, int length, uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts) { -int rc; -int sep = 0; int defer_mode = PASS, dnssec_mode = PASS; -int save_retrans = dns_retrans, save_retry = dns_retry; -int type; -int failrc = FAIL; +int save_retrans = dns_retrans, save_retry = dns_retry; +int sep = 0, rc, type, failrc = FAIL; const uschar * outsep = CUS"\n", * outsep2 = NULL; uschar * equals, * domain, * found; -dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_answer * dnsa = store_get_dns_answer(); /*TTT alloc */ +dns_scan dnss = {0}; /* Because we're working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ -gstring * yield = string_get(256); +gstring * yield = string_get_tainted(256, GET_TAINTED); /*TTT alloc*/ /* If the string starts with '>' we change the output separator. If it's followed by ';' or ',' we set the TXT output separator. */ @@ -406,6 +403,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) remain = rr->size - ++data_offset; if (chunk_len > remain) chunk_len = remain; + /*TTT*/ yield = string_catn(yield, US ((rr->data) + data_offset), chunk_len); data_offset += chunk_len; @@ -430,6 +428,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) if (payload_length > MAX_TLSA_EXPANDED_SIZE) payload_length = MAX_TLSA_EXPANDED_SIZE; + /*TTT*/ yield = string_fmt_append(yield, "%d%c%d%c%d%c%.*H", usage, *outsep2, selector, *outsep2, @@ -439,9 +438,15 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) else /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SOA, T_SRV */ { int priority, weight, port; - uschar s[264]; uschar * p = US rr->data; + /* NB: this memory is released implicitly by the call + gstring_release_unused(yield) below. We used to use a stack-auto, but + I want to track taint wherever possible. The dnsa is not (yet) + allocated using taint-marked memory. */ +#define LCL_BUF_SIZE 264 + uschar * buf = store_get(LCL_BUF_SIZE, GET_TAINTED); + switch (type) { case T_MXH: @@ -453,8 +458,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) case T_MX: if (rr_bad_size(rr, sizeof(uint16_t))) continue; GETSHORT(priority, p); - sprintf(CS s, "%d%c", priority, *outsep2); - yield = string_cat(yield, s); + yield = string_fmt_append(yield, "%d%c", priority, *outsep2); break; case T_SRV: @@ -462,9 +466,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) GETSHORT(priority, p); GETSHORT(weight, p); GETSHORT(port, p); - sprintf(CS s, "%d%c%d%c%d%c", priority, *outsep2, + yield = string_fmt_append(yield, "%d%c%d%c%d%c", priority, *outsep2, weight, *outsep2, port, *outsep2); - yield = string_cat(yield, s); break; case T_CSA: @@ -481,20 +484,18 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) authorization status in the weight field. */ if (Ustrcmp(found, domain) != 0) - { - if (port & 1) *s = 'X'; /* explicit authorization required */ - else *s = '?'; /* no subdomain assertions here */ - } + yield = string_catn(yield, port & 1 + ? US"X " /* explicit authorization required */ + : US"? ", /* no subdomain assertions here */ + 2); + else if (weight > 3) + continue; else - { - if (weight < 2) *s = 'N'; /* not authorized */ - else if (weight == 2) *s = 'Y'; /* authorized */ - else if (weight == 3) *s = '?'; /* unauthorizable */ - else continue; /* invalid */ - } - - s[1] = ' '; - yield = string_catn(yield, s, 2); + yield = string_catn(yield, + weight < 2 ? US"N " /* not authorized */ + : weight == 2 ? US"Y " /* authorized */ + : US"? ", /* unauthorizable */ + 2); break; default: @@ -503,8 +504,9 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* GETSHORT() has advanced the pointer to the target domain. */ + /*TTT*/ rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, - (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); + (DN_EXPAND_ARG4_TYPE)buf, LCL_BUF_SIZE); /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ @@ -515,7 +517,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, s); + else yield = string_cat(yield, buf); if (type == T_SOA && outsep2 != NULL) { @@ -524,15 +526,16 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) p += rc; yield = string_catn(yield, outsep2, 1); + /*TTT*/ rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, - (DN_EXPAND_ARG4_TYPE)s, sizeof(s)); + (DN_EXPAND_ARG4_TYPE)buf, LCL_BUF_SIZE); if (rc < 0) { log_write(0, LOG_MAIN, "responsible-mailbox truncated: type=%s " "domain=%s", dns_text_type(type), domain); break; } - else yield = string_cat(yield, s); + else yield = string_cat(yield, buf); p += rc; if (!rr_bad_increment(rr, p, 5 * sizeof(uint32_t))) @@ -540,12 +543,12 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) GETLONG(serial, p); GETLONG(refresh, p); GETLONG(retry, p); GETLONG(expire, p); GETLONG(minimum, p); } - sprintf(CS s, "%c%lu%c%lu%c%lu%c%lu%c%lu", + yield = string_fmt_append(yield, "%c%lu%c%lu%c%lu%c%lu%c%lu", *outsep2, serial, *outsep2, refresh, *outsep2, retry, *outsep2, expire, *outsep2, minimum); - yield = string_cat(yield, s); } } +#undef LCL_BUF_SIZE } /* Loop for list of returned records */ /* Loop for set of A-lookup types */ @@ -564,7 +567,7 @@ dns_retrans = save_retrans; dns_retry = save_retry; dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ -if (!yield || !yield->ptr) +if (gstring_length(yield) == 0) rc = failrc; else { diff --git a/src/src/miscmods/dkim.c b/src/src/miscmods/dkim.c index ccb649ca1..4bd87bbf9 100644 --- a/src/src/miscmods/dkim.c +++ b/src/src/miscmods/dkim.c @@ -81,9 +81,9 @@ static uschar * dkim_exim_query_dns_txt(const uschar * name) { dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; rmark reset_point = store_mark(); -gstring * g = string_get_tainted(256, GET_TAINTED); +gstring * g = string_get_tainted(256, GET_TAINTED); /*TTT alloc*/ lookup_dnssec_authenticated = NULL; if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED) @@ -100,6 +100,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); { uschar len = rr->data[rr_offset++]; + /*TTT*/ g = string_catn(g, US(rr->data + rr_offset), len); if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN) goto bad; diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index d6e27c892..1669d8400 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -228,7 +228,7 @@ const uschar * dmarc_dns_lookup(const uschar * dom) { dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; const uschar * res = NULL; expand_level++; @@ -256,7 +256,7 @@ if (dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL) if ( rr->type == T_TXT && len > 9 && Ustrncmp(rdata, "v=DMARC1;", 9) == 0) if (!res) - res = string_copyn_taint(rdata, len, GET_TAINTED); + res = string_copyn_taint(rdata, len, GET_TAINTED); /*XXX*/ else /* RFC 7489 6.6.3 step 5: multiple records are treated as no record */ { diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index 4febe7f4e..d97995d56 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -67,7 +67,7 @@ SPF_dns_exim_lookup(SPF_dns_server_t *spf_dns_server, const char *domain, ns_type rr_type, int should_cache) { dns_answer * dnsa = store_get_dns_answer(); -dns_scan dnss; +dns_scan dnss = {0}; SPF_dns_rr_t * spfrr; unsigned found = 0; @@ -134,9 +134,16 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; s += 2; /* skip the MX precedence field */ case T_PTR: { - uschar * buf = store_malloc(256); - (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, - (DN_EXPAND_ARG4_TYPE)buf, 256); + /* We lose taint-tracking here, really just assuming the data + given to the spf library will never leak back out. Not sure if + the lib assumes it can free this (it does for srr.rr) - meaning we + cannot use pool store. The use of malloc also for T_TXT implies so. */ + + uschar * buf = store_malloc(256); /*TTT alloc*/ + /*TTT*/ + if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, + (DN_EXPAND_ARG4_TYPE)buf, 256) < 0) + continue; s = buf; break; } @@ -160,12 +167,13 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; if ( !(chunk_len = s[offset++]) || rr->size < offset + chunk_len /* ignore bogus size chunks */ ) break; - g = string_catn(g, s+offset , chunk_len); + g = string_catn(g, s+offset , chunk_len); /*TTT*/ } if (!g) continue; + s = string_copy_malloc(string_from_gstring(g)); /*TTT*/ + gstring_reset(g); gstring_release_unused(g); - s = string_copy_malloc(string_from_gstring(g)); DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_lookup '%s'\n", s); break; } @@ -174,7 +182,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; case T_AAAA: default: { - uschar * buf = store_malloc(dnsa->answerlen + 1); + uschar * buf = store_malloc(dnsa->answerlen + 1); /*TTT alloc*/ s = memcpy(buf, s, dnsa->answerlen + 1); break; } diff --git a/src/src/store.c b/src/src/store.c index 4daa92512..e265acd4c 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -1217,7 +1217,7 @@ return yield; } void * -store_malloc_3(size_t size, const char *func, int linenumber) +store_malloc_3(size_t size, const char * func, int linenumber) { if (n_nonpool_blocks++ > max_nonpool_blocks) max_nonpool_blocks = n_nonpool_blocks; diff --git a/src/src/string.c b/src/src/string.c index 472008382..4e122a97b 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -618,9 +618,10 @@ Returns: copy of string in new store, de-escaped */ uschar * -string_copy_dnsdomain(uschar * s) +string_copy_dnsdomain(const uschar * s) { uschar * yield; +/*TTT*/ uschar * ss = yield = store_get(Ustrlen(s) + 1, GET_TAINTED); /* always treat as tainted */ while (*s) diff --git a/src/src/structs.h b/src/src/structs.h index a6261afcb..22a4bba90 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -760,11 +760,11 @@ typedef struct search_cache { uncompressed, but the data pointer is into the raw data. */ typedef struct { - uschar name[DNS_MAXNAME]; /* domain name */ - int type; /* record type */ - unsigned short ttl; /* time-to-live, seconds */ - int size; /* size of data */ - const uschar *data; /* pointer to data */ + uschar *name; /* domain name */ + int type; /* record type */ + unsigned short ttl; /* time-to-live, seconds */ + int size; /* size of data */ + const uschar *data; /* pointer to data */ } dns_record; /* Structure for holding the result of a DNS query. A touch over @@ -826,6 +826,9 @@ typedef struct { #ifdef SUPPORT_DANE BOOL dane:1; /* TLSA says connection must do dane */ + /*TTT alloc*/ + /* Strictly, this should use tainted mem. Also, is rather large - 64k - so + perhaps should be allocated only when needed (for DANE)? */ dns_answer tlsa_dnsa; /* strictly, this should use tainted mem */ #endif } smtp_connect_args; diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index b78c33fcb..1610387d9 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3397,7 +3397,7 @@ after verification is done.*/ static BOOL dane_tlsa_load(exim_gnutls_state_st * state, const dns_answer * dnsa) { -dns_scan dnss; +dns_scan dnss = {0}; int i; const char ** dane_data; int * dane_data_len; @@ -3416,7 +3416,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; ) if (rr->type == T_TLSA && rr->size > 3) { const uschar * p = rr->data; -/*XXX need somehow to mark rr and its data as tainted. Doues this mean copying it? */ +/*XXX need somehow to mark rr and its data as tainted. Doues this mean copying it? *//*TTT*/ uint8_t usage = p[0], sel = p[1], type = p[2]; DEBUG(D_tls) @@ -3438,7 +3438,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; } tls_out.tlsa_usage |= 1<size; } diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index eea1f15d3..40acee7a3 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -3940,7 +3940,7 @@ static int dane_tlsa_load(SSL * ssl, const host_item * host, const dns_answer * dnsa, uschar ** errstr) { -dns_scan dnss; +dns_scan dnss = {0}; const char * hostnames[2] = { CS host->name, NULL }; int found = 0; @@ -3972,6 +3972,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; } found++; + /*TTT*/ switch (DANESSL_add_tlsa(ssl, usage, selector, mdname, p, rr->size - 3)) { default: diff --git a/src/src/tls.c b/src/src/tls.c index dd82c7156..041cca5e9 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -879,7 +879,10 @@ tls_client_adjunct_start(host_item * host, client_conn_ctx * cctx, { union sockaddr_46 interface_sock; EXIM_SOCKLEN_T size = sizeof(interface_sock); + +/* Large (64k if DANE supported) */ smtp_connect_args conn_args = {.host = host }; + tls_support tls_dummy = { .sni = NULL }; uschar * errstr; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 7160f0616..1f2161ae2 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -4045,8 +4045,11 @@ int yield = OK; int save_errno; int rc; -uschar *message = NULL; -smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted, for the data buffers */ +uschar * message = NULL; + +/* Large (12k, 66k if DANE supported). Tainted, for the data buffers */ +smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); + BOOL pass_message = FALSE; #ifndef DISABLE_ESMTP_LIMITS BOOL mail_limit = FALSE; @@ -5346,7 +5349,7 @@ smtp_transport_closedown(transport_instance * tblock) { const smtp_transport_options_block * ob = tblock->drinst.options_block; client_conn_ctx cctx; -smtp_context sx = {0}; +smtp_context sx = {0}; /* Large (12k, 66k if DANE supported) */ uschar buffer[256]; uschar inbuffer[4096]; uschar outbuffer[16]; @@ -5381,7 +5384,7 @@ int smtp_write_atrn(address_item * addr, cut_t * cutp) { const smtp_transport_options_block * ob = addr->transport->drinst.options_block; -smtp_context sx = {0}; +smtp_context sx = {0}; /* Large (12k, 66k if DANE supported */ uschar buffer[256]; uschar inbuffer[4096]; uschar outbuffer[256]; diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 49e3c8b96..506d6094a 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -144,7 +144,7 @@ typedef struct { const uschar * from_addr; address_item * addrlist; - smtp_connect_args conn_args; + smtp_connect_args conn_args; /* Large (if DANE supported) */ int port; BOOL verify:1; diff --git a/src/src/transports/smtp_socks.c b/src/src/transports/smtp_socks.c index 436674e9b..c17b808e9 100644 --- a/src/src/transports/smtp_socks.c +++ b/src/src/transports/smtp_socks.c @@ -258,6 +258,8 @@ for(;;) { int idx; host_item proxy; + + /* Large (64k if DANE supported) */ smtp_connect_args proxy_sc = {.sock = -1}; if ((idx = socks_get_proxy(proxies, nproxies)) < 0) diff --git a/src/src/verify.c b/src/src/verify.c index 18c53c1e8..6696ec4d9 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -16,7 +16,7 @@ caching was contributed by Kevin Fleming (but I hacked it around a bit). */ #define CUTTHROUGH_CMD_TIMEOUT 30 /* timeout for cutthrough-routing calls */ #define CUTTHROUGH_DATA_TIMEOUT 60 /* timeout for cutthrough-routing calls */ -static smtp_context ctctx; +static smtp_context ctctx; /* Large (12k, 66k if DANE supported */ uschar ctbuffer[8192]; @@ -703,7 +703,8 @@ coding means skipping this whole loop and doing the append separately. */ log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, addr->message); - if (!sx) sx = store_get(sizeof(*sx), GET_TAINTED); /* tainted buffers */ + /* Large (12k, 66k if DANE supported. Tainted, for the receive buffers */ + if (!sx) sx = store_get(sizeof(*sx), GET_TAINTED); memset(sx, 0, sizeof(*sx)); sx->addrlist = sx->first_addr = addr; @@ -1417,7 +1418,7 @@ Used for static uschar cutthrough_response(client_conn_ctx * cctx, char expect, uschar ** copy, int timeout) { -smtp_context sx = {0}; +smtp_context sx = {0}; /* Large (12k, 66k if DANE supported) */ uschar inbuffer[4096]; uschar responsebuffer[4096]; commit 6b77712fcc9e4daf673751f0302c1ae003ed7dce Author: Jeremy Harris Date: Sun Dec 7 13:17:41 2025 +0000 DMARC: fix retval for module init diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index 8d840ae84..49ad795c2 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -63,9 +63,9 @@ extern uschar * dmarc_history_file; /* File to store dmarc results */ extern uschar * dmarc_tld_file; /* Mozilla TLDs text file */ -void +BOOL dmarc_local_init(void) -{} +{ return TRUE; } gstring * dmarc_version_report(gstring * g) diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index 02eb5dbd3..084adab28 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -48,6 +48,7 @@ if (!dmarc_regex_ri) dmarc_regex_ri = regex_must_compile(US "^\\d{1,10}$", MCS_CACHEABLE, FALSE); if (!dmarc_regex_fo) dmarc_regex_fo = regex_must_compile(US "^[01ds]$", MCS_CACHEABLE, FALSE); +return TRUE; } commit 01c6fb5f07c0d7555e45ab0409dd8e551359dc2c Author: Jeremy Harris Date: Sun Dec 7 14:16:30 2025 +0000 tidying diff --git a/src/src/exim.c b/src/src/exim.c index 32ca1e1d2..d35168d60 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -988,13 +988,13 @@ has the effect of collapsing source routes. Arguments: s the address string flags flag bits for verify_address() - exit_value to be set for failures + ret exit value so far -Returns: nothing +Returns: updated exit value */ -static void -test_address(const uschar * s, int flags, int * exit_value) +static int +test_address(const uschar * s, int flags, int ret) { int start, end, domain; uschar * parse_error = NULL; @@ -1003,16 +1003,17 @@ const uschar * address = parse_extract_address(s, &parse_error, if (!address) { fprintf(stdout, "syntax error: %s\n", parse_error); - *exit_value = 2; + ret = 2; } else { /* NB we lose stdio buffering here */ int rc = verify_address(deliver_make_addr(address,TRUE), fileno(stdout), flags, -1, -1, -1, NULL, NULL, NULL); - if (rc == FAIL) *exit_value = 2; - else if (rc == DEFER && *exit_value == 0) *exit_value = 1; + if (rc == FAIL) ret = 2; + else if (rc == DEFER && ret == EXIT_SUCCESS) ret = EXIT_FAILURE; } +return ret; } @@ -5302,8 +5303,7 @@ stdin. Set debug_level to at least D_v to get full output for address testing. if (verify_address_mode || f.address_test_mode) { - int exit_value = 0; - int flags = vopt_qualify; + int exit_value = EXIT_SUCCESS, flags = vopt_qualify; if (verify_address_mode) { @@ -5320,33 +5320,35 @@ if (verify_address_mode || f.address_test_mode) DEBUG(D_verify) debug_print_ids(US"Address testing:"); } - if (recipients_arg < argc) + if (recipients_arg < argc) /* addresses on cmdline */ while (recipients_arg < argc) { /* Supplied addresses are tainted since they come from a user */ uschar * s = string_copy_taint( - exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"), + exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, + "address verification"), GET_TAINTED); while (*s) { BOOL finished = FALSE; uschar * ss = parse_find_address_end(s, FALSE); if (*ss == ',') *ss = 0; else finished = TRUE; - test_address(s, flags, &exit_value); + exit_value = test_address(s, flags, exit_value); s = ss; if (!finished) while (*++s == ',' || isspace(*s)) ; } } - else for (;;) + else for (;;) /* addresses from stdin */ { const uschar * s = get_stdinput(NULL, NULL); if (!s) break; - test_address(string_copy_taint( - exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"), + exit_value = test_address(string_copy_taint( + exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, + "address verification (stdin)"), GET_TAINTED), - flags, &exit_value); + flags, exit_value); } route_tidyup(); diff --git a/src/src/lookups/psl.c b/src/src/lookups/psl.c index 9171192a3..3b2af489e 100644 --- a/src/src/lookups/psl.c +++ b/src/src/lookups/psl.c @@ -46,7 +46,7 @@ psl_gen_find(void * handle, const uschar * keystring, int length, uschar ** result, uschar ** errmsg, BOOL is_regdom) { uschar rulebuf[128], * res = NULL; -const uschar * s, * k, * kmatch; +const uschar * s, * k, * kmatch = NULL; unsigned res_label_cnt = 0, nlabels; BOOL key_utf8; @@ -138,7 +138,7 @@ while ((s = US fgets(CS rulebuf, sizeof(rulebuf), handle))) kmatch = k; } - nonmatch: + nonmatch: ; } } /* kmatch is the key trail after the regdom. label */ diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index 084adab28..a3434a146 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -359,7 +359,7 @@ if (!dmarc_abort && !sender_host_authenticated) .ri = US"86400", }; - int sr = SPF_RESULT_INVALID, spf_origin; + int sr = SPF_RESULT_INVALID /*, spf_origin*/; uschar * spf_human_readable = NULL, * spf_sender_domain = NULL; unsigned dkim_sig_count = 0; gstring * dkim_history_buffer = NULL; @@ -525,7 +525,7 @@ if (!dmarc_abort && !sender_host_authenticated) } spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; - spf_origin = DMARC_POLICY_SPF_ORIGIN_HELO; + /* spf_origin = DMARC_POLICY_SPF_ORIGIN_HELO; */ spf_human_readable = US""; } else @@ -544,7 +544,7 @@ if (!dmarc_abort && !sender_host_authenticated) sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR : ARES_RESULT_UNKNOWN; /*XXX hmm, spf_origin never used? */ - spf_origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; + /* spf_origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; */ DEBUG(D_receive) debug_printf_indent("DMARC: using SPF sender domain = %s\n", spf_sender_domain); diff --git a/src/src/moan.c b/src/src/moan.c index 01bf4f578..e5af5e511 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -666,7 +666,7 @@ void moan_smtp_batch(const uschar * cmd_buffer, const char * format, ...) { va_list ap; -int yield = (receive_messagecount > 0)? 1 : 2; +int yield = receive_messagecount > 0 ? EXIT_FAILURE : 2; DEBUG(D_any) debug_printf("Handling error in batched SMTP input\n"); diff --git a/src/src/string.c b/src/src/string.c index 4e122a97b..6be0b7678 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1835,9 +1835,9 @@ while (*fp) else die_tainted(US"string_vformat", func, line); #endif - - INSERT_STRING: /* Come to from %D or %M above */ - +#ifndef COMPILE_UTILITY + INSERT_STRING: /* Come from %D or %M above */ +#endif { BOOL truncated = FALSE; commit c038d63e56be080c1bf8043b2fc5c3aac4b57544 Author: Jeremy Harris Date: Mon Dec 8 11:37:18 2025 +0000 DMARC: downgrade detailed result logging to debug diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index 49ad795c2..ce000ef8e 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -431,8 +431,8 @@ The EDITME provides a DMARC_API variable */ dmarc_alignment_dkim = dmarc_dkim_alignment == DMARC_POLICY_DKIM_ALIGNMENT_PASS; - if (LOGGING(dmarc_verbose)) - log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + DEBUG(D_receive) + debug_printf_indent("DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, dmarc_alignment_spf ? "yes" : "no", diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index a3434a146..aa28df583 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -631,17 +631,14 @@ use the sp. Otherwise use the p. */ if (has_dmarc_record && !dmarc_abort) { - /* Log results. */ - - if (LOGGING(dmarc_verbose)) - log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s " + DEBUG(D_receive) + debug_printf_indent("DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, dmarc_alignment_spf ? "yes" : "no", dmarc_alignment_dkim ? "yes" : "no", dmarc_status_text); - /* History file, for later aggregate reporting. */ dmarc_pct = atoi(CCS dmarc_parsed.pct); commit abef0531c0676680cab9b1fbd91da4482e35d45d Author: Jeremy Harris Date: Mon Dec 8 16:02:57 2025 +0000 DMARC: fix for empty env-from. Bug 1994 diff --git a/src/src/expand.c b/src/src/expand.c index 1b5980f5b..e222e8e75 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -719,6 +719,7 @@ static var_entry var_table[] = { { "spf_result", vtype_module, US"spf" }, { "spf_result_guessed", vtype_module, US"spf" }, { "spf_smtp_comment", vtype_module, US"spf" }, + { "spf_used_domain", vtype_module, US"spf" }, #endif { "spool_directory", vtype_stringptr, &spool_directory }, { "spool_inodes", vtype_pinodes, (void *)TRUE }, diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index ce000ef8e..a18100c81 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -206,30 +206,19 @@ if (!dmarc_abort && !sender_host_authenticated) int sr = SPF_RESULT_INVALID, origin; uschar * spf_human_readable = NULL, * spf_sender_domain; gstring * dkim_history_buffer = NULL; - typedef const pdkim_signature * (*sigs_fn_t)(void); + typedef const pdkim_signature * (*dkim_sigs_fn_t)(void); + typedef int (*spf_fn_t)(uschar **); - /* Use the envelope sender domain for this part of DMARC */ + if (dmarc_spf_mod_info) + sr = ((spf_fn_t *) dmarc_spf_mod_info->functions)[SPF_GET_RESULTS] + (&spf_human_readable); - spf_sender_domain = expand_string(US"$sender_address_domain"); - - { - typedef int (*fn_t)(uschar **); - if (dmarc_spf_mod_info) - sr = ((fn_t *) dmarc_spf_mod_info->functions)[SPF_GET_RESULTS] - (&spf_human_readable); - } + spf_sender_domain = expand_string(US"$spf_used_domain"); if (sr == SPF_RESULT_INVALID) { - /* No spf data means null envelope sender so generate a domain name - from the sender_helo_name */ - - if (!spf_sender_domain || !*spf_sender_domain) - { - spf_sender_domain = sender_helo_name; - log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", - spf_sender_domain); - } + DEBUG(D_receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); + dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; origin = DMARC_POLICY_SPF_ORIGIN_HELO; @@ -237,11 +226,12 @@ if (!dmarc_abort && !sender_host_authenticated) } else { - dmarc_spf_result = sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE : - sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS : - sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL : - sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL : - DMARC_POLICY_SPF_OUTCOME_NONE; + dmarc_spf_result = + sr == SPF_RESULT_NEUTRAL ? DMARC_POLICY_SPF_OUTCOME_NONE : + sr == SPF_RESULT_PASS ? DMARC_POLICY_SPF_OUTCOME_PASS : + sr == SPF_RESULT_FAIL ? DMARC_POLICY_SPF_OUTCOME_FAIL : + sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL : + DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL ? ARES_RESULT_NEUTRAL : sr == SPF_RESULT_PASS ? ARES_RESULT_PASS : sr == SPF_RESULT_FAIL ? ARES_RESULT_FAIL : @@ -269,7 +259,7 @@ if (!dmarc_abort && !sender_host_authenticated) the opendmarc context, further building the DMARC reply. */ for(const pdkim_signature * sig = - (((sigs_fn_t *)dmarc_dkim_mod_info->functions)[DKIM_SIGS_LIST])(); + (((dkim_sigs_fn_t *)dmarc_dkim_mod_info->functions)[DKIM_SIGS_LIST])(); sig; sig = sig->next) { int dkim_result, dkim_ares_result, vs, ves; diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index aa28df583..f0c91868b 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -360,7 +360,8 @@ if (!dmarc_abort && !sender_host_authenticated) }; int sr = SPF_RESULT_INVALID /*, spf_origin*/; - uschar * spf_human_readable = NULL, * spf_sender_domain = NULL; + uschar * spf_human_readable = NULL; + const uschar * spf_sender_domain = NULL; unsigned dkim_sig_count = 0; gstring * dkim_history_buffer = NULL; typedef const pdkim_signature * (*sigs_fn_t)(void); @@ -502,30 +503,19 @@ if (!dmarc_abort && !sender_host_authenticated) int spf_result; typedef int (*fn_t)(uschar **); - /* Use the envelope sender domain for this part of DMARC */ - - spf_sender_domain = expand_string(US"$sender_address_domain"); - if (dmarc_spf_mod_info) sr = ((fn_t *) dmarc_spf_mod_info->functions)[SPF_GET_RESULTS] (&spf_human_readable); + spf_sender_domain = expand_string(CUS"$spf_used_domain"); + if (sr == SPF_RESULT_INVALID) { - /* No spf data means null envelope sender so generate a domain name - from the sender_helo_name */ - DEBUG(D_receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); - if (!spf_sender_domain || !*spf_sender_domain) - { - spf_sender_domain = sender_helo_name; - log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n", - spf_sender_domain); - } spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; - /* spf_origin = DMARC_POLICY_SPF_ORIGIN_HELO; */ + /* spf_origin = DMARC_POLICY_SPF_ORIGIN_HELO; not used, and we'd want to ask the spf impl really */ spf_human_readable = US""; } else diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index d97995d56..a0cdb8dc6 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -42,7 +42,8 @@ uschar * spf_smtp_comment = NULL; uschar * spf_smtp_comment_template /* Used to be: "Please%_see%_http://www.open-spf.org/Why?id=%{S}&ip=%{C}&receiver=%{R}" */ = US"Please%_see%_http://www.open-spf.org/Why"; -BOOL spf_result_guessed = FALSE; +BOOL spf_result_guessed = FALSE; +const uschar * spf_used_domain = NULL; @@ -409,6 +410,9 @@ else spf_received = US SPF_response_get_received_spf(spf_response); spf_result = US SPF_strresult(SPF_response_result(spf_response)); spf_smtp_comment = US SPF_response_get_smtp_comment(spf_response); + spf_used_domain = sender_address && *sender_address + ? expand_string(US"$sender_address_domain") + : sender_helo_name; rc = SPF_response_result(spf_response); @@ -595,6 +599,7 @@ static var_entry spf_variables[] = { { "spf_result", vtype_stringptr, &spf_result }, { "spf_result_guessed", vtype_bool, &spf_result_guessed }, { "spf_smtp_comment", vtype_stringptr, &spf_smtp_comment }, + { "spf_used_domain", vtype_stringptr, &spf_used_domain }, }; misc_module_info spf_module_info = diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index 55741eef0..c30e0efe4 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -43,7 +43,8 @@ uschar * spf_smtp_comment = NULL; uschar * spf_smtp_comment_template /* Used to be: "Please%_see%_http://www.open-spf.org/Why?id=%{S}&ip=%{C}&receiver=%{R}" */ = US"Please%_see%_http://www.open-spf.org/Why"; -BOOL spf_result_guessed = FALSE; +BOOL spf_result_guessed = FALSE; +const uschar * spf_used_domain = NULL; static const misc_module_info * spf_perl_mi = NULL; @@ -196,6 +197,10 @@ else uschar * t = Ustrchr(s, ')'); /* grab a (comment) if there is one */ if (t) spf_header_comment = string_copyn(s+1, t-s-1); } + + spf_used_domain = sender_address && *sender_address + ? expand_string(US"$sender_address_domain") + : sender_helo_name; } res = match_isinlist(spf_result, &arglist, @@ -344,6 +349,7 @@ static var_entry spf_variables[] = { { "spf_result", vtype_stringptr, &spf_result }, { "spf_result_guessed", vtype_bool, &spf_result_guessed }, { "spf_smtp_comment", vtype_stringptr, &spf_smtp_comment }, + { "spf_used_domain", vtype_stringptr, &spf_used_domain }, }; misc_module_info spf_module_info = commit b064cc0ef055fdcb91c971234b756e494f64e347 Author: Jeremy Harris Date: Tue Dec 9 10:59:13 2025 +0000 DMARC: rework module API diff --git a/src/src/acl.c b/src/src/acl.c index b3c45668a..63478ca7d 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3939,25 +3939,20 @@ for (; cb; cb = cb->next) /* See comment on ACLC_SPF wrt. coding issues */ { misc_module_info * mi = misc_mod_find(US"dmarc", &log_message); - typedef const uschar * (*efn_t)(void); - const uschar * expanded_query; + typedef int (*pfn_t)(void); + typedef int (*mfn_t)(const uschar * const *); if (!mi) - { rc = DEFER; break; } /* shouldn't happen */ - - if (!f.dmarc_has_been_checked) /* only once per message */ + rc = DEFER; /* shouldn't happen */ + else { - typedef int (*pfn_t)(void); - (void) (((pfn_t *) mi->functions)[DMARC_PROCESS]) (); - f.dmarc_has_been_checked = TRUE; + if (!f.dmarc_has_been_checked) /* only once per message */ + { + (void) (((pfn_t *) mi->functions)[DMARC_PROCESS]) (); + f.dmarc_has_been_checked = TRUE; + } + rc = (((mfn_t *) mi->functions)[DMARC_RESULT_INLIST]) (&arg); } - - /* used long way of dmarc_exim_expand_query() in case we need more - view into the process in the future. */ - - expanded_query = (((efn_t *) mi->functions)[DMARC_EXPAND_QUERY]) (); - rc = match_isinlist(expanded_query, - &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL); } break; #endif diff --git a/src/src/globals.c b/src/src/globals.c index 610c72909..6c8e8ec05 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -838,6 +838,7 @@ volatile sig_atomic_t had_command_sigterm = 0; volatile sig_atomic_t had_data_timeout = 0; volatile sig_atomic_t had_data_sigint = 0; const uschar *headers_charset = US HEADERS_CHARSET; +const uschar *header_from = NULL; /* mainly for dmarc */ int header_insert_maxlen = 64 * 1024; header_line *header_last = NULL; header_line *header_list = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 1c133f5ea..977107f58 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -633,6 +633,7 @@ extern volatile sig_atomic_t had_command_timeout; /* Alarm sighandler called * extern volatile sig_atomic_t had_command_sigterm; /* TERM sighandler called */ extern volatile sig_atomic_t had_data_timeout; /* Alarm sighandler called */ extern volatile sig_atomic_t had_data_sigint; /* TERM/INT sighandler called */ +extern const uschar *header_from; /* Text of the From: header */ extern int header_insert_maxlen; /* Max for inserting headers */ extern int header_maxsize; /* Max total length for header */ extern int header_line_maxsize; /* Max for an individual line */ diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index a18100c81..5a5ea7398 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -161,7 +161,7 @@ is locally generated and relying on fixups to add it. Just skip the entire DMARC system if we can't find a From: header....or if there was a previous error. */ -if (!dmarc_from_header) +if (!header_from) { DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); dmarc_abort = TRUE; @@ -173,10 +173,10 @@ else if (!dmarc_abort) int dummy, domain; f.parse_allow_group = TRUE; - end_addr = parse_find_address_end(dmarc_from_header, FALSE); + end_addr = parse_find_address_end(header_from, FALSE); s = *end_addr - ? string_copyn(dmarc_from_header, end_addr - dmarc_from_header) - : dmarc_from_header; + ? string_copyn(header_from, end_addr - header_from) + : header_from; if ((dmarc_header_from_sender = parse_extract_address(s, &errormsg, &dummy, &dummy, &domain, FALSE))) dmarc_header_from_sender += domain; @@ -193,7 +193,7 @@ else if (!dmarc_abort) { log_write(0, LOG_MAIN|LOG_PANIC, "failure to store header From: in DMARC: %s, header was '%s'", - opendmarc_policy_status_to_str(libdm_status), dmarc_from_header); + opendmarc_policy_status_to_str(libdm_status), header_from); dmarc_abort = TRUE; } } @@ -335,7 +335,7 @@ The EDITME provides a DMARC_API variable */ DEBUG(D_receive) debug_printf_indent("DMARC skipping (%s), unsure what to do with %s", opendmarc_policy_status_to_str(libdm_status), - dmarc_from_header); + header_from); has_dmarc_record = FALSE; break; } @@ -458,14 +458,17 @@ dmarc_exim_expand_defaults(void) return f.dmarc_disable_verify ? US"off" : US"none"; } -/*API*/ -const uschar * -dmarc_exim_expand_query(void) +/*API +Check result against list. Return OK/FAIL/DEFER. +*/ +int +dmarc_result_inlist(const uschar * const * listp) { -if (f.dmarc_disable_verify || !dmarc_pctx) - return dmarc_exim_expand_defaults(); - -return dmarc_status; +const uschar * res = + f.dmarc_disable_verify || !dmarc_pctx + ? dmarc_exim_expand_defaults() + : dmarc_status; +return match_isinlist(res, listp, 0, NULL, NULL, MCL_STRING, TRUE, NULL); } diff --git a/src/src/miscmods/dmarc.h b/src/src/miscmods/dmarc.h index 6f8c456dd..fe3138cf2 100644 --- a/src/src/miscmods/dmarc.h +++ b/src/src/miscmods/dmarc.h @@ -120,7 +120,6 @@ extern BOOL dmarc_abort; extern uschar * dmarc_header_from_sender; extern uschar * dmarc_pass_fail; -extern const uschar * dmarc_from_header; extern const misc_module_info * dmarc_dkim_mod_info; extern const misc_module_info * dmarc_spf_mod_info; extern int dmarc_spf_ares_result; diff --git a/src/src/miscmods/dmarc_api.h b/src/src/miscmods/dmarc_api.h index 54b1630a6..e99b45804 100644 --- a/src/src/miscmods/dmarc_api.h +++ b/src/src/miscmods/dmarc_api.h @@ -12,5 +12,4 @@ /* Function table entry numbers */ #define DMARC_PROCESS 0 -#define DMARC_EXPAND_QUERY 1 -#define DMARC_STORE_FROMHDR 2 +#define DMARC_RESULT_INLIST 1 diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index 1669d8400..35b832c59 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -15,7 +15,7 @@ extern BOOL dmarc_local_init(void); extern void dmarc_local_msg_init(void); extern gstring * dmarc_version_report(gstring *); extern int dmarc_process(void); -extern const uschar * dmarc_exim_expand_query(void); +extern const uschar * dmarc_result_inlist(const uschar * const *); /* Other modules needed for services */ @@ -26,7 +26,6 @@ const misc_module_info * dmarc_arc_mod_info; /* Working data */ BOOL dmarc_abort; uschar * dmarc_pass_fail; /* for authres */ -const uschar * dmarc_from_header; uschar * dmarc_header_from_sender; /* results */ @@ -96,7 +95,6 @@ dmarc_msg_init(void) multiple messages in one connection. */ f.dmarc_has_been_checked = FALSE; -dmarc_from_header = NULL; dmarc_header_from_sender = NULL; dmarc_spf_ares_result = ARES_RESULT_UNDEFINED; dmarc_status = US"none"; @@ -140,18 +138,6 @@ dmarc_domain_policy = dmarc_status = dmarc_status_text = } -/* API: dmarc_store_data stores the header data so that subsequent dmarc_process -can access the data. Cleared by msg_init. -Called after the entire message has been received, with the From: header. */ - -static void -dmarc_store_fromhdr(const uschar * hdr) -{ -/* No debug output because would change every test debug output */ -dmarc_from_header = hdr; -} - - /* Accept an error_block struct, initialize if empty, parse to the end, and append the two strings passed to it. Used for adding variable amounts of value:pair data to the forensic emails. */ @@ -501,8 +487,7 @@ static optionlist dmarc_options[] = { static void * dmarc_functions[] = { [DMARC_PROCESS] = (void *) dmarc_process, - [DMARC_EXPAND_QUERY] = (void *) dmarc_exim_expand_query, - [DMARC_STORE_FROMHDR] = (void *) dmarc_store_fromhdr, + [DMARC_RESULT_INLIST] = (void *) dmarc_result_inlist, }; /* dmarc_forensic_sender is provided for visibility of the the option setting diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index f0c91868b..96628dee1 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -310,7 +310,7 @@ is locally generated and relying on fixups to add it. Just skip the entire DMARC system if we can't find a From: header....or if there was a previous error. */ -if (!dmarc_from_header) +if (!header_from) { DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); dmarc_abort = TRUE; @@ -323,10 +323,10 @@ else int dummy, domain; f.parse_allow_group = TRUE; - end_addr = parse_find_address_end(dmarc_from_header, FALSE); + end_addr = parse_find_address_end(header_from, FALSE); s = *end_addr - ? string_copyn(dmarc_from_header, end_addr - dmarc_from_header) - : dmarc_from_header; + ? string_copyn(header_from, end_addr - header_from) + : header_from; if ((dmarc_header_from_sender = parse_extract_address(s, &errormsg, &dummy, &dummy, &domain, FALSE))) dmarc_header_from_sender += domain; @@ -668,14 +668,15 @@ dmarc_exim_expand_defaults(void) return f.dmarc_disable_verify ? US"off" : US"none"; } -/*API*/ -const uschar * -dmarc_exim_expand_query(void) +/*API +Check result against list. Return OK/FAIL/DEFER. +*/ +int +dmarc_result_inlist(const uschar * const * listp) { -if (f.dmarc_disable_verify ) // || !dmarc_pctx) - return dmarc_exim_expand_defaults(); - -return dmarc_status; +const uschar * res = + f.dmarc_disable_verify ? dmarc_exim_expand_defaults() : dmarc_status; +return match_isinlist(res, listp, 0, NULL, NULL, MCL_STRING, TRUE, NULL); } diff --git a/src/src/receive.c b/src/src/receive.c index 7827d0288..f1833c5a0 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1732,47 +1732,36 @@ not. */ BOOL receive_msg(BOOL extract_recip) { -int rc = FAIL; -int msg_size = 0; -int process_info_len = Ustrlen(process_info); +int rc = FAIL, msg_size = 0, process_info_len = Ustrlen(process_info); +int header_size = 256, had_zero = 0, prevlines_length = 0, ptr = 0; + int error_rc = error_handling == ERRORS_SENDER ? errors_sender_rc : EXIT_FAILURE; -int header_size = 256; -int had_zero = 0; -int prevlines_length = 0; const int id_resolution = BASE_62 == 62 && !host_number_string ? 1 : BASE_62 != 62 && host_number_string ? 4 : 2; -int ptr = 0; - -BOOL contains_resent_headers = FALSE; -BOOL extracted_ignored = FALSE; -BOOL first_line_ended_crlf = TRUE_UNSET; -BOOL smtp_yield = TRUE; -BOOL yield = FALSE; +BOOL contains_resent_headers = FALSE, extracted_ignored = FALSE; +BOOL first_line_ended_crlf = TRUE_UNSET, smtp_yield = TRUE, yield = FALSE; BOOL resents_exist = FALSE; -uschar *resent_prefix = US""; -uschar *blackholed_by = NULL; -uschar *blackhole_log_msg = US""; +uschar * resent_prefix = US"", * blackholed_by = NULL; +uschar * blackhole_log_msg = US""; enum {NOT_TRIED, TMP_REJ, PERM_REJ, ACCEPTED} cutthrough_done = NOT_TRIED; flock_t lock_data; -error_block *bad_addresses = NULL; +error_block * bad_addresses = NULL; -uschar *frozen_by = NULL; -uschar *queued_by = NULL; +uschar * frozen_by = NULL, * queued_by = NULL; -uschar *errmsg; +uschar * errmsg; rmark rcvd_log_reset_point; gstring * g; struct stat statbuf; /* Final message to give to SMTP caller, and messages from ACLs */ -uschar *smtp_reply = NULL; -uschar *user_msg, *log_msg; +uschar * smtp_reply = NULL, * user_msg, * log_msg; /* Working header pointers */ @@ -1808,6 +1797,7 @@ search_tidyup(); /* Extracting the recipient list from an input file is incompatible with cutthrough delivery with the no-spool option. It shouldn't be possible to set up the combination, but just in case kill any ongoing connection. */ + if (extract_recip || !smtp_input) cancel_cutthrough_connection(TRUE, US"not smtp input"); @@ -1815,7 +1805,8 @@ if (extract_recip || !smtp_input) header. Temporarily mark it as "old", i.e. not to be used. We keep header_last pointing to the end of the chain to make adding headers simple. */ -received_header = header_list = header_last = store_get(sizeof(header_line), GET_UNTAINTED); +received_header = header_list = header_last = + store_get(sizeof(header_line), GET_UNTAINTED); header_list->next = NULL; header_list->type = htype_old; header_list->text = NULL; @@ -1842,11 +1833,7 @@ received_count = 1; /* For the one we will add */ if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX; -/* While reading the message, the following counts are computed. */ - -message_linecount = body_linecount = body_zerocount = - max_received_linelength = 0; - +header_from = NULL; #ifdef WITH_CONTENT_SCAN /* reset non-per-part mime variables */ mime_is_coverletter = 0; @@ -1857,6 +1844,11 @@ mime_part_count = -1; if (misc_mod_msg_init() != OK) goto CONN_GONE; +/* While reading the message, the following counts are computed. */ + +message_linecount = body_linecount = body_zerocount = + max_received_linelength = 0; + /* In SMTP sessions we may receive several messages in one connection. Before each subsequent one, we wait for the clock to tick at the level of message-id granularity. @@ -2170,7 +2162,7 @@ OVERSIZE: beyond it. If it turns out to be a real header, internal binary zeros will be squashed later. */ - next->text[ptr] = 0; + next->text[ptr] = '\0'; next->slen = ptr; store_release_above(next->text + ptr + 1); @@ -2483,17 +2475,7 @@ for (header_line * h = header_list->next; h; h = h->next) case htype_from: h->type = htype_from; -#ifdef EXIM_HAVE_DMARC - if (!is_resent && !f.dmarc_disable_verify) - { - misc_module_info * mi = misc_mod_findonly(US"dmarc"); - if (mi) - { - typedef void (*fn_t)(const uschar *); - (((fn_t *) mi->functions)[DMARC_STORE_FROMHDR]) (h->text); - } - } -#endif + if (!is_resent) header_from = h->text; if (!resents_exist || is_resent) { from_header = h; commit 6b109f69cfc8804105f373dd22936d7b9edd66f9 Author: Jeremy Harris Date: Sat Dec 13 11:58:46 2025 +0000 Debug: tweaks diff --git a/src/src/drtables.c b/src/src/drtables.c index 45b1ade16..bf1c3e530 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -287,7 +287,7 @@ void * dl; struct misc_module_info * mi; const char * errormsg; -EARLY_DEBUG(D_any, "loading module %q\n", name); +EARLY_DEBUG(D_any, "Loading module %q\n", name); if (!(dl = mod_open(name, US"miscmod", errstr))) { if (errstr) EARLY_DEBUG(D_any, " mod_open: %s\n", *errstr); @@ -313,7 +313,7 @@ if (mi->dyn_magic != MISC_MODULE_MAGIC) return FALSE; } -EARLY_DEBUG(D_lookup, "loaded %q\n", name); +EARLY_DEBUG(D_lookup, "Loaded module %q\n", name); misc_mod_add(mi); return mi; } diff --git a/src/src/readconf.c b/src/src/readconf.c index 37d9c6b85..7840fd0ac 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -3853,7 +3853,7 @@ else if ((errormsg = dlerror())) { log_write(0, LOG_MAIN|LOG_PANIC, - "%s does not appear to be a %s module (%s)\n", fname, class, errormsg); + "%s does not appear to be a %s module (%s)\n", fname, class, errormsg); dlclose(dl); break; } @@ -3864,7 +3864,8 @@ else store_pool = POOL_PERM; add_driver_info(info_anchor, di, size_of_info); store_pool = old_pool; - DEBUG(D_any) debug_printf("Loaded %s %s\n", d->driver_name, class); + DEBUG(D_any) + debug_printf("Loaded module %q (%s)\n", d->driver_name, class); closedir(dd); goto found; } commit acdc767008460bf5e86a1bf39b43e8da7bd6e90d Author: Andreas Metzler Date: Sat Dec 13 14:52:14 2025 +0000 Build: linker invocation ordering Apparently some linkers are sensitive to positioning of library args in the commandline diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 70dc886ab..b38fcd360 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -313,7 +313,13 @@ fi cp ../src/lookups/Makefile $look_mf_pre EGREP="$egrep" ../scripts/lookups-Makefile -# make the Makefiles for routers, transports, auths and miscmods +# Make the Makefiles for routers, transports, auths and miscmods +# +# Columns in the here-file: +# 1 "class" the subdir name to work in +# 2 "classdef" is a prefix on the driver name, used for pulling +# construction data from Local/Makefile +# (remainder) "names" a list of driver names, in caps # An _ prefix on a name means the control in Local/Makefile is DISABLED_ # while read class classdef names diff --git a/src/src/auths/Makefile b/src/src/auths/Makefile index 6eab96a66..44ca8d8fb 100644 --- a/src/src/auths/Makefile +++ b/src/src/auths/Makefile @@ -31,8 +31,8 @@ auths.a: $(OBJ) SO_FLAGS = -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) .c.so:; @echo "$(CC) -shared $*.c" - $(FE)$(CC) $(SO_FLAGS) $(AUTH_$*_INCLUDE) $(AUTH_$*_LIBS) \ - $*.c -o $@ + $(FE)$(CC) $(SO_FLAGS) $(AUTH_$*_INCLUDE) $*.c $(AUTH_$*_LIBS) \ + -o $@ $(OBJ) $(MOD): $(HDRS) diff --git a/src/src/lookups/Makefile b/src/src/lookups/Makefile index 27ae3fe1e..560a5cba5 100644 --- a/src/src/lookups/Makefile +++ b/src/src/lookups/Makefile @@ -48,7 +48,9 @@ lookups.a: avail_static_lookups.o $(OBJS) $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c .c.so:; @echo "$(CC) -shared $*.c" - $(FE)$(CC) $(LOOKUP_$*_INCLUDE) $(LOOKUP_$*_LIBS) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@ + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) \ + $(LOOKUP_$*_INCLUDE) $(INCLUDE) $(DLFLAGS) $*.c \ + $(LOOKUP_$*_LIBS) -o $@ cdb.o cdb.so: $(HDRS) cdb.c dbmdb.o dbmdb.so: $(HDRS) dbmdb.c diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index e92c34941..2d44059ba 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -27,9 +27,9 @@ miscmods.a: $(OBJ) $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c .c.so:; @echo "$(CC) -shared $*.c" - $(FE)$(CC) $(SUPPORT_$*_INCLUDE) $(SUPPORT_$*_LIBS) \ - -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) \ - $(DLFLAGS) $*.c -o $@ + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) \ + $(SUPPORT_$*_INCLUDE) $(INCLUDE) $(DLFLAGS) $*.c \ + $(SUPPORT_$*_LIBS) -o $@ # Note that the sources from pdkim/ are linked into the build.../miscmods/ dir # by scripts/Makelinks. @@ -68,10 +68,10 @@ dkim.o: # Similarly, we want a single .so for the dynamic-load module dkim.so: @echo "$(CC) -shared dkim.c dkim_transport.c pdkim.c signing.c" - $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) -o $@ \ - $(SUPPORT_$*_INCLUDE) $(SUPPORT_$*_LIBS) \ - $(CFLAGS) $(INCLUDE) $(TLS_INCLUDE) $(DLFLAGS) \ - dkim.c dkim_transport.c pdkim.c signing.c + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) \ + $(SUPPORT_$*_INCLUDE) $(INCLUDE) $(TLS_INCLUDE) $(DLFLAGS) \ + dkim.c dkim_transport.c pdkim.c signing.c $(SUPPORT_$*_LIBS) \ + -o $@ # spf_perl is special; Configure-Makefile asks for it but we actually # build resulting in a file named spf.so because the module-loading @@ -81,9 +81,9 @@ dkim.so: spf_perl.so: @echo "$(CC) -shared $*.c" - $(FE)$(CC) $(SUPPORT_SPF_PERL_INCLUDE) $(SUPPORT_SPF_PERL_LIBS) \ - -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) \ - $(DLFLAGS) spf_perl.c -o spf.so + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) \ + $(SUPPORT_SPF_PERL_INCLUDE) $(INCLUDE) $(DLFLAGS) \ + spf_perl.c $(SUPPORT_SPF_PERL_LIBS) -o spf.so # DMARC dmarc.o dmarc_native.o: @@ -96,10 +96,9 @@ dmarc.o dmarc_native.o: # dmarc_native is special in the same way as spf_perl dmarc.so dmarc_native.so: @echo "$(CC) -shared $*.c dmarc_common.c" - $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) -o dmarc.so \ - $(SUPPORT_$*_INCLUDE) $(SUPPORT_$*_LIBS) \ - $(CFLAGS) $(INCLUDE) $(TLS_INCLUDE) $(DLFLAGS) \ - $*.c dmarc_common.c + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) \ + $(SUPPORT_$*_INCLUDE) $(INCLUDE) $(TLS_INCLUDE) $(DLFLAGS) \ + $*.c dmarc_common.c $(SUPPORT_$*_LIBS) -o dmarc.so # Compile instructions for static perl.o for when EXIM_PERL is set # Dynamic is managed all via scripts/Configure-Makefile diff --git a/src/src/routers/Makefile b/src/src/routers/Makefile index 1b2953d40..32515fcf8 100644 --- a/src/src/routers/Makefile +++ b/src/src/routers/Makefile @@ -26,7 +26,8 @@ routers.a: $(OBJ) $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c .c.so:; @echo "$(CC) -shared $*.c" - $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@ + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) \ + $(DLFLAGS) $*.c -o $@ commit d9081efaca19d0bef80c0dbc3ffa045207f3171e Author: Jeremy Harris Date: Sat Dec 13 23:52:08 2025 +0000 Re-order module init in "-bV" support diff --git a/src/src/exim.c b/src/src/exim.c index d35168d60..693301899 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1334,11 +1334,13 @@ Currently they are output in misc_mod_add() */ show_string(is_stdout, g); g = NULL; + /* Has to be before the lookups as the spf lookup calls into the spf module */ + init_misc_mod_list(); + init_lookup_list(); tree_walk(lookups_tree, lookup_version_report_cb, &g); show_string(is_stdout, g); g = NULL; - init_misc_mod_list(); #ifdef WHITELIST_D_MACROS g = string_fmt_append(g, "WHITELIST_D_MACROS: %q\n", WHITELIST_D_MACROS); commit 4a11617127599c2a40552f5f7e9bf0e863f10e8d Merge: d9081efac d46a67277 Author: Heiko Schlittermann (HS12-RIPE) Date: Tue Dec 16 12:55:32 2025 +0100 Merge branch 'exim-4.99+fixes' (EXIM-Security-2025-12-09.1, CVE-2025-67896) * exim-4.99+fixes: doc: update about CVE-2025-67896 fix: release process docbook2texi EXIM-Security-2025-12-09.1 doc: update Changelog (relates #7) Testsuite: add testing for sqlite db external usage return scan result into key parameter move to blobs for keys as well as data. refactor sqlite3_ calls to reduce duplication new: xtextencode CVE-2025-30232 Squashed from fix/cve-2025-26794 (fixes CVE-26794) diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index d2d30969b..9a65d8b19 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -67,6 +67,7 @@ required by Exim's process transitions)? /* Include file ordering problem */ extern void debug_printf_indent(const char *, ...) PRINTF_FUNCTION(1,2); +static inline BOOL is_tainted(const void *); #ifdef USE_SQLITE @@ -102,15 +103,8 @@ the default is the NDBM interface (which seems to be a wrapper for GDBM) */ #endif /* !USE_GDBM */ - - - - /* Wrappers for open/close with debug tracing */ -extern void debug_printf_indent(const char *, ...); -static inline BOOL is_tainted(const void *); - static inline EXIM_DB * exim_dbopen(const uschar * name, const uschar * dirname, int flags, unsigned mode) diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index 40d50b8c0..dd88dd98b 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -17,7 +17,7 @@ backend provider. */ /* Basic DB type */ # define EXIM_DB sqlite3 -# define EXIM_CURSOR int +# define EXIM_CURSOR sqlite3_stmt # /* The datum type used for queries */ # define EXIM_DATUM blob @@ -25,12 +25,6 @@ backend provider. */ /* Some text for messages */ # define EXIM_DBTYPE "sqlite3" -/* Utility functionss */ - -extern uschar *xtextencode(const uschar *, int); -extern int xtextdecode(const uschar *, uschar**); - - /* Access functions */ static inline BOOL @@ -54,10 +48,12 @@ if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK) sqlite3_busy_timeout(dbp, 5000); if (flags & O_CREAT) ret = sqlite3_exec(dbp, - "CREATE TABLE IF NOT EXISTS tbl (ky TEXT PRIMARY KEY, dat BLOB);", + "CREATE TABLE IF NOT EXISTS tblblob (ky BLOB PRIMARY KEY, dat BLOB);", NULL, NULL, NULL); if (ret != SQLITE_OK) sqlite3_close(dbp); + /* in case we are migrating, drop the old table, return code not needed */ + (void) sqlite3_exec(dbp, "DROP TABLE IF EXISTS tbl;", NULL, NULL, NULL); } else DEBUG(D_hints_lookup) debug_printf_indent("sqlite_open(flags 0x%x mode %04o) %s\n", @@ -82,148 +78,143 @@ sqlite3_close(dbp); return NULL; } -/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */ -/* note we alloc'n'copy - the caller need not do so */ -/* result has a NUL appended, but the length is as per the DB */ - -static inline BOOL -exim_dbget__(EXIM_DB * dbp, const uschar * s, EXIM_DATUM * res) +static inline sqlite3_stmt * +exim_sqlbind_blob(EXIM_DB * dbp, sqlite3_stmt *stmt, int *bindcolp, EXIM_DATUM *data ) { -sqlite3_stmt * statement; -int ret; - -res->len = (size_t) -1; -/* DEBUG(D_hints_lookup) debug_printf_indent("exim_dbget__(%s)\n", s); */ -if ((ret = sqlite3_prepare_v2(dbp, CCS s, -1, &statement, NULL)) != SQLITE_OK) +if (data && stmt) { - DEBUG(D_hints_lookup) - debug_printf_indent("prepare fail: %s\n", sqlite3_errmsg(dbp)); - return FALSE; - } -if (sqlite3_step(statement) != SQLITE_ROW) - { - /* DEBUG(D_hints_lookup) - debug_printf_indent("step fail: %s\n", sqlite3_errmsg(dbp)); */ - sqlite3_finalize(statement); - return FALSE; - } - -res->len = sqlite3_column_bytes(statement, 0); -# ifdef COMPILE_UTILITY -if (!(res->data = malloc(res->len +1))) - { sqlite3_finalize(statement); return FALSE; } -# else -res->data = store_get(res->len +1, GET_TAINTED); + if (SQLITE_OK != sqlite3_bind_blob(stmt, *bindcolp, data->data, data->len, SQLITE_STATIC)) + { +# ifdef SQL_DEBUG + fprintf(stderr, EXIM_DBTYPE " bind to value %d: %s\n", *bindcolp, sqlite3_errmsg(dbp)); # endif -memcpy(res->data, sqlite3_column_blob(statement, 0), res->len); -res->data[res->len] = '\0'; -/* DEBUG(D_hints_lookup) debug_printf_indent("res %d bytes: '%.*s'\n", - (int)res->len, (int)res->len, res->data); */ -sqlite3_finalize(statement); -return TRUE; + sqlite3_finalize(stmt); + stmt = NULL; + } + else + { + (*bindcolp)++; + } + } +return stmt; } -static inline BOOL -exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res) +/* We use a common prepare/bind mechanism with optional value binding */ +static inline sqlite3_stmt * +exim_sqlprep(EXIM_DB * dbp, const char *query, EXIM_DATUM *key, EXIM_DATUM *data ) { -# define FMT "SELECT dat FROM tbl WHERE ky = '%s';" -uschar * encoded_key, * qry; -BOOL ret; +sqlite3_stmt * stmt = NULL; /* don't make it static, as it depends on the dbp */ +int bindcol = 1; -# ifdef COMPILE_UTILITY -if (!(encoded_key = xtextencode(key->data, key->len))) - return FALSE; -# else -encoded_key = xtextencode(key->data, key->len); +if (SQLITE_OK != sqlite3_prepare_v2(dbp, query, strlen(query), &stmt, NULL)) + { +# ifdef SQL_DEBUG + fprintf(stderr, EXIM_DBTYPE " prepare %s: %s\n", query, sqlite3_errmsg(dbp)); # endif -/* DEBUG(D_hints_lookup) debug_printf_indent("exim_dbget(k len %d '%s')\n", - (int)key->len, encoded_key); */ + goto DONE; + } -# ifdef COMPILE_UTILITY +# ifdef SQL_DEBUG +DEBUG(D_hints_lookup) debug_printf_indent("prepared SQL: %s\n", sqlite3_sql(stmt)); +# endif + +stmt = exim_sqlbind_blob(dbp, stmt, &bindcol, key); +stmt = exim_sqlbind_blob(dbp, stmt, &bindcol, data); + +# ifdef SQL_DEBUG +if (stmt) { - int i = snprintf(NULL, 0, FMT, encoded_key) + 1; - if (!(qry = malloc(i))) - return FALSE; - snprintf(CS qry, i, FMT, encoded_key); - ret = exim_dbget__(dbp, qry, res); - free(qry); + DEBUG(D_hints_lookup) debug_printf_indent("expanded SQL: %s\n", sqlite3_expanded_sql(stmt)); } -free(encoded_key); -# else -qry = string_sprintf(FMT, encoded_key); -ret = exim_dbget__(dbp, qry, res); # endif -return ret; -# undef FMT -} +DONE: -/* Note that we return claiming a duplicate record for any error. -It seem not uncommon to get a "database is locked" error. +return stmt; +} -Keys are stored xtext-encoded (which is mostly readable, for plaintext). -Values are stored in a BLOB type in the DB, for which the SQL interface -is hex-encoded. */ -# define EXIM_DBPUTB_OK 0 -# define EXIM_DBPUTB_DUP (-1) static inline int -exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const uschar * alt) +exim_sqlstep(EXIM_DB * dbp, sqlite3_stmt * stmt, EXIM_DATUM *res ) { -int hlen = data->len * 2, off = 0, res; -# define FMT "INSERT OR %s INTO tbl (ky,dat) VALUES ('%s', X'%.*s');" -uschar * encoded_key, * qry; +int rv = SQLITE_MISUSE; + +switch ((rv = sqlite3_step(stmt))) + { + case SQLITE_DONE: /* might want to call sqlite3_reset(stmt); here */ + goto DONE; + case SQLITE_ROW: if (!res) + { + /* allow for fetch but didn't want data (existence check ?) */ + goto DONE; + } + res->len = sqlite3_column_bytes(stmt, 0); # ifdef COMPILE_UTILITY -uschar * hex = malloc(hlen+1), dummy[1]; -if (!hex) return EXIM_DBPUTB_DUP; /* best we can do */ + res->data = malloc(res->len +1); + if (! res->data ) goto DONE; # else -uschar * hex = store_get(hlen+1, data->data); + res->data = store_get(res->len +1, GET_TAINTED); +# endif + memcpy(res->data, sqlite3_column_blob(stmt, 0), res->len); + res->data[res->len] = '\0'; + goto DONE; + default: +# ifdef SQL_DEBUG + fprintf(stderr, EXIM_DBTYPE " step: %s: %s\n", sqlite3_expanded_sql(stmt), sqlite3_errmsg(dbp)); # endif + goto DONE; + } -/* Encode the value for the SQL API */ +DONE: +return rv; +} -for (const uschar * s = data->data, * t = s + data->len; s < t; s++, off += 2) - sprintf(CS hex + off, "%02X", *s); -# ifdef COMPILE_UTILITY -if (!(encoded_key = xtextencode(key->data, key->len))) - return EXIM_DBPUTB_DUP; -res = snprintf(CS dummy, 0, FMT, alt, encoded_key, hlen, hex) +1; -if (!(qry = malloc(res))) return EXIM_DBPUTB_DUP; -snprintf(CS qry, res, FMT, alt, encoded_key, hlen, hex); -DEBUG(D_hints_lookup) debug_printf_indent("exim_s_dbp(%s)\n", qry); - -res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); -free(qry); -free(encoded_key); -free(hex); +/* simplest case when updating a single row or fetching a single row */ +static inline int +exim_sqlprep_step(EXIM_DB * dbp, const char *query, EXIM_DATUM *key, EXIM_DATUM *data, EXIM_DATUM *res ) +{ +int more = SQLITE_ERROR; +sqlite3_stmt * stmt = NULL; /* don't make it static, as it depends on the dbp */ -# else -encoded_key = xtextencode(key->data, key->len); -qry = string_sprintf(FMT, alt, encoded_key, hlen, hex); -/* DEBUG(D_hints_lookup) debug_printf_indent("exim_s_dbp(%s)\n", qry); */ +if ((stmt = exim_sqlprep(dbp, query, key, data ))) + { + more = exim_sqlstep(dbp, stmt, res ); + sqlite3_finalize(stmt); + stmt = NULL; + } +return more; +} -res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); -/* DEBUG(D_hints_lookup) debug_printf_indent("exim_s_dbp res %d\n", res); */ -# endif +/* EXIM_DBGET - returns the value associated with the key. */ +static inline BOOL +exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res) +{ +const char query[] = "SELECT dat FROM tblblob WHERE ky = ?"; +return (exim_sqlprep_step(dbp, query, key, NULL, res ) == SQLITE_ROW); +} -# ifdef COMPILE_UTILITY -if (res != SQLITE_OK) - DEBUG(D_hints_lookup) - debug_printf_indent("sqlite3_exec: %s\n", sqlite3_errmsg(dbp)); -# endif -return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP; -# undef FMT +/* Note that we return claiming a duplicate record for any error. + * It seem not uncommon to get a "database is locked" error. +*/ +# define EXIM_DBPUTB_OK 0 +# define EXIM_DBPUTB_DUP (-1) + +static inline int +exim_s_dbp(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data, const char * sql) +{ +return (SQLITE_DONE == exim_sqlprep_step(dbp, sql, key, data, NULL )) ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP; } /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ - static inline int exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data) { -/* DEBUG(D_hints_lookup) debug_printf_indent("exim_dbput()\n"); */ -(void) exim_s_dbp(dbp, key, data, US"REPLACE"); +# ifdef SQL_DEBUG +DEBUG(D_hints_lookup) debug_printf_indent(EXIM_DBTYPE " put: key:%.*W data:%.*W\n", key->len, key->data, data->len, data->data ); +# endif +(void) exim_s_dbp(dbp, key, data, "INSERT OR REPLACE INTO tblblob (ky, dat) VALUES(?, ?)"); return 0; } @@ -234,110 +225,52 @@ return 0; static inline int exim_dbputb(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data) { -return exim_s_dbp(dbp, key, data, US"ABORT"); +return exim_s_dbp(dbp, key, data, "INSERT OR ABORT INTO tblblob (ky, dat) VALUES(?, ?)"); } /* EXIM_DBDEL */ static inline int exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key) { -# define FMT "DELETE FROM tbl WHERE ky = '%s';" -uschar * encoded_key, * qry; -int res; - -# ifdef COMPILE_UTILITY -if (!(encoded_key = xtextencode(key->data, key->len))) - return EXIM_DBPUTB_DUP; -res = snprintf(NULL, 0, FMT, encoded_key) +1; /* res includes nul */ -if (!(qry = malloc(res))) return SQLITE_NOMEM; -snprintf(CS qry, res, FMT, encoded_key); -res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); -free(qry); - -# else -encoded_key = xtextencode(key->data, key->len); -qry = string_sprintf(FMT, encoded_key); -res = sqlite3_exec(dbp, CS qry, NULL, NULL, NULL); - -# endif - -return res == SQLITE_OK ? EXIM_DBPUTB_OK : EXIM_DBPUTB_DUP; -# undef FMT +const char query[] = "DELETE FROM tblblob WHERE ky = ?"; +return (SQLITE_DONE == exim_sqlprep_step(dbp, query, key, NULL, NULL )) ? 0 : -1; } - /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */ -/* Cursors are inefficiently emulated by repeating searches */ static inline EXIM_CURSOR * exim_dbcreate_cursor(EXIM_DB * dbp) { -# ifdef COMPILE_UTILITY -EXIM_CURSOR * c = malloc(sizeof(int)); -if (!c) return NULL; -# else -EXIM_CURSOR * c = store_malloc(sizeof(int)); +EXIM_CURSOR * cursor; + +cursor = exim_sqlprep(dbp, "SELECT ky FROM tblblob ORDER BY ky", NULL, NULL ); +if (!cursor) return NULL; +# ifdef SQL_DEBUG +DEBUG(D_hints_lookup) debug_printf_indent("prepared query: %s\n", sqlite3_sql(cursor)); # endif -*c = 0; -return c; + +return cursor; } /* EXIM_DBSCAN */ -/* Note that we return the (next) key, not the record value. -We allocate memory for the return. */ - +/* Note that we return the (next) key into the key parameter, not the res parameter. */ static inline BOOL -exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res, BOOL first, - EXIM_CURSOR * cursor) +exim_dbscan(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res /* unused */, BOOL first /*unused*/, EXIM_CURSOR * cursor) { -# define FMT "SELECT ky FROM tbl ORDER BY ky LIMIT 1 OFFSET %d;" -uschar * qry; -EXIM_DATUM encoded_key; -BOOL ret; - -# ifdef COMPILE_UTILITY -int i = snprintf(NULL, 0, FMT, *cursor)+1; - -if (!(qry = malloc(i))) return FALSE; -snprintf(CS qry, i, FMT, *cursor); -DEBUG(D_hints_lookup) debug_printf_indent("exim_dbscan(%s)\n", qry); -ret = exim_dbget__(dbp, qry, &encoded_key); -free(qry); - -# else /*!COMPILE_UTILITY*/ -qry = string_sprintf(FMT, *cursor); -DEBUG(D_hints_lookup) debug_printf_indent("exim_dbscan(%s)\n", qry); -ret = exim_dbget__(dbp, qry, &encoded_key); - -# endif /*COMPILE_UTILITY*/ - -DEBUG(D_hints_lookup) - debug_printf_indent("exim_dbscan ret %c\n", ret ? 'T':'F'); - -if (ret) - { - key->len = xtextdecode(encoded_key.data, &key->data); - *cursor = *cursor + 1; - } -return ret; -# undef FMT +return (exim_sqlstep(dbp, cursor, key )==SQLITE_ROW); } /* EXIM_DBDELETE_CURSOR - terminate scanning operation. */ static inline void exim_dbdelete_cursor(EXIM_CURSOR * cursor) { -# ifdef COMPILE_UTILITY -free(cursor); -# else -store_free(cursor); -# endif +if(cursor) + sqlite3_finalize(cursor); } - /* EXIM_DBCLOSE */ static inline void -exim_dbclose_multi__(EXIM_DB * dbp) +exim_dbclose_multi__(EXIM_DB *dbp) { sqlite3_close(dbp); } @@ -359,19 +292,19 @@ exim_dbclose_multi__(dbp); static inline uschar * exim_datum_data_get(EXIM_DATUM * dp) { return US dp->data; } -static inline void + +static void exim_datum_data_set(EXIM_DATUM * dp, void * s) { dp->data = s; } - -static inline unsigned + +static unsigned exim_datum_size_get(EXIM_DATUM * dp) { return dp->len; } + static inline void exim_datum_size_set(EXIM_DATUM * dp, unsigned n) { dp->len = n; } - - static inline void exim_datum_init(EXIM_DATUM * dp) { dp->data = NULL; } /* compiler quietening */ @@ -386,7 +319,7 @@ exim_datum_free(EXIM_DATUM * dp) # define EXIM_DB_RLIMIT 150 - /* End of hints_sqlite.h */ /* vi: aw ai sw=2 + * */ commit 227e467d611d9c5bcb942f2b2635e4466a8c7fd6 Author: Jeremy Harris Date: Mon Dec 15 13:43:19 2025 +0000 Fast-ramp: do not notify daemon during high load-avg diff --git a/src/src/queue.c b/src/src/queue.c index 97238ba1a..46f7f3d57 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -1695,6 +1695,13 @@ int fd; DEBUG(D_queue_run) debug_printf("%s: %s\n", __FUNCTION__, msgid); +if ( deliver_queue_load_max >= 0 + && os_getloadavg() > deliver_queue_load_max) + { + DEBUG(D_queue_run) debug_printf(" - avoided due to load-avg\n"); + return; + } + buf[0] = NOTIFY_MSG_QRUN; memcpy(buf+1, msgid, MESSAGE_ID_LENGTH+1); Ustrcpy(buf+1+MESSAGE_ID_LENGTH+1, queue_name); commit d09946f296565ebdd640b07d9bee0b30283d186d Author: Jeremy Harris Date: Mon Dec 15 15:32:12 2025 +0000 Fix DISABLE_ESMTP_LIMITS build diff --git a/src/src/globals.c b/src/src/globals.c index 6c8e8ec05..6d2b27227 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -648,6 +648,7 @@ unsigned continue_flags = 0; unsigned continue_limit_mail = 0; unsigned continue_limit_rcpt = 0; unsigned continue_limit_rcptdom= 0; +#endif int continue_fd = -1; uschar *continue_proxy_cipher = NULL; BOOL continue_proxy_dane = FALSE; @@ -662,7 +663,6 @@ const uschar *continue_transport = NULL; open_db *continue_retry_db = NULL; open_db *continue_wait_db = NULL; #endif -#endif uschar *csa_status = NULL; cut_t cutthrough = { /* All remaining items 0/FALSE/NULL */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 1f2161ae2..8ea3d882a 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -4051,9 +4051,7 @@ uschar * message = NULL; smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); BOOL pass_message = FALSE; -#ifndef DISABLE_ESMTP_LIMITS BOOL mail_limit = FALSE; -#endif #ifdef SUPPORT_DANE BOOL dane_held; #endif @@ -4971,7 +4969,6 @@ DEBUG(D_transport) sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : ""); if (sx->completed_addr && sx->ok && sx->send_quit) -#ifndef DISABLE_ESMTP_LIMITS if (mail_limit = continue_sequence >= sx->max_mail) { DEBUG(D_transport) @@ -4984,7 +4981,6 @@ if (sx->completed_addr && sx->ok && sx->send_quit) process. */ } else -#endif { BOOL send_rst; smtp_compare_t t_compare = @@ -5299,7 +5295,6 @@ if (dane_held) } #endif -#ifndef DISABLE_ESMTP_LIMITS if (mail_limit && sx->first_addr) { /* Reset the sequence count since we closed the connection. This is flagged @@ -5309,7 +5304,6 @@ if (mail_limit && sx->first_addr) continue_sequence = 1; /* for consistency */ goto REPEAT_CONN; /* open a fresh connection */ } -#endif OUT: smtp_debug_cmd_report(); commit 5103de3423da39e0edcbd556ab2633c8d5c09c5f Author: Jeremy Harris Date: Wed Dec 17 15:56:32 2025 +0000 dscp module diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index b38fcd360..9b766d6ee 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -332,7 +332,7 @@ done <<-END routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS - miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SPF SPF_PERL + miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SPF SPF_PERL END # See if there is a definition of EXIM_PERL in what we have built so far. diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 517310c8a..35b58ec04 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -90,7 +90,7 @@ done cd .. # miscellaneous modules -# Note that the file in the miscmods/pdkim/ source subdir get linked to the +# Note that the files in the miscmods/pdkim/ source subdir get linked to the # destination miscmods/ dir d="miscmods" mkdir $d @@ -102,6 +102,7 @@ for f in dummy.c \ pdkim/crypt_ver.h pdkim/pdkim.c pdkim/pdkim.h \ pdkim/pdkim_hash.h pdkim/signing.c pdkim/signing.h \ dmarc.c dmarc_common.c dmarc.h dmarc_api.h dmarc_native.c \ + dscp.c dscp_api.h \ exim_filter.c exim_filter_api.h \ pam.c pam_api.h \ perl.c perl_api.h \ diff --git a/src/src/EDITME b/src/src/EDITME index 1c9d834dd..98baae7d5 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -577,6 +577,9 @@ SUPPORT_DANE=yes # SUPPORT_SIEVE_FILTER=2 +# Uncomment the line to include DSCP support. Set to 2 for a module build. +# SUPPORT_DSCP + #------------------------------------------------------------------------------ # Compiling Exim with content scanning support: If you want to compile Exim # with support for message body content scanning, set WITH_CONTENT_SCAN to diff --git a/src/src/acl.c b/src/src/acl.c index 63478ca7d..bc4f6af6d 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -3498,44 +3498,18 @@ for (; cb; cb = cb->next) f.dmarc_enable_forensic = TRUE; break; #endif - +#ifdef SUPPORT_DSCP case CONTROL_DSCP: - if (*p == '/') - { - int af, socklevel, optname, value; - /* If we are acting on stdin, the setsockopt may fail if stdin is not - a socket; we can accept that, we'll just debug-log failures anyway. */ - if (smtp_in_fd < 0) return ERROR; - if ((af = ip_get_address_family(smtp_in_fd)) < 0) - { - HDEBUG(D_acl) - debug_printf_indent("smtp input is probably not a socket [%s], not setting DSCP\n", - strerror(errno)); - break; - } - if (dscp_lookup(p+1, af, &socklevel, &optname, &value)) - if (setsockopt(smtp_in_fd, socklevel, optname, - &value, sizeof(value)) < 0) - { - HDEBUG(D_acl) debug_printf_indent("failed to set input DSCP[%s]: %s\n", - p+1, strerror(errno)); - } - else - { - HDEBUG(D_acl) debug_printf_indent("set input DSCP to %q\n", p+1); - } - else - { - *log_msgptr = string_sprintf("unrecognised DSCP value in \"control=%s\"", arg); - return ERROR; - } - } - else - { - *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg); - return ERROR; - } + { + misc_module_info * mi = misc_mod_find(US"dscp", &log_message); + typedef uschar * (*fn_t)(const uschar *, const uschar *); + if (!mi) + rc = DEFER; + else if ((*log_msgptr = ((fn_t *) mi->functions)[DSCP_ACL] (arg, p))) + rc = ERROR; break; + } +#endif case CONTROL_ERROR: return ERROR; diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 71146ae3b..ba9f50b01 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -155,6 +155,7 @@ Do not put spaces between # and the 'define'. #define SUPPORT_DMARC #define DMARC_API 100400 #define DMARC_TLD_FILE "/etc/exim/opendmarc.tlds" +#define SUPPORT_DSCP #define SUPPORT_I18N #define SUPPORT_I18N_2008 #define SUPPORT_MAILDIR diff --git a/src/src/drtables.c b/src/src/drtables.c index bf1c3e530..e21d47047 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -356,7 +356,7 @@ return NULL; int misc_mod_conn_init(const uschar * sender_helo_name, - const uschar * sender_host_address, const uschar * * errstr) + const uschar * sender_host_address, const uschar ** errstr) { for (const misc_module_info * mi = misc_module_list; mi; mi = mi->next) if (mi->conn_init) @@ -495,6 +495,9 @@ extern misc_module_info spf_module_info; #if defined(EXPERIMENTAL_ARC) && (!defined(SUPPORT_ARC) || SUPPORT_ARC!=2) extern misc_module_info arc_module_info; #endif +#if defined(SUPPORT_DSCP) && SUPPORT_DSCP!=2 +extern misc_module_info dscp_module_info; +#endif #if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) extern misc_module_info radius_module_info; #endif @@ -531,6 +534,9 @@ onetime = TRUE; /* dmarc depends on spf/dkim/arc so this add must go after, for the both-static case */ misc_mod_add(&dmarc_module_info); #endif +#if defined(SUPPORT_DSCP) && SUPPORT_DSCP!=2 + misc_mod_add(&dscp_module_info); +#endif #if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) misc_mod_add(&radius_module_info); #endif diff --git a/src/src/exim.c b/src/src/exim.c index 693301899..383fe8247 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1186,6 +1186,9 @@ g = string_cat(g, US"Support for:"); #ifndef DISABLE_DNSSEC g = string_cat(g, US" DNSSEC"); #endif +#ifdef SUPPORT_DSCP + g = string_cat(g, US" DSCP"); +#endif #ifndef DISABLE_ESMTP_LIMITS g = string_cat(g, US" ESMTP_Limits"); #endif @@ -1382,7 +1385,9 @@ switch(request) "If the string is not recognised, you'll get this help (on stderr).\n" "\n" " exim -bI:help this information\n" +#ifdef SUPPORT_DSCP " exim -bI:dscp list of known dscp value keywords\n" +#endif " exim -bI:sieve list of supported sieve extensions\n" ); return; @@ -1396,9 +1401,16 @@ switch(request) fprintf(stream, "Sieve filtering not available\n"); } return; +#ifdef SUPPORT_DSCP case CMDINFO_DSCP: - dscp_list_to_stream(stream); + { + uschar * dummy_errstr; + misc_module_info * mi = misc_mod_find(US"dscp", &dummy_errstr); + typedef void (*fn_t)(FILE *); + if (mi) ((fn_t *) mi->functions)[DSCP_KEYWORDS] (stream); + } return; +#endif } } @@ -2419,15 +2431,11 @@ on the second character (the one after '-'), to save some effort. */ info_flag = CMDINFO_HELP; if (Ustrlen(p)) if (strcmpic(p, CUS"sieve") == 0) - { - info_flag = CMDINFO_SIEVE; - info_stdout = TRUE; - } + { info_flag = CMDINFO_SIEVE; info_stdout = TRUE; } +#ifdef SUPPORT_DSCP else if (strcmpic(p, CUS"dscp") == 0) - { - info_flag = CMDINFO_DSCP; - info_stdout = TRUE; - } + { info_flag = CMDINFO_DSCP; info_stdout = TRUE; } +#endif else if (strcmpic(p, CUS"help") == 0) info_stdout = TRUE; } diff --git a/src/src/exim.h b/src/src/exim.h index 538f354e2..07b017a01 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -558,6 +558,9 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #ifdef EXPERIMENTAL_ARC # include "miscmods/arc_api.h" #endif +#ifdef SUPPORT_DSCP +# include "miscmods/dscp_api.h" +#endif #ifdef RADIUS_CONFIG_FILE # include "miscmods/radius_api.h" #endif diff --git a/src/src/expand.c b/src/src/expand.c index e222e8e75..b0500037d 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -8753,8 +8753,7 @@ uschar * expand_string_copy(const uschar * string) { const uschar * yield = expand_string(string); -if (yield == string) yield = string_copy(string); -return US yield; +return yield == string ? string_copy(string) : US yield; } diff --git a/src/src/functions.h b/src/src/functions.h index ec13c544e..4e56c14a4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -216,8 +216,6 @@ extern void dns_pattern_init(void); extern int dns_special_lookup(dns_answer *, const uschar *, int, const uschar **); extern dns_record *dns_next_rr(const dns_answer *, dns_scan *, int); extern uschar *dns_text_type(int); -extern void dscp_list_to_stream(FILE *); -extern BOOL dscp_lookup(const uschar *, int, int *, int *, int *); extern void enq_end(uschar *); extern unsigned enq_start(uschar *, unsigned); @@ -290,7 +288,6 @@ extern int ip_bind(int, int, const uschar *, int); extern int ip_connect(int, int, const uschar *, int, int, const blob *); extern int ip_connectedsocket(int, const uschar *, int, int, int, host_item *, uschar **, const blob *); -extern int ip_get_address_family(int); extern void ip_keepalive(int, const uschar *, BOOL); extern int ip_recv(client_conn_ctx *, uschar *, int, time_t); extern int ip_socket(int, int); diff --git a/src/src/ip.c b/src/src/ip.c index f48fa82a9..80038e3ec 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -681,179 +681,6 @@ return -1; - -/************************************************* -* Lookup address family of potential socket * -*************************************************/ - -/* Given a file-descriptor, check to see if it's a socket and, if so, -return the address family; detects IPv4 vs IPv6. If not a socket then -return -1. - -The value 0 is typically AF_UNSPEC, which should not be seen on a connected -fd. If the return is -1, the errno will be from getsockname(); probably -ENOTSOCK or ECONNRESET. - -Arguments: socket-or-not fd -Returns: address family or -1 -*/ - -int -ip_get_address_family(int fd) -{ -struct sockaddr_storage ss; -socklen_t sslen = sizeof(ss); - -if (getsockname(fd, (struct sockaddr *) &ss, &sslen) < 0) - return -1; - -return (int) ss.ss_family; -} - - - - -/************************************************* -* Lookup DSCP settings for a socket * -*************************************************/ - -struct dscp_name_tableentry { - const uschar *name; - int value; -}; -/* Keep both of these tables sorted! */ -static struct dscp_name_tableentry dscp_table[] = { -#ifdef IPTOS_DSCP_AF11 - { CUS"af11", IPTOS_DSCP_AF11 }, - { CUS"af12", IPTOS_DSCP_AF12 }, - { CUS"af13", IPTOS_DSCP_AF13 }, - { CUS"af21", IPTOS_DSCP_AF21 }, - { CUS"af22", IPTOS_DSCP_AF22 }, - { CUS"af23", IPTOS_DSCP_AF23 }, - { CUS"af31", IPTOS_DSCP_AF31 }, - { CUS"af32", IPTOS_DSCP_AF32 }, - { CUS"af33", IPTOS_DSCP_AF33 }, - { CUS"af41", IPTOS_DSCP_AF41 }, - { CUS"af42", IPTOS_DSCP_AF42 }, - { CUS"af43", IPTOS_DSCP_AF43 }, - { CUS"ef", IPTOS_DSCP_EF }, -#endif -#ifdef IPTOS_LOWCOST - { CUS"lowcost", IPTOS_LOWCOST }, -#endif - { CUS"lowdelay", IPTOS_LOWDELAY }, -#ifdef IPTOS_MINCOST - { CUS"mincost", IPTOS_MINCOST }, -#endif - { CUS"reliability", IPTOS_RELIABILITY }, - { CUS"throughput", IPTOS_THROUGHPUT } -}; -static int dscp_table_size = - sizeof(dscp_table) / sizeof(struct dscp_name_tableentry); - -/* DSCP values change by protocol family, and so do the options used for -setsockopt(); this utility does all the lookups. It takes an unexpanded -option string, expands it, strips off affix whitespace, then checks if it's -a number. If all of what's left is a number, then that's how the option will -be parsed and success/failure is a range check. If it's not all a number, -then it must be a supported keyword. - -Arguments: - dscp_name a string, so far unvalidated - af address_family in use - level setsockopt level to use - optname setsockopt name to use - dscp_value value for dscp_name - -Returns: TRUE if okay to setsockopt(), else FALSE - -*level and *optname may be set even if FALSE is returned -*/ - -BOOL -dscp_lookup(const uschar *dscp_name, int af, - int *level, int *optname, int *dscp_value) -{ -uschar *dscp_lookup, *p; -int first, last; -long rawlong; - -if (af == AF_INET) - { - *level = IPPROTO_IP; - *optname = IP_TOS; - } -#if HAVE_IPV6 && defined(IPV6_TCLASS) -else if (af == AF_INET6) - { - *level = IPPROTO_IPV6; - *optname = IPV6_TCLASS; - } -#endif -else - { - DEBUG(D_transport) - debug_printf("Unhandled address family %d in dscp_lookup()\n", af); - return FALSE; - } -if (!dscp_name) - { - DEBUG(D_transport) - debug_printf("[empty DSCP]\n"); - return FALSE; - } -dscp_lookup = expand_string(US dscp_name); -if (dscp_lookup == NULL || *dscp_lookup == '\0') - return FALSE; - -p = dscp_lookup + Ustrlen(dscp_lookup) - 1; -while (isspace(*p)) *p-- = '\0'; -while (isspace(*dscp_lookup) && dscp_lookup < p) dscp_lookup++; -if (*dscp_lookup == '\0') - return FALSE; - -rawlong = Ustrtol(dscp_lookup, &p, 0); -if (p != dscp_lookup && *p == '\0') - { - /* We have six bits available, which will end up shifted to fit in 0xFC mask. - RFC 2597 defines the values unshifted. */ - if (rawlong < 0 || rawlong > 0x3F) - { - DEBUG(D_transport) - debug_printf("DSCP value %ld out of range, ignored.\n", rawlong); - return FALSE; - } - *dscp_value = rawlong << 2; - return TRUE; - } - -first = 0; -last = dscp_table_size; -while (last > first) - { - int middle = (first + last)/2; - int c = Ustrcmp(dscp_lookup, dscp_table[middle].name); - if (c == 0) - { - *dscp_value = dscp_table[middle].value; - return TRUE; - } - else if (c > 0) - first = middle + 1; - else - last = middle; - } -return FALSE; -} - -void -dscp_list_to_stream(FILE *stream) -{ -for (int i = 0; i < dscp_table_size; ++i) - fprintf(stream, "%s\n", dscp_table[i].name); -} - - /* End of ip.c */ /* vi: aw ai sw=2 */ diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index a8ebc40d4..4778ace64 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -212,6 +212,9 @@ due to conflicts with other common macros. */ #ifdef EXPERIMENTAL_DCC builtin_macro_create(US"_HAVE_DCC"); #endif +#ifdef SUPPORT_DSCP + builtin_macro_create(US"_HAVE_DSCP"); +#endif #ifdef EXPERIMENTAL_DSN_INFO builtin_macro_create(US"_HAVE_DSN_INFO"); #endif diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index 2d44059ba..e129fe8bc 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -41,6 +41,7 @@ dmarc.o dmarc.so: $(HDRS) spf.h pdkim.h dmarc.h \ dmarc.c dmarc_common.c dmarc_native.o dmarc_native.so: $(HDRS) spf.h pdkim.h dmarc.h \ dmarc_native.c dmarc_common.c +dscp.o dscp.so: $(HDRS) dscp.c dummy.o: dummy.c exim_filter.o exim_filter.so: $(HDRS) exim_filter.c pam.o pam.so: $(HDRS) pam.c diff --git a/src/src/miscmods/dscp.c b/src/src/miscmods/dscp.c new file mode 100644 index 000000000..8c25833d9 --- /dev/null +++ b/src/src/miscmods/dscp.c @@ -0,0 +1,278 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* DSCP support for Exim + Copyright (c) The Exim Maintainers - 2025 + License: GPL + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "../exim.h" +#if defined SUPPORT_DSCP + +# include "../functions.h" + +/******************************************************************************/ +/* Utility functions */ + +/************************************************* +* Lookup address family of potential socket * +*************************************************/ + +/* Given a file-descriptor, check to see if it's a socket and, if so, +return the address family; detects IPv4 vs IPv6. If not a socket then +return -1. + +The value 0 is typically AF_UNSPEC, which should not be seen on a connected +fd. If the return is -1, the errno will be from getsockname(); probably +ENOTSOCK or ECONNRESET. + +Arguments: socket-or-not fd +Returns: address family or -1 +*/ + +static int +ip_get_address_family(int fd) +{ +struct sockaddr_storage ss; +socklen_t sslen = sizeof(ss); + +if (getsockname(fd, (struct sockaddr *) &ss, &sslen) < 0) + return -1; + +return (int) ss.ss_family; +} + + + +/************************************************* +* Lookup DSCP settings for a socket * +*************************************************/ + +struct dscp_name_tableentry { + const uschar *name; + int value; +}; +/* Keep both of these tables sorted! */ +static struct dscp_name_tableentry dscp_table[] = { +#ifdef IPTOS_DSCP_AF11 + { CUS"af11", IPTOS_DSCP_AF11 }, + { CUS"af12", IPTOS_DSCP_AF12 }, + { CUS"af13", IPTOS_DSCP_AF13 }, + { CUS"af21", IPTOS_DSCP_AF21 }, + { CUS"af22", IPTOS_DSCP_AF22 }, + { CUS"af23", IPTOS_DSCP_AF23 }, + { CUS"af31", IPTOS_DSCP_AF31 }, + { CUS"af32", IPTOS_DSCP_AF32 }, + { CUS"af33", IPTOS_DSCP_AF33 }, + { CUS"af41", IPTOS_DSCP_AF41 }, + { CUS"af42", IPTOS_DSCP_AF42 }, + { CUS"af43", IPTOS_DSCP_AF43 }, + { CUS"ef", IPTOS_DSCP_EF }, +#endif +#ifdef IPTOS_LOWCOST + { CUS"lowcost", IPTOS_LOWCOST }, +#endif + { CUS"lowdelay", IPTOS_LOWDELAY }, +#ifdef IPTOS_MINCOST + { CUS"mincost", IPTOS_MINCOST }, +#endif + { CUS"reliability", IPTOS_RELIABILITY }, + { CUS"throughput", IPTOS_THROUGHPUT } +}; +static int dscp_table_size = + sizeof(dscp_table) / sizeof(struct dscp_name_tableentry); + +/* DSCP values change by protocol family, and so do the options used for +setsockopt(); this utility does all the lookups. It takes an unexpanded +option string, expands it, strips off affix whitespace, then checks if it's +a number. If all of what's left is a number, then that's how the option will +be parsed and success/failure is a range check. If it's not all a number, +then it must be a supported keyword. + +Arguments: + dscp_name a string, so far unvalidated + af address_family in use + level setsockopt level to use + optname setsockopt name to use + dscp_value value for dscp_name + +Returns: TRUE if okay to setsockopt(), else FALSE + +*level and *optname may be set even if FALSE is returned +*/ + +static BOOL +dscp_lookup(const uschar * dscp_name, int af, + int * level, int * optname, int * dscp_value) +{ +uschar * dscp_lookup, * p; +int first, last; +long rawlong; + +if (af == AF_INET) + { *level = IPPROTO_IP; *optname = IP_TOS; } +#if HAVE_IPV6 && defined(IPV6_TCLASS) +else if (af == AF_INET6) + { *level = IPPROTO_IPV6; *optname = IPV6_TCLASS; } +#endif +else + { + DEBUG(D_transport) + debug_printf("Unhandled address family %d in dscp_lookup()\n", af); + return FALSE; + } +if (!dscp_name) + { + DEBUG(D_transport) + debug_printf("[empty DSCP]\n"); + return FALSE; + } +dscp_lookup = expand_string_copy(dscp_name); +if (!dscp_lookup || !*dscp_lookup) + return FALSE; + +p = dscp_lookup + Ustrlen(dscp_lookup) - 1; +while (isspace(*p)) *p-- = '\0'; +while (isspace(*dscp_lookup) && dscp_lookup < p) dscp_lookup++; +if (*dscp_lookup == '\0') + return FALSE; + +rawlong = Ustrtol(dscp_lookup, &p, 0); +if (p != dscp_lookup && *p == '\0') + { + /* We have six bits available, which will end up shifted to fit in 0xFC mask. + RFC 2597 defines the values unshifted. */ + if (rawlong < 0 || rawlong > 0x3F) + { + DEBUG(D_transport) + debug_printf("DSCP value %ld out of range, ignored.\n", rawlong); + return FALSE; + } + *dscp_value = rawlong << 2; + return TRUE; + } + +first = 0; +last = dscp_table_size; +while (last > first) + { + int middle = (first + last)/2; + int c = Ustrcmp(dscp_lookup, dscp_table[middle].name); + if (c == 0) + { + *dscp_value = dscp_table[middle].value; + return TRUE; + } + else if (c > 0) + first = middle + 1; + else + last = middle; + } +return FALSE; +} + +/******************************************************************************/ + +/*API +Set DSCP on stdin. Called from ACL control. +Return error message on fail, NULL on ok. +*/ + +static uschar * +dscp_acl(const uschar * control, const uschar * opt) +{ +int af, socklevel, optname, value; + +if (*opt != '/') + return string_sprintf("syntax error in \"control=%s\"", control); + +/* If we are acting on stdin, the setsockopt may fail if stdin is +not a socket; we can accept that, we'll just debug-log failures +anyway. */ +if (smtp_in_fd < 0) return US"no stdin"; +if ((af = ip_get_address_family(smtp_in_fd)) < 0) + { + HDEBUG(D_acl) debug_printf_indent( + "smtp input is probably not a socket [%s], not setting DSCP\n", + strerror(errno)); + return NULL; + } +if (!dscp_lookup(++opt, af, &socklevel, &optname, &value)) + return string_sprintf("unrecognised DSCP value in \"control=%s\"", control); + +value = setsockopt(smtp_in_fd, socklevel, optname, + &value, sizeof(value)); +HDEBUG(D_acl) + if (value < 0) + debug_printf_indent("failed to set input DSCP[%s]: %s\n", + opt, strerror(errno)); + else + debug_printf_indent("set input DSCP to %q\n", opt); +return NULL; +} + + +/*API +Set DSCP on given socket; called from smtp transport. +Can silently fail. +*/ + +static void +dscp_transport(int sock, const uschar * dscp_str, int host_af) +{ +int dscp_value, dscp_level, dscp_option; + +if ( dscp_str + && dscp_lookup(dscp_str, host_af, &dscp_level, &dscp_option, &dscp_value) + ) + { + HDEBUG(D_transport|D_acl|D_v) + debug_printf_indent("DSCP %q=%x ", dscp_str, dscp_value); + + if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0) + HDEBUG(D_transport|D_acl|D_v) + debug_printf_indent("failed to set DSCP: %s ", strerror(errno)); + + /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the + option for both; ignore failures here */ + + if ( host_af == AF_INET6 + && dscp_lookup(dscp_str, AF_INET, &dscp_level, &dscp_option, &dscp_value) + ) + (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)); + } +} + + +/*API: output known DSCP names */ +static void +dscp_keywords(FILE * stream) +{ +for (int i = 0; i < dscp_table_size; ++i) + fprintf(stream, "%s\n", dscp_table[i].name); +} + +/******************************************************************************/ +/* Module API */ + +static void * dscp_functions[] = { + [DSCP_ACL] = (void *) dscp_acl, + [DSCP_TRANSPORT] = (void *) dscp_transport, + [DSCP_KEYWORDS] = (void *) dscp_keywords, +}; + +misc_module_info dscp_module_info = +{ + .name = US"dscp", +# ifdef DYNLOOKUP + .dyn_magic = MISC_MODULE_MAGIC, +# endif + .functions = dscp_functions, + .functions_count = nelem(dscp_functions), +}; + +#endif /* SUPPORT_DSCP */ +/* vi: aw ai sw=2 + */ diff --git a/src/src/miscmods/dscp_api.h b/src/src/miscmods/dscp_api.h new file mode 100644 index 000000000..ce355319d --- /dev/null +++ b/src/src/miscmods/dscp_api.h @@ -0,0 +1,16 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* API definitions for the arcmodule */ + + +/* Function table entry numbers */ + +#define DSCP_ACL 0 +#define DSCP_TRANSPORT 1 +#define DSCP_KEYWORDS 2 diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 465acb5ed..790a0c005 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -276,10 +276,7 @@ Update those with the state. Return the fd, or -1 with errno set. int smtp_boundsock(smtp_connect_args * sc) { -transport_instance * tb = sc->tblock; -smtp_transport_options_block * ob = tb->drinst.options_block; -const uschar * dscp = ob->dscp; -int sock, dscp_value, dscp_level, dscp_option; +int sock; if ((sock = ip_socket(SOCK_STREAM, sc->host_af)) < 0) return -1; @@ -290,23 +287,23 @@ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("failed to set NODELAY: %s ", strerror(errno)); +#ifdef SUPPORT_DSCP /* Set DSCP value, if we can. For now, if we fail to set the value, we don't bomb out, just log it and continue in default traffic class. */ - -GET_OPTION("dscp"); -if (dscp && dscp_lookup(dscp, sc->host_af, &dscp_level, &dscp_option, &dscp_value)) { - HDEBUG(D_transport|D_acl|D_v) - debug_printf_indent("DSCP %q=%x ", dscp, dscp_value); - if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0) - HDEBUG(D_transport|D_acl|D_v) - debug_printf_indent("failed to set DSCP: %s ", strerror(errno)); - /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the - option for both; ignore failures here */ - if (sc->host_af == AF_INET6 && - dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value)) - (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)); + transport_instance * tb = sc->tblock; + smtp_transport_options_block * ob = tb->drinst.options_block; + GET_OPTION("dscp"); + if (ob->dscp) + { + uschar * dummy_errstr; + misc_module_info * mi = misc_mod_find(US"dscp", &dummy_errstr); + typedef void (*fn_t)(int, const uschar *, int); + if (mi) + ((fn_t *) mi->functions)[DSCP_TRANSPORT] (sock, ob->dscp, sc->host_af); + } } +#endif /* Bind to a specific interface if requested. Caller must ensure the interface is the same type (IPv4 or IPv6) as the outgoing address. */ commit 732c68f17cb249e6d40727ab0a043ded0fed2247 Author: Jeremy Harris Date: Sun Dec 14 12:52:18 2025 +0000 socks module diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 9b766d6ee..82e93d2ad 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -332,7 +332,7 @@ done <<-END routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS - miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SPF SPF_PERL + miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SOCKS SPF SPF_PERL END # See if there is a definition of EXIM_PERL in what we have built so far. diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 35b58ec04..1875c6963 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -66,7 +66,7 @@ cd $d # Makefile is generated for f in README appendfile.h appendfile.c autoreply.h \ autoreply.c lmtp.h lmtp.c pipe.h pipe.c queuefile.c queuefile.h \ - smtp.h smtp.c smtp_socks.c tf_maildir.c tf_maildir.h + smtp.h smtp.c tf_maildir.c tf_maildir.h do ln -s ../../src/$d/$f $f done @@ -108,6 +108,7 @@ for f in dummy.c \ perl.c perl_api.h \ radius.c radius_api.h \ sieve_filter.c sieve_filter_api.h \ + socks.c socks_api.h \ spf.c spf_perl.c spf.h spf_api.h do ln -s ../../src/$d/$f `basename $f` diff --git a/src/src/EDITME b/src/src/EDITME index 98baae7d5..695cceafd 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1131,7 +1131,7 @@ ZCAT_COMMAND=/usr/bin/zcat # Proxying. # # If you may want to use outbound (client-side) proxying, using Socks5, -# uncomment the line below. +# uncomment the line below. To build as a dynamic module set it to 2. # SUPPORT_SOCKS=yes diff --git a/src/src/drtables.c b/src/src/drtables.c index e21d47047..3c714ba24 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -513,6 +513,9 @@ extern misc_module_info exim_filter_module_info; #if !defined(DISABLE_SIEVE_FILTER) && (!defined(SUPPORT_SIEVE_FILTER) || SUPPORT_SIEVE_FILTER!=2) extern misc_module_info sieve_filter_module_info; #endif +#if defined(SUPPORT_SOCKS) && SUPPORT_SOCKS!=2 +extern misc_module_info socks_module_info; +#endif void init_misc_mod_list(void) @@ -537,9 +540,6 @@ onetime = TRUE; #if defined(SUPPORT_DSCP) && SUPPORT_DSCP!=2 misc_mod_add(&dscp_module_info); #endif -#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) - misc_mod_add(&radius_module_info); -#endif #if defined(SUPPORT_PAM) && SUPPORT_PAM!=2 misc_mod_add(&pam_module_info); #endif @@ -552,6 +552,12 @@ onetime = TRUE; #if !defined(DISABLE_SIEVE_FILTER) && (!defined(SUPPORT_SIEVE_FILTER) || SUPPORT_SIEVE_FILTER!=2) misc_mod_add(&sieve_filter_module_info); #endif +#if defined(SUPPORT_SOCKS) && SUPPORT_SOCKS!=2 + misc_mod_add(&socks_module_info); +#endif +#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) + misc_mod_add(&radius_module_info); +#endif } diff --git a/src/src/exim.c b/src/src/exim.c index 383fe8247..e955d2488 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -3093,6 +3093,8 @@ on the second character (the one after '-'), to save some effort. */ #ifdef SUPPORT_SOCKS /* -MCp: Socks proxy in use; nearside IP, port, external IP, port */ + /*XXX Neatness might have this code in the socks module, but having to + load a dynamic version puely for this? However, of logging moved there...*/ case 'p': proxy_session = TRUE; if (++i < argc) { diff --git a/src/src/exim.h b/src/src/exim.h index 07b017a01..4bd0a87e7 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -570,6 +570,9 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #ifdef EXIM_PERL # include "miscmods/perl_api.h" #endif +#ifdef SUPPORT_SOCKS +# include "miscmods/socks_api.h" +#endif #include "miscmods/exim_filter_api.h" #include "miscmods/sieve_filter_api.h" diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index e129fe8bc..a5fbba441 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -48,6 +48,7 @@ pam.o pam.so: $(HDRS) pam.c perl.o perl.so: $(HDRS) perl.c radius.o radius.so: $(HDRS) radius.c sieve_filter.o sieve_filter.so: $(HDRS) sieve_filter.c +socks.o socks.so: $(HDRS) socks_api.h ../transports/smtp.h socks.c spf.o spf.so: $(HDRS) spf.h spf.c spf_perl.o spf_perl.so: $(HDRS) spf.h spf_perl.c diff --git a/src/src/transports/smtp_socks.c b/src/src/miscmods/socks.c similarity index 94% rename from src/src/transports/smtp_socks.c rename to src/src/miscmods/socks.c index c17b808e9..6694044da 100644 --- a/src/src/transports/smtp_socks.c +++ b/src/src/miscmods/socks.c @@ -10,15 +10,10 @@ /* SOCKS version 5 proxy, client-mode */ #include "../exim.h" -#include "smtp.h" +#include "../transports/smtp.h" #ifdef SUPPORT_SOCKS /* entire file */ -#ifndef nelem -# define nelem(arr) (sizeof(arr)/sizeof(*arr)) -#endif - - /* Defaults */ #define SOCKS_PORT 1080 #define SOCKS_TIMEOUT 5 @@ -187,18 +182,18 @@ return -1; -/* Make a connection via a socks proxy +/*API: Make a connection via a socks proxy Arguments: sc details for making connection: host, af, interface, transport early_data data to send down the smtp channel (once proxied) Return value: - 0 on success; -1 on failure, with errno set + connected file descriptor on success; -1 on failure, with errno set */ -int -socks_sock_connect(smtp_connect_args * sc, const blob * early_data) +static int +socks_sock_connect(const smtp_connect_args * sc, const blob * early_data) { transport_instance * tb = sc->tblock; smtp_transport_options_block * ob = tb->drinst.options_block; @@ -407,6 +402,24 @@ rcv_err: return -1; } +/******************************************************************************/ +/* Module API */ + +static void * socks_functions[] = { + [SOCKS_CONNECT] = (void *) socks_sock_connect, +}; + +misc_module_info socks_module_info = +{ + .name = US"socks", +# ifdef DYNLOOKUP + .dyn_magic = MISC_MODULE_MAGIC, +# endif + + .functions = socks_functions, + .functions_count = nelem(socks_functions), +}; + #endif /* entire file */ /* vi: aw ai sw=2 */ diff --git a/src/src/miscmods/socks_api.h b/src/src/miscmods/socks_api.h new file mode 100644 index 000000000..6a083d3cb --- /dev/null +++ b/src/src/miscmods/socks_api.h @@ -0,0 +1,14 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* API definitions for the socks module */ + + +/* Function table entry numbers */ + +#define SOCKS_CONNECT 0 diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 790a0c005..a5557d09e 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -520,7 +520,12 @@ if (ob->socks_proxy) return -1; } if (*ob->socks_proxy) - return socks_sock_connect(sc, early_data); + { + uschar * dummy_errmsg; + misc_module_info * mi = misc_mod_find(US"socks", &dummy_errmsg); + typedef int (*fn_t) (const smtp_connect_args *, const blob *); + return mi ? ((fn_t *) mi->functions)[SOCKS_CONNECT] (sc, early_data) : -1; + } } #endif diff --git a/src/src/transports/Makefile b/src/src/transports/Makefile index 89cadc568..761cf01c8 100644 --- a/src/src/transports/Makefile +++ b/src/src/transports/Makefile @@ -11,12 +11,12 @@ # MAGIC-TAG-MODS-OBJ-RULES-GO-HERE -OBJ += smtp_socks.o tf_maildir.o +OBJ += tf_maildir.o all: transports.a $(MODS) $(FE): -transports.a: $(OBJ) smtp_socks.o tf_maildir.o +transports.a: $(OBJ) tf_maildir.o @$(RM_COMMAND) -f transports.a @echo "$(AR) transports.a" @$(AR) transports.a $(OBJ) @@ -39,7 +39,6 @@ lmtp.o lmtp.so: lmtp.c lmtp.h pipe.o pipe.so: pipe.c pipe.h queuefile.o queuefile.so: queuefile.c queuefile.h smtp.o: smtp.c smtp.h -smtp_socks.o: smtp_socks.c smtp.h tf_maildir.o: tf_maildir.c tf_maildir.h appendfile.h diff --git a/src/src/transports/smtp.h b/src/src/transports/smtp.h index 506d6094a..72b3b00ba 100644 --- a/src/src/transports/smtp.h +++ b/src/src/transports/smtp.h @@ -250,9 +250,4 @@ extern BOOL smtp_transport_entry(transport_instance *, address_item *); extern void smtp_transport_closedown(transport_instance *); - -#ifdef SUPPORT_SOCKS -extern int socks_sock_connect(smtp_connect_args *, const blob *); -#endif - /* End of transports/smtp.h */ commit ee143587852f7a6937a6997da730b4e02e427fc4 Author: Jeremy Harris Date: Sun Dec 14 18:23:37 2025 +0000 xclient module diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index f713ad3ca..9f26eff0f 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -541,8 +541,7 @@ OBJ_WITH_CONTENT_SCAN = malware.o mime.o regex.o spam.o spool_mbox.o OBJ_EXPERIMENTAL = dane.o \ dcc.o \ imap_utf7.o \ - utf8.o \ - xclient.o + utf8.o # Targets for final binaries; the main one has a build number which is # updated each time. We don't bother with that for the auxiliaries. @@ -939,7 +938,6 @@ dane.o: $(HDRS) dane.c dane-openssl.c dcc.o: $(HDRS) dcc.h dcc.c imap_utf7.o: $(HDRS) imap_utf7.c utf8.o: $(HDRS) utf8.c -xclient.o: $(HDRS) xclient.c # The module containing tables of available lookups, routers, auths, and # transports must be rebuilt if any of them are. However, because the makefiles diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 82e93d2ad..9a7351482 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -332,7 +332,7 @@ done <<-END routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS - miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SOCKS SPF SPF_PERL + miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SOCKS SPF SPF_PERL XCLIENT END # See if there is a definition of EXIM_PERL in what we have built so far. diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 1875c6963..642cd7302 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -109,7 +109,8 @@ for f in dummy.c \ radius.c radius_api.h \ sieve_filter.c sieve_filter_api.h \ socks.c socks_api.h \ - spf.c spf_perl.c spf.h spf_api.h + spf.c spf_perl.c spf.h spf_api.h \ + xclient.c xclient_api.h do ln -s ../../src/$d/$f `basename $f` done @@ -158,7 +159,7 @@ done # EXPERIMENTAL_* for f in dcc.c dcc.h dane.c dane-openssl.c \ - danessl.h imap_utf7.c utf8.c xclient.c + danessl.h imap_utf7.c utf8.c do ln -s ../src/$f $f done diff --git a/src/src/EDITME b/src/src/EDITME index 695cceafd..9e5b25029 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -707,7 +707,8 @@ DISABLE_MAL_MKS=yes # Uncomment the following line to add SRV smtps support # EXPERIMENTAL_SRV_SMTPS=yes # -# Uncomment the following line to add XCLIENT support +# Uncomment the following line to add XCLIENT support. +# Set to 2 for a dynamic-load module. # EXPERIMENTAL_XCLIENT=yes ############################################################################### diff --git a/src/src/drtables.c b/src/src/drtables.c index 3c714ba24..4df612c65 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -498,24 +498,28 @@ extern misc_module_info arc_module_info; #if defined(SUPPORT_DSCP) && SUPPORT_DSCP!=2 extern misc_module_info dscp_module_info; #endif -#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) -extern misc_module_info radius_module_info; -#endif #if defined(SUPPORT_PAM) && SUPPORT_PAM!=2 extern misc_module_info pam_module_info; #endif #if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2) extern misc_module_info perl_module_info; #endif +#if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) +extern misc_module_info radius_module_info; +#endif +#if defined(SUPPORT_SOCKS) && SUPPORT_SOCKS!=2 +extern misc_module_info socks_module_info; +#endif +#if defined(EXPERIMENTAL_XCLIENT) && EXPERIMENTAL_XCLIENT!=2 +extern misc_module_info xclient_module_info; +#endif + #if !defined(DISABLE_EXIM_FILTER) && (!defined(SUPPORT_EXIM_FILTER) || SUPPORT_EXIM_FILTER!=2) extern misc_module_info exim_filter_module_info; #endif #if !defined(DISABLE_SIEVE_FILTER) && (!defined(SUPPORT_SIEVE_FILTER) || SUPPORT_SIEVE_FILTER!=2) extern misc_module_info sieve_filter_module_info; #endif -#if defined(SUPPORT_SOCKS) && SUPPORT_SOCKS!=2 -extern misc_module_info socks_module_info; -#endif void init_misc_mod_list(void) @@ -543,6 +547,9 @@ onetime = TRUE; #if defined(SUPPORT_PAM) && SUPPORT_PAM!=2 misc_mod_add(&pam_module_info); #endif +#if defined(EXPERIMENTAL_XCLIENT) && EXPERIMENTAL_XCLIENT!=2 + misc_mod_add(&xclient_module_info); +#endif #if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2) misc_mod_add(&perl_module_info); #endif diff --git a/src/src/exim.h b/src/src/exim.h index 4bd0a87e7..7b4270cad 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -561,9 +561,6 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #ifdef SUPPORT_DSCP # include "miscmods/dscp_api.h" #endif -#ifdef RADIUS_CONFIG_FILE -# include "miscmods/radius_api.h" -#endif #ifdef SUPPORT_PAM # include "miscmods/pam_api.h" #endif @@ -573,6 +570,12 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #ifdef SUPPORT_SOCKS # include "miscmods/socks_api.h" #endif +#ifdef RADIUS_CONFIG_FILE +# include "miscmods/radius_api.h" +#endif +#ifdef EXPERIMENTAL_XCLIENT +# include "miscmods/xclient_api.h" +#endif #include "miscmods/exim_filter_api.h" #include "miscmods/sieve_filter_api.h" diff --git a/src/src/functions.h b/src/src/functions.h index 4e56c14a4..f07799321 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -706,10 +706,6 @@ extern BOOL write_chunk(transport_ctx *, const uschar *, int); extern ssize_t write_to_fd_buf(int, const uschar *, size_t); extern uschar *wrap_header(const uschar *, unsigned, unsigned, const uschar *, unsigned); -#ifdef EXPERIMENTAL_XCLIENT -extern uschar * xclient_smtp_command(uschar *, int *, BOOL *); -extern gstring * xclient_smtp_advertise_str(gstring *); -#endif extern uschar *xtextencode(const uschar *, int); extern int xtextdecode(const uschar *, uschar **); diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index a5fbba441..f731088ba 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -43,14 +43,15 @@ dmarc_native.o dmarc_native.so: $(HDRS) spf.h pdkim.h dmarc.h \ dmarc_native.c dmarc_common.c dscp.o dscp.so: $(HDRS) dscp.c dummy.o: dummy.c -exim_filter.o exim_filter.so: $(HDRS) exim_filter.c -pam.o pam.so: $(HDRS) pam.c -perl.o perl.so: $(HDRS) perl.c -radius.o radius.so: $(HDRS) radius.c -sieve_filter.o sieve_filter.so: $(HDRS) sieve_filter.c -socks.o socks.so: $(HDRS) socks_api.h ../transports/smtp.h socks.c -spf.o spf.so: $(HDRS) spf.h spf.c -spf_perl.o spf_perl.so: $(HDRS) spf.h spf_perl.c +exim_filter.o exim_filter.so: $(HDRS) exim_filter.c +pam.o pam.so: $(HDRS) pam.c +perl.o perl.so: $(HDRS) perl.c +radius.o radius.so: $(HDRS) radius.c +sieve_filter.o sieve_filter.so: $(HDRS) sieve_filter.c +socks.o socks.so: $(HDRS) socks_api.h ../transports/smtp.h socks.c +spf.o spf.so: $(HDRS) spf.h spf.c +spf_perl.o spf_perl.so: $(HDRS) spf.h spf_perl.c +xclient.o xclient.so: $(HDRS) xclient_api.h xclient.c diff --git a/src/src/miscmods/xclient.c b/src/src/miscmods/xclient.c new file mode 100644 index 000000000..77bf743a4 --- /dev/null +++ b/src/src/miscmods/xclient.c @@ -0,0 +1,356 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2023 - 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "../exim.h" + +#ifdef EXPERIMENTAL_XCLIENT + +/* This is a proxy protocol. + +From https://www.postfix.org/XCLIENT_README.html I infer two generations of +protocol. The more recent one obviates the utility of the HELO attribute, since +it mandates the proxy always sending a HELO/EHLO smtp command following (a +successful) XCLIENT command, and that will carry a NELO name (which we assume, +though it isn't specified, will be the actual one presented to the proxy by the +possibly-new client). The same applies to the PROTO attribute. */ + +# define XCLIENT_V2 + +enum xclient_cmd_e { + XCLIENT_CMD_UNKNOWN, + XCLIENT_CMD_ADDR, + XCLIENT_CMD_NAME, + XCLIENT_CMD_PORT, + XCLIENT_CMD_LOGIN, + XCLIENT_CMD_DESTADDR, + XCLIENT_CMD_DESTPORT, +# ifdef XCLIENT_V1 + XCLIENT_CMD_HELO, + XCLIENT_CMD_PROTO, +# endif +}; + +struct xclient_cmd { + const uschar * str; + unsigned len; +} xclient_cmds[] = { + [XCLIENT_CMD_UNKNOWN] = { NULL }, + [XCLIENT_CMD_ADDR] = { US"ADDR", 4 }, + [XCLIENT_CMD_NAME] = { US"NAME", 4 }, + [XCLIENT_CMD_PORT] = { US"PORT", 4 }, + [XCLIENT_CMD_LOGIN] = { US"LOGIN", 5 }, + [XCLIENT_CMD_DESTADDR] = { US"DESTADDR", 8 }, + [XCLIENT_CMD_DESTPORT] = { US"DESTPORT", 8 }, +# ifdef XCLIENT_V1 + [XCLIENT_CMD_HELO] = { US"HELO", 4 }, + [XCLIENT_CMD_PROTO] = { US"PROTO", 5 }, +# endif +}; + +/************************************************* +* XCLIENT proxy implementation * +*************************************************/ + +/* Arguments: + code points to the coded string + end points to the end of coded string + ptr where to put the pointer to the result, which is in + dynamic store +Returns: the number of bytes in the result, excluding the final zero; + -1 if the input is malformed +*/ + +static int +xclient_xtextdecode(const uschar * code, const uschar * end, uschar ** ptr) +{ +return xtextdecode(string_copyn(code, end-code), ptr); +} + +/************************************************* +* Check XCLIENT line and set sender_address * +*************************************************/ + + +/* Check the format of a XCLIENT line. +Arguments: + s the data portion of the line (already past any white space) + resp result: smtp respose code + flagp input: helo seen output: fail is fatal + +Return: NULL on success, or error message +*/ + +# define XCLIENT_UNAVAIL US"[UNAVAILABLE]" +# define XCLIENT_TEMPUNAVAIL US"[TEMPUNAVAIL]" + +static uschar * +xclient_smtp_command(const uschar * s, int * resp, BOOL * flagp) +{ +const uschar * word = s; +uschar * errmsg = NULL; +enum { + XCLIENT_READ_COMMAND = 0, + XCLIENT_READ_VALUE, + XCLIENT_SKIP_SPACES +} state = XCLIENT_SKIP_SPACES; +enum xclient_cmd_e cmd; +static BOOL xc_proxy_session = FALSE; + +if ( !*flagp + && verify_check_host(&hosts_require_helo) == OK) + { + *resp = 503; + *flagp= FALSE; + return US"no HELO/EHLO given"; + } + +/* If already in a proxy session, do not re-check permission. */ + +if (!xc_proxy_session && verify_check_host(&hosts_xclient) == FAIL) + { + *resp = 501; + *flagp= TRUE; + return US"XCLIENT command used when not advertised"; + } + +if (sender_address) + { + *resp = 503; + *flagp= FALSE; + return US"mail transaction in progress"; + } + +if (!*word) + { + errmsg = US"XCLIENT must have at least one operand"; + goto fatal_501; + } + +for (state = XCLIENT_SKIP_SPACES; *s; ) + switch (state) + { + case XCLIENT_READ_COMMAND: + { + int len; + + word = s; + while (*s && *s != '=') s++; + len = s - word; + if (!*s) + { + errmsg = string_sprintf("XCLIENT: missing value for parameter '%.*s'", + len, word); + goto fatal_501; + } + + DEBUG(D_transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); + cmd = XCLIENT_CMD_UNKNOWN; + for (struct xclient_cmd * x = xclient_cmds + 1; + x < xclient_cmds + nelem(xclient_cmds); x++) + if (len == x->len && strncmpic(word, x->str, len) == 0) + { + cmd = x - xclient_cmds; + break; + } + if (cmd == XCLIENT_CMD_UNKNOWN) + { + errmsg = string_sprintf("XCLIENT: unrecognised parameter '%.*s'", + len, word); + goto fatal_501; + } + state = XCLIENT_READ_VALUE; + } + break; + + case XCLIENT_READ_VALUE: + { + int old_pool = store_pool; + int len; + uschar * val; + + word = ++s; /* skip the = */ + Uskip_nonwhite(&s); + len = s - word; + + DEBUG(D_transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); + if (len == 0) + { errmsg = US"XCLIENT: zero-length value for param"; goto fatal_501; } + + if ( len == 13 + && ( strncmpic(word, XCLIENT_UNAVAIL, 13) == 0 + || strncmpic(word, XCLIENT_TEMPUNAVAIL, 13) == 0 + ) ) + val = NULL; + + else if ((len = xclient_xtextdecode(word, s, &val)) == -1) + { + errmsg = string_sprintf("failed xtext decode for XCLIENT: '%.*s'", len, word); + goto fatal_501; + } + + store_pool = POOL_PERM; + switch (cmd) + { + case XCLIENT_CMD_ADDR: + proxy_local_address = sender_host_address; + sender_host_address = val ? string_copyn(val, len) : NULL; + break; + case XCLIENT_CMD_NAME: + sender_host_name = val ? string_copyn(val, len) : NULL; + break; + case XCLIENT_CMD_PORT: + proxy_local_port = sender_host_port; + sender_host_port = val ? Uatoi(val) : 0; + break; + case XCLIENT_CMD_DESTADDR: + proxy_external_address = val ? string_copyn(val, len) : NULL; + break; + case XCLIENT_CMD_DESTPORT: + proxy_external_port = val ? Uatoi(val) : 0; + break; + + case XCLIENT_CMD_LOGIN: + if (val) + { + authenticated_id = string_copyn(val, len); + sender_host_authenticated = US"xclient"; + authentication_failed = FALSE; + } + else + { + authenticated_id = NULL; + sender_host_authenticated = NULL; + } + break; + +# ifdef XCLIENT_V1 + case XCLIENT_CMD_HELO: + sender_helo_name = val ? string_copyn(val, len) : NULL; + break; + case XCLIENT_CMD_PROTO: + if (!val) + { store_pool = old_pool; errmsg = US"missing proto for XCLIENT"; goto fatal_501; } + else if (len == 4 && strncmpic(val, US"SMTP", 4) == 0) + *esmtpflag = FALSE; /* function arg */ + else if (len == 5 && strncmpic(val, US"ESMTP", 5) == 0) + *esmtpflag = TRUE; + else + { store_pool = old_pool; errmsg = US"bad proto for XCLIENT"; goto fatal_501; } + break; +# endif + default: break; /* stupid compiler silencing */ + } + store_pool = old_pool; + state = XCLIENT_SKIP_SPACES; + break; + } + + case XCLIENT_SKIP_SPACES: + Uskip_whitespace(&s); + state = XCLIENT_READ_COMMAND; + break; + + default: + errmsg = US"unhandled XCLIENT parameter type"; + goto fatal_501; + } + +if (!proxy_local_address) + { errmsg = US"missing ADDR for XCLIENT"; goto fatal_501; } +if (!proxy_local_port) + { errmsg = US"missing PORT for XCLIENT"; goto fatal_501; } +if (state != XCLIENT_SKIP_SPACES) + { errmsg = US"bad state parsing XCLIENT parameters"; goto fatal_501; } + +host_build_sender_fullhost(); +proxy_session = TRUE; /* global */ +xc_proxy_session = TRUE; /* local */ +*resp = 220; +return NULL; + +fatal_501: + *flagp= TRUE; + *resp = 501; + return errmsg; +} + +# undef XCLIENT_UNAVAIL +# undef XCLIENT_TEMPUNAVAIL + + +/*API*/ +static gstring * +xclient_smtp_advertise_str(gstring * g) +{ +g = string_catn(g, US"-XCLIENT ", 8); +for (int i = 1; i < nelem(xclient_cmds); i++) + { + g = string_catn(g, US" ", 1); + g = string_cat(g, xclient_cmds[i].str); + } +return string_catn(g, US"\r\n", 2); +} + + +/*API +Return: true if the cmd was good and the protocol started +*/ + +static int +xclient_protocol_start(const uschar * smtp_cmd_data, int * donep, + BOOL helo_seen) +{ +BOOL fatal = helo_seen; +uschar * errmsg; +int resp; + +if (!(errmsg = xclient_smtp_command(smtp_cmd_data, &resp, &fatal))) + { + /*XXX unclear in spec. if this needs to be an ESMTP banner, + nor whether we get the original client's HELO after (or a proxy fake). + We require that we do; the following HELO/EHLO handling will set + sender_helo_name as normal. */ + + smtp_printf("%d XCLIENT success\r\n", SP_NO_MORE, resp); + return TRUE; + } +else if (fatal) + *donep = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg); +else + { + smtp_printf("%d %s\r\n", SP_NO_MORE, resp, errmsg); + log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s", + host_and_ident(FALSE), errmsg); + } + +return FALSE; +} + +/******************************************************************************/ +/* Module API */ + +static void * xclient_functions[] = { + [XCLIENT_PROTO_ADVERTISE] = (void *) xclient_smtp_advertise_str, + [XCLIENT_PROTO_START] = (void *) xclient_protocol_start, +}; + +misc_module_info xclient_module_info = +{ + .name = US"xclient", +# ifdef DYNLOOKUP + .dyn_magic = MISC_MODULE_MAGIC, +# endif + .functions = xclient_functions, + .functions_count = nelem(xclient_functions), +}; +#endif /*EXPERIMENTAL_XCLIENT*/ + +/* vi: aw ai sw=2 +*/ +/* End of xclient.c */ + diff --git a/src/src/miscmods/xclient_api.h b/src/src/miscmods/xclient_api.h new file mode 100644 index 000000000..e59296395 --- /dev/null +++ b/src/src/miscmods/xclient_api.h @@ -0,0 +1,15 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* API definitions for the proxy-protocol module */ + + +/* Function table entry numbers */ + +#define XCLIENT_PROTO_ADVERTISE 0 +#define XCLIENT_PROTO_START 1 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index d694c8d7a..222fc5b93 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -3811,6 +3811,9 @@ smtp_setup_msg(void) int done = 0; BOOL toomany = FALSE, discarded = FALSE, last_was_rej_mail = FALSE, last_was_rcpt = FALSE; +#ifdef EXPERIMENTAL_XCLIENT +static misc_module_info * xclient_mi = NULL; +#endif rmark reset_point = store_mark(); DEBUG(D_receive) debug_printf("smtp_setup_msg entered\n"); @@ -4433,8 +4436,17 @@ while (done <= 0) #ifdef EXPERIMENTAL_XCLIENT if (proxy_session || verify_check_host(&hosts_xclient) != FAIL) { + uschar * dummy_errmsg; + typedef gstring * (*fn_t) (gstring *); + + if ( !xclient_mi + && !(xclient_mi = misc_mod_find(US"xclient", &dummy_errmsg))) + { + smtp_closedown(US"Temporary local problem - please try later"); + return FALSE; + } g = string_catn(g, smtp_code, 3); - g = xclient_smtp_advertise_str(g); + g = ((fn_t *) xclient_mi->functions)[XCLIENT_PROTO_ADVERTISE] (g); } #endif #ifndef DISABLE_PRDR @@ -4516,37 +4528,21 @@ while (done <= 0) #ifdef EXPERIMENTAL_XCLIENT case XCLIENT_CMD: - { - BOOL fatal = fl.helo_seen; - uschar * errmsg; - int resp; - HAD(SCH_XCLIENT); smtp_mailcmd_count++; - if ((errmsg = xclient_smtp_command(smtp_cmd_data, &resp, &fatal))) - if (fatal) - done = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg); - else - { - smtp_printf("%d %s\r\n", SP_NO_MORE, resp, errmsg); - log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s", - host_and_ident(FALSE), errmsg); - } + if (!xclient_mi) + done = synprot_error(L_smtp_syntax_error, 501, NULL, + US"XCLIENT command used when not advertised"); else { - fl.helo_seen = FALSE; /* Require another EHLO */ - smtp_code = string_sprintf("%d", resp); - - /*XXX unclear in spec. if this needs to be an ESMTP banner, - nor whether we get the original client's HELO after (or a proxy fake). - We require that we do; the following HELO/EHLO handling will set - sender_helo_name as normal. */ - - smtp_printf("%s XCLIENT success\r\n", SP_NO_MORE, smtp_code); + typedef BOOL (*fn_t) (const uschar *, int *, BOOL); + BOOL started = ((fn_t *) xclient_mi->functions)[XCLIENT_PROTO_START] + (smtp_cmd_data, &done, fl.helo_seen); + if (started) + fl.helo_seen = FALSE; /* Require another EHLO */ } break; /* XCLIENT */ - } #endif commit fda16457fbba6a11abdb09370ce21ea09f9e64f7 Author: Jeremy Harris Date: Sun Dec 14 15:32:48 2025 +0000 proxy-protocol module diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 9f26eff0f..ff733b490 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -557,7 +557,7 @@ OBJ_EXIM = acl.o atrn.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o \ deliver.o directory.o dns.o drtables.o enq.o exim.o expand.o \ filtertest.o globals.o dnsbl.o hash.o \ header.o host.o host_address.o ip.o log.o lss.o match.o md5.o moan.o \ - os.o parse.o priv.o proxy.o queue.o \ + os.o parse.o priv.o queue.o \ rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o regex_cache.o \ route.o search.o smtp_in.o smtp_out.o spool_in.o spool_out.o \ std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \ @@ -895,7 +895,6 @@ moan.o: $(HDRS) moan.c os.o: $(HDRS) $(OS_C_INCLUDES) os.c parse.o: $(HDRS) parse.c priv.o: $(HDRS) priv.c -proxy.o: $(HDRS) proxy.c queue.o: $(HDRS) queue.c rda.o: $(HDRS) rda.c readconf.o: $(HDRS) readconf.c diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 9a7351482..84a8abbb2 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -332,7 +332,7 @@ done <<-END routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP auths AUTH CRAM_MD5 CYRUS_SASL DOVECOT EXTERNAL GSASL HEIMDAL_GSSAPI PLAINTEXT SPA TLS - miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL RADIUS _SIEVE_FILTER SOCKS SPF SPF_PERL XCLIENT + miscmods SUPPORT ARC _DKIM DMARC DMARC_NATIVE DSCP _EXIM_FILTER PAM PERL PROXY RADIUS _SIEVE_FILTER SOCKS SPF SPF_PERL XCLIENT END # See if there is a definition of EXIM_PERL in what we have built so far. diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 642cd7302..5219d3dbc 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -106,6 +106,7 @@ for f in dummy.c \ exim_filter.c exim_filter_api.h \ pam.c pam_api.h \ perl.c perl_api.h \ + proxy.c proxy_api.h \ radius.c radius_api.h \ sieve_filter.c sieve_filter_api.h \ socks.c socks_api.h \ @@ -139,7 +140,7 @@ for f in blob.h dbfunctions.h exim.h functions.h globals.h \ debug.c deliver.c directory.c dns.c dnsbl.c drtables.c dummies.c enq.c \ exim.c exim_dbmbuild.c exim_dbutil.c exim_lock.c expand.c filtertest.c \ globals.c hash.c header.c host.c host_address.c ip.c log.c lss.c match.c \ - md5.c moan.c parse.c priv.c proxy.c queue.c rda.c readconf.c receive.c \ + md5.c moan.c parse.c priv.c queue.c rda.c readconf.c receive.c \ retry.c rewrite.c regex_cache.c rfc2047.c route.c search.c setenv.c \ environment.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c \ store.c string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-cipher-stdname.c \ diff --git a/src/src/EDITME b/src/src/EDITME index 9e5b25029..8977f624b 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1137,7 +1137,7 @@ ZCAT_COMMAND=/usr/bin/zcat # SUPPORT_SOCKS=yes # If you may want to use inbound (server-side) proxying, using Proxy Protocol, -# uncomment the line below. +# uncomment the line below. To build as a dynamic module set it to 2. # SUPPORT_PROXY=yes diff --git a/src/src/drtables.c b/src/src/drtables.c index 4df612c65..833c352c0 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -504,6 +504,9 @@ extern misc_module_info pam_module_info; #if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2) extern misc_module_info perl_module_info; #endif +#if defined(SUPPORT_PROXY) && SUPPORT_PROXY!=2 +extern misc_module_info proxy_module_info; +#endif #if defined(RADIUS_CONFIG_FILE) && (!defined(SUPPORT_RADIUS) || SUPPORT_RADIUS!=2) extern misc_module_info radius_module_info; #endif @@ -553,6 +556,9 @@ onetime = TRUE; #if defined(EXIM_PERL) && (!defined(SUPPORT_PERL) || SUPPORT_PERL!=2) misc_mod_add(&perl_module_info); #endif +#if defined(SUPPORT_PROXY) && SUPPORT_PROXY!=2 + misc_mod_add(&proxy_module_info); +#endif #if !defined(DISABLE_EXIM_FILTER) && (!defined(SUPPORT_EXIM_FILTER) || SUPPORT_EXIM_FILTER!=2) misc_mod_add(&exim_filter_module_info); #endif diff --git a/src/src/exim.h b/src/src/exim.h index 7b4270cad..70911b0f8 100644 --- a/src/src/exim.h +++ b/src/src/exim.h @@ -567,6 +567,9 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly. #ifdef EXIM_PERL # include "miscmods/perl_api.h" #endif +#ifdef SUPPORT_PROXY +# include "miscmods/proxy_api.h" +#endif #ifdef SUPPORT_SOCKS # include "miscmods/socks_api.h" #endif diff --git a/src/src/functions.h b/src/src/functions.h index f07799321..b48103922 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -407,10 +407,6 @@ const misc_module_info * perl_startup(const uschar *); extern void priv_drop_temp(const uid_t, const gid_t); extern void priv_restore(void); -#ifdef SUPPORT_PROXY -extern BOOL proxy_protocol_host(void); -extern void proxy_protocol_setup(void); -#endif extern BOOL queue_action(const uschar *, int, const uschar **, int, int); extern void queue_check_only(void); diff --git a/src/src/globals.c b/src/src/globals.c index 6d2b27227..2d1354236 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -286,15 +286,15 @@ struct global_flags f = .parse_allow_group = FALSE, .parse_found_group = FALSE, .pipelining_enable = TRUE, -#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) - .proxy_session_failed = FALSE, -#endif .queue_2stage = FALSE, .queue_only_policy = FALSE, .queue_run_local = FALSE, .queue_running = FALSE, .queue_smtp = FALSE, +#if defined(SUPPORT_PROXY) + .quit_cmd_only = FALSE, +#endif .really_exim = TRUE, .receive_call_bombout = FALSE, diff --git a/src/src/globals.h b/src/src/globals.h index 977107f58..52c46f169 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -256,15 +256,15 @@ extern struct global_flags { BOOL parse_allow_group :1; /* Allow group syntax */ BOOL parse_found_group :1; /* In the middle of a group */ BOOL pipelining_enable :1; /* As it says */ -#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) - BOOL proxy_session_failed :1; /* TRUE if required proxy negotiation failed */ -#endif BOOL queue_2stage :1; /* Run queue in 2-stage manner */ BOOL queue_only_policy :1; /* ACL or local_scan wants queue_only */ BOOL queue_run_local :1; /* Local deliveries only in queue run */ BOOL queue_running :1; /* TRUE for queue running process and */ BOOL queue_smtp :1; /* Disable all immediate SMTP (-odqs)*/ +#ifdef SUPPORT_PROXY + BOOL quit_cmd_only :1; /* TRUE if required proxy negotiation failed */ +#endif BOOL really_exim :1; /* FALSE in utilities */ BOOL receive_call_bombout :1; /* Flag for crashing log */ diff --git a/src/src/miscmods/Makefile b/src/src/miscmods/Makefile index f731088ba..1076c6daf 100644 --- a/src/src/miscmods/Makefile +++ b/src/src/miscmods/Makefile @@ -46,6 +46,7 @@ dummy.o: dummy.c exim_filter.o exim_filter.so: $(HDRS) exim_filter.c pam.o pam.so: $(HDRS) pam.c perl.o perl.so: $(HDRS) perl.c +proxy.o proxy.so: $(HDRS) proxy_api.h proxy.c radius.o radius.so: $(HDRS) radius.c sieve_filter.o sieve_filter.so: $(HDRS) sieve_filter.c socks.o socks.so: $(HDRS) socks_api.h ../transports/smtp.h socks.c diff --git a/src/src/proxy.c b/src/src/miscmods/proxy.c similarity index 95% rename from src/src/proxy.c rename to src/src/miscmods/proxy.c index c8230b009..320b57ea8 100644 --- a/src/src/proxy.c +++ b/src/src/miscmods/proxy.c @@ -11,9 +11,17 @@ * Proxy-Protocol support * ************************************************/ -#include "exim.h" +#include "../exim.h" #ifdef SUPPORT_PROXY + + +static void +command_timeout_handler(int sig) +{ +had_command_timeout = sig; +} + /************************************************* * Check if host is required proxy host * *************************************************/ @@ -25,7 +33,7 @@ Arguments: none Returns: boolean for Proxy Protocol needed */ -BOOL +static BOOL proxy_protocol_host(void) { if ( sender_host_address @@ -34,6 +42,7 @@ if ( sender_host_address { DEBUG(D_receive) debug_printf("Detected proxy protocol configured host\n"); + /* having this set when we could still fail is ugly */ proxy_session = TRUE; } return proxy_session; @@ -114,6 +123,7 @@ debug_printf("PROXY<<%3.*H\n", (int)(end - start), buf + start); } +/*API*/ /************************************************* * Setup host for proxy protocol * *************************************************/ @@ -123,11 +133,11 @@ so exit with an error if do not find the exact required pieces. This includes an incorrect number of spaces separating args. Arguments: none -Returns: Boolean success +Returns: TRUE iff success */ -void -proxy_protocol_setup(void) +static BOOL +proxy_protocol(void) { union { struct { @@ -201,6 +211,10 @@ const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"; uschar * iptype; /* To display debug info */ BOOL yield = FALSE; +if (!proxy_protocol_host()) + return TRUE; + +os_non_restarting_signal(SIGALRM, command_timeout_handler); ALARM(proxy_protocol_timeout); do @@ -496,6 +510,8 @@ done: should cause a synchronization failure */ proxyfail: + + ALARM(0); DEBUG(D_receive) if (had_command_timeout) debug_printf("Timeout while reading proxy header\n"); @@ -506,15 +522,29 @@ proxyfail: host_build_sender_fullhost(); } else - { - f.proxy_session_failed = TRUE; DEBUG(D_receive) debug_printf("Failure to extract proxied host, only QUIT allowed\n"); - } -ALARM(0); -return; +return yield; } + + +/******************************************************************************/ +/* Module API */ + +static void * proxy_functions[] = { + [PROXY_PROTO_START] = (void *) proxy_protocol, +}; + +misc_module_info proxy_module_info = +{ + .name = US"proxy", +# ifdef DYNLOOKUP + .dyn_magic = MISC_MODULE_MAGIC, +# endif + .functions = proxy_functions, + .functions_count = nelem(proxy_functions), +}; #endif /*SUPPORT_PROXY*/ /* vi: aw ai sw=2 diff --git a/src/src/miscmods/proxy_api.h b/src/src/miscmods/proxy_api.h new file mode 100644 index 000000000..4cd57908c --- /dev/null +++ b/src/src/miscmods/proxy_api.h @@ -0,0 +1,14 @@ +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) The Exim Maintainers 2025 */ +/* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* API definitions for the proxy-protocol module */ + + +/* Function table entry numbers */ + +#define PROXY_PROTO_START 0 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 222fc5b93..3ffb6fe8b 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1308,8 +1308,8 @@ if required. */ for (smtp_cmd_list * p = cmd_list; p < cmd_list + nelem(cmd_list); p++) { #ifdef SUPPORT_PROXY - /* Only allow QUIT command if Proxy Protocol parsing failed */ - if (proxy_session && f.proxy_session_failed && p->cmd != QUIT_CMD) + /* If Proxy Protocol parsing failed, only allow QUIT command */ + if (f.quit_cmd_only && p->cmd != QUIT_CMD) continue; #endif if ( p->len @@ -1363,8 +1363,8 @@ for (smtp_cmd_list * p = cmd_list; p < cmd_list + nelem(cmd_list); p++) } #ifdef SUPPORT_PROXY -/* Only allow QUIT command if Proxy Protocol parsing failed */ -if (proxy_session && f.proxy_session_failed) +/* If Proxy Protocol parsing failed, only allow QUIT command */ +if (f.quit_cmd_only) return PROXY_FAIL_IGNORE_CMD; #endif @@ -2668,11 +2668,20 @@ proxy_session = FALSE; /* If valid Proxy Protocol source is connecting, set up session. Failure will not allow any SMTP function other than QUIT. */ -f.proxy_session_failed = FALSE; -if (proxy_protocol_host()) +f.quit_cmd_only = FALSE; +if (hosts_proxy) { - os_non_restarting_signal(SIGALRM, command_timeout_handler); - proxy_protocol_setup(); + uschar * dummy_errmsg; + misc_module_info * mi; + typedef BOOL (*fn_t) (void); + + if (!(mi = misc_mod_find(US"proxy", &dummy_errmsg))) + { + smtp_closedown(US"Temporary local problem - please try later"); + return FALSE; + } + if (!((fn_t *) mi->functions)[PROXY_PROTO_START] ()) + f.quit_cmd_only = TRUE; } #endif commit 53e771b0ddaa89477793c8955ed474acf42c32b5 Author: Jeremy Harris Date: Thu Dec 18 10:50:33 2025 +0000 Docs: more notes on DBM lookups diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 7c2dbcce3..3ed78901b 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -381,6 +381,16 @@ no guarantee of alignment. Since all the records used by Exim need to be properly aligned to pick out the timestamps, etc., we might as well do the copying centrally here. +Callers: + dbfn_read_with_length (below) + dbfn_read dbfunctions.h + (assorted hintsdb uses) + (assorted hintsdb uses) + dbfn_read_enforce_length (below) + (assorted hintsdb uses) + exim_dbutil.c utils + lookups/dbmdb.c lookup dbm + Arguments: dbblock a pointer to an open database block key the key of the record to be read diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index dd88dd98b..1772a85c7 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -187,6 +187,11 @@ return more; } /* EXIM_DBGET - returns the value associated with the key. */ +/* Callers: + dbfn_read_klen lookup-dbm, hints general + autoreply_transport_entry autoreply tpt + dbfn_read_with_length utils +*/ static inline BOOL exim_dbget(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * res) { @@ -208,6 +213,12 @@ return (SQLITE_DONE == exim_sqlprep_step(dbp, sql, key, data, NULL )) ? EXIM_DBP } /* EXIM_DBPUT - returns nothing useful, assumes replace mode */ +/* Callers: + dbfn_write hints general + autoreply_transport_entry autoreply tpt + main(dbmbuild) utils + dbfn_write utils +*/ static inline int exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data) { @@ -229,6 +240,10 @@ return exim_s_dbp(dbp, key, data, "INSERT OR ABORT INTO tblblob (ky, dat) VALUES } /* EXIM_DBDEL */ +/* Callers + dbfn_delete hints general + dnfn_delete utils +*/ static inline int exim_dbdel(EXIM_DB * dbp, EXIM_DATUM * key) { commit a51a01811d1b0984603662609a6b7f0845b34387 Author: Jeremy Harris Date: Fri Nov 28 12:45:10 2025 +0000 exim_dumpdb for lookup-dbm files diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 42396fe8b..be1cf710e 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -30,25 +30,23 @@ There are a number of common subroutines, followed by three main programs, whose inclusion is controlled by -D on the compilation command. */ +#include #include "exim.h" #include "hintsdb.h" /* Identifiers for the different database types. */ -#define type_retry 1 -#define type_wait 2 -#define type_misc 3 -#define type_callout 4 -#define type_ratelimit 5 -#define type_tls 6 -#define type_seen 7 - +enum dbtype { type_retry = 1, type_wait, type_misc, type_callout, + type_ratelimit, type_tls, type_seen, type_dbm +}; /* This is used by our cut-down dbfn_open(). */ -uschar *spool_directory; +uschar * spool_directory = NULL; +const uschar * lockfile_name = NULL; +BOOL dbmdb = FALSE; BOOL keyonly = FALSE; BOOL utc = FALSE; @@ -110,7 +108,15 @@ sigalrm_seen = 1; static void usage(const uschar * name, const uschar * options) { -printf("Usage: exim_%s%s \n", name, options); +uschar * s = store_get(Ustrlen(options), options), * t = s; + +if (Ustrchr(options, 'L')) + printf("Usage: exim_%s -L \n\n", name); + +/* drop the L from options */ +do { if (*options != 'L') *t++ = *options; } while (*options++); + +printf("Usage: exim_%s%s \n", name, s); printf(" = retry | misc | wait- | callout | ratelimit | tls | seen\n"); exit(EXIT_FAILURE); } @@ -146,6 +152,8 @@ second of them to be sure it is a known database name. */ static int check_args(int argc, uschar **argv, const uschar * name, const uschar * options) { +if (dbmdb && argc - optind == 1) return type_dbm; + if (argc - optind == 2) { const uschar * aname = argv[optind + 1]; @@ -172,9 +180,10 @@ opterr = 0; while ((opt = getopt(argc, (char * const *)argv, CCS opts)) != -1) switch (opt) { + case 'L': dbmdb = TRUE; break; case 'k': keyonly = TRUE; break; case 'z': utc = TRUE; break; - default: usage(name, US" [-z] [-k]"); + default: usage(name, US" [-kLz]"); } } @@ -322,29 +331,40 @@ dbfn_open(const uschar * name, int flags, open_db * dbblock, { int rc; struct flock lock_data; -uschar * dirname, * filename; +uschar * dname, * filename; /* The first thing to do is to open a separate file on which to lock. This ensures that Exim has exclusive use of the database before it even tries to open it. If there is a database, there should be a lock file in existence; -if no lockfile we infer there is no database and error out. We open the +if no lockfile and a create fails, we assume it was the spooldir perms (and +we have no write perms) and there is no database - and error out. We open the lockfile using the r/w mode requested for the DB, users lacking permission for the DB access mode will error out here. */ -if ( asprintf(CSS &dirname, "%s/db", spool_directory) < 0 - || asprintf(CSS &filename, "%s/%s.lockfile", dirname, name) < 0) +if (dbmdb) + { + if (asprintf(CSS &filename, "%s.lockfile", name) < 0) + return NULL; + dname = Ustrchr(name, '/') /* path has dirs */ + ? US dirname(CS string_copy(name)) + : US "."; + } +else if ( asprintf(CSS &dname, "%s/db", spool_directory) < 0 + || asprintf(CSS &filename, "%s/%s.lockfile", dname, name) < 0) return NULL; dbblock->readonly = (flags & O_ACCMODE) == O_RDONLY; dbblock->lockfd = -1; if (exim_lockfile_needed()) { - if ((dbblock->lockfd = Uopen(filename, flags, 0)) < 0) + if ((dbblock->lockfd = Uopen(filename, dbmdb ? flags | O_CREAT : flags, + 0600)) < 0) { printf("** Failed to open database lock file %s: %s\n", filename, strerror(errno)); return NULL; } + lockfile_name = string_copy(filename); /* Now we must get a lock on the opened lock file; do this with a blocking lock that times out. */ @@ -366,6 +386,7 @@ if (exim_lockfile_needed()) filename, errno == ETIMEDOUT ? "timed out" : strerror(errno)); (void)close(dbblock->lockfd); + unlink(CS filename); return NULL; } @@ -373,11 +394,14 @@ if (exim_lockfile_needed()) exclusive access to the database, so we can go ahead and open it. */ } -if (asprintf(CSS &filename, "%s/%s", dirname, name) < 0) return NULL; +if ((dbmdb + ? asprintf(CSS &filename, "%s", name) + : asprintf(CSS &filename, "%s/%s", dname, name) + ) < 0) return NULL; if (!(dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() - ? exim_dbopen_multi(filename, dirname, flags, 0) - : exim_dbopen(filename, dirname, flags, 0))) + ? exim_dbopen_multi(filename, dname, flags, 0) + : exim_dbopen(filename, dname, flags, 0))) { printf("** Failed to open hintsdb file %s for %s: %s%s\n", filename, dbblock->readonly ? "reading" : "writing", strerror(errno), @@ -388,6 +412,7 @@ if (!(dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() #endif ); if (dbblock->lockfd >= 0) (void)close(dbblock->lockfd); + unlink(CCS lockfile_name); return NULL; } @@ -590,26 +615,33 @@ return yield; *************************************************/ int -main(int argc, char **cargv) +main(int argc, char ** cargv) { -int dbdata_type = 0; -int yield = 0; +int dbdata_type = 0, yield = 0; open_db dbblock; -open_db *dbm; -EXIM_CURSOR *cursor; -uschar **argv = USS cargv; +open_db * dbm; +EXIM_CURSOR * cursor; +uschar ** argv = USS cargv; +const uschar * file; uschar keybuffer[1024]; store_init(); -options(argc, argv, US"dumpdb", US"kz"); +options(argc, argv, US"dumpdb", US"kLz"); /* Check the arguments, and open the database */ -dbdata_type = check_args(argc, argv, US"dumpdb", US" [-z] [-k]"); +dbdata_type = check_args(argc, argv, US"dumpdb", US" [-kLz]"); argc -= optind; argv += optind; -spool_directory = argv[0]; -if (!(dbm = dbfn_open(argv[1], O_RDONLY, &dbblock, FALSE, TRUE))) +if (dbmdb) + file = argv[0]; +else + { + spool_directory = argv[0]; + file = argv[1]; + } + +if (!(dbm = dbfn_open(file, O_RDONLY, &dbblock, FALSE, TRUE))) exit(EXIT_FAILURE); /* Scan the file, formatting the information for each entry. Note @@ -772,11 +804,15 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); seen = (dbdata_seen *)value; printf("%s\t%s\n", keybuffer, print_time(seen->time_stamp)); break; + + case type_dbm: + printf("%s\t%s\n", keybuffer, value); } store_reset(reset_point); } dbfn_close(dbm); +unlink(CCS lockfile_name); return yield; } commit e76fd60f5560db45225a4e2a35c5c4a27217464b Author: Jeremy Harris Date: Sat Nov 29 12:56:09 2025 +0000 exim_fixdb for lookup-dbm files diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index ff733b490..9524dcef9 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -586,7 +586,7 @@ exim: buildlookups buildauths buildrouters buildtransports buildmisc \ # The utility for dumping the contents of an exim database -OBJ_DUMPDB = exim_dumpdb.o util-os.o util-store.o util-xtextencode.o +OBJ_DUMPDB = exim_dumpdb.o util-os.o util-store.o util-string.o exim_dumpdb: $(OBJ_DUMPDB) @echo "$(LNCC) -o exim_dumpdb" @@ -601,7 +601,7 @@ exim_dumpdb: $(OBJ_DUMPDB) # The utility for interrogating/fixing the contents of an exim database -OBJ_FIXDB = exim_fixdb.o util-os.o util-store.o util-md5.o util-xtextencode.o +OBJ_FIXDB = exim_fixdb.o util-os.o util-store.o util-md5.o exim_fixdb: $(OBJ_FIXDB) @echo "$(LNCC) -o exim_fixdb" @@ -616,7 +616,7 @@ exim_fixdb: $(OBJ_FIXDB) # The utility for tidying the contents of an exim database -OBJ_TIDYDB = exim_tidydb.o util-os.o util-store.o util-xtextencode.o +OBJ_TIDYDB = exim_tidydb.o util-os.o util-store.o exim_tidydb: $(OBJ_TIDYDB) @echo "$(LNCC) -o exim_tidydb" @@ -632,7 +632,7 @@ exim_tidydb: $(OBJ_TIDYDB) # The utility for building dbm files -OBJ_DBMBUILD = exim_dbmbuild.o util-xtextencode.o +OBJ_DBMBUILD = exim_dbmbuild.o exim_dbmbuild: $(OBJ_DBMBUILD) @echo "$(LNCC) -o exim_dbmbuild" @@ -682,7 +682,6 @@ OBJ_MONBIN = util-host_address.o \ util-string.o \ util-tod.o \ util-tree.o \ - util-xtextencode.o \ $(MONBIN) eximon.bin: $(EXIMON_EDITME) eximon $(OBJ_MONBIN) ../exim_monitor/em_version.c \ @@ -843,10 +842,6 @@ util-tree.o: $(HDRS) tree.c @echo "$(CC) -DCOMPILE_UTILITY tree.c" $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-tree.o tree.c -util-xtextencode.o: $(HDRS) xtextencode.c - @echo "$(CC) -DCOMPILE_UTILITY xtextencode.c" - $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-xtextencode.o xtextencode.c - util-os.o: $(HDRS) os.c @echo "$(CC) -DCOMPILE_UTILITY os.c" $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) \ diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index be1cf710e..26dca7dbd 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -52,7 +52,7 @@ BOOL utc = FALSE; /******************************************************************************/ - /* dummies needed by Solaris build */ + /* dummies needed by Solaris build */ void millisleep(int msec) {} @@ -61,20 +61,6 @@ readconf_printtime(int t) { return NULL; } const uschar * expand_string_2(const uschar * string, BOOL * textonly_p) { return NULL; } -gstring * -string_catn(gstring * g, const uschar * s, int count) -{ return NULL; } -gstring * -string_vformat_trc(gstring * g, const uschar * func, unsigned line, - unsigned size_limit, unsigned flags, const char *format, va_list ap) -{ return NULL; } -uschar * -string_sprintf_trc(const char * fmt, const uschar * func, unsigned line, ...) -{ return NULL; } -BOOL -string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, - const char * fmt, ...) -{ return FALSE; } const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } @@ -442,7 +428,9 @@ else exim_dbclose(dbp->dbptr); if (dbp->lockfd >= 0) - (void) close(dbp->lockfd); + { (void) close(dbp->lockfd); dbp->lockfd = -1; } +unlink(CCS lockfile_name); +lockfile_name = NULL; } @@ -516,15 +504,13 @@ Returns: the yield of the underlying dbm or db "write" function. If this */ int -dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length) +dbfn_write(open_db * dbblock, const uschar * key, void * ptr, int length) { EXIM_DATUM key_datum, value_datum; -dbdata_generic *gptr = (dbdata_generic *)ptr; int klen = Ustrlen(key) + 1; uschar * key_copy = store_get(klen, key); memcpy(key_copy, key, klen); -gptr->time_stamp = time(NULL); exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ exim_datum_init(&value_datum); /* to be cleared before use. */ @@ -738,9 +724,18 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); break; case type_misc: - printf("%s %s\n", print_time(((dbdata_generic *)value)->time_stamp), - keybuffer); + /* It might be nice to recognize the subtypes of "misc" DBs (by the + key prefix?) for better decode. For now, dump the raw data. */ + + { + dbdata_generic * recp = (dbdata_generic *)value; + uschar * dp = US (recp + 1); + int dlen = length = sizeof(dbdata_generic); + + printf("%s %s\n", print_time(recp->time_stamp), keybuffer); + printf("%s\n", string_sprintf("%.*q\n", dlen, dp)); break; + } case type_callout: callout = (dbdata_callout_cache *)value; @@ -806,13 +801,12 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); break; case type_dbm: - printf("%s\t%s\n", keybuffer, value); + printf("%s\t%.*s\n", keybuffer, length, value); } store_reset(reset_point); } dbfn_close(dbm); -unlink(CCS lockfile_name); return yield; } @@ -860,22 +854,30 @@ int dbdata_type; uschar **argv = USS cargv; uschar buffer[256]; uschar name[256]; +const uschar * file; rmark reset_point; -uschar * aname; store_init(); -options(argc, argv, US"fixdb", US"z"); -name[0] = 0; /* No name set */ +options(argc, argv, US"fixdb", US"Lz"); +*name = '\0'; /* No name set */ /* Sort out the database type, verify what we are working on and then process user requests */ -dbdata_type = check_args(argc, argv, US"fixdb", US" [-z]"); +dbdata_type = check_args(argc, argv, US"fixdb", US" [-Lz]"); argc -= optind; argv += optind; -spool_directory = argv[0]; -aname = argv[1]; -printf("Modifying Exim hints database %s/db/%s\n", spool_directory, aname); +if (dbmdb) + { + file = argv[0]; + printf("Modifying Exim dbm database %s\n", file); + } +else + { + spool_directory = argv[0]; + file = argv[1]; + printf("Modifying Exim hints database %s/db/%s\n", spool_directory, file); + } for(; (reset_point = store_mark()); store_reset(reset_point)) { @@ -888,9 +890,8 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) dbdata_ratelimit *ratelimit; dbdata_ratelimit_unique *rate_unique; dbdata_tls_session *session; - int oldlength; - uschar *t; - uschar field[256], value[256]; + int oldlength, newlength; + uschar * t, field[256], value[256]; printf("> "); if (Ufgets(buffer, 256, stdin) == NULL) break; @@ -904,7 +905,7 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) if ((isdigit((uschar)buffer[0]) && (buffer[1] == ' ' || buffer[1] == '\0')) || Ustrcmp(buffer, "d") == 0) { - if (name[0] == 0) + if (!*name) { printf("No previous record name is set\n"); continue; @@ -913,167 +914,175 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) } else { - name[0] = 0; + *name = '\0'; (void)sscanf(CS buffer, "%s %s %s", name, field, value); } /* Handle an update request */ - if (field[0] != 0) + if (*field) { int verify = 1; - if (!(dbm = dbfn_open(aname, O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) + if (!(dbm = dbfn_open(file, O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) continue; if (Ustrcmp(field, "d") == 0) { - if (value[0] != 0) printf("unexpected value after \"d\"\n"); - else printf("%s\n", (dbfn_delete(dbm, name) < 0)? - "not found" : "deleted"); + if (*value) + printf("unexpected value after \"d\"\n"); + else + printf("%s\n", dbfn_delete(dbm, name) < 0 ? "not found" : "deleted"); dbfn_close(dbm); continue; } - else if (isdigit((uschar)field[0])) + else if (dbdata_type == type_dbm || isdigit((uschar)field[0])) { - int fieldno = Uatoi(field); - if (value[0] == 0) + if (!*value) { printf("value missing\n"); dbfn_close(dbm); continue; } + else if (!(record = dbfn_read_with_length(dbm, name, &oldlength))) + printf("not found\n"); else - { - record = dbfn_read_with_length(dbm, name, &oldlength); - if (record == NULL) printf("not found\n"); else - { - time_t tt; - /*int length = 0; Stops compiler warning */ + { + int fieldno = Uatoi(field); + time_t tt; + /*int length = 0; Stops compiler warning */ - switch(dbdata_type) - { - case type_retry: - retry = (dbdata_retry *)record; - /* length = sizeof(dbdata_retry) + Ustrlen(retry->text); */ + newlength = oldlength; + switch(dbdata_type) + { + case type_retry: + retry = (dbdata_retry *)record; + /* length = sizeof(dbdata_retry) + Ustrlen(retry->text); */ + + switch(fieldno) + { + case 0: retry->basic_errno = Uatoi(value); + break; + case 1: retry->more_errno = Uatoi(value); + break; + case 2: if ((tt = read_time(value)) > 0) retry->first_failed = tt; + else printf("bad time value\n"); + break; + case 3: if ((tt = read_time(value)) > 0) retry->last_try = tt; + else printf("bad time value\n"); + break; + case 4: if ((tt = read_time(value)) > 0) retry->next_try = tt; + else printf("bad time value\n"); + break; + case 5: if (Ustrcmp(value, "yes") == 0) retry->expired = TRUE; + else if (Ustrcmp(value, "no") == 0) retry->expired = FALSE; + else printf("\"yes\" or \"no\" expected=n"); + break; + default: printf("unknown field number\n"); + verify = 0; + break; + } + break; - switch(fieldno) - { - case 0: retry->basic_errno = Uatoi(value); - break; - case 1: retry->more_errno = Uatoi(value); - break; - case 2: if ((tt = read_time(value)) > 0) retry->first_failed = tt; - else printf("bad time value\n"); - break; - case 3: if ((tt = read_time(value)) > 0) retry->last_try = tt; - else printf("bad time value\n"); - break; - case 4: if ((tt = read_time(value)) > 0) retry->next_try = tt; - else printf("bad time value\n"); - break; - case 5: if (Ustrcmp(value, "yes") == 0) retry->expired = TRUE; - else if (Ustrcmp(value, "no") == 0) retry->expired = FALSE; - else printf("\"yes\" or \"no\" expected=n"); - break; - default: printf("unknown field number\n"); - verify = 0; - break; - } - break; + case type_wait: + printf("Can't change contents of wait database record\n"); + break; - case type_wait: - printf("Can't change contents of wait database record\n"); - break; + case type_misc: + printf("Can't change contents of misc database record\n"); + break; - case type_misc: - printf("Can't change contents of misc database record\n"); + case type_callout: + callout = (dbdata_callout_cache *)record; + /* length = sizeof(dbdata_callout_cache); */ + switch(fieldno) + { + case 0: callout->result = Uatoi(value); + break; + case 1: callout->postmaster_result = Uatoi(value); + break; + case 2: callout->random_result = Uatoi(value); + break; + default: printf("unknown field number\n"); + verify = 0; + break; + } break; - case type_callout: - callout = (dbdata_callout_cache *)record; - /* length = sizeof(dbdata_callout_cache); */ - switch(fieldno) - { - case 0: callout->result = Uatoi(value); - break; - case 1: callout->postmaster_result = Uatoi(value); - break; - case 2: callout->random_result = Uatoi(value); + case type_ratelimit: + ratelimit = (dbdata_ratelimit *)record; + switch(fieldno) + { + case 0: if ((tt = read_time(value)) > 0) ratelimit->time_stamp = tt; + else printf("bad time value\n"); + break; + case 1: ratelimit->time_usec = Uatoi(value); + break; + case 2: ratelimit->rate = Ustrtod(value, NULL); + break; + case 3: if (Ustrstr(name, "/unique/") != NULL + && oldlength >= sizeof(dbdata_ratelimit_unique)) + { + rate_unique = (dbdata_ratelimit_unique *)record; + if ((tt = read_time(value)) > 0) rate_unique->bloom_epoch = tt; + else printf("bad time value\n"); break; - default: printf("unknown field number\n"); - verify = 0; - break; - } - break; - - case type_ratelimit: - ratelimit = (dbdata_ratelimit *)record; - switch(fieldno) - { - case 0: if ((tt = read_time(value)) > 0) ratelimit->time_stamp = tt; - else printf("bad time value\n"); - break; - case 1: ratelimit->time_usec = Uatoi(value); - break; - case 2: ratelimit->rate = Ustrtod(value, NULL); - break; - case 3: if (Ustrstr(name, "/unique/") != NULL - && oldlength >= sizeof(dbdata_ratelimit_unique)) + } + /* else fall through */ + case 4: + case 5: if (Ustrstr(name, "/unique/") != NULL + && oldlength >= sizeof(dbdata_ratelimit_unique)) + { + /* see acl.c */ + BOOL seen; + unsigned hash, hinc; + uschar md5sum[16]; + md5 md5info; + md5_start(&md5info); + md5_end(&md5info, value, Ustrlen(value), md5sum); + hash = md5sum[0] << 0 | md5sum[1] << 8 + | md5sum[2] << 16 | md5sum[3] << 24; + hinc = md5sum[4] << 0 | md5sum[5] << 8 + | md5sum[6] << 16 | md5sum[7] << 24; + rate_unique = (dbdata_ratelimit_unique *)record; + seen = TRUE; + for (unsigned n = 0; n < 8; n++, hash += hinc) { - rate_unique = (dbdata_ratelimit_unique *)record; - if ((tt = read_time(value)) > 0) rate_unique->bloom_epoch = tt; - else printf("bad time value\n"); - break; - } - /* else fall through */ - case 4: - case 5: if (Ustrstr(name, "/unique/") != NULL - && oldlength >= sizeof(dbdata_ratelimit_unique)) - { - /* see acl.c */ - BOOL seen; - unsigned hash, hinc; - uschar md5sum[16]; - md5 md5info; - md5_start(&md5info); - md5_end(&md5info, value, Ustrlen(value), md5sum); - hash = md5sum[0] << 0 | md5sum[1] << 8 - | md5sum[2] << 16 | md5sum[3] << 24; - hinc = md5sum[4] << 0 | md5sum[5] << 8 - | md5sum[6] << 16 | md5sum[7] << 24; - rate_unique = (dbdata_ratelimit_unique *)record; - seen = TRUE; - for (unsigned n = 0; n < 8; n++, hash += hinc) + int bit = 1 << (hash % 8); + int byte = (hash / 8) % rate_unique->bloom_size; + if ((rate_unique->bloom[byte] & bit) == 0) { - int bit = 1 << (hash % 8); - int byte = (hash / 8) % rate_unique->bloom_size; - if ((rate_unique->bloom[byte] & bit) == 0) - { - seen = FALSE; - if (fieldno == 5) rate_unique->bloom[byte] |= bit; - } + seen = FALSE; + if (fieldno == 5) rate_unique->bloom[byte] |= bit; } - printf("%s %s\n", - seen ? "seen" : fieldno == 5 ? "added" : "unseen", value); - break; } - /* else fall through */ - default: printf("unknown field number\n"); - verify = 0; - break; - } - break; + printf("%s %s\n", + seen ? "seen" : fieldno == 5 ? "added" : "unseen", value); + break; + } + /* else fall through */ + default: printf("unknown field number\n"); + verify = 0; + break; + } + break; - case type_tls: - printf("Can't change contents of tls database record\n"); - break; - } + case type_tls: + printf("Can't change contents of tls database record\n"); + break; - dbfn_write(dbm, name, record, oldlength); - } - } + case type_dbm: + record = value; + newlength = Ustrlen(value); + break; + } + + if (dbdata_type != type_dbm) + ((dbdata_generic *)record)->time_stamp = time(NULL); + + dbfn_write(dbm, name, record, newlength); + } } else @@ -1092,18 +1101,21 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) /* Handle a read request, or verify after an update. */ - if (!(dbm = dbfn_open(aname, O_RDONLY, &dbblock, FALSE, TRUE))) + if (!(dbm = dbfn_open(file, O_RDONLY, &dbblock, FALSE, TRUE))) continue; if (!(record = dbfn_read_with_length(dbm, name, &oldlength))) { printf("record %s not found\n", name); - name[0] = 0; + *name = '\0'; } else { int count_bad = 0; - printf("%s\n", CS print_time(((dbdata_generic *)record)->time_stamp)); + + if (dbdata_type != type_dbm) + printf("%s\n", CS print_time(((dbdata_generic *)record)->time_stamp)); + switch(dbdata_type) { case type_retry: @@ -1113,7 +1125,7 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) printf("2 first failed: %s\n", print_time(retry->first_failed)); printf("3 last try: %s\n", print_time(retry->last_try)); printf("4 next try: %s\n", print_time(retry->next_try)); - printf("5 expired: %s\n", (retry->expired)? "yes" : "no"); + printf("5 expired: %s\n", retry->expired ? "yes" : "no"); break; case type_wait: @@ -1185,6 +1197,9 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) printf("0 time stamp: %s\n", print_time(session->time_stamp)); printf("1 session: .%s\n", session->session); break; + + case type_dbm: + printf("0 value: %.*s\n", oldlength, record); } } @@ -1451,6 +1466,7 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) if (update) { printf("updated %s\n", key); + wait->time_stamp = time(NULL); dbfn_write(dbm, key, wait, sizeof(dbdata_wait) + wait->count * MESSAGE_ID_LENGTH); } diff --git a/src/src/functions.h b/src/src/functions.h index b48103922..bfe34f391 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -594,6 +594,7 @@ extern int string_is_ip_addressX(const uschar *, int *, const uschar **); extern BOOL string_is_utf8(const uschar *); #endif extern const uschar *string_printing2(const uschar *, int); +extern const uschar *string_printing3(const uschar *, int, int); extern uschar *string_split_message(uschar *); extern uschar *string_unprinting(uschar *); #ifdef SUPPORT_I18N diff --git a/src/src/hintsdb_structs.h b/src/src/hintsdb_structs.h index 3eb8b3386..c77190f38 100644 --- a/src/src/hintsdb_structs.h +++ b/src/src/hintsdb_structs.h @@ -25,8 +25,10 @@ typedef struct { } open_db; -/* Structures for records stored in exim database dbm files. They all -start with the same fields, described in the generic type. */ +/* Structures for records stored in exim database hinsts files. They all +start with the same fields, described in the generic type. +DBM databases are used for hints files. +*/ typedef struct { commit 73d3b73c090557b9f11cef78623cf11b81e9c7a9 Author: Jeremy Harris Date: Sat Nov 29 21:02:12 2025 +0000 track tainted values through hintsdb storage diff --git a/src/src/acl.c b/src/src/acl.c index bc4f6af6d..7ec3a898c 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -2826,7 +2826,7 @@ if (!dbd) { HDEBUG(D_acl) debug_printf_indent("ratelimit initializing new key's rate data\n"); dbd = &dbdb->dbd; - dbd->time_stamp = tv.tv_sec; + dbd->gen.time_stamp = tv.tv_sec; dbd->time_usec = tv.tv_usec; dbd->rate = count; } @@ -2876,7 +2876,7 @@ else double this_time = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; - double prev_time = (double)dbd->time_stamp + double prev_time = (double)dbd->gen.time_stamp + (double)dbd->time_usec / 1000000.0; /* We must avoid division by zero, and deal gracefully with the clock going @@ -2893,7 +2893,7 @@ else using the smoothing factor a. In order to measure sized events, multiply the instantaneous rate by the count of bytes or recipients etc. */ - dbd->time_stamp = tv.tv_sec; + dbd->gen.time_stamp = tv.tv_sec; dbd->time_usec = tv.tv_usec; dbd->rate = (1 - a) * count / i_over_p + a * dbd->rate; @@ -3048,7 +3048,7 @@ dbd = dbfn_read_with_length(dbm, key, NULL); now = time(NULL); if (dbd) /* an existing record */ { - time_t diff = now - dbd->time_stamp; /* time since the record was written */ + time_t diff = now - dbd->gen.time_stamp; /* time since record was written */ if (before ? diff >= interval : diff < interval) yield = OK; @@ -3057,13 +3057,13 @@ if (dbd) /* an existing record */ { HDEBUG(D_acl) debug_printf_indent("seen db not written (readonly)\n"); } else if (mode == SEEN_WRITE || !before) { - dbd->time_stamp = now; + dbd->gen.time_stamp = now; dbfn_write(dbm, key, dbd, sizeof(*dbd)); HDEBUG(D_acl) debug_printf_indent("seen db written (update)\n"); } else if (diff >= refresh) { - dbd->time_stamp = now - interval; + dbd->gen.time_stamp = now - interval; dbfn_write(dbm, key, dbd, sizeof(*dbd)); HDEBUG(D_acl) debug_printf_indent("seen db written (refresh)\n"); } @@ -3072,7 +3072,7 @@ else { /* No record found, yield always FAIL */ if (mode != SEEN_READONLY) { - dbdata_seen d = {.time_stamp = now}; + dbdata_seen d = {.gen = {.time_stamp = now}}; dbfn_write(dbm, key, &d, sizeof(*dbd)); HDEBUG(D_acl) debug_printf_indent("seen db written (create)\n"); } diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 3ed78901b..0a05524e1 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -410,6 +410,7 @@ void * yield; EXIM_DATUM key_datum, result_datum; uschar * key_copy = store_get(klen, key); unsigned dlen; +BOOL tainted; memcpy(key_copy, key, klen); @@ -426,13 +427,17 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; } -/* Assume the data store could have been tainted. Properly, we should -store the taint status with the data. */ - dlen = exim_datum_size_get(&result_datum); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); -yield = store_get(dlen+1, hintsdb ? GET_TAINTED : GET_UNTAINTED); +/* Hintsdb uses store the taint of the payload of the value in the value. +For non-hints uses we have no provenance, so assume untainted */ + +tainted = hintsdb + ? ((dbdata_generic *) exim_datum_data_get(&result_datum))->tainted + : FALSE; + +yield = store_get(dlen+1, tainted ? GET_TAINTED : GET_UNTAINTED); memcpy(yield, exim_datum_data_get(&result_datum), dlen); ((uschar *)yield)[dlen] = '\0'; if (length) *length = dlen; @@ -498,6 +503,8 @@ return NULL; *************************************************/ /* +All callers are writing a hintsdb record. + Arguments: dbblock a pointer to an open database block key the key of the record to be written @@ -509,7 +516,7 @@ Returns: the yield of the underlying dbm or db "write" function. If this */ int -dbfn_write(open_db *dbblock, const uschar *key, void *ptr, int length) +dbfn_write(open_db * dbblock, const uschar * key, void * ptr, int length) { EXIM_DATUM key_datum, value_datum; dbdata_generic *gptr = (dbdata_generic *)ptr; @@ -518,6 +525,7 @@ uschar * key_copy = store_get(klen, key); memcpy(key_copy, key, klen); gptr->time_stamp = time(NULL); +gptr->tainted = is_tainted(ptr); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_write: key=%s datalen %d\n", key, length); diff --git a/src/src/deliver.c b/src/src/deliver.c index c978e67b5..cf3a41156 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2932,7 +2932,7 @@ while (addr_local) DEBUG(D_retry) { debug_printf("retry record exists: age=%s ", - readconf_printtime(now - retry_record->time_stamp)); + readconf_printtime(now - retry_record->gen.time_stamp)); debug_printf("(max %s)\n", readconf_printtime(retry_data_expire)); debug_printf(" time to retry = %s expired = %d\n", readconf_printtime(retry_record->next_try - now), @@ -2941,7 +2941,7 @@ while (addr_local) if (f.queue_running && !f.deliver_force) { - ok = (now - retry_record->time_stamp > retry_data_expire) + ok = (now - retry_record->gen.time_stamp > retry_data_expire) || (now >= retry_record->next_try) || retry_record->expired; @@ -7827,7 +7827,7 @@ while (addr_new) /* Loop until all addresses dealt with */ { domain_retry_record = dbfn_read(dbm_file, addr->domain_retry_key); if ( domain_retry_record - && now - domain_retry_record->time_stamp > retry_data_expire + && now - domain_retry_record->gen.time_stamp > retry_data_expire ) { DEBUG(D_deliver|D_retry) @@ -7837,7 +7837,7 @@ while (addr_new) /* Loop until all addresses dealt with */ address_retry_record = dbfn_read(dbm_file, addr->address_retry_key); if ( address_retry_record - && now - address_retry_record->time_stamp > retry_data_expire + && now - address_retry_record->gen.time_stamp > retry_data_expire ) { DEBUG(D_deliver|D_retry) @@ -7851,7 +7851,7 @@ while (addr_new) /* Loop until all addresses dealt with */ addr->address_retry_key, sender_address); address_retry_record = dbfn_read(dbm_file, altkey); if ( address_retry_record - && now - address_retry_record->time_stamp > retry_data_expire) + && now - address_retry_record->gen.time_stamp > retry_data_expire) { DEBUG(D_deliver|D_retry) debug_printf_indent("address retry record present but expired\n"); diff --git a/src/src/enq.c b/src/src/enq.c index 8129b3b2b..372607daf 100644 --- a/src/src/enq.c +++ b/src/src/enq.c @@ -53,7 +53,7 @@ if (!(dbm_file = dbfn_open(US"misc", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) proceed with the connection unless the record is very old. */ serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize)); -if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60) +if (serial_record && time(NULL) - serial_record->gen.time_stamp < 6*60*60) { if (serial_record->count >= lim) { diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 26dca7dbd..2c03be1c5 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -380,10 +380,7 @@ if (exim_lockfile_needed()) exclusive access to the database, so we can go ahead and open it. */ } -if ((dbmdb - ? asprintf(CSS &filename, "%s", name) - : asprintf(CSS &filename, "%s/%s", dname, name) - ) < 0) return NULL; +if (asprintf(CSS &filename, "%s", name) < 0) return NULL; if (!(dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() ? exim_dbopen_multi(filename, dname, flags, 0) @@ -461,6 +458,7 @@ EXIM_DATUM key_datum, result_datum; int klen = Ustrlen(key) + 1; uschar * key_copy = store_get(klen, key); unsigned dlen; +BOOL tainted; memcpy(key_copy, key, klen); @@ -475,7 +473,15 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; we should store the taint status along with the data. */ dlen = exim_datum_size_get(&result_datum); -yield = store_get(dlen, GET_TAINTED); + +/* Hintsdb uses store the taint of the payload of the value in the value. +For non-hints uses we have no provenance, so assume untainted */ + +tainted = dbmdb + ? FALSE + : ((dbdata_generic *) exim_datum_data_get(&result_datum))->tainted; + +yield = store_get(dlen, tainted ? GET_TAINTED : GET_UNTAINTED); memcpy(yield, exim_datum_data_get(&result_datum), dlen); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); if (length) *length = dlen; @@ -733,7 +739,33 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); int dlen = length = sizeof(dbdata_generic); printf("%s %s\n", print_time(recp->time_stamp), keybuffer); - printf("%s\n", string_sprintf("%.*q\n", dlen, dp)); + if ( Ustrncmp(keybuffer, "etrn-", 5) == 0 + || Ustrncmp(keybuffer, "tpt-serialize-", 14) == 0 + || Ustrncmp(keybuffer, "host-serialize-", 15) == 0 + ) + printf("serialize %.*s: %d running\n", + (int)(Ustrchr(keybuffer, '-') - keybuffer), keybuffer, + ((dbdata_serialize *)recp)->count); + else + { + uschar * s = keybuffer + Ustrlen(keybuffer) - 5; + if (s > keybuffer && Ustrcmp(s, ".EHLO") == 0) + { + ehlo_resp_precis * erp = &((dbdata_ehlo_resp *)recp)->data; + + printf("helo/ehlo %.*s clr %04x/%04x cry %04x/%04x", + (int)(s - keybuffer), keybuffer, + erp->cleartext_features, erp->cleartext_auths, + erp->crypted_features, erp->crypted_auths); + + if (sizeof(*erp) > 4 * sizeof(unsigned short)) + printf(" lim %05d/%05d/%05d", + erp->limit_mail, erp->limit_rcpt, erp->limit_rcptdom); + putchar('\n'); + } + else + printf("%s\n", string_sprintf("%.*q\n", dlen, dp)); + } break; } @@ -745,7 +777,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); if (length == sizeof(dbdata_callout_cache_address)) { printf("%s %s callout=%s\n", - print_time(((dbdata_generic *)value)->time_stamp), + print_time(callout->gen.time_stamp), keybuffer, print_cache(callout->result)); } @@ -755,7 +787,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); else if (length == sizeof(dbdata_callout_cache)) { printf("%s %s callout=%s postmaster=%s", - print_time(((dbdata_generic *)value)->time_stamp), + print_time(callout->gen.time_stamp), keybuffer, print_cache(callout->result), print_cache(callout->postmaster_result)); @@ -775,7 +807,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); ratelimit = (dbdata_ratelimit *)value; rate_unique = (dbdata_ratelimit_unique *)value; printf("%s.%06d rate: %10.3f epoch: %s size: %u key: %s\n", - print_time(ratelimit->time_stamp), + print_time(ratelimit->gen.time_stamp), ratelimit->time_usec, ratelimit->rate, print_time(rate_unique->bloom_epoch), rate_unique->bloom_size, keybuffer); @@ -784,7 +816,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); { ratelimit = (dbdata_ratelimit *)value; printf("%s.%06d rate: %10.3f key: %s\n", - print_time(ratelimit->time_stamp), + print_time(ratelimit->gen.time_stamp), ratelimit->time_usec, ratelimit->rate, keybuffer); } @@ -797,7 +829,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); case type_seen: seen = (dbdata_seen *)value; - printf("%s\t%s\n", keybuffer, print_time(seen->time_stamp)); + printf("%s\t%s\n", keybuffer, print_time(seen->gen.time_stamp)); break; case type_dbm: @@ -1014,8 +1046,10 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) ratelimit = (dbdata_ratelimit *)record; switch(fieldno) { - case 0: if ((tt = read_time(value)) > 0) ratelimit->time_stamp = tt; - else printf("bad time value\n"); + case 0: if ((tt = read_time(value)) > 0) + ratelimit->gen.time_stamp = tt; + else + printf("bad time value\n"); break; case 1: ratelimit->time_usec = Uatoi(value); break; @@ -1079,7 +1113,11 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) } if (dbdata_type != type_dbm) - ((dbdata_generic *)record)->time_stamp = time(NULL); + { + dbdata_generic * p = (dbdata_generic *)record; + p->time_stamp = time(NULL); + p->tainted = FALSE; + } dbfn_write(dbm, name, record, newlength); } @@ -1179,7 +1217,7 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) case type_ratelimit: ratelimit = (dbdata_ratelimit *)record; - printf("0 time stamp: %s\n", print_time(ratelimit->time_stamp)); + printf("0 time stamp: %s\n", print_time(ratelimit->gen.time_stamp)); printf("1 fract. time: .%06d\n", ratelimit->time_usec); printf("2 sender rate: % .3f\n", ratelimit->rate); if (Ustrstr(name, "/unique/") != NULL @@ -1193,8 +1231,8 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) break; case type_tls: - session = (dbdata_tls_session *)value; - printf("0 time stamp: %s\n", print_time(session->time_stamp)); + session = (dbdata_tls_session *)record; + printf("0 time stamp: %s\n", print_time(session->gen.time_stamp)); printf("1 session: .%s\n", session->session); break; @@ -1360,10 +1398,10 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) /* Leave corrupt records alone */ - if (wait->time_stamp > time(NULL)) + if (wait->gen.time_stamp > time(NULL)) { printf("**** Data for '%s' corrupted\n time in future: %s\n", - key, print_time(((dbdata_generic *)value)->time_stamp)); + key, print_time(wait->gen.time_stamp)); continue; } if (wait->count > WAIT_NAME_MAX) @@ -1381,7 +1419,7 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) /* Record over 1 year old; just remove it */ - if (wait->time_stamp < time(NULL) - 365*24*60*60) + if (wait->gen.time_stamp < time(NULL) - 365*24*60*60) { dbfn_delete(dbm, key); printf("deleted %s (too old)\n", key); @@ -1466,7 +1504,8 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) if (update) { printf("updated %s\n", key); - wait->time_stamp = time(NULL); + wait->gen.time_stamp = time(NULL); + /* leave the taint marker unchanged */ dbfn_write(dbm, key, wait, sizeof(dbdata_wait) + wait->count * MESSAGE_ID_LENGTH); } diff --git a/src/src/hintsdb_structs.h b/src/src/hintsdb_structs.h index c77190f38..f4d72fdc9 100644 --- a/src/src/hintsdb_structs.h +++ b/src/src/hintsdb_structs.h @@ -32,7 +32,8 @@ DBM databases are used for hints files. typedef struct { - time_t time_stamp; /* Timestamp of writing */ + time_t time_stamp; /* Timestamp of writing */ + BOOL tainted; /* metadata for the "value" part of the record */ } dbdata_generic; @@ -40,7 +41,7 @@ typedef struct { address. */ typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ time_t first_failed; /* Time of first failure */ time_t last_try; /* Time of last try */ @@ -72,7 +73,7 @@ handle the old type of record, we retain the old definition. The different kinds of record can be distinguished by their different lengths. */ typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ int result; int postmaster_result; /* Postmaster is accepted */ @@ -80,7 +81,7 @@ typedef struct { } dbdata_callout_cache_obs; typedef struct { - time_t time_stamp; /* Timestamp of last address check */ + dbdata_generic gen; /* Timestamp of last address check */ /*************/ int result; /* accept or reject */ } dbdata_callout_cache_address; @@ -90,7 +91,7 @@ last so that if somebody reverts to an older Exim, the new records will still make sense because they match the old layout. */ typedef struct { - time_t time_stamp; /* Time stamp of last connection */ + dbdata_generic gen; /* Time stamp of last connection */ /*************/ int result; /* Domain reject or accept */ int postmaster_result; /* Postmaster result */ @@ -103,7 +104,7 @@ typedef struct { host for a particular transport. */ typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ int count; /* Count of message ids */ int sequence; /* Sequence for continued records */ @@ -123,7 +124,7 @@ at present in use. The same structure is used for recording a running ETRN process. */ typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ int count; /* Reserved for possible connection count */ } dbdata_serialize; @@ -133,7 +134,7 @@ typedef struct { ACL condition. */ typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ int time_usec; /* Fractional part of time, from gettimeofday() */ double rate; /* Smoothed sending rate at that time */ @@ -151,7 +152,7 @@ typedef struct { /* For "seen" ACL condition */ typedef struct { - time_t time_stamp; + dbdata_generic gen; } dbdata_seen; #ifndef DISABLE_PIPE_CONNECT @@ -174,14 +175,14 @@ typedef struct { } ehlo_resp_precis; typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ ehlo_resp_precis data; } dbdata_ehlo_resp; #endif typedef struct { - time_t time_stamp; + dbdata_generic gen; /*************/ uschar verify_override:1; uschar ocsp:3; diff --git a/src/src/retry.c b/src/src/retry.c index 24b2fa66a..515c94288 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -227,7 +227,7 @@ if (!host_retry_record) { DEBUG(D_transport|D_retry) debug_printf_indent("no host retry record\n"); } -else if (now - host_retry_record->time_stamp > retry_data_expire) +else if (now - host_retry_record->gen.time_stamp > retry_data_expire) { host_retry_record = NULL; DEBUG(D_transport|D_retry) debug_printf_indent("host retry record too old\n"); @@ -237,7 +237,7 @@ if (!message_retry_record) { DEBUG(D_transport|D_retry) debug_printf_indent("no message retry record\n"); } -else if (now - message_retry_record->time_stamp > retry_data_expire) +else if (now - message_retry_record->gen.time_stamp > retry_data_expire) { message_retry_record = NULL; DEBUG(D_transport|D_retry) @@ -744,7 +744,7 @@ for (int i = 0; i < 3; i++) retry_record = dbfn_read_with_length(dbm_file, rti->key, &message_space); if ( retry_record - && now - retry_record->time_stamp > retry_data_expire) + && now - retry_record->gen.time_stamp > retry_data_expire) retry_record = NULL; if (!retry_record) diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 3ffb6fe8b..abc893ddc 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -5748,7 +5748,8 @@ while (done <= 0) /* Compute the serialization key for this command. We used (all the way back to 4.00) to include the given string as part of the key, but this opens a security hole for hintsdb types that use a command-string for - operations. All ETRN with the same command hash are serialized */ + operations. So, use a hash of the string. All ETRN with the same command + hash are serialized */ md5 hash; uschar *digest = store_get(16, GET_TAINTED); @@ -5756,11 +5757,7 @@ while (done <= 0) md5_start(&hash); md5_end(&hash, smtp_cmd_argument, Ustrlen(smtp_cmd_argument), digest); - etrn_serialize_key = string_sprintf("etrn-" /* don't we have a function doing exactly this? */ - "%02x%02x%02x%02x" "%02x%02x%02x%02x" /* we have, since 2024-09-xx we can use %.16H */ - "%02x%02x%02x%02x" "%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15]); + etrn_serialize_key = string_sprintf("etrn-%.16H", digest); /* If a command has been specified for running as a result of ETRN, we permit any argument to ETRN. If not, only the # standard form is diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 40acee7a3..9d3f5af73 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -4035,7 +4035,7 @@ if (tlsp->host_resumable) #else /* Use, fairly arbitrilarily, what we as server would */ f.running_in_test_harness ? TESTSUITE_TICKET_LIFE : ssl_session_timeout; #endif - time_t now = time(NULL), expires = lifetime + dt->time_stamp; + time_t now = time(NULL), expires = lifetime + dt->gen.time_stamp; if (expires < now) { DEBUG(D_tls) debug_printf("session expired (by " TIME_T_FMT "s from %lus)\n", now - expires, lifetime); diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 8ea3d882a..80a70b490 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -992,7 +992,7 @@ if ( sx->early_pipe_active debug_printf("no ehlo-resp record!\n"); else debug_printf("ehlo-resp record is %.0f seconds old\n", - difftime(time(NULL), er->time_stamp)); + difftime(time(NULL), er->gen.time_stamp)); } dbfn_delete(dbm_file, ehlo_resp_key); @@ -1018,7 +1018,7 @@ else dbfn_close(dbm_file); DEBUG(D_transport) debug_printf("no ehlo-resp record\n"); } - else if (time(NULL) - er->time_stamp > retry_data_expire) + else if (time(NULL) - er->gen.time_stamp > retry_data_expire) { DEBUG(D_transport) debug_printf("ehlo-resp record too old\n"); dbfn_close(dbm_file); diff --git a/src/src/verify.c b/src/src/verify.c index 6696ec4d9..be9ea7fe4 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -63,7 +63,7 @@ negative = cache_record->result != ccache_accept || expire = negative? negative_expire : positive_expire; now = time(NULL); -if (now - cache_record->time_stamp > expire) +if (now - cache_record->gen.time_stamp > expire) { HDEBUG(D_verify) debug_printf_indent("callout cache: %s record expired for %s\n", type, key); return NULL; @@ -81,7 +81,7 @@ if (type[0] == 'd' && cache_record->result != ccache_reject) { dbdata_callout_cache * new = store_get(sizeof(dbdata_callout_cache), GET_UNTAINTED); memcpy(new, cache_record, length); - new->postmaster_stamp = new->random_stamp = new->time_stamp; + new->postmaster_stamp = new->random_stamp = new->gen.time_stamp; cache_record = new; } commit de32296674ed4e57cb5a8efa3bb3f2c838d03d1a Author: Jeremy Harris Date: Sun Nov 30 10:19:10 2025 +0000 add version checking and grooming for hintsdb records diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 0a05524e1..64807a7b8 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -17,25 +17,29 @@ with database files like $spooldirectory/db/ */ /* Functions for accessing Exim's hints database, which consists of a number of -different DBM files. This module does not contain code for reading DBM files -for (e.g.) alias expansion. That is all contained within the general search -functions. As Exim now has support for several DBM interfaces, all the relevant +different DBM files. Also used for the readonly access for dbm lookup +expansions via the general search functions, for non-hints DBM file. + +As Exim now has support for several DBM interfaces, all the relevant functions are called as inlinable functions from an included file. -All the data in Exim's database is in the nature of *hints*. Therefore it +All the data in Exim's hists database is in the nature of *hints*. Therefore it doesn't matter if it gets destroyed by accident. These functions are not supposed to implement a "safe" database. -Keys are passed in as C strings, and the terminating zero *is* used when -building the dbm files. This just makes life easier when scanning the files +For hints, keys are passed in as C strings - and the terminating zero *is* used +when building the dbm files. This just makes life easier when scanning the files sequentially. -Synchronization is required on the database files, and this is achieved by -means of locking on independent lock files. (Earlier attempts to lock on the -DBM files themselves were never completely successful.) Since callers may in -general want to do more than one read or write while holding the lock, there -are separate open and close functions. However, the calling modules should -arrange to hold the locks for the bare minimum of time. +For many of the DBM interfaces, synchronization is required on the database +files; and this is achieved by means of locking on independent lock files. +(Earlier attempts to lock on the DBM files themselves were never completely +successful.) Since callers may in general want to do more than one read or write +while holding the lock, there are separate open and close functions. +However, the calling modules should arrange to hold the locks for the bare +minimum of time. +A predicate call is provided to tell if this locking is required, as opposed +to being built-in to the DBM. API: exim_lockfile_needed facilities predicate @@ -62,6 +66,13 @@ Users: peer capability cache callout & quota cache DBM lookup type + + +NOTE: the autoreply transport accesses a DBM database using +exim_db{open,close,get,put} directly, not using this layer. + +The DBM interface is selected at build time from one of the +files src/hintsdb/hints_*.h */ @@ -430,12 +441,30 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) dlen = exim_datum_size_get(&result_datum); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); -/* Hintsdb uses store the taint of the payload of the value in the value. -For non-hints uses we have no provenance, so assume untainted */ +if (hintsdb) + { + dbdata_generic * gp = (dbdata_generic *) exim_datum_data_get(&result_datum); -tainted = hintsdb - ? ((dbdata_generic *) exim_datum_data_get(&result_datum))->tainted - : FALSE; + if (dlen < sizeof(dbdata_generic)) + { + DEBUG(D_hints_lookup) + debug_printf_indent("dbfn_read: bad record size %u\n", dlen); + return NULL; + } + if (gp->version != HINTS_VERSION) + { + DEBUG(D_hints_lookup) + debug_printf_indent("dbfn_read: bad record version %u\n", gp->version); + return NULL; + } + + /* Hintsdb uses store the taint of the payload of the value in the value. + For non-hints uses we have no provenance, so assume untainted */ + + tainted = gp->tainted; + } +else + tainted = FALSE; yield = store_get(dlen+1, tainted ? GET_TAINTED : GET_UNTAINTED); memcpy(yield, exim_datum_data_get(&result_datum), dlen); @@ -519,13 +548,14 @@ int dbfn_write(open_db * dbblock, const uschar * key, void * ptr, int length) { EXIM_DATUM key_datum, value_datum; -dbdata_generic *gptr = (dbdata_generic *)ptr; +dbdata_generic * gptr = (dbdata_generic *)ptr; int klen = Ustrlen(key) + 1; uschar * key_copy = store_get(klen, key); memcpy(key_copy, key, klen); -gptr->time_stamp = time(NULL); +gptr->version = HINTS_VERSION; gptr->tainted = is_tainted(ptr); +gptr->time_stamp = time(NULL); DEBUG(D_hints_lookup) debug_printf_indent("dbfn_write: key=%s datalen %d\n", key, length); diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 2c03be1c5..f3842874f 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -380,7 +380,8 @@ if (exim_lockfile_needed()) exclusive access to the database, so we can go ahead and open it. */ } -if (asprintf(CSS &filename, "%s", name) < 0) return NULL; +/* Drop the ".lockfile" off the name */ +*Ustrrchr(filename, '.') = '\0'; if (!(dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() ? exim_dbopen_multi(filename, dname, flags, 0) @@ -447,7 +448,7 @@ Arguments: length where to put the length (or NULL if length not wanted). Includes overhead. Returns: a pointer to the retrieved record, or - NULL if the record is not found + NULL if the record is not found or bad */ void * @@ -467,26 +468,42 @@ exim_datum_init(&result_datum); /* to be cleared before use. */ exim_datum_data_set(&key_datum, key_copy); exim_datum_size_set(&key_datum, klen); -if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; - -/* Assume for now that anything stored could have been tainted. Properly -we should store the taint status along with the data. */ +if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) + return NULL; dlen = exim_datum_size_get(&result_datum); +DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); +if (length) *length = dlen; /* Hintsdb uses store the taint of the payload of the value in the value. For non-hints uses we have no provenance, so assume untainted */ -tainted = dbmdb - ? FALSE - : ((dbdata_generic *) exim_datum_data_get(&result_datum))->tainted; +if (dbmdb) + tainted = FALSE; +else + { + dbdata_generic * gp = (dbdata_generic *) exim_datum_data_get(&result_datum); + if (dlen < sizeof(dbdata_generic)) + { + DEBUG(D_hints_lookup) + debug_printf_indent("dbfn_read: bad record size %u\n", dlen); + return NULL; + } + if (gp->version != HINTS_VERSION) + { + DEBUG(D_hints_lookup) + debug_printf_indent("dbfn_read: bad record version %u; deleting\n", + gp->version); + return NULL; + } + + tainted = gp->tainted; + } yield = store_get(dlen, tainted ? GET_TAINTED : GET_UNTAINTED); memcpy(yield, exim_datum_data_get(&result_datum), dlen); -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); -if (length) *length = dlen; +exim_datum_free(&result_datum); /* Some DBM libs require freeing */ -exim_datum_free(&result_datum); /* Some DBM libs require freeing */ return yield; } @@ -726,13 +743,10 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); printf("%s ", name); t += MESSAGE_ID_LENGTH; } - printf("\n"); + putchar('\n'); break; case type_misc: - /* It might be nice to recognize the subtypes of "misc" DBs (by the - key prefix?) for better decode. For now, dump the raw data. */ - { dbdata_generic * recp = (dbdata_generic *)value; uschar * dp = US (recp + 1); @@ -1368,16 +1382,26 @@ the store each time round. */ for (; keychain && (reset_point = store_mark()); store_reset(reset_point)) { - dbdata_generic *value; + dbdata_generic * value; + int size = 0; key = keychain->key; keychain = keychain->next; - value = dbfn_read_with_length(dbm, key, NULL); + value = dbfn_read_with_length(dbm, key, &size); /* A continuation record may have been deleted or renamed already, so - non-existence is not serious. */ + non-existence is not serious. Also, for a back-version record we get + a null value - so attempt a delete. */ - if (!value) continue; + if (!value) + { + if (size) + { + printf(" deleted %s (bad record version)\n", key); + dbfn_delete(dbm, key); + } + continue; + } /* Delete if too old */ diff --git a/src/src/hintsdb_structs.h b/src/src/hintsdb_structs.h index f4d72fdc9..fdca1f468 100644 --- a/src/src/hintsdb_structs.h +++ b/src/src/hintsdb_structs.h @@ -25,17 +25,20 @@ typedef struct { } open_db; -/* Structures for records stored in exim database hinsts files. They all +/* Structures for records stored in exim database hints files. They all start with the same fields, described in the generic type. DBM databases are used for hints files. */ typedef struct { - time_t time_stamp; /* Timestamp of writing */ + unsigned version; BOOL tainted; /* metadata for the "value" part of the record */ + time_t time_stamp; /* Timestamp of writing */ } dbdata_generic; +#define HINTS_VERSION 2 + /* This structure keeps track of retry information for a host or a local address. */ commit 7873db47ac111972cc46b42e741fd437ec7a9869 Author: Jeremy Harris Date: Thu Dec 18 11:03:22 2025 +0000 Add notes on alternates to prototype Makefile diff --git a/src/src/EDITME b/src/src/EDITME index 8977f624b..0edeedaa2 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -654,8 +654,8 @@ DISABLE_MAL_MKS=yes # Uncomment the following to remove the fast-ramp two-phase-queue-run support # DISABLE_QUEUE_RAMP=yes -# Uncomment the following lines to add SRS (Sender Rewriting Scheme) support -# using only native facilities. +# Uncomment the following lines to add SRS (Sender Rewriting Scheme) support. +# This needs no library. # SUPPORT_SRS=yes # Uncomment the following to remove support for the ESMTP extension "WELLKNOWN" @@ -693,6 +693,9 @@ DISABLE_MAL_MKS=yes # 1.3.2-3 works. It seems that the OpenDMARC project broke their API. # Use this option if you need to build with an old library (1.3.x) # DMARC_API=100300 +# +# As an alternative, see EXPERIMENTAL_DMARC_NATIVE +# in doc-txt/experimental-spec.txt # Uncomment the following line to add ARC (Authenticated Received Chain) # support. You must have SPF and DKIM support enabled also. @@ -1177,6 +1180,8 @@ ZCAT_COMMAND=/usr/bin/zcat # LDFLAGS += -lspf2 # SUPPORT_SPF_LIBS= -lspf2 +# As an alternative, see EXPERIMENTAL_SPF_PERL +# in doc-txt/experimental-spec.txt #------------------------------------------------------------------------------ # Support for authentication via Radius is also available. The Exim support, commit dbb8fa7d6275bb2a21d9a7803b3ab902a2e15301 Author: Jeremy Harris Date: Thu Dec 18 13:30:02 2025 +0000 Utils; fix exim_dumpdb build for non- pipe-connect diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index f3842874f..3ef241a4e 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -763,6 +763,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); else { uschar * s = keybuffer + Ustrlen(keybuffer) - 5; +#ifndef DISABLE_PIPE_CONNECT if (s > keybuffer && Ustrcmp(s, ".EHLO") == 0) { ehlo_resp_precis * erp = &((dbdata_ehlo_resp *)recp)->data; @@ -778,6 +779,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); putchar('\n'); } else +#endif printf("%s\n", string_sprintf("%.*q\n", dlen, dp)); } break; @@ -847,7 +849,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor); break; case type_dbm: - printf("%s\t%.*s\n", keybuffer, length, value); + printf("%s\t%.*s\n", keybuffer, length, CS value); } store_reset(reset_point); } commit 0b98b3d655993f08104b9caf71be382cee57bd79 Author: Jeremy Harris Date: Thu Dec 18 13:35:42 2025 +0000 Avoid function name conflict with Solaris libgen diff --git a/src/src/acl.c b/src/src/acl.c index 7ec3a898c..b236eb2de 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -4095,7 +4095,7 @@ for (; cb; cb = cb->next) #ifdef WITH_CONTENT_SCAN case ACLC_REGEX: - rc = regex(&arg, textonly); + rc = exim_regex(&arg, textonly); break; #endif diff --git a/src/src/functions.h b/src/src/functions.h index bfe34f391..1923ca5b6 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -446,7 +446,7 @@ extern int_eximarith_t receive_statvfs(BOOL, int *); extern void receive_swallow_smtp(void); extern int recv_fd_from_sock(int); #ifdef WITH_CONTENT_SCAN -extern int regex(const uschar **, BOOL); +extern int exim_regex(const uschar **, BOOL); extern void regex_vars_clear(void); #endif extern void regex_at_daemon(const uschar *); diff --git a/src/src/regex.c b/src/src/regex.c index ff52d349c..43f7a9403 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -113,7 +113,7 @@ for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; int -regex(const uschar ** listptr, BOOL cacheable) +exim_regex(const uschar ** listptr, BOOL cacheable) { unsigned long mbox_size; FILE * mbox_file; commit 7b81731f51c53643c30d330596779a1c2f7eeb73 Author: Jeremy Harris Date: Thu Dec 18 16:04:24 2025 +0000 Build: Solaris diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 9524dcef9..d0c00e431 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -601,7 +601,7 @@ exim_dumpdb: $(OBJ_DUMPDB) # The utility for interrogating/fixing the contents of an exim database -OBJ_FIXDB = exim_fixdb.o util-os.o util-store.o util-md5.o +OBJ_FIXDB = exim_fixdb.o util-os.o util-store.o util-string.o util-md5.o exim_fixdb: $(OBJ_FIXDB) @echo "$(LNCC) -o exim_fixdb" commit fc6c642e1bfecab156b65c992697dbf1b3002b8b Author: Jeremy Harris Date: Thu Dec 18 19:13:06 2025 +0000 Build: Solaris diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index d0c00e431..699f485c1 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -616,7 +616,7 @@ exim_fixdb: $(OBJ_FIXDB) # The utility for tidying the contents of an exim database -OBJ_TIDYDB = exim_tidydb.o util-os.o util-store.o +OBJ_TIDYDB = exim_tidydb.o util-os.o util-store.o util-string.o exim_tidydb: $(OBJ_TIDYDB) @echo "$(LNCC) -o exim_tidydb" commit e46d2bb2bd33044b45cd9cc508a50f63d91aa0f8 Author: Jeremy Harris Date: Fri Dec 19 10:29:58 2025 +0000 Utils: eliminate use of asprintf() diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 3ef241a4e..6ffcf764c 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -329,15 +329,16 @@ for the DB access mode will error out here. */ if (dbmdb) { - if (asprintf(CSS &filename, "%s.lockfile", name) < 0) - return NULL; + filename = string_sprintf("%s.lockfile", name); dname = Ustrchr(name, '/') /* path has dirs */ ? US dirname(CS string_copy(name)) : US "."; } -else if ( asprintf(CSS &dname, "%s/db", spool_directory) < 0 - || asprintf(CSS &filename, "%s/%s.lockfile", dname, name) < 0) - return NULL; +else + { + dname = string_sprintf("%s/db", spool_directory); + filename = string_sprintf("%s/%s.lockfile", dname, name); + } dbblock->readonly = (flags & O_ACCMODE) == O_RDONLY; dbblock->lockfd = -1; commit cb28da1d541b29ce86ea862f00f6c278117cbcb9 Author: Jeremy Harris Date: Fri Dec 19 20:27:36 2025 +0000 Tidying diff --git a/src/src/exim.c b/src/src/exim.c index e955d2488..d8851d782 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -85,7 +85,11 @@ function_store_nullfree(void * block, void * tag) *************************************************/ enum commandline_info { CMDINFO_NONE=0, - CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_DSCP }; + CMDINFO_HELP, CMDINFO_SIEVE, +#ifdef SUPPORT_DSCP + CMDINFO_DSCP +#endif +}; diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 6ffcf764c..b6977513b 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -1254,7 +1254,7 @@ for(; (reset_point = store_mark()); store_reset(reset_point)) break; case type_dbm: - printf("0 value: %.*s\n", oldlength, record); + printf("0 value: %.*s\n", oldlength, CS record); } } diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index 35b832c59..ab0027f17 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -15,7 +15,7 @@ extern BOOL dmarc_local_init(void); extern void dmarc_local_msg_init(void); extern gstring * dmarc_version_report(gstring *); extern int dmarc_process(void); -extern const uschar * dmarc_result_inlist(const uschar * const *); +extern int dmarc_result_inlist(const uschar * const *); /* Other modules needed for services */ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 80a70b490..7274050f1 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -1126,8 +1126,6 @@ sx->pending_EHLO = FALSE; if (pending_BANNER) { - const uschar * s; - DEBUG(D_transport) debug_printf("%s expect banner\n", __FUNCTION__); (*countp)--; if (!smtp_reap_banner(sx)) @@ -1140,9 +1138,12 @@ if (pending_BANNER) # if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) GET_OPTION("host_name_extract"); - s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; - if (!s) s = HNE_DEFAULT; - ehlo_response_lbserver(sx, s); + { + const uschar * s; + s = ((smtp_transport_options_block *)sx->conn_args.ob)->host_name_extract; + if (!s) s = HNE_DEFAULT; + ehlo_response_lbserver(sx, s); + } # endif } @@ -2677,8 +2678,6 @@ goto SEND_QUIT; #ifndef DISABLE_TLS if (sx->smtps) { - const uschar * s; - smtp_peer_options |= OPTION_TLS; suppress_tls = FALSE; ob->tls_tempfail_tryclear = FALSE; @@ -2690,8 +2689,11 @@ goto SEND_QUIT; force resumption attempts. */ GET_OPTION("host_name_extract"); - if (!(s = ob->host_name_extract)) s = US"never-LB"; - ehlo_response_lbserver(sx, s); + { + const uschar * s; + if (!(s = ob->host_name_extract)) s = US"never-LB"; + ehlo_response_lbserver(sx, s); + } # endif smtp_record_protocol_sequence(sx, US"s"); goto TLS_NEGOTIATE; @@ -2784,8 +2786,6 @@ goto SEND_QUIT; if (!sx->early_pipe_active) #endif { - const uschar * s; - sx->peer_offered = ehlo_response(sx->buffer, OPTION_TLS /* others checked later */ #ifndef DISABLE_PIPE_CONNECT @@ -2824,8 +2824,11 @@ goto SEND_QUIT; #endif #if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME) GET_OPTION("host_name_extract"); - if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; - ehlo_response_lbserver(sx, s); + { + const uschar * s; + if (!(s = ob->host_name_extract)) s = HNE_DEFAULT; + ehlo_response_lbserver(sx, s); + } #endif } commit 8783c47fcae5a69aea91cb37da694070185569e5 Author: Andreas Metzler Date: Sun Dec 21 12:42:13 2025 +0000 typo, c'n'p errors diff --git a/src/src/EDITME b/src/src/EDITME index 0edeedaa2..21d81f43c 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -320,8 +320,8 @@ SPOOL_DIRECTORY=/var/spool/exim # is historic). # You need to add -export-dynamic -rdynamic to EXTRALIBS. You may also need to # add -ldl to EXTRALIBS so that dlopen() is available to Exim. You need to -# define CFLAGS_DYNAIC and LOOKUP_MODULE_DIR below so the builds are done right, -# and so the exim binary actually loads dynamic lookup modules. +# define CFLAGS_DYNAMIC and LOOKUP_MODULE_DIR below so the builds are done +# right, and so the exim binary actually loads dynamic lookup modules. ROUTER_ACCEPT=yes ROUTER_DNSLOOKUP=yes @@ -350,8 +350,8 @@ ROUTER_REDIRECT=yes # is historic). # You need to add -export-dynamic -rdynamic to EXTRALIBS. You may also need to # add -ldl to EXTRALIBS so that dlopen() is available to Exim. You need to -# define CFLAGS_DYNAIC and LOOKUP_MODULE_DIR below so the builds are done right, -# and so the exim binary actually loads dynamic lookup modules. +# define CFLAGS_DYNAMIC and LOOKUP_MODULE_DIR below so the builds are done +# right, and so the exim binary actually loads dynamic lookup modules. # The smtp transport cannot be built as a module. TRANSPORT_APPENDFILE=yes @@ -874,7 +874,7 @@ FIXED_NEVER_USERS=root # right and so the exim binary actually loads dynamic lookup modules. # # Libraries being built as modules should be added to respective -# LOOKUP_*_INCLUDE and LOOKUP_*_LIBS rather than the the ones for the +# AUTH_*_INCLUDE and AUTH_*_LIBS rather than the the ones for the # core exim build. This gets them linked with the module instead. # The heimdal does build but we have no test coverage so it is not know to work. commit 91586f969ddddc4ff4339167c05141141a4b6272 Author: Jeremy Harris Date: Sun Dec 21 15:54:59 2025 +0000 Cmdline option for list of dynamic-load modules diff --git a/src/src/drtables.c b/src/src/drtables.c index 833c352c0..1b9dc0c98 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -224,6 +224,7 @@ const pcre2_code * regex_islookupmod = regex_must_compile( if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) g = string_cat(g, US"FAIL exim_opendir"); else + { for (struct dirent * ent; ent = readdir(dd); ) { void * dl; @@ -246,6 +247,8 @@ else dlclose(dl); } } + closedir(dd); + } #endif /*!LOOKUP_MODULE_DIR*/ return g; } @@ -574,5 +577,37 @@ onetime = TRUE; } +void +mod_names(FILE * stream) +{ +#ifdef LOOKUP_MODULE_DIR +DIR * dd; +gstring * list = NULL; +const pcre2_code * regex_ismodule = regex_must_compile( + US"^([a-z0-9]+)_(?:lookup|auth|router|transport|miscmod)\\." + DYNLIB_FN_EXT "$", + MCS_NOFLAGS, TRUE); + +if ((dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) + { + for (struct dirent * ent; ent = readdir(dd); ) + if (regex_match_and_setup(regex_ismodule, US ent->d_name, 0, 0)) + list = string_append_listele(list, ' ', expand_nstring[1]); + closedir(dd); + + if (list) + fprintf(stream, "Installed modules: %s\n", string_from_gstring(list)); + else + fprintf(stream, "No modules are installed\n"); + } +else + fprintf(stream, "Modules directory not readable\n"); + +#else +fprintf(stream, "Loadable-module support is not available\n"); +#endif +} + + #endif /*!MACRO_PREDEF*/ /* End of drtables.c */ diff --git a/src/src/exim.c b/src/src/exim.c index d8851d782..055882ad0 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -85,7 +85,7 @@ function_store_nullfree(void * block, void * tag) *************************************************/ enum commandline_info { CMDINFO_NONE=0, - CMDINFO_HELP, CMDINFO_SIEVE, + CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_MODULES, #ifdef SUPPORT_DSCP CMDINFO_DSCP #endif @@ -1392,9 +1392,13 @@ switch(request) #ifdef SUPPORT_DSCP " exim -bI:dscp list of known dscp value keywords\n" #endif +" exim -bI:modules list of loadable modules\n" " exim -bI:sieve list of supported sieve extensions\n" ); return; + case CMDINFO_MODULES: + mod_names(stream); + return; case CMDINFO_SIEVE: { const misc_module_info * mi; @@ -2436,6 +2440,8 @@ on the second character (the one after '-'), to save some effort. */ if (Ustrlen(p)) if (strcmpic(p, CUS"sieve") == 0) { info_flag = CMDINFO_SIEVE; info_stdout = TRUE; } + else if (strcmpic(p, CUS"modules") == 0) + { info_flag = CMDINFO_MODULES; info_stdout = TRUE; } #ifdef SUPPORT_DSCP else if (strcmpic(p, CUS"dscp") == 0) { info_flag = CMDINFO_DSCP; info_stdout = TRUE; } diff --git a/src/src/functions.h b/src/src/functions.h index 1923ca5b6..fe9d718ea 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -376,6 +376,7 @@ extern void moan_write_references(FILE *, uschar *); #ifdef LOOKUP_MODULE_DIR //extern void mod_load_check(const uschar *); #endif +extern void mod_names(FILE *); extern FILE *modefopen(const uschar *, const char *, mode_t); extern int open_cutthrough_connection(address_item *, BOOL); commit 6d75a89d2f506f88cfddf092440af5b2d54f07df Author: Jeremy Harris Date: Sun Dec 21 18:01:26 2025 +0000 Invalidate more variables at smtp-reset diff --git a/src/src/deliver.c b/src/src/deliver.c index cf3a41156..a984ee21e 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -174,8 +174,10 @@ deliver_set_expansions(address_item * addr) { if (!addr) { - const uschar ***p = address_expansions; - while (*p) **p++ = NULL; + for (const uschar ***p = address_expansions; *p; ) **p++ = NULL; + deliver_host_port = 0; + deliver_recipients = NULL; + router_var = NULL; return; } diff --git a/src/src/globals.c b/src/src/globals.c index 2d1354236..d04feb24f 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -188,6 +188,8 @@ when verifying one address while routing/verifying another. We have to have the size explicit, because it is referenced from more than one module. */ const uschar **address_expansions[ADDRESS_EXPANSIONS_COUNT] = { + CUSS &address_file, + CUSS &address_pipe, CUSS &deliver_address_data, CUSS &deliver_domain, CUSS &deliver_domain_data, @@ -198,12 +200,13 @@ const uschar **address_expansions[ADDRESS_EXPANSIONS_COUNT] = { CUSS &deliver_localpart_orig, CUSS &deliver_localpart_parent, CUSS &deliver_localpart_prefix, + CUSS &deliver_localpart_prefix_v, CUSS &deliver_localpart_suffix, + CUSS &deliver_localpart_suffix_v, CUSS (uschar **)(&deliver_recipients), CUSS &deliver_host, + CUSS &deliver_host_address, CUSS &deliver_home, - CUSS &address_file, - CUSS &address_pipe, CUSS &self_hostname, NULL }; diff --git a/src/src/log.c b/src/src/log.c index 41f91a1ad..64587a9f2 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1323,7 +1323,7 @@ va_end(ap); } /* As the above, but adds in LOG_PANIC_DIE. -We have this as a wripper so that we can mark it as never returning, +We have this as a wrapper so that we can mark it as never returning, for the benefit of static analysers. */ void diff --git a/src/src/macros.h b/src/src/macros.h index 6c7d8b085..0070ef7ed 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -119,7 +119,7 @@ don't make the file descriptors two-way. */ verifying. This has to be explicit because it is referenced in more than one source module. */ -#define ADDRESS_EXPANSIONS_COUNT 19 +#define ADDRESS_EXPANSIONS_COUNT 21 /* The maximum permitted number of command-line (-D) macro definitions. We need a limit only to make it easier to generate argument vectors for re-exec diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index abc893ddc..da919048c 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1736,6 +1736,8 @@ Returns: a replacement reset point rmark smtp_reset(rmark reset_point) { +deliver_set_expansions(NULL); + recipients_list = NULL; rcpt_count = rcpt_defer_count = rcpt_fail_count = raw_recipients_count = recipients_count = recipients_list_max = 0; @@ -1760,11 +1762,8 @@ f.active_local_from_check = local_from_check; /* Can be set by ACL */ f.active_local_sender_retain = local_sender_retain; /* Can be set by ACL */ sending_ip_address = NULL; return_path = sender_address = NULL; -deliver_localpart_data = deliver_domain_data = recipient_data = sender_data = NULL; /* Can be set by ACL */ recipient_verify_failure = NULL; -deliver_localpart_parent = deliver_localpart_orig = NULL; -deliver_domain_parent = deliver_domain_orig = NULL; callout_address = NULL; submission_name = NULL; /* Can be set by ACL */ raw_sender = NULL; /* After SMTP rewrite, before qualifying */ @@ -1778,7 +1777,6 @@ dnslist_domain = dnslist_matched = NULL; dsn_ret = 0; dsn_envid = NULL; -deliver_host = deliver_host_address = NULL; /* Can be set by ACL */ #ifndef DISABLE_TLS memset(&tls_out, 0, sizeof(tls_out)); /* Can be set by callout */ tls_out.active.sock = -1; commit bfd2759002fd2b5b376a1544e8fc59f313dc4e9c Author: Jeremy Harris Date: Mon Dec 22 10:10:01 2025 +0000 Disable -bI:sieve for sieve-less builds. Bug 3184 diff --git a/src/src/EDITME b/src/src/EDITME index 21d81f43c..f641a6699 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -566,7 +566,6 @@ SUPPORT_DANE=yes # SUPPORT_EXIM_FILTER=2 -#------------------------------------------------------------------------------ # Compiling with support for Sieve filters is the default. To disable this # uncomment the line below. @@ -577,6 +576,7 @@ SUPPORT_DANE=yes # SUPPORT_SIEVE_FILTER=2 +#------------------------------------------------------------------------------ # Uncomment the line to include DSCP support. Set to 2 for a module build. # SUPPORT_DSCP diff --git a/src/src/drtables.c b/src/src/drtables.c index 1b9dc0c98..29ae84bd6 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -348,8 +348,9 @@ if ((mi = misc_mod_findonly(name))) return mi; #ifdef LOOKUP_MODULE_DIR return misc_mod_load(name, errstr); #else -*errstr = string_sprintf("module %q not built-in, and" - " no setting for LOOKUP_MODULE_DIR", name); +if (errstr) + *errstr = string_sprintf("module %q not built-in, and" + " no setting for LOOKUP_MODULE_DIR", name); return NULL; #endif /*LOOKUP_MODULE_DIR*/ } diff --git a/src/src/exim.c b/src/src/exim.c index 055882ad0..8c5089f7b 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -85,7 +85,10 @@ function_store_nullfree(void * block, void * tag) *************************************************/ enum commandline_info { CMDINFO_NONE=0, - CMDINFO_HELP, CMDINFO_SIEVE, CMDINFO_MODULES, + CMDINFO_HELP, CMDINFO_MODULES, +#ifndef DISABLE_SIEVE_FILTER + CMDINFO_SIEVE, +#endif #ifdef SUPPORT_DSCP CMDINFO_DSCP #endif @@ -1393,27 +1396,30 @@ switch(request) " exim -bI:dscp list of known dscp value keywords\n" #endif " exim -bI:modules list of loadable modules\n" +#ifndef DISABLE_SIEVE_FILTER " exim -bI:sieve list of supported sieve extensions\n" +#endif ); return; case CMDINFO_MODULES: mod_names(stream); return; +#ifndef DISABLE_SIEVE_FILTER case CMDINFO_SIEVE: { - const misc_module_info * mi; + misc_module_info * mi = misc_mod_find(US"sieve_filter", NULL); typedef void (*fn_t)(FILE *); - if ((mi = misc_mod_find(US"sieve_filter", NULL))) + if (mi) (((fn_t *) mi->functions)[SIEVE_EXTENSIONS]) (stream); else fprintf(stream, "Sieve filtering not available\n"); } return; +#endif #ifdef SUPPORT_DSCP case CMDINFO_DSCP: { - uschar * dummy_errstr; - misc_module_info * mi = misc_mod_find(US"dscp", &dummy_errstr); + misc_module_info * mi = misc_mod_find(US"dscp", NULL); typedef void (*fn_t)(FILE *); if (mi) ((fn_t *) mi->functions)[DSCP_KEYWORDS] (stream); } @@ -2438,10 +2444,12 @@ on the second character (the one after '-'), to save some effort. */ const uschar * p = argrest+1; info_flag = CMDINFO_HELP; if (Ustrlen(p)) - if (strcmpic(p, CUS"sieve") == 0) - { info_flag = CMDINFO_SIEVE; info_stdout = TRUE; } - else if (strcmpic(p, CUS"modules") == 0) + if (strcmpic(p, CUS"modules") == 0) { info_flag = CMDINFO_MODULES; info_stdout = TRUE; } +#ifndef DISABLE_SIEVE_FILTER + else if (strcmpic(p, CUS"sieve") == 0) + { info_flag = CMDINFO_SIEVE; info_stdout = TRUE; } +#endif #ifdef SUPPORT_DSCP else if (strcmpic(p, CUS"dscp") == 0) { info_flag = CMDINFO_DSCP; info_stdout = TRUE; } diff --git a/src/src/expand.c b/src/src/expand.c index b0500037d..85d27b534 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2802,7 +2802,8 @@ switch(cond_type = identify_operator(&s, &opname)) case ECOND_RADIUS: #ifdef RADIUS_CONFIG_FILE { - const misc_module_info * mi = misc_mod_find(US"radius", NULL); + uschar * dummy_errstr; + const misc_module_info * mi = misc_mod_find(US"radius", &dummy_errstr); typedef int (*fn_t)(const uschar *, uschar **); if (!mi) goto COND_FAILED_NOT_COMPILED; diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index a8404d9bf..e41e1dcb0 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -84,8 +84,7 @@ return FAIL; gstring * spf_version_report(gstring * g) { -uschar * dummy_errmsg; -misc_module_info * mi = misc_mod_find(US"spf", &dummy_errmsg); +misc_module_info * mi = misc_mod_find(US"spf", NULL); return mi && mi->lib_vers_report ? mi->lib_vers_report(g) : g; } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index da919048c..643d88ca2 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2669,11 +2669,10 @@ Failure will not allow any SMTP function other than QUIT. */ f.quit_cmd_only = FALSE; if (hosts_proxy) { - uschar * dummy_errmsg; misc_module_info * mi; typedef BOOL (*fn_t) (void); - if (!(mi = misc_mod_find(US"proxy", &dummy_errmsg))) + if (!(mi = misc_mod_find(US"proxy", NULL))) { smtp_closedown(US"Temporary local problem - please try later"); return FALSE; @@ -4443,11 +4442,10 @@ while (done <= 0) #ifdef EXPERIMENTAL_XCLIENT if (proxy_session || verify_check_host(&hosts_xclient) != FAIL) { - uschar * dummy_errmsg; typedef gstring * (*fn_t) (gstring *); if ( !xclient_mi - && !(xclient_mi = misc_mod_find(US"xclient", &dummy_errmsg))) + && !(xclient_mi = misc_mod_find(US"xclient", NULL))) { smtp_closedown(US"Temporary local problem - please try later"); return FALSE; diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index a5557d09e..2712ee0ce 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -296,8 +296,7 @@ bomb out, just log it and continue in default traffic class. */ GET_OPTION("dscp"); if (ob->dscp) { - uschar * dummy_errstr; - misc_module_info * mi = misc_mod_find(US"dscp", &dummy_errstr); + misc_module_info * mi = misc_mod_find(US"dscp", NULL); typedef void (*fn_t)(int, const uschar *, int); if (mi) ((fn_t *) mi->functions)[DSCP_TRANSPORT] (sock, ob->dscp, sc->host_af); @@ -521,8 +520,7 @@ if (ob->socks_proxy) } if (*ob->socks_proxy) { - uschar * dummy_errmsg; - misc_module_info * mi = misc_mod_find(US"socks", &dummy_errmsg); + misc_module_info * mi = misc_mod_find(US"socks", NULL); typedef int (*fn_t) (const smtp_connect_args *, const blob *); return mi ? ((fn_t *) mi->functions)[SOCKS_CONNECT] (sc, early_data) : -1; } commit 711a7387e0200c5dda3f9d0a744dae18afb80351 Author: Jeremy Harris Date: Tue Dec 23 13:07:35 2025 +0000 Keep handle open for module dir diff --git a/src/src/drtables.c b/src/src/drtables.c index 29ae84bd6..ec9ca3c67 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -221,7 +221,7 @@ DIR * dd; const pcre2_code * regex_islookupmod = regex_must_compile( US"^([a-z0-9]+)_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE); -if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) +if (!(dd = open_module_dir())) g = string_cat(g, US"FAIL exim_opendir"); else { @@ -247,7 +247,6 @@ else dlclose(dl); } } - closedir(dd); } #endif /*!LOOKUP_MODULE_DIR*/ return g; @@ -448,7 +447,7 @@ DEBUG(D_lookup) debug_printf_indent("Total %d built-in lookups\n", lookup_list_c #ifdef LOOKUP_MODULE_DIR -if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) +if (!(dd = open_module_dir())) { EARLY_DEBUG(D_lookup, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); log_write(0, LOG_MAIN|LOG_PANIC, @@ -476,7 +475,6 @@ else log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr); } } - closedir(dd); } EARLY_DEBUG(D_lookup, "Loaded %d dynamic lookup modules\n", countmodules); @@ -589,12 +587,11 @@ const pcre2_code * regex_ismodule = regex_must_compile( DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE); -if ((dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) +if ((dd = open_module_dir())) { for (struct dirent * ent; ent = readdir(dd); ) if (regex_match_and_setup(regex_ismodule, US ent->d_name, 0, 0)) list = string_append_listele(list, ' ', expand_nstring[1]); - closedir(dd); if (list) fprintf(stream, "Installed modules: %s\n", string_from_gstring(list)); diff --git a/src/src/functions.h b/src/src/functions.h index fe9d718ea..b2c2626ab 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1327,7 +1327,7 @@ if (f.running_in_test_harness && f.testsuite_delays) millisleep(millisec); /* Taint-checked file opens. Return values/errno per open(2). */ static inline int -exim_open2(const char *pathname, int flags) +exim_open2(const char * pathname, int flags) { if (!is_tainted(pathname)) return open(pathname, flags); log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); @@ -1344,7 +1344,7 @@ return -1; } #ifdef EXIM_HAVE_OPENAT static inline int -exim_openat(int dirfd, const char *pathname, int flags) +exim_openat(int dirfd, const char * pathname, int flags) { if (!is_tainted(pathname)) return openat(dirfd, pathname, flags); log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); @@ -1362,7 +1362,7 @@ return -1; #endif static inline FILE * -exim_fopen(const char *pathname, const char *mode) +exim_fopen(const char * pathname, const char * mode) { if (!is_tainted(pathname)) return fopen(pathname, mode); log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); @@ -1379,6 +1379,18 @@ errno = EACCES; return NULL; } +#ifdef LOOKUP_MODULE_DIR +static inline DIR * +open_module_dir(void) +{ +if (module_dir) + rewinddir(module_dir); +else + module_dir = exim_opendir(CUS LOOKUP_MODULE_DIR); +return module_dir; +} +#endif + /******************************************************************************/ # if !defined(COMPILE_UTILITY) diff --git a/src/src/globals.c b/src/src/globals.c index d04feb24f..e5de80ea4 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1101,6 +1101,9 @@ int mime_is_coverletter = 0; int mime_is_rfc822 = 0; int mime_part_count = -1; #endif +#ifdef LOOKUP_MODULE_DIR +DIR * module_dir = NULL; +#endif uid_t *never_users = NULL; uschar *notifier_socket = US"$spool_directory/" NOTIFIER_SOCKET_NAME ; diff --git a/src/src/globals.h b/src/src/globals.h index 52c46f169..313062890 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -769,6 +769,9 @@ extern int mime_is_coverletter; extern int mime_is_rfc822; extern int mime_part_count; #endif +#ifdef LOOKUP_MODULE_DIR +extern DIR * module_dir; +#endif extern BOOL mua_wrapper; /* TRUE when Exim is wrapping an MUA */ diff --git a/src/src/readconf.c b/src/src/readconf.c index 7840fd0ac..417a786e3 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -3819,7 +3819,7 @@ for (di = *info_anchor; di; di = di->next) #ifdef LOOKUP_MODULE_DIR /* Potentially a loadable module. Look for a file with the right name. */ -if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR))) +if (!(dd = open_module_dir())) log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR); else @@ -3828,7 +3828,7 @@ else d->driver_name, class); const char * errormsg; - DEBUG(D_any) debug_printf("Loading %s %s driver from %s\n", + DEBUG(D_any) debug_printf("Loading %q %s driver from %s\n", d->driver_name, class, LOOKUP_MODULE_DIR); for(struct dirent * ent; ent = readdir(dd); ) if (Ustrcmp(ent->d_name, fname) == 0) @@ -3866,7 +3866,6 @@ else store_pool = old_pool; DEBUG(D_any) debug_printf("Loaded module %q (%s)\n", d->driver_name, class); - closedir(dd); goto found; } @@ -3876,7 +3875,6 @@ else dlclose(dl); break; } - closedir(dd); } #endif /* LOOKUP_MODULE_DIR */ commit b3881e820e87ccaabfb2c4a08d3cd07974c59b75 Author: Jeremy Harris Date: Wed Dec 24 13:48:55 2025 +0000 Move lookup options & variables from global to module diff --git a/src/src/drtables.c b/src/src/drtables.c index ec9ca3c67..20034e7ce 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -152,7 +152,7 @@ return dl; /* Try to load a lookup module with the given name. Arguments: - name name of the lookup + name name of the module errstr if not NULL, place "open fail" error message here Return: boolean success @@ -211,6 +211,15 @@ return TRUE; #endif /*LOOKUP_MODULE_DIR*/ +const lookup_info * +lookup_find(const uschar * name, uschar ** errstr) +{ +const lookup_info * li; +if ((li = lookup_findonly(name))) return li; +lookup_mod_load(name, errstr); +return lookup_findonly(name); +} + /* Look at all the lookup module files and add a name from each lookup type */ gstring * diff --git a/src/src/expand.c b/src/src/expand.c index 85d27b534..ab0c0b37a 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -459,10 +459,10 @@ static var_entry var_table[] = { { "address_file", vtype_stringptr, &address_file }, { "address_pipe", vtype_stringptr, &address_pipe }, #ifdef EXPERIMENTAL_ARC - { "arc_domains", vtype_module, US"arc" }, - { "arc_oldest_pass", vtype_module, US"arc" }, - { "arc_state", vtype_module, US"arc" }, - { "arc_state_reason", vtype_module, US"arc" }, + { "arc_domains", vtype_misc_module, US"arc" }, + { "arc_oldest_pass", vtype_misc_module, US"arc" }, + { "arc_state", vtype_misc_module, US"arc" }, + { "arc_state_reason", vtype_misc_module, US"arc" }, #endif { "atrn_host", vtype_stringptr, &atrn_host }, { "atrn_mode", vtype_stringptr, &atrn_mode }, @@ -491,36 +491,36 @@ static var_entry var_table[] = { { "dcc_result", vtype_stringptr, &dcc_result }, #endif #ifndef DISABLE_DKIM - { "dkim_algo", vtype_module, US"dkim" }, - { "dkim_bodylength", vtype_module, US"dkim" }, - { "dkim_canon_body", vtype_module, US"dkim" }, - { "dkim_canon_headers", vtype_module, US"dkim" }, - { "dkim_copiedheaders", vtype_module, US"dkim" }, - { "dkim_created", vtype_module, US"dkim" }, - { "dkim_cur_signer", vtype_module, US"dkim" }, - { "dkim_domain", vtype_module, US"dkim" }, - { "dkim_expires", vtype_module, US"dkim" }, - { "dkim_headernames", vtype_module, US"dkim" }, - { "dkim_identity", vtype_module, US"dkim" }, - { "dkim_key_granularity",vtype_module, US"dkim" }, - { "dkim_key_length", vtype_module, US"dkim" }, - { "dkim_key_nosubdomains",vtype_module, US"dkim" }, - { "dkim_key_notes", vtype_module, US"dkim" }, - { "dkim_key_srvtype", vtype_module, US"dkim" }, - { "dkim_key_testing", vtype_module, US"dkim" }, - { "dkim_selector", vtype_module, US"dkim" }, - { "dkim_signers", vtype_module, US"dkim" }, - { "dkim_verify_reason", vtype_module, US"dkim" }, - { "dkim_verify_signers", vtype_module, US"dkim" }, - { "dkim_verify_status", vtype_module, US"dkim" }, + { "dkim_algo", vtype_misc_module, US"dkim" }, + { "dkim_bodylength", vtype_misc_module, US"dkim" }, + { "dkim_canon_body", vtype_misc_module, US"dkim" }, + { "dkim_canon_headers", vtype_misc_module, US"dkim" }, + { "dkim_copiedheaders", vtype_misc_module, US"dkim" }, + { "dkim_created", vtype_misc_module, US"dkim" }, + { "dkim_cur_signer", vtype_misc_module, US"dkim" }, + { "dkim_domain", vtype_misc_module, US"dkim" }, + { "dkim_expires", vtype_misc_module, US"dkim" }, + { "dkim_headernames", vtype_misc_module, US"dkim" }, + { "dkim_identity", vtype_misc_module, US"dkim" }, + { "dkim_key_granularity",vtype_misc_module, US"dkim" }, + { "dkim_key_length", vtype_misc_module, US"dkim" }, + { "dkim_key_nosubdomains",vtype_misc_module, US"dkim" }, + { "dkim_key_notes", vtype_misc_module, US"dkim" }, + { "dkim_key_srvtype", vtype_misc_module, US"dkim" }, + { "dkim_key_testing", vtype_misc_module, US"dkim" }, + { "dkim_selector", vtype_misc_module, US"dkim" }, + { "dkim_signers", vtype_misc_module, US"dkim" }, + { "dkim_verify_reason", vtype_misc_module, US"dkim" }, + { "dkim_verify_signers", vtype_misc_module, US"dkim" }, + { "dkim_verify_status", vtype_misc_module, US"dkim" }, #endif #ifdef EXIM_HAVE_DMARC - { "dmarc_alignment_dkim",vtype_module, US"dmarc" }, - { "dmarc_alignment_spf", vtype_module, US"dmarc" }, - { "dmarc_domain_policy", vtype_module, US"dmarc" }, - { "dmarc_status", vtype_module, US"dmarc" }, - { "dmarc_status_text", vtype_module, US"dmarc" }, - { "dmarc_used_domain", vtype_module, US"dmarc" }, + { "dmarc_alignment_dkim",vtype_misc_module, US"dmarc" }, + { "dmarc_alignment_spf", vtype_misc_module, US"dmarc" }, + { "dmarc_domain_policy", vtype_misc_module, US"dmarc" }, + { "dmarc_status", vtype_misc_module, US"dmarc" }, + { "dmarc_status_text", vtype_misc_module, US"dmarc" }, + { "dmarc_used_domain", vtype_misc_module, US"dmarc" }, #endif { "dnslist_domain", vtype_stringptr, &dnslist_domain }, { "dnslist_matched", vtype_stringptr, &dnslist_matched }, @@ -554,7 +554,7 @@ static var_entry var_table[] = { { "interface_port", vtype_int, &interface_port }, { "item", vtype_stringptr, &iterate_item }, #ifdef LOOKUP_LDAP - { "ldap_dn", vtype_stringptr, &eldap_dn }, + { "ldap_dn", vtype_lookup_module, US"ldap" }, #endif { "load_average", vtype_load_avg, NULL }, { "local_part", vtype_stringptr, &deliver_localpart }, @@ -713,13 +713,13 @@ static var_entry var_table[] = { { "spam_score_int", vtype_stringptr, &spam_score_int }, #endif #ifdef EXIM_HAVE_SPF - { "spf_guess", vtype_module, US"spf" }, - { "spf_header_comment", vtype_module, US"spf" }, - { "spf_received", vtype_module, US"spf" }, - { "spf_result", vtype_module, US"spf" }, - { "spf_result_guessed", vtype_module, US"spf" }, - { "spf_smtp_comment", vtype_module, US"spf" }, - { "spf_used_domain", vtype_module, US"spf" }, + { "spf_guess", vtype_misc_module, US"spf" }, + { "spf_header_comment", vtype_misc_module, US"spf" }, + { "spf_received", vtype_misc_module, US"spf" }, + { "spf_result", vtype_misc_module, US"spf" }, + { "spf_result_guessed", vtype_misc_module, US"spf" }, + { "spf_smtp_comment", vtype_misc_module, US"spf" }, + { "spf_used_domain", vtype_misc_module, US"spf" }, #endif { "spool_directory", vtype_stringptr, &spool_directory }, { "spool_inodes", vtype_pinodes, (void *)TRUE }, @@ -2161,7 +2161,7 @@ switch (vp->type) } #endif - case vtype_module: + case vtype_misc_module: { uschar * errstr; misc_module_info * mi = misc_mod_find(val, &errstr); diff --git a/src/src/functions.h b/src/src/functions.h index b2c2626ab..57ae06c58 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -307,6 +307,8 @@ extern void log_write_die(unsigned, int, const char * format, ...) extern const lookup_info * lookup_with_acq_num(unsigned); extern gstring *lookup_dynamic_supported(gstring *); +extern const lookup_info * lookup_find(const uschar *, uschar **); +extern const lookup_info * lookup_findonly(const uschar *); #ifdef LOOKUP_MODULE_DIR extern BOOL lookup_one_mod_load(const uschar *, uschar **); #endif diff --git a/src/src/globals.c b/src/src/globals.c index e5de80ea4..4fe89f727 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -58,39 +58,6 @@ BOOL opt_perl_taintmode = FALSE; tree_node *dlobj_anchor = NULL; #endif -#ifdef LOOKUP_LDAP -uschar *eldap_ca_cert_dir = NULL; -uschar *eldap_ca_cert_file = NULL; -uschar *eldap_cert_file = NULL; -uschar *eldap_cert_key = NULL; -uschar *eldap_cipher_suite = NULL; -uschar *eldap_default_servers = NULL; -uschar *eldap_require_cert = NULL; -int eldap_version = -1; -BOOL eldap_start_tls = FALSE; -#endif - -#ifdef LOOKUP_MYSQL -uschar *mysql_servers = NULL; -#endif - -#ifdef LOOKUP_ORACLE -uschar *oracle_servers = NULL; -#endif - -#ifdef LOOKUP_PGSQL -uschar *pgsql_servers = NULL; -#endif - -#ifdef LOOKUP_REDIS -uschar *redis_servers = NULL; -#endif - -#ifdef LOOKUP_SQLITE -uschar *sqlite_dbfile = NULL; -int sqlite_lock_timeout = 5; -#endif - #ifdef SUPPORT_MOVE_FROZEN_MESSAGES BOOL move_frozen_messages = FALSE; #endif @@ -908,7 +875,6 @@ uschar *keep_environment = NULL; int keep_malformed = 4*24*60*60; /* 4 days */ -uschar *eldap_dn = NULL; const uschar *letter_digit_hyphen_dot = US"abcdefghijklmnopqrstuvwxyz" ".-0123456789" diff --git a/src/src/globals.h b/src/src/globals.h index 313062890..f8cd0548b 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -40,39 +40,6 @@ extern BOOL opt_perl_taintmode; /* Enable taint mode in Perl */ extern tree_node *dlobj_anchor; /* Tree of dynamically-loaded objects */ #endif -#ifdef LOOKUP_LDAP -extern uschar *eldap_ca_cert_dir; /* Directory with CA certificates */ -extern uschar *eldap_ca_cert_file; /* CA certificate file */ -extern uschar *eldap_cert_file; /* Certificate file */ -extern uschar *eldap_cert_key; /* Certificate key file */ -extern uschar *eldap_cipher_suite; /* Allowed cipher suite */ -extern uschar *eldap_default_servers; /* List of default servers */ -extern uschar *eldap_require_cert; /* Peer certificate checking strategy */ -extern BOOL eldap_start_tls; /* Use STARTTLS */ -extern int eldap_version; /* LDAP version */ -#endif - -#ifdef LOOKUP_MYSQL -extern uschar *mysql_servers; /* List of servers and connect info */ -#endif - -#ifdef LOOKUP_ORACLE -extern uschar *oracle_servers; /* List of servers and connect info */ -#endif - -#ifdef LOOKUP_PGSQL -extern uschar *pgsql_servers; /* List of servers and connect info */ -#endif - -#ifdef LOOKUP_REDIS -extern uschar *redis_servers; /* List of servers and connect info */ -#endif - -#ifdef LOOKUP_SQLITE -extern uschar *sqlite_dbfile; /* Filname for database */ -extern int sqlite_lock_timeout; /* Internal lock waiting timeout */ -#endif - #ifdef SUPPORT_MOVE_FROZEN_MESSAGES extern BOOL move_frozen_messages; /* Get them out of the normal directory */ #endif @@ -677,7 +644,6 @@ extern int journal_fd; /* Fd for journal file */ extern uschar *keep_environment; /* Whitelist for environment variables */ extern int keep_malformed; /* Time to keep malformed messages */ -extern uschar *eldap_dn; /* Where LDAP DNs are left */ extern const uschar *letter_digit_hyphen_dot; /* Legitimate DNS host name chars */ #ifndef DISABLE_ESMTP_LIMITS extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */ diff --git a/src/src/lookupapi.h b/src/src/lookupapi.h index b8ec17880..84f150e03 100644 --- a/src/src/lookupapi.h +++ b/src/src/lookupapi.h @@ -50,15 +50,21 @@ typedef struct lookup_info { unsigned); /* lookup type index */ gstring * (*version_report)( /* diagnostic function */ gstring *); /* string to appand to */ + + void * options; + unsigned options_count; + void * variables; + unsigned variables_count; } lookup_info; /* This magic number is used by the following lookup_module_info structure for checking API compatibility. It used to be equivalent to the string"LMM3" */ -#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4935 +#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4936 /* Version 2 adds: version_report */ /* Version 3 change: non/cache becomes TTL in seconds */ /* Version 4 add: index on quoting function */ /* Version 5 change: version report now adds to a gstring */ +/* Version 6 add: options */ typedef struct lookup_module_info { uint magic; diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 0a00633ab..06b82aa4c 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -74,6 +74,19 @@ LDAP_LIB_OPENLDAP1 SEARCH_LDAP_DN lookup). */ +static uschar * eldap_ca_cert_dir = NULL; /* Directory with CA certificates */ +static uschar * eldap_ca_cert_file = NULL; /* CA certificate file */ +static uschar * eldap_cert_file = NULL; /* Certificate file */ +static uschar * eldap_cert_key = NULL; /* Certificate key file */ +static uschar * eldap_cipher_suite = NULL; /* Allowed cipher suite */ +static uschar * eldap_default_servers = NULL; /* List of default servers */ +static uschar * eldap_require_cert = NULL; /* Peer certificate checking strategy */ +static int eldap_version = -1; /* Use STARTTLS */ +static BOOL eldap_start_tls = FALSE; /* LDAP version */ + +static uschar * eldap_dn; /* Where LDAP DNs are left */ + + /* Structure and anchor for caching connections. */ typedef struct ldap_connection { @@ -87,7 +100,7 @@ typedef struct ldap_connection { LDAP *ld; } LDAP_CONNECTION; -static LDAP_CONNECTION *ldap_connections = NULL; +static LDAP_CONNECTION * ldap_connections = NULL; @@ -1587,16 +1600,42 @@ return string_cat(g, "Library version: LDAP: (unknown)\n"); } +/******************************************************************************/ +/* Module API */ + +static optionlist eldap_options[] = { + { "ldap_ca_cert_dir", opt_stringptr, {&eldap_ca_cert_dir} }, + { "ldap_ca_cert_file", opt_stringptr, {&eldap_ca_cert_file} }, + { "ldap_cert_file", opt_stringptr, {&eldap_cert_file} }, + { "ldap_cert_key", opt_stringptr, {&eldap_cert_key} }, + { "ldap_cipher_suite", opt_stringptr, {&eldap_cipher_suite} }, + { "ldap_default_servers", opt_stringptr, {&eldap_default_servers} }, + { "ldap_require_cert", opt_stringptr, {&eldap_require_cert} }, + { "ldap_start_tls", opt_bool, {&eldap_start_tls} }, + { "ldap_version", opt_int, {&eldap_version} }, +}; + +static var_entry eldap_variables[] = { + { "ldap_dn", vtype_stringptr, &eldap_dn }, +}; + static lookup_info ldap_lookup_info = { - .name = US"ldap", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = eldap_open, /* open function */ - .check = NULL, /* check function */ - .find = eldap_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = eldap_tidy, /* tidy function */ - .quote = eldap_quote, /* quoting function */ - .version_report = ldap_version_report /* version reporting */ + .name = US"ldap", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = eldap_open, /* open function */ + .check = NULL, /* check function */ + .find = eldap_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = eldap_tidy, /* tidy function */ + .quote = eldap_quote, /* quoting function */ + .version_report = ldap_version_report, /* version reporting */ + + /* This lookup name matches the modules name, so access options here */ + .options = eldap_options, + .options_count = nelem(eldap_options), + + .variables = eldap_variables, + .variables_count = nelem(eldap_variables), }; static lookup_info ldapdn_lookup_info = { diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c index f28e9154f..dca125188 100644 --- a/src/src/lookups/mysql.c +++ b/src/src/lookups/mysql.c @@ -64,6 +64,8 @@ with versions before 10.2, as they do not define there there specific symbols. #endif +static uschar * mysql_servers = NULL; /* List of servers and connect info */ + /* Structure and anchor for caching connections. */ typedef struct mysql_connection { @@ -478,18 +480,28 @@ g = string_fmt_append(g, return g; } +/******************************************************************************/ +/* Module API */ + +static optionlist mysql_glbl_options[] = { + { "mysql_servers", opt_stringptr, {&mysql_servers} } +}; + /* These are the lookup_info blocks for this driver */ static lookup_info mysql_lookup_info = { - .name = US"mysql", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = mysql_open, /* open function */ - .check = NULL, /* no check function */ - .find = mysql_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = mysql_tidy, /* tidy function */ - .quote = mysql_quote, /* quoting function */ - .version_report = mysql_version_report /* version reporting */ + .name = US"mysql", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = mysql_open, /* open function */ + .check = NULL, /* no check function */ + .find = mysql_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = mysql_tidy, /* tidy function */ + .quote = mysql_quote, /* quoting function */ + .version_report = mysql_version_report, /* version reporting */ + + .options = mysql_glbl_options, + .options_count = nelem(mysql_glbl_options), }; #ifdef DYNLOOKUP diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c index e4eedbe28..9472fc2ff 100644 --- a/src/src/lookups/oracle.c +++ b/src/src/lookups/oracle.c @@ -69,6 +69,11 @@ typedef struct Ora_Define { ub2 col_retlen, col_retcode; } Ora_Define; + + +static uschar * oracle_servers = NULL; /* List of servers and connect info */ + + /* Structure and anchor for caching connections. */ typedef struct oracle_connection { @@ -604,16 +609,26 @@ return g; } +/******************************************************************************/ +/* Module API */ + +static optionlist oracle_options[] = { + { "oracle_servers", opt_stringptr, {&oracle_servers} } +}; + static lookup_info _lookup_info = { - .name = US"oracle", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = oracle_open, /* open function */ - .check = NULL, /* check function */ - .find = oracle_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = oracle_tidy, /* tidy function */ - .quote = oracle_quote, /* quoting function */ - .version_report = oracle_version_report /* version reporting */ + .name = US"oracle", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = oracle_open, /* open function */ + .check = NULL, /* check function */ + .find = oracle_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = oracle_tidy, /* tidy function */ + .quote = oracle_quote, /* quoting function */ + .version_report = oracle_version_report, /* version reporting */ + + .options = oracle_options, + .options_count = nelem(oracle_options), }; #ifdef DYNLOOKUP diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c index 7071cb4ab..bef6c59e2 100644 --- a/src/src/lookups/pgsql.c +++ b/src/src/lookups/pgsql.c @@ -16,6 +16,9 @@ socket extension. */ #include /* The system header */ + +static uschar * pgsql_servers = NULL; /* List of servers and connect info */ + /* Structure and anchor for caching connections. */ typedef struct pgsql_connection { @@ -490,16 +493,26 @@ return g; } +/******************************************************************************/ +/* Module API */ + +static optionlist pgsql_options[] = { + { "pgsql_servers", opt_stringptr, {&pgsql_servers} } +}; + static lookup_info _lookup_info = { - .name = US"pgsql", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = pgsql_open, /* open function */ - .check = NULL, /* no check function */ - .find = pgsql_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = pgsql_tidy, /* tidy function */ - .quote = pgsql_quote, /* quoting function */ - .version_report = pgsql_version_report /* version reporting */ + .name = US"pgsql", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = pgsql_open, /* open function */ + .check = NULL, /* no check function */ + .find = pgsql_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = pgsql_tidy, /* tidy function */ + .quote = pgsql_quote, /* quoting function */ + .version_report = pgsql_version_report, /* version reporting */ + + .options = pgsql_options, + .options_count = nelem(pgsql_options), }; #ifdef DYNLOOKUP diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index 61c264a73..e88ded154 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -15,9 +15,7 @@ #include -#ifndef nele -# define nele(arr) (sizeof(arr) / sizeof(*arr)) -#endif +static uschar * redis_servers = NULL; /* List of servers and connect info */ /* Structure and anchor for caching connections. */ typedef struct redis_connection { @@ -26,7 +24,7 @@ typedef struct redis_connection { redisContext *handle; } redis_connection; -static redis_connection *redis_connections = NULL; +static redis_connection * redis_connections = NULL; static void * @@ -210,7 +208,7 @@ if(sdata[1]) Uskip_whitespace(&s); - for (i = 0; *s && i < nele(argv); i++) + for (i = 0; *s && i < nelem(argv); i++) { gstring * g; @@ -438,17 +436,27 @@ return string_fmt_append(g, "Library version: REDIS: Compile: %d.%d.%d\n", +/******************************************************************************/ +/* Module API */ + +static optionlist redis_options[] = { + { "redis_servers", opt_stringptr, {&redis_servers} } +}; + /* These are the lookup_info blocks for this driver */ static lookup_info redis_lookup_info = { - .name = US"redis", /* lookup name */ - .type = lookup_querystyle, /* query-style lookup */ - .open = redis_open, /* open function */ - .check = NULL, /* no check function */ - .find = redis_find, /* find function */ - .close = NULL, /* no close function */ - .tidy = redis_tidy, /* tidy function */ - .quote = redis_quote, /* quoting function */ - .version_report = redis_version_report /* version reporting */ + .name = US"redis", /* lookup name */ + .type = lookup_querystyle, /* query-style lookup */ + .open = redis_open, /* open function */ + .check = NULL, /* no check function */ + .find = redis_find, /* find function */ + .close = NULL, /* no close function */ + .tidy = redis_tidy, /* tidy function */ + .quote = redis_quote, /* quoting function */ + .version_report = redis_version_report, /* version reporting */ + + .options = redis_options, + .options_count = nelem(redis_options), }; #ifdef DYNLOOKUP diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index eb23b8631..c91440e1e 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -12,6 +12,9 @@ #include +static uschar * sqlite_dbfile = NULL; /* Filename for database */ +static int sqlite_lock_timeout = 5;/* Internal lock waiting timeout */ + /************************************************* * Open entry point * @@ -173,20 +176,31 @@ g = string_fmt_append(g, return g; } +/******************************************************************************/ +/* Module API */ + +static optionlist sqlite_options[] = { + { "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} }, + { "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} }, +}; + static lookup_info _lookup_info = { - .name = US"sqlite", /* lookup name */ - .type = lookup_absfilequery, /* query-style lookup, starts with file name */ - .open = sqlite_open, /* open function */ - .check = NULL, /* no check function */ - .find = sqlite_find, /* find function */ - .close = sqlite_close, /* close function */ - .tidy = NULL, /* no tidy function */ - .quote = sqlite_quote, /* quoting function */ - .version_report = sqlite_version_report /* version reporting */ + .name = US"sqlite", /* lookup name */ + .type = lookup_absfilequery, /* query-style lookup, starts with file name */ + .open = sqlite_open, /* open function */ + .check = NULL, /* no check function */ + .find = sqlite_find, /* find function */ + .close = sqlite_close, /* close function */ + .tidy = NULL, /* no tidy function */ + .quote = sqlite_quote, /* quoting function */ + .version_report = sqlite_version_report, /* version reporting */ + + .options = sqlite_options, + .options_count = nelem(sqlite_options), }; #ifdef DYNLOOKUP -#define sqlite_lookup_module_info _lookup_module_info +# define sqlite_lookup_module_info _lookup_module_info #endif static lookup_info *_lookup_list[] = { &_lookup_info }; diff --git a/src/src/macros.h b/src/src/macros.h index 0070ef7ed..f6b240322 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -707,7 +707,8 @@ can be easily tested as a group. That is the only use of opt_bool_last. */ enum { opt_bit = 32, opt_bool_verify, opt_bool_set, opt_expand_bool, opt_bool_last, opt_rewrite, opt_timelist, opt_uid, opt_gid, opt_uidlist, opt_gidlist, - opt_expand_uid, opt_expand_gid, opt_func, opt_void, opt_module }; + opt_expand_uid, opt_expand_gid, opt_func, opt_void, + opt_lookup_module, opt_misc_module }; /* There's a high-ish bit which is used to flag duplicate options, kept for compatibility, which shouldn't be output. Also used for hidden options diff --git a/src/src/readconf.c b/src/src/readconf.c index 417a786e3..46adac621 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -47,7 +47,7 @@ static optionlist optionlist_config[] = { { "acl_smtp_data_prdr", opt_stringptr, {&acl_smtp_data_prdr} }, #endif #ifndef DISABLE_DKIM - { "acl_smtp_dkim", opt_module, {US"dkim"} }, + { "acl_smtp_dkim", opt_misc_module, {US"dkim"} }, #endif { "acl_smtp_etrn", opt_stringptr, {&acl_smtp_etrn} }, { "acl_smtp_expn", opt_stringptr, {&acl_smtp_expn} }, @@ -118,16 +118,16 @@ static optionlist optionlist_config[] = { #endif { "disable_ipv6", opt_bool, {&disable_ipv6} }, #ifndef DISABLE_DKIM - { "dkim_verify_hashes", opt_module, {US"dkim"} }, - { "dkim_verify_keytypes", opt_module, {US"dkim"} }, - { "dkim_verify_min_keysizes", opt_module, {US"dkim"} }, - { "dkim_verify_minimal", opt_module, {US"dkim"} }, - { "dkim_verify_signers", opt_module, {US"dkim"} }, + { "dkim_verify_hashes", opt_misc_module, {US"dkim"} }, + { "dkim_verify_keytypes", opt_misc_module, {US"dkim"} }, + { "dkim_verify_min_keysizes", opt_misc_module, {US"dkim"} }, + { "dkim_verify_minimal", opt_misc_module, {US"dkim"} }, + { "dkim_verify_signers", opt_misc_module, {US"dkim"} }, #endif #ifdef EXIM_HAVE_DMARC - { "dmarc_forensic_sender", opt_module, {US"dmarc"} }, - { "dmarc_history_file", opt_module, {US"dmarc"} }, - { "dmarc_tld_file", opt_module, {US"dmarc"} }, + { "dmarc_forensic_sender", opt_misc_module, {US"dmarc"} }, + { "dmarc_history_file", opt_misc_module, {US"dmarc"} }, + { "dmarc_tld_file", opt_misc_module, {US"dmarc"} }, #endif { "dns_again_means_nonexist", opt_stringptr, {&dns_again_means_nonexist} }, { "dns_check_names_pattern", opt_stringptr, {&check_dns_names_pattern} }, @@ -192,15 +192,15 @@ static optionlist optionlist_config[] = { { "keep_environment", opt_stringptr, {&keep_environment} }, { "keep_malformed", opt_time, {&keep_malformed} }, #ifdef LOOKUP_LDAP - { "ldap_ca_cert_dir", opt_stringptr, {&eldap_ca_cert_dir} }, - { "ldap_ca_cert_file", opt_stringptr, {&eldap_ca_cert_file} }, - { "ldap_cert_file", opt_stringptr, {&eldap_cert_file} }, - { "ldap_cert_key", opt_stringptr, {&eldap_cert_key} }, - { "ldap_cipher_suite", opt_stringptr, {&eldap_cipher_suite} }, - { "ldap_default_servers", opt_stringptr, {&eldap_default_servers} }, - { "ldap_require_cert", opt_stringptr, {&eldap_require_cert} }, - { "ldap_start_tls", opt_bool, {&eldap_start_tls} }, - { "ldap_version", opt_int, {&eldap_version} }, + { "ldap_ca_cert_dir", opt_lookup_module, {US"ldap"} }, + { "ldap_ca_cert_file", opt_lookup_module, {US"ldap"} }, + { "ldap_cert_file", opt_lookup_module, {US"ldap"} }, + { "ldap_cert_key", opt_lookup_module, {US"ldap"} }, + { "ldap_cipher_suite", opt_lookup_module, {US"ldap"} }, + { "ldap_default_servers", opt_lookup_module, {US"ldap"} }, + { "ldap_require_cert", opt_lookup_module, {US"ldap"} }, + { "ldap_start_tls", opt_lookup_module, {US"ldap"} }, + { "ldap_version", opt_lookup_module, {US"ldap"} }, #endif #ifndef DISABLE_ESMTP_LIMITS { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} }, @@ -231,7 +231,7 @@ static optionlist optionlist_config[] = { #endif { "mua_wrapper", opt_bool, {&mua_wrapper} }, #ifdef LOOKUP_MYSQL - { "mysql_servers", opt_stringptr, {&mysql_servers} }, + { "mysql_servers", opt_lookup_module, {US"mysql"} }, #endif { "never_users", opt_uidlist, {&never_users} }, { "notifier_socket", opt_stringptr, {¬ifier_socket} }, @@ -239,7 +239,7 @@ static optionlist optionlist_config[] = { { "openssl_options", opt_stringptr, {&openssl_options} }, #endif #ifdef LOOKUP_ORACLE - { "oracle_servers", opt_stringptr, {&oracle_servers} }, + { "oracle_servers", opt_lookup_module, {US"oracle"} }, #endif { "panic_coredump", opt_bool, {&panic_coredump} }, { "percent_hack_domains", opt_stringptr, {&percent_hack_domains} }, @@ -249,7 +249,7 @@ static optionlist optionlist_config[] = { { "perl_taintmode", opt_bool, {&opt_perl_taintmode} }, #endif #ifdef LOOKUP_PGSQL - { "pgsql_servers", opt_stringptr, {&pgsql_servers} }, + { "pgsql_servers", opt_lookup_module, {US"pgsql"} }, #endif { "pid_file_path", opt_stringptr, {&pid_file_path} }, { "pipelining_advertise_hosts", opt_stringptr, {&pipelining_advertise_hosts} }, @@ -290,7 +290,7 @@ static optionlist optionlist_config[] = { { "recipients_max", opt_stringptr, {&recipients_max} }, { "recipients_max_reject", opt_bool, {&recipients_max_reject} }, #ifdef LOOKUP_REDIS - { "redis_servers", opt_stringptr, {&redis_servers} }, + { "redis_servers", opt_lookup_module, {US"redis"} }, #endif { "remote_max_parallel", opt_int, {&remote_max_parallel} }, { "remote_sort_domains", opt_stringptr, {&remote_sort_domains} }, @@ -336,15 +336,15 @@ static optionlist optionlist_config[] = { { "spamd_address", opt_stringptr, {&spamd_address} }, #endif #ifdef EXIM_HAVE_SPF - { "spf_guess", opt_module, {US"spf"} }, - { "spf_smtp_comment_template",opt_module, {US"spf"} }, + { "spf_guess", opt_misc_module, {US"spf"} }, + { "spf_smtp_comment_template",opt_misc_module, {US"spf"} }, #endif { "split_spool_directory", opt_bool, {&split_spool_directory} }, { "spool_directory", opt_stringptr, {&spool_directory} }, { "spool_wireformat", opt_bool, {&spool_wireformat} }, #ifdef LOOKUP_SQLITE - { "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} }, - { "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} }, + { "sqlite_dbfile", opt_lookup_module, {US"sqlite"} }, + { "sqlite_lock_timeout", opt_lookup_module, {US"sqlite"} }, #endif { "strict_acl_vars", opt_bool, {&strict_acl_vars} }, { "strip_excess_angle_brackets", opt_bool, {&strip_excess_angle_brackets} }, @@ -1762,13 +1762,10 @@ Returns: TRUE if an option was read successfully, */ static BOOL -readconf_handle_option(uschar *buffer, optionlist *oltop, int last, - void *data_block, uschar *unknown_txt) +readconf_handle_option(uschar * buffer, optionlist * oltop, int last, + void * data_block, uschar * unknown_txt) { -int ptr; -int offset = 0; -int count, type, value; -int issecure = 0; +int ptr, offset = 0, count, type, value, issecure = 0; uid_t uid; gid_t gid; BOOL boolvalue = TRUE; @@ -2507,10 +2504,23 @@ switch (type) ol->v.fn(name, s, 0); break; - case opt_module: + case opt_lookup_module: { uschar * errstr; - misc_module_info * mi = misc_mod_find(US ol->v.value, &errstr); + const lookup_info * li = lookup_find(US ol->v.value, &errstr); + if (!li) + log_write_die(0, LOG_CONFIG_IN, + "failed to find %s module for %s: %s", US ol->v.value, name, errstr); + + oltop = li->options; + last = li->options_count; + goto sublist; + } + + case opt_misc_module: + { + uschar * errstr; + const misc_module_info * mi = misc_mod_find(US ol->v.value, &errstr); if (!mi) log_write_die(0, LOG_CONFIG_IN, "failed to find %s module for %s: %s", US ol->v.value, name, errstr); diff --git a/src/src/search.c b/src/src/search.c index e09f3ab4e..e81806379 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -54,8 +54,8 @@ static rmark search_reset_point = NULL; * Validate a plain lookup type name * *************************************************/ -static const lookup_info * -internal_search_findtype(const uschar * name) +const lookup_info * +lookup_findonly(const uschar * name) { tree_node * t = tree_search(lookups_tree, name); return t ? t->data.ptr : NULL; @@ -81,7 +81,7 @@ const lookup_info * li; if (name[len]) name = string_copyn(name, len); -if ((li = internal_search_findtype(name))) +if ((li = lookup_findonly(name))) return li; #ifdef LOOKUP_MODULE_DIR @@ -89,7 +89,7 @@ if ((li = internal_search_findtype(name))) debug_printf_indent("searchtype %s not initially found\n", name); if (lookup_one_mod_load(name, NULL)) - if ((li = internal_search_findtype(name))) + if ((li = lookup_findonly(name))) return li; else { DEBUG(D_lookup) debug_printf_indent("find retry failed\n"); } diff --git a/src/src/structs.h b/src/src/structs.h index 22a4bba90..52b540356 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -1012,7 +1012,8 @@ enum vtypes { #ifndef DISABLE_DKIM vtype_dkim, /* Lookup of value in DKIM signature */ #endif - vtype_module, /* variable lives in a module; value is module name */ + vtype_lookup_module, /* variable lives in a module; value is module name */ + vtype_misc_module, /* variable lives in a module; value is module name */ }; /* Type for main variable table */ commit d6c8c56fd08000ea9da90d4cf506870a6a7e205b Author: Jeremy Harris Date: Wed Dec 24 14:18:00 2025 +0000 Docs: build note diff --git a/src/src/EDITME b/src/src/EDITME index f641a6699..ec187e919 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -751,6 +751,8 @@ DISABLE_MAL_MKS=yes # sqlite # USE_SQLITE = yes # DBMLIB = -lsqlite3 +# If using Gnu Make this is usable: +# DBMLIB = $(shell pkg-config --libs sqlite3) #------------------------------------------------------------------------------ commit 928e43f00d3b88e2684fdd530545932895ef684b Author: Jeremy Harris Date: Wed Dec 24 14:51:36 2025 +0000 Fix non-LOOKUP_MODULE_DIR build Broken-by: b3881e820e87 diff --git a/src/src/drtables.c b/src/src/drtables.c index 20034e7ce..21c9feb60 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -214,9 +214,11 @@ return TRUE; const lookup_info * lookup_find(const uschar * name, uschar ** errstr) { +#ifdef LOOKUP_MODULE_DIR const lookup_info * li; if ((li = lookup_findonly(name))) return li; lookup_mod_load(name, errstr); +#endif return lookup_findonly(name); } commit a87bd5b303e01724fa4cec576a5d824186a8074c Author: Jeremy Harris Date: Thu Dec 25 09:16:09 2025 +0000 daemon_modules_preload option diff --git a/src/src/daemon.c b/src/src/daemon.c index 056bf6311..e8432196c 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1667,6 +1667,21 @@ return string_from_gstring(g); } + +static void +daemon_preload_modules(void) +{ +#ifdef LOOKUP_MODULE_DIR +uschar namebuf[32]; +const uschar * list = daemon_modules_load, * ele; +int sep = 0; + +while (ele = string_nextinlist(&list, &sep, namebuf, sizeof(namebuf))) + mod_load_anyclass(ele); +#endif +} + + /************************************************* * Exim Daemon Mainline * *************************************************/ @@ -1733,6 +1748,10 @@ debugging lines get the pid added. */ DEBUG(D_any|D_v) debug_selector |= D_pid; +/* Get any requested dynamic-load modules loaded */ + +daemon_preload_modules(); + /* Allocate enough pollstructs for inetd mode plus the ancillary sockets; also used when there are no listen sockets. */ diff --git a/src/src/drtables.c b/src/src/drtables.c index 21c9feb60..ec2c4c33a 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -209,6 +209,35 @@ if (!lookup_mod_load(name, errstr)) return FALSE; return TRUE; } + +/* Try to load a module of any class, given just the name. +This is used for the daemon_modules_load option. +Do not bother with class auth,router,transport - readconf will load if used. +*/ + +void +mod_load_anyclass(const uschar * name) +{ +DIR * dd; +const pcre2_code * regex_class; + +/* Find the class for this name, by checking the lookup modules dir. +We assume the .so files there are properly worded, and that the names +are distinct. */ + +if (!(dd = open_module_dir())) return; + +regex_class = regex_must_compile( + string_sprintf("^%s_(lookup|miscmod)\\." DYNLIB_FN_EXT "$", name), + MCS_NOFLAGS, TRUE); + +for (struct dirent * ent; ent = readdir(dd); ) + if (regex_match_and_setup(regex_class, US ent->d_name, 0, 0)) + if (Ustrcmp(expand_nstring[1], "miscmod") == 0) + (void) misc_mod_find(name, NULL); + else /* assume "lookup" */ + if (!tree_search(lookups_tree, name)) lookup_one_mod_load(name, NULL); +} #endif /*LOOKUP_MODULE_DIR*/ const lookup_info * @@ -303,7 +332,7 @@ const char * errormsg; EARLY_DEBUG(D_any, "Loading module %q\n", name); if (!(dl = mod_open(name, US"miscmod", errstr))) { - if (errstr) EARLY_DEBUG(D_any, " mod_open: %s\n", *errstr); + if (errstr && *errstr) EARLY_DEBUG(D_any, " mod_open: %s\n", *errstr); return NULL; } diff --git a/src/src/exim.c b/src/src/exim.c index 8c5089f7b..7e90e927c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1756,10 +1756,6 @@ len = Ustrlen(big_buffer); (void) macros_expand(0, &len, ¯o_found); -#ifdef LOOKUP_MODULE_DIR -//mod_load_check(big_buffer); -#endif - if (isupper(big_buffer[0]) && !(macro_found & MACRO_FIRST)) { if (macro_read_assignment(big_buffer)) diff --git a/src/src/functions.h b/src/src/functions.h index 57ae06c58..fd6cab0d5 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -376,7 +376,7 @@ extern BOOL moan_to_sender(int, const error_block *, const header_line *, extern void moan_write_from(FILE *); extern void moan_write_references(FILE *, uschar *); #ifdef LOOKUP_MODULE_DIR -//extern void mod_load_check(const uschar *); +extern void mod_load_anyclass(const uschar *); #endif extern void mod_names(FILE *); extern FILE *modefopen(const uschar *, const char *, mode_t); diff --git a/src/src/globals.c b/src/src/globals.c index 4fe89f727..2b2270899 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -639,6 +639,7 @@ cut_t cutthrough = { /* All remaining items 0/FALSE/NULL */ .cctx = {.sock = -1}, /* open connection */ }; +uschar *daemon_modules_load = NULL; int daemon_notifier_fd = -1; uschar *daemon_smtp_port = US"smtp"; int daemon_startup_retries = 9; diff --git a/src/src/globals.h b/src/src/globals.h index f8cd0548b..befaf308b 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -461,6 +461,7 @@ typedef struct { } cut_t; extern cut_t cutthrough; /* Deliver-concurrently */ +extern uschar *daemon_modules_load; /* Dyn-load modules to preload */ extern int daemon_notifier_fd; /* Unix socket for notifications */ extern uschar *daemon_smtp_port; /* Can be a list of ports */ extern int daemon_startup_retries; /* Number of times to retry */ diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c index 4778ace64..59894cbb3 100644 --- a/src/src/macro_predef.c +++ b/src/src/macro_predef.c @@ -385,6 +385,7 @@ avail_list(drtable, tag, US"static", FALSE); avail_list(drtable, tag, US"dynamic", TRUE); } +/* Make lists of the drivers (by class, and static/dynamic) we are building */ static void avail(void) { diff --git a/src/src/readconf.c b/src/src/readconf.c index 46adac621..356321765 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -98,6 +98,7 @@ static optionlist optionlist_config[] = { { "check_spool_space", opt_Kint, {&check_spool_space} }, { "chunking_advertise_hosts", opt_stringptr, {&chunking_advertise_hosts} }, { "commandline_checks_require_admin", opt_bool,{&commandline_checks_require_admin} }, + { "daemon_modules_load", opt_stringptr, {&daemon_modules_load} }, { "daemon_smtp_port", opt_stringptr|opt_hidden, {&daemon_smtp_port} }, { "daemon_smtp_ports", opt_stringptr, {&daemon_smtp_port} }, { "daemon_startup_retries", opt_int, {&daemon_startup_retries} }, @@ -1290,12 +1291,6 @@ if (strncmpic(s, US"begin ", 6) == 0) return NULL; } -#ifdef LOOKUP_MODULE_DIR -/* Check for any required module load operations */ - -//mod_load_check(s); -#endif - /* Return the first non-blank character. */ return s; @@ -4420,9 +4415,9 @@ store_pool = POOL_PERM; } store_pool = old_pool; -/* Read the config file "authenticators" section, creating an auth instance list. -For any yet-undiscovered driver, check for a loadable module and add it to -those available. */ +/* Read the config file "authenticators" section, creating an auth instance +list. For any yet-undiscovered driver, check for a loadable module and add it +to those available. */ readconf_driver_init((driver_instance **)&auths, /* chain anchor */ (driver_info **)&auths_available, /* available drivers */ commit 71f1ce17a7ceda7ec778b84188d74419ab082e1e Author: Jeremy Harris Date: Fri Dec 26 14:10:30 2025 +0000 constify diff --git a/src/src/expand.c b/src/src/expand.c index ab0c0b37a..23ae31baa 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2227,8 +2227,9 @@ Returns: -1 OK; string pointer updated, but in "skipping" mode */ static int -read_subs(uschar ** sub, int n, int m, const uschar ** sptr, esi_flags flags, - BOOL check_end, uschar * name, BOOL * resetok, unsigned * textonly_p) +read_subs(const uschar ** sub, int n, int m, const uschar ** sptr, + esi_flags flags, BOOL check_end, uschar * name, + BOOL * resetok, unsigned * textonly_p) { const uschar * s = *sptr; unsigned textonly_l = 0; @@ -2864,7 +2865,7 @@ switch(cond_type = identify_operator(&s, &opname)) Uskip_whitespace(&s); if (*s++ != '{') goto COND_FAILED_CURLY_START; /*}*/ - switch(read_subs(sub, nelem(sub), 1, &s, + switch(read_subs(CUSS sub, nelem(sub), 1, &s, yield ? ESI_NOFLAGS : ESI_SKIPPING, TRUE, name, resetok, NULL)) { case 1: expand_string_message = US"too few arguments or bracketing " @@ -2913,7 +2914,7 @@ switch(cond_type = identify_operator(&s, &opname)) goto COND_FAILED_NOT_COMPILED; #else { - uschar *sub[4]; + const uschar * sub[4]; Uskip_whitespace(&s); if (*s++ != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */ switch(read_subs(sub, nelem(sub), 2, &s, @@ -3521,15 +3522,15 @@ switch(cond_type = identify_operator(&s, &opname)) case ECOND_BOOL: case ECOND_BOOL_LAX: { - uschar *sub_arg[1]; - uschar *t, *t2; + uschar * sub_arg[1]; + uschar * t, * t2; uschar *ourname; size_t len; BOOL boolvalue = FALSE; if (Uskip_whitespace(&s) != '{') goto COND_FAILED_CURLY_START; /* }-for-text-editors */ ourname = cond_type == ECOND_BOOL_LAX ? US"bool_lax" : US"bool"; - switch(read_subs(sub_arg, 1, 1, &s, + switch(read_subs(CUSS sub_arg, 1, 1, &s, yield ? ESI_NOFLAGS : ESI_SKIPPING, FALSE, ourname, resetok, NULL)) { case 1: expand_string_message = string_sprintf( @@ -3590,7 +3591,7 @@ switch(cond_type = identify_operator(&s, &opname)) case ECOND_INBOUND_SRS: /* ${if inbound_srs {local_part}{secret} {yes}{no}} */ { - uschar * sub[2]; + const uschar * sub[2]; const pcre2_code * re; pcre2_match_data * md; PCRE2_SIZE * ovec; @@ -3622,7 +3623,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (sub[0][0] == '"') quoting = 1; - else for (uschar * s = sub[0]; *s; s++) + else for (const uschar * s = sub[0]; *s; s++) if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL) { quoting = 1; break; } if (quoting) @@ -5023,7 +5024,7 @@ while (*s) /* known to be untainted */ uschar * user_msg; int rc; - switch(read_subs(sub, nelem(sub), 1, &s, flags, TRUE, name, &resetok, NULL)) + switch(read_subs(CUSS sub, nelem(sub), 1, &s, flags, TRUE, name, &resetok, NULL)) { case -1: continue; /* skipping */ case 1: goto EXPAND_FAILED_CURLY; @@ -5056,7 +5057,7 @@ while (*s) /* known to be untainted */ case EITEM_AUTHRESULTS: /* ${authresults {mysystemname}} */ { - uschar * sub_arg[1]; + const uschar * sub_arg[1]; switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, flags, TRUE, name, &resetok, NULL)) { @@ -5131,8 +5132,7 @@ while (*s) /* known to be untainted */ #ifdef SUPPORT_I18N case EITEM_IMAPFOLDER: { /* ${imapfolder {name}{sep}{specials}} */ - uschar * sub_arg[3]; - const uschar * encoded; + const uschar * sub_arg[3], * encoded; switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, flags, TRUE, name, &resetok, NULL)) { @@ -5357,7 +5357,7 @@ while (*s) /* known to be untainted */ #else /* EXIM_PERL */ { - uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2]; + const uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2]; gstring * new_yield; const misc_module_info * mi; @@ -5386,10 +5386,10 @@ while (*s) /* known to be untainted */ sub_arg[EXIM_PERL_MAX_ARGS + 1] = NULL; { typedef gstring * (*fn_t) - (gstring *, uschar **, uschar *, const uschar **); + (gstring *, uschar **, const uschar *, const uschar **); new_yield = (((fn_t *) mi->functions)[PERL_CAT]) (yield, &expand_string_message, - sub_arg[0], CUSS sub_arg + 1); + sub_arg[0], sub_arg + 1); } /* NULL yield indicates failure; if the message pointer has been set to @@ -5425,7 +5425,7 @@ while (*s) /* known to be untainted */ uschar * sub_arg[3], * domain; const uschar * p; - switch(read_subs(sub_arg, 3, 2, &s, flags, TRUE, name, &resetok, NULL)) + switch(read_subs(CUSS sub_arg, 3, 2, &s, flags, TRUE, name, &resetok, NULL)) { case -1: continue; /* If skipping, we don't actually do anything */ case 1: goto EXPAND_FAILED_CURLY; @@ -5477,7 +5477,7 @@ while (*s) /* known to be untainted */ case EITEM_PRVSCHECK: { - uschar * sub_arg[3], * p; + const uschar * sub_arg[3], * p; gstring * g; const pcre2_code * re; @@ -5612,7 +5612,7 @@ while (*s) /* known to be untainted */ case EITEM_READFILE: { FILE * f; - uschar * sub_arg[2]; + const uschar * sub_arg[2]; if (expand_forbid & RDO_READFILE) { @@ -5647,7 +5647,7 @@ while (*s) /* known to be untainted */ case EITEM_READSOCK: { const uschar * arg; - uschar * sub_arg[4]; + const uschar * sub_arg[4]; if (expand_forbid & RDO_READSOCK) { @@ -5947,7 +5947,7 @@ while (*s) /* known to be untainted */ { int oldptr = gstring_length(yield); int o2m; - uschar * sub[3]; + const uschar * sub[3]; switch(read_subs(sub, 3, 3, &s, flags, TRUE, name, &resetok, NULL)) { @@ -5989,7 +5989,7 @@ while (*s) /* known to be untainted */ Ensure that sub[2] is set in the ${length } case. */ sub[2] = NULL; - switch(read_subs(sub, item_type == EITEM_LENGTH ? 2:3, 2, &s, flags, + switch(read_subs(CUSS sub, item_type == EITEM_LENGTH ? 2:3, 2, &s, flags, TRUE, name, &resetok, NULL)) { case -1: continue; /* skipping */ @@ -6056,14 +6056,15 @@ while (*s) /* known to be untainted */ case EITEM_HMAC: { - uschar * sub[3]; + const uschar * sub[3]; md5 md5_base; hctx sha1_ctx; void * use_base; int type; int hashlen; /* Number of octets for the hash algorithm's output */ int hashblocklen; /* Number of octets the hash algorithm processes */ - uschar * keyptr, * p; + const uschar * keyptr; + uschar * p; unsigned int keylen; uschar keyhash[MAX_HASHLEN]; @@ -6162,7 +6163,7 @@ while (*s) /* known to be untainted */ int moffset, moffsetextra, slen; pcre2_match_data * md; int emptyopt; - uschar * subject, * sub[3]; + const uschar * subject, * sub[3]; int save_expand_nmax = save_expand_strings(save_expand_nstring, save_expand_nlength); unsigned sub_textonly = 0; @@ -6617,7 +6618,7 @@ while (*s) /* known to be untainted */ case EITEM_LISTQUOTE: { - uschar * sub[2]; + const uschar * sub[2]; switch(read_subs(sub, 2, 2, &s, flags, TRUE, name, &resetok, NULL)) { case -1: continue; /* skipping */ @@ -7130,7 +7131,7 @@ while (*s) /* known to be untainted */ goto EXPAND_FAILED; } - switch(read_subs(argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, flags, + switch(read_subs(CUSS argv, EXPAND_DLFUNC_MAX_ARGS + 2, 2, &s, flags, TRUE, name, &resetok, NULL)) { case -1: continue; /* skipping */ @@ -7235,7 +7236,7 @@ while (*s) /* known to be untainted */ case EITEM_SRS_ENCODE: /* ${srs_encode {secret} {return_path} {orig_domain}} */ { - uschar * sub[3]; + const uschar * sub[3]; uschar cksum[4]; gstring * g = NULL; BOOL quoted = FALSE; diff --git a/src/src/functions.h b/src/src/functions.h index fd6cab0d5..9d4201a7b 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -279,8 +279,8 @@ extern int host_nmtoa(int, const int *, int, uschar *, int); extern uschar *host_ntoa(int, const void *, uschar *, int *); extern int host_scan_for_local_hosts(host_item *, host_item **, BOOL *); -extern uschar *imap_utf7_encode(uschar *, const uschar *, - uschar, uschar *, uschar **); +extern const uschar *imap_utf7_encode(const uschar *, const uschar *, + uschar, const uschar *, uschar **); extern void invert_address(uschar *, uschar *); extern int ip_addr(void *, int, const uschar *, int); diff --git a/src/src/imap_utf7.c b/src/src/imap_utf7.c index 09a32e689..a1abec7a0 100644 --- a/src/src/imap_utf7.c +++ b/src/src/imap_utf7.c @@ -11,14 +11,14 @@ #ifdef SUPPORT_I18N -uschar * -imap_utf7_encode(uschar *string, const uschar *charset, uschar sep, - uschar *specials, uschar **error) +const uschar * +imap_utf7_encode(const uschar * string, const uschar * charset, uschar sep, + const uschar * specials, uschar ** error) { static uschar encode_base64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; size_t slen; -uschar *sptr; +const uschar * sptr; gstring * yield = NULL; int i = 0; /* compiler quietening */ uschar c = 0; /* compiler quietening */ @@ -26,7 +26,7 @@ BOOL base64mode = FALSE; BOOL lastsep = FALSE; uschar utf16buf[256]; uschar *utf16ptr; -uschar *s; +const uschar * s; uschar outbuf[256]; uschar *outptr = outbuf; #if HAVE_ICONV diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index 5877d3dea..c94836f0b 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -275,7 +275,7 @@ yield string */ static gstring * call_perl_cat(gstring * yield, uschar ** errstrp, - uschar * name, const uschar ** arg) + const uschar * name, const uschar ** arg) { dSP; SV * sv; @@ -294,7 +294,7 @@ SAVETMPS; PUSHMARK(SP); while (*arg) XPUSHs(newSVpv(CCS (*arg++), 0)); PUTBACK; -items = perl_call_pv(CS name, G_SCALAR|G_EVAL); +items = perl_call_pv(CS string_copy(name), G_SCALAR|G_EVAL); items = items; /* stupid compiler quietening */ SPAGAIN; sv = POPs; commit e38b380adcf53f4f9771d0e1444afb1f4b79a801 Author: Jeremy Harris Date: Fri Dec 26 14:25:51 2025 +0000 func prototypes diff --git a/src/exim_monitor/em_TextPop.c b/src/exim_monitor/em_TextPop.c index 83f4cf514..c58d8bf71 100644 --- a/src/exim_monitor/em_TextPop.c +++ b/src/exim_monitor/em_TextPop.c @@ -136,11 +136,8 @@ static char search_text_trans[] = /* ARGSUSED */ void -_XawTextDoSearchAction(w, event, params, num_params) -Widget w; -XEvent *event; -String * params; -Cardinal * num_params; +_XawTextDoSearchAction(Widget w, XEvent * event, String * params, + Cardinal * num_params) { TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w))); Boolean popdown = FALSE; @@ -162,11 +159,8 @@ Cardinal * num_params; /* ARGSUSED */ void -_XawTextPopdownSearchAction(w, event, params, num_params) -Widget w; -XEvent *event; -String * params; -Cardinal * num_params; +_XawTextPopdownSearchAction(Widget w, XEvent * event, String * params, + Cardinal * num_params) { TextWidget tw = (TextWidget) XtParent(XtParent(XtParent(w))); @@ -183,10 +177,7 @@ Cardinal * num_params; /* ARGSUSED */ static void -PopdownSearch(w, closure, call_data) -Widget w; -XtPointer closure; -XtPointer call_data; +PopdownSearch(Widget w, XtPointer closure, XtPointer call_data) { struct SearchAndReplace * search = (struct SearchAndReplace *) closure; @@ -204,10 +195,7 @@ XtPointer call_data; /* ARGSUSED */ static void -SearchButton(w, closure, call_data) -Widget w; -XtPointer closure; -XtPointer call_data; +SearchButton(Widget w, XtPointer closure, XtPointer call_data) { (void) DoSearch( (struct SearchAndReplace *) closure ); } @@ -235,11 +223,7 @@ XtPointer call_data; #define SEARCH_HEADER ("Text Widget - Search():") void -_XawTextSearch(w, event, params, num_params) -Widget w; -XEvent *event; -String * params; -Cardinal * num_params; +_XawTextSearch(Widget w, XEvent *event, String * params, Cardinal * num_params) { TextWidget ctx = (TextWidget)w; XawTextScanDirection dir; @@ -337,9 +321,7 @@ replace_active = replace_active; /* PH - shuts compilers up */ */ static void -AddSearchChildren(form, ptr, tw) -Widget form, tw; -char * ptr; +AddSearchChildren(Widget form, char * ptr, Widget tw) { Arg args[10]; Cardinal num_args; @@ -455,8 +437,7 @@ char * ptr; /* ARGSUSED */ static Boolean -DoSearch(search) -struct SearchAndReplace * search; +DoSearch(struct SearchAndReplace * search) { char msg[BUFSIZ]; Widget tw = XtParent(search->search_popup); @@ -530,10 +511,7 @@ msg2 = msg2; /* PH - shuts compilers up */ */ static void -SetResource(w, res_name, value) -Widget w; -char * res_name; -XtArgVal value; +SetResource(Widget w, char * res_name, XtArgVal value) { Arg args[1]; @@ -548,8 +526,7 @@ XtArgVal value; */ static String -GetString(text) -Widget text; +GetString(Widget text) { String string; Arg args[1]; @@ -570,9 +547,7 @@ Widget text; */ static void -CenterWidgetOnPoint(w, event) -Widget w; -XEvent *event; +CenterWidgetOnPoint(Widget w, XEvent *event) { Arg args[3]; Cardinal num_args; @@ -668,8 +643,7 @@ CreateDialog(Widget parent, String ptr, String name, */ static Widget -GetShell(w) -Widget w; +GetShell(Widget w) { while ((w != NULL) && !XtIsShell(w)) w = XtParent(w); @@ -677,14 +651,7 @@ Widget w; return (w); } -/* Add proper prototype to keep IRIX 6 compiler happy. PH */ - -static Boolean InParams(String, String *, Cardinal); - -static Boolean InParams(str, p, n) - String str; - String *p; - Cardinal n; +static Boolean InParams(String str, String *p, Cardinal n) { int i; for (i=0; i < n; p++, i++) @@ -694,11 +661,11 @@ static Boolean InParams(str, p, n) static char *WM_DELETE_WINDOW = "WM_DELETE_WINDOW"; -static void WMProtocols(w, event, params, num_params) - Widget w; /* popup shell */ - XEvent *event; - String *params; - Cardinal *num_params; +static void WMProtocols( + Widget w, /* popup shell */ + XEvent *event, + String *params, + Cardinal *num_params) { Atom wm_delete_window; Atom wm_protocols; @@ -730,8 +697,8 @@ static void WMProtocols(w, event, params, num_params) } } -static void SetWMProtocolTranslations(w) - Widget w; /* realized popup shell */ +static void SetWMProtocolTranslations( + Widget w) /* realized popup shell */ { int i; XtAppContext app_context; commit 84030909c23fbdd6aabcd38b6853d6097f33982d Author: Bernard Quatermass Date: Fri Dec 26 15:29:40 2025 +0000 last push to github commit d06324cdd0ee9fc3180810bc5e818da715f0be23 Author: Bernard Quatermass Date: Fri Dec 26 15:31:18 2025 +0000 Readme.pod removed in favour of up-to-date README.md commit af14bc8cf9b19e8a53131c209d6cff2b82d6b476 Author: Jeremy Harris Date: Sat Dec 27 15:47:45 2025 +0000 string-handling: insert space for empty item when building stringlist diff --git a/src/src/string.c b/src/src/string.c index 6be0b7678..b37606cf3 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1060,7 +1060,7 @@ return NULL; ************************************************/ /* This function is used to build a list, returning an allocated null-terminated growable string. The given element has any embedded separator characters -doubled. +doubled. A zero-length element results in a single space addition. Despite having the same growable-string interface as string_cat() the list is always returned null-terminated. @@ -1082,13 +1082,18 @@ uschar * sp; if (list && list->ptr) list = string_catn(list, &sep, 1); -while((sp = Ustrchr(ele, sep))) +if (!*ele) + list = string_catn(list, US" ", 1); +else { - list = string_catn(list, ele, sp-ele+1); - list = string_catn(list, &sep, 1); - ele = sp+1; + while((sp = Ustrchr(ele, sep))) + { + list = string_catn(list, ele, sp-ele+1); + list = string_catn(list, &sep, 1); + ele = sp+1; + } + list = string_cat(list, ele); } -list = string_cat(list, ele); (void) string_from_gstring(list); return list; } commit 13835a3c1e057efad7da269c0f93bf2eac850205 Author: Jeremy Harris Date: Mon Dec 29 00:14:20 2025 +0000 LDAP: support module load triggered by variable access diff --git a/src/src/expand.c b/src/src/expand.c index 23ae31baa..3c68ab2e9 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2175,6 +2175,30 @@ switch (vp->type) "failed to find %s module for %s: %s", US val, name, errstr); return US""; } + + case vtype_lookup_module: + { + uschar * errstr = NULL; + const tree_node * t = tree_search(lookups_tree, val); +#ifdef LOOKUP_MODULE_DIR + if (!t) + { + lookup_one_mod_load(val, &errstr); + t = tree_search(lookups_tree, val); + } +#endif + if (t) + { + const lookup_info * li = t->data.ptr; + table = li->variables; + table_count = li->variables_count; + goto sublist; + } + log_write(0, LOG_MAIN|LOG_PANIC, + "failed to find %s module for %s%s%s", US val, name, + errstr ? ": " : "", errstr); + return US""; + } } return NULL; /* Unknown variable. Silences static checkers. */ commit 40d39e3522a6f66e21591341c33b33c05864287d Author: Jeremy Harris Date: Fri Jan 9 17:01:11 2026 +0000 tidying diff --git a/src/src/log.c b/src/src/log.c index 64587a9f2..40bdfcd0c 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -462,15 +462,14 @@ to create the file; if running as root, this must be done in a subprocess to avoid races. Arguments: - fd where to return the resulting file descriptor type lt_main, lt_reject, lt_panic, or lt_debug tag optional tag to include in the name (only hooked up for debug) -Returns: nothing +Returns: fd */ -static void -open_log(int * fd, int type, const uschar * tag) +static int +open_log(int type, const uschar * tag) { uid_t euid; BOOL ok, ok2; @@ -555,8 +554,10 @@ if (!ok) /* We now have the file name. After a successful open, return. */ -if ((*fd = log_open_as_exim(buffer)) >= 0) - return; + { + int fd = log_open_as_exim(buffer); + if (fd >= 0) return fd; + } euid = geteuid(); @@ -567,10 +568,7 @@ just bombing out, force the log to stderr and carry on if stderr is available. */ if (euid != root_uid && euid != exim_uid && log_stderr) - { - *fd = fileno(log_stderr); - return; - } + return fileno(log_stderr); /* Otherwise this is a disaster. This call is deliberately ONLY to the panic log. If possible, save a copy of the original line that was being logged. If we @@ -1144,7 +1142,7 @@ if ( flags & LOG_MAIN if (mainlogfd < 0) { - open_log(&mainlogfd, lt_main, NULL); /* No return on error */ + mainlogfd = open_log(lt_main, NULL); /* No return on error */ if (fstat(mainlogfd, &statbuf) >= 0) mainlog_inode = statbuf.st_ino; } @@ -1247,7 +1245,7 @@ if (flags & LOG_REJECT) if (rejectlogfd < 0) { - open_log(&rejectlogfd, lt_reject, NULL); /* No return on error */ + rejectlogfd = open_log(lt_reject, NULL); /* No return on error */ if (fstat(rejectlogfd, &statbuf) >= 0) rejectlog_inode = statbuf.st_ino; } @@ -1280,7 +1278,7 @@ if (flags & LOG_PANIC) if (logging_mode & LOG_MODE_FILE) { panic_recurseflag = TRUE; - open_log(&paniclogfd, lt_panic, NULL); /* Won't return on failure */ + paniclogfd = open_log(lt_panic, NULL); /* Won't return on failure */ panic_recurseflag = FALSE; if (panic_save_buffer) @@ -1560,13 +1558,12 @@ if (opts) /* When activating from a transport process we may never have logged at all resulting in certain setup not having been done. Hack this for now so we -do not segfault; note that nondefault log locations will not work */ +do not segfault; note that nondefault log locations (set via log_file_path) +will not work for that case. */ if (!*file_path) set_file_path(); -open_log(&debug_fd, lt_debug, tag_name); - -if (debug_fd != -1) +if ((debug_fd = open_log(lt_debug, tag_name)) != -1) debug_file = fdopen(debug_fd, "w"); else log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log"); commit 4dd582c432c7f8817d1484b91bb5607851d85ebb Author: Jeremy Harris Date: Tue Jan 13 14:57:07 2026 +0000 Tidying: move ETRN handling out-of-line diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 643d88ca2..bfcdb22af 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -3786,6 +3786,185 @@ if (!(s = expand_string(s))) return *s ? Uatoi(s) : 0; } + + +static int +etrn_handle(uschar ** user_msgp, uschar ** log_msgp) +{ +int rc; +uschar * etrn_command, * etrn_serialize_key = NULL; +const uschar ** argv; +void (*oldsignal)(int); +pid_t pid; + +if (sender_address) + return synprot_error(L_smtp_protocol_error, 503, NULL, + US"ETRN is not permitted inside a transaction"); + +log_write(L_etrn, LOG_MAIN, "ETRN %s received from %s", smtp_cmd_argument, + host_and_ident(FALSE)); + +GET_OPTION("acl_smtp_etrn"); +if ((rc = acl_check(ACL_WHERE_ETRN, NULL, acl_smtp_etrn, + user_msgp, log_msgp)) != OK) + return smtp_handle_acl_fail(ACL_WHERE_ETRN, rc, *user_msgp, *log_msgp); + +/* Compute the serialization key for this command. We used (all the way +back to 4.00) to include the given string as part of the key, but this +opens a security hole for hintsdb types that use a command-string for +operations. So, use a hash of the string. All ETRN with the same command +hash are serialized */ + +if (smtp_etrn_serialize) + { + md5 hash; + uschar * digest = store_get(16, GET_TAINTED); + + md5_start(&hash); + md5_end(&hash, smtp_cmd_argument, Ustrlen(smtp_cmd_argument), digest); + + etrn_serialize_key = string_sprintf("etrn-%.16H", digest); + } + +/* If a command has been specified for running as a result of ETRN, we +permit any argument to ETRN. If not, only the # standard form is +permitted, since that is strictly the only kind of ETRN that can be +implemented according to the RFC. */ + +GET_OPTION("smtp_etrn_command"); +if (smtp_etrn_command) + { + uschar * error; + BOOL rc; + etrn_command = smtp_etrn_command; + deliver_domain = smtp_cmd_data; + rc = transport_set_up_command(&argv, smtp_etrn_command, + TSUC_EXPAND_ARGS, 0, NULL, US"ETRN processing", &error); + deliver_domain = NULL; + if (!rc) + { + log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s", + error); + smtp_printf("458 Internal failure\r\n", SP_NO_MORE); + return 0; + } + } + +/* Else set up to call Exim with the -R option. */ + +else + { + if (*smtp_cmd_data++ != '#') + return synprot_error(L_smtp_syntax_error, 501, NULL, + US"argument must begin with #"); + + etrn_command = US"exim -R"; + argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, NULL, TRUE, + *queue_name ? 4 : 2, + US"-R", smtp_cmd_data, + US"-MCG", queue_name); + } + +/* If we are host-testing, don't actually do anything. */ + +if (host_checking) + { + HDEBUG(D_any) + { + debug_printf("ETRN command is: %s\n", etrn_command); + debug_printf("ETRN command execution skipped\n"); + } + if (*user_msgp) + smtp_user_msg(US"250", *user_msgp); + else + smtp_printf("250 OK\r\n", SP_NO_MORE); + return 0; + } + + +/* If ETRN queue runs are to be serialized, check the database to +ensure one isn't already running. */ + +if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1)) + { + smtp_printf("458 Already processing %s\r\n", SP_NO_MORE, smtp_cmd_data); + return 0; + } + +/* Fork a child process and run the command. We don't want to have to +wait for the process at any point, so set SIGCHLD to SIG_IGN before +forking. It should be set that way anyway for external incoming SMTP, +but we save and restore to be tidy. If serialization is required, we +actually run the command in yet another process, so we can wait for it +to complete and then remove the serialization lock. */ + +oldsignal = signal(SIGCHLD, SIG_IGN); + +if ((pid = exim_fork(US"etrn-command")) == 0) + { + smtp_input = FALSE; /* This process is not associated with the */ + smtp_inout_close(); /* SMTP call any more. */ + + signal(SIGCHLD, SIG_DFL); /* Want to catch child */ + + /* If not serializing, do the exec right away. Otherwise, fork down + into another process. */ + + if ( !smtp_etrn_serialize + || (pid = exim_fork(US"etrn-serialised-command")) == 0) + { + DEBUG(D_exec) debug_print_argv(argv); + exim_nullstd(); /* Ensure std{in,out,err} exist */ + /* argv[0] should be untainted, from child_exec_exim() */ + execv(CS argv[0], (char *const *)argv); + log_write_die(0, LOG_MAIN, "exec of %q (ETRN) failed: %s", + etrn_command, strerror(errno)); + _exit(EXIT_FAILURE); /* paranoia */ + } + + /* Obey this if smtp_serialize and the 2nd fork yielded non-zero. That + is, we are in the first subprocess, after forking again. All we can do + for a failing fork is to log it. Otherwise, wait for the 2nd process to + complete, before removing the serialization. */ + + if (pid < 0) + log_write(0, LOG_MAIN|LOG_PANIC, "2nd fork for serialized ETRN " + "failed: %s", strerror(errno)); + else + { + int status; + DEBUG(D_any) debug_printf("waiting for serialized ETRN process %d\n", + (int)pid); + (void)wait(&status); + DEBUG(D_any) debug_printf("serialized ETRN process %d ended\n", + (int)pid); + } + + if (smtp_etrn_serialize) enq_end(etrn_serialize_key); + exim_underbar_exit(EXIT_SUCCESS); + } + +/* Back in the top level SMTP process. Check that we started a subprocess +and restore the signal state. */ + +if (pid < 0) + { + log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s", + strerror(errno)); + smtp_printf("458 Unable to fork process\r\n", SP_NO_MORE); + if (smtp_etrn_serialize) enq_end(etrn_serialize_key); + } +else + if (*user_msgp) + smtp_user_msg(US"250", *user_msgp); + else + smtp_printf("250 OK\r\n", SP_NO_MORE); + +signal(SIGCHLD, oldsignal); +return 0; +} + + /************************************************* * Initialize for SMTP incoming message * *************************************************/ @@ -3870,14 +4049,10 @@ value. The values are 2 larger than the required yield of the function. */ while (done <= 0) { - const uschar ** argv; - uschar * etrn_command, * etrn_serialize_key, * errmess; - uschar * log_msg, * smtp_code; + uschar * errmess, * log_msg, * smtp_code; uschar * user_msg = NULL, * recipient = NULL, * hello = NULL; uschar * s, * ss; BOOL was_rej_mail = FALSE, was_rcpt = FALSE; - void (*oldsignal)(int); - pid_t pid; int start, end, sender_domain, recipient_domain; int rc, c, dsn_flags; uschar * orcpt = NULL; @@ -5723,176 +5898,9 @@ while (done <= 0) case ETRN_CMD: HAD(SCH_ETRN); - if (sender_address) - { - done = synprot_error(L_smtp_protocol_error, 503, NULL, - US"ETRN is not permitted inside a transaction"); - break; - } - - log_write(L_etrn, LOG_MAIN, "ETRN %s received from %s", smtp_cmd_argument, - host_and_ident(FALSE)); - - GET_OPTION("acl_smtp_etrn"); - if ((rc = acl_check(ACL_WHERE_ETRN, NULL, acl_smtp_etrn, - &user_msg, &log_msg)) != OK) - { - done = smtp_handle_acl_fail(ACL_WHERE_ETRN, rc, user_msg, log_msg); - break; - } - - /* Compute the serialization key for this command. We used (all the way - back to 4.00) to include the given string as part of the key, but this - opens a security hole for hintsdb types that use a command-string for - operations. So, use a hash of the string. All ETRN with the same command - hash are serialized */ - - md5 hash; - uschar *digest = store_get(16, GET_TAINTED); - - md5_start(&hash); - md5_end(&hash, smtp_cmd_argument, Ustrlen(smtp_cmd_argument), digest); - - etrn_serialize_key = string_sprintf("etrn-%.16H", digest); - - /* If a command has been specified for running as a result of ETRN, we - permit any argument to ETRN. If not, only the # standard form is - permitted, since that is strictly the only kind of ETRN that can be - implemented according to the RFC. */ - - GET_OPTION("smtp_etrn_command"); - if (smtp_etrn_command) - { - uschar * error; - BOOL rc; - etrn_command = smtp_etrn_command; - deliver_domain = smtp_cmd_data; - rc = transport_set_up_command(&argv, smtp_etrn_command, - TSUC_EXPAND_ARGS, 0, NULL, US"ETRN processing", &error); - deliver_domain = NULL; - if (!rc) - { - log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s", - error); - smtp_printf("458 Internal failure\r\n", SP_NO_MORE); - break; - } - } - - /* Else set up to call Exim with the -R option. */ - - else - { - if (*smtp_cmd_data++ != '#') - { - done = synprot_error(L_smtp_syntax_error, 501, NULL, - US"argument must begin with #"); - break; - } - etrn_command = US"exim -R"; - argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, NULL, TRUE, - *queue_name ? 4 : 2, - US"-R", smtp_cmd_data, - US"-MCG", queue_name); - } - - /* If we are host-testing, don't actually do anything. */ - - if (host_checking) - { - HDEBUG(D_any) - { - debug_printf("ETRN command is: %s\n", etrn_command); - debug_printf("ETRN command execution skipped\n"); - } - if (user_msg == NULL) smtp_printf("250 OK\r\n", SP_NO_MORE); - else smtp_user_msg(US"250", user_msg); - break; - } - - - /* If ETRN queue runs are to be serialized, check the database to - ensure one isn't already running. */ - - if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1)) - { - smtp_printf("458 Already processing %s\r\n", SP_NO_MORE, smtp_cmd_data); - break; - } - - /* Fork a child process and run the command. We don't want to have to - wait for the process at any point, so set SIGCHLD to SIG_IGN before - forking. It should be set that way anyway for external incoming SMTP, - but we save and restore to be tidy. If serialization is required, we - actually run the command in yet another process, so we can wait for it - to complete and then remove the serialization lock. */ - - oldsignal = signal(SIGCHLD, SIG_IGN); - - if ((pid = exim_fork(US"etrn-command")) == 0) - { - smtp_input = FALSE; /* This process is not associated with the */ - smtp_inout_close(); /* SMTP call any more. */ - - signal(SIGCHLD, SIG_DFL); /* Want to catch child */ - - /* If not serializing, do the exec right away. Otherwise, fork down - into another process. */ - - if ( !smtp_etrn_serialize - || (pid = exim_fork(US"etrn-serialised-command")) == 0) - { - DEBUG(D_exec) debug_print_argv(argv); - exim_nullstd(); /* Ensure std{in,out,err} exist */ - /* argv[0] should be untainted, from child_exec_exim() */ - execv(CS argv[0], (char *const *)argv); - log_write_die(0, LOG_MAIN, "exec of %q (ETRN) failed: %s", - etrn_command, strerror(errno)); - _exit(EXIT_FAILURE); /* paranoia */ - } - - /* Obey this if smtp_serialize and the 2nd fork yielded non-zero. That - is, we are in the first subprocess, after forking again. All we can do - for a failing fork is to log it. Otherwise, wait for the 2nd process to - complete, before removing the serialization. */ - - if (pid < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "2nd fork for serialized ETRN " - "failed: %s", strerror(errno)); - else - { - int status; - DEBUG(D_any) debug_printf("waiting for serialized ETRN process %d\n", - (int)pid); - (void)wait(&status); - DEBUG(D_any) debug_printf("serialized ETRN process %d ended\n", - (int)pid); - } - - enq_end(etrn_serialize_key); - exim_underbar_exit(EXIT_SUCCESS); - } - - /* Back in the top level SMTP process. Check that we started a subprocess - and restore the signal state. */ - - if (pid < 0) - { - log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s", - strerror(errno)); - smtp_printf("458 Unable to fork process\r\n", SP_NO_MORE); - if (smtp_etrn_serialize) enq_end(etrn_serialize_key); - } - else - if (!user_msg) - smtp_printf("250 OK\r\n", SP_NO_MORE); - else - smtp_user_msg(US"250", user_msg); - - signal(SIGCHLD, oldsignal); + done = etrn_handle(&user_msg, &log_msg); break; - case BADARG_CMD: done = synprot_error(L_smtp_syntax_error, 501, NULL, US"unexpected argument data"); commit 7a7e1513914f2ded45e5e51426d77ec78b4f6d54 Author: Jeremy Harris Date: Tue Jan 13 21:20:07 2026 +0000 tidying diff --git a/src/exim_monitor/em_globals.c b/src/exim_monitor/em_globals.c index 5627a2277..45dc6f298 100644 --- a/src/exim_monitor/em_globals.c +++ b/src/exim_monitor/em_globals.c @@ -131,11 +131,6 @@ time_t deliver_frozen_at = 0; BOOL deliver_manual_thaw = FALSE; #ifndef DISABLE_DKIM -uschar *dkim_cur_signer = NULL; -uschar *dkim_signers = NULL; -uschar *dkim_signing_domain = NULL; -uschar *dkim_signing_selector = NULL; -uschar *dkim_verify_signers = US"$dkim_signers"; unsigned dkim_collect_input = 0; BOOL dkim_disable_verify = FALSE; #endif diff --git a/src/src/spool_in.c b/src/src/spool_in.c index b475c3955..2dde341f0 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -266,7 +266,6 @@ tree_nonrecipients = NULL; #ifndef DISABLE_DKIM f.dkim_disable_verify = FALSE; # ifdef COMPILE_UTILITY -dkim_signers = NULL; dkim_collect_input = 0; #else { commit f92a63ebf6bcf991a09a0429808c61e2407bb10f Author: Jeremy Harris Date: Fri Jan 16 20:01:33 2026 +0000 DNS: fix memory leak diff --git a/src/src/host.c b/src/src/host.c index 95694635a..130334793 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -19,6 +19,11 @@ of Exim. */ #include "exim.h" +static int +host_find_bydns_internal(host_item *, const uschar *, + int, const uschar *, const uschar *, const uschar *, const dnssec_domains *, + const uschar **, BOOL *, dns_answer *); + /* Static variable for preserving the list of interface addresses in case it is used more than once. */ @@ -1770,8 +1775,9 @@ for (uschar * hname = sender_host_name; hname; hname = *aliases++) dnssec_domains d = { .request = sender_host_dnssec ? US"*" : NULL, .require = NULL }; - if ( (rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A | HOST_FIND_BY_AAAA, - NULL, NULL, NULL, &d, NULL, NULL)) == HOST_FOUND + if ( (rc = host_find_bydns_internal(&h, NULL, + HOST_FIND_BY_A | HOST_FIND_BY_AAAA, + NULL, NULL, NULL, &d, NULL, NULL, dnsa)) == HOST_FOUND || rc == HOST_FOUND_LOCAL ) { @@ -1851,6 +1857,7 @@ yield = FAIL; out: expand_level--; + store_free_dns_answer(dnsa); return yield; } @@ -2198,6 +2205,7 @@ function as it may be called to set the addresses of hosts taken from MX records. Arguments: + dnsa a dns_answer area to use (avoid alloc another) host points to the host item we're filling in lastptr points to pointer to last host item in a chain of host items (may be updated if host is last and gets @@ -2219,7 +2227,7 @@ Returns: HOST_FIND_FAILED couldn't find A record */ static int -set_address_from_dns(host_item *host, host_item **lastptr, +set_address_from_dns(dns_answer * dnsa, host_item *host, host_item **lastptr, const uschar *ignore_target_hosts, BOOL allow_ip, const uschar **fully_qualified_name, BOOL dnssec_request, BOOL dnssec_require, int whichrrs) @@ -2228,7 +2236,6 @@ host_item * thishostlast = NULL; /* Indicates not yet filled in anything */ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; int i; -dns_answer * dnsa; #ifndef DISABLE_TLS /* Copy the host name at this point to the value which is used for @@ -2254,8 +2261,6 @@ if (allow_ip && string_is_ip_address(host->name, NULL) != 0) return HOST_FOUND; } -dnsa = store_get_dns_answer(); - /* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice, looking for AAAA records the first time. However, unless doing standalone testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global. @@ -2467,7 +2472,6 @@ i = host->address : HOST_IGNORED; out: - store_free_dns_answer(dnsa); return i; } @@ -2518,19 +2522,19 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain; an address of the local host */ -int -host_find_bydns(host_item * host, const uschar * ignore_target_hosts, +static int +host_find_bydns_internal(host_item * host, const uschar * ignore_target_hosts, int whichrrs, const uschar * srv_svclist, const uschar * srv_fail_domains, const uschar * mx_fail_domains, const dnssec_domains * dnssec_d, - const uschar ** fully_qualified_name, BOOL * removed) + const uschar ** fully_qualified_name, BOOL * removed, + dns_answer * dnsa) { host_item * h, * last; #ifdef EXPERIMENTAL_SRV_SMTPS BOOL srv_smtps = FALSE; #endif int rc = DNS_FAIL, ind_type = 0, yield; -dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss = {0}; BOOL dnssec_require, dnssec_request; dnssec_status_t dnssec; @@ -2726,7 +2730,7 @@ if (rc != DNS_SUCCEED) host->tls_needs = SRV_TLS_UNK; #endif lookup_dnssec_authenticated = NULL; - rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE, + rc = set_address_from_dns(dnsa, host, &last, ignore_target_hosts, FALSE, fully_qualified_name, dnssec_request, dnssec_require, whichrrs); /* If one or more address records have been found, check that none of them @@ -3047,7 +3051,7 @@ for (h = host; h != last->next; h = h->next) { if (h->address) continue; /* Inserted by a multihomed host */ - rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip, + rc = set_address_from_dns(dnsa, h, &last, ignore_target_hosts, allow_mx_to_ip, NULL, dnssec_request, dnssec_require, whichrrs & HOST_FIND_IPV4_ONLY ? HOST_FIND_BY_A : HOST_FIND_BY_A | HOST_FIND_BY_AAAA); @@ -3172,6 +3176,20 @@ DEBUG(D_host_lookup) out: dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ +return yield; +} + +int +host_find_bydns(host_item * host, const uschar * ignore_target_hosts, + int whichrrs, + const uschar * srv_svclist, const uschar * srv_fail_domains, + const uschar * mx_fail_domains, const dnssec_domains * dnssec_d, + const uschar ** fully_qualified_name, BOOL * removed) +{ +dns_answer * dnsa = store_get_dns_answer(); +int yield = host_find_bydns_internal(host, ignore_target_hosts, whichrrs, + srv_svclist, srv_fail_domains, mx_fail_domains, dnssec_d, + fully_qualified_name, removed, dnsa); store_free_dns_answer(dnsa); return yield; } commit 7d5f543c395691cdffdba8013ee4684834f6cb01 Author: Jeremy Harris Date: Mon Jan 19 00:57:15 2026 +0000 DMARC (native): ignore tags failing verification diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index 96628dee1..9fa4a1924 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -192,24 +192,30 @@ tag policy_tags[] = { /* Handle one potential tag Return: boolean success; else parsing error - -RFC 7489 6.3 :- unknown tags are ignored */ -static int +static BOOL parse_tag(const uschar * tagrecord, dmarc_policy_record * prp) { const uschar * e = Ustrchr(tagrecord, '='), * s; /* RFC 6736 3.2 tagspec must have = */ -if (!*e) +if (!e) + { + DEBUG(D_receive) + debug_printf_indent("DMARC: missing '=' for tag in %q\n", tagrecord); return FALSE; + } /* RFC 6736 3.2 ignore whitespace between tag name and = */ for (s = e; s > tagrecord && isspace(s[-1]); ) s--; /* RFC 6736 3.2 tag name at least 1 char */ if (s == tagrecord) + { + DEBUG(D_receive) + debug_printf_indent("DMARC: missing tag name in %q\n", tagrecord); return FALSE; + } /* search for tag name in our table of known ones */ for (tag * ptp = policy_tags; ptp < policy_tags + nelem(policy_tags); ptp++) @@ -226,13 +232,20 @@ for (tag * ptp = policy_tags; ptp < policy_tags + nelem(policy_tags); ptp++) s = e + 1; Uskip_whitespace(&s); - if (!ptp->verify(s)) DEBUG(D_receive) + if (ptp->verify(s)) + { + *vp = string_copy(s); + return TRUE; + } + DEBUG(D_receive) debug_printf_indent("DMARC: bad value for tag %q: %q\n", ptp->name, s); - *vp = string_copy(s); - break; + return FALSE; } } -return TRUE; + +DEBUG(D_receive) + debug_printf_indent("DMARC: no recognised tag in %q\n", tagrecord); +return FALSE; } static BOOL @@ -242,10 +255,10 @@ dmarc_local_parse_policy(const uschar * rr, dmarc_policy_record * prp) int sep = ';'; /* RFC 6736 3.2 :- ignore whitespace preceding tag-name and after value */ +/* RFC 7489 6.3 :- syntax errors and unknown tags are ignored */ for (uschar * tagspec; tagspec = string_nextinlist(&rr, &sep, NULL, 0); ) - if (!parse_tag(tagspec, prp)) - return FALSE; + (void) parse_tag(tagspec, prp); return TRUE; } commit bdb65dd6fd1af3f7d186adc05bfe27f11b1403d4 Author: Jeremy Harris Date: Mon Jan 19 14:52:58 2026 +0000 Debug: add "macro" channel diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index b365643bb..081d1041b 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -207,6 +207,9 @@ else fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n"); #endif +fprintf(new, "#define EXIM_ULONG_BITS %u\n", + sizeof(unsigned long) == 8 ? 64 : 32); + /* Now search the makefile for certain settings */ if (!(base = fopen("Makefile", "rb"))) diff --git a/src/src/daemon.c b/src/src/daemon.c index e8432196c..a37cc7cc6 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -188,7 +188,7 @@ pid_t pid; union sockaddr_46 interface_sockaddr; EXIM_SOCKLEN_T ifsize = sizeof(interface_sockaddr); int max_for_this_host = 0; -int save_log_selector = *log_selector; +unsigned long save_log_selector = *log_selector; gstring * whofrom; rmark reset_point = store_mark(); diff --git a/src/src/exim.c b/src/src/exim.c index 7e90e927c..e11250cc0 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2822,7 +2822,7 @@ on the second character (the one after '-'), to save some effort. */ /* Use an intermediate variable so that we don't set debugging while decoding the debugging bits. */ - unsigned int selector = D_default; + unsigned long selector = D_default; debug_selector = 0; debug_file = NULL; if (*argrest == 'd') diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 8cb06fefe..c6c884125 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -77,7 +77,7 @@ const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) struct global_flags f; -unsigned int log_selector[1]; +unsigned long log_selector[1]; uschar * queue_name; BOOL split_spool_directory; @@ -98,7 +98,7 @@ const uschar *hex_digits = CUS"0123456789abcdef"; * Debug output * *******************/ -unsigned int debug_selector = 0; /* set -1 for debugging */ +unsigned long debug_selector = 0; /* set -1 for debugging */ void debug_printf(const char * fmt, ...) diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index b6977513b..2955861fa 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -65,7 +65,7 @@ const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } struct global_flags f; -unsigned int log_selector[1]; +unsigned long log_selector[1]; uschar * queue_name; BOOL split_spool_directory; @@ -113,7 +113,7 @@ exit(EXIT_FAILURE); * Debug output * *******************/ -unsigned int debug_selector = 0; /* set -1 for debugging */ +unsigned long debug_selector = 0; /* set -1 for debugging */ void debug_printf(const char * fmt, ...) diff --git a/src/src/functions.h b/src/src/functions.h index 9d4201a7b..677972e01 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -139,8 +139,8 @@ extern BOOL bdat_hasc(void); extern int bdat_ungetc(int); extern void bdat_flush_data(void); -extern void bits_clear(unsigned int *, size_t, int *); -extern void bits_set(unsigned int *, size_t, int *); +extern void bits_clear(unsigned long *, size_t, int *); +extern void bits_set(unsigned long *, size_t, int *); extern void cancel_cutthrough_connection(BOOL, const uschar *); extern gstring *cat_file(FILE *, gstring *, const uschar *); @@ -188,7 +188,7 @@ extern void debug_pretrigger_discard(void); extern void debug_print_socket(int); extern void debug_trigger_fire(void); -extern void decode_bits(unsigned int *, size_t, int *, +extern void decode_bits(unsigned long *, size_t, int *, const uschar *, bit_table *, int, uschar *, int); extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); diff --git a/src/src/globals.c b/src/src/globals.c index 2b2270899..90906e923 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -657,6 +657,7 @@ FILE *debug_file = NULL; int debug_notall[] = { Di_memory, Di_noutf8, + Di_macro, -1 }; bit_table debug_options[] = { /* must be in alphabetical order and use @@ -678,6 +679,7 @@ bit_table debug_options[] = { /* must be in alphabetical order and use BIT_TABLE(D, load), BIT_TABLE(D, local_scan), BIT_TABLE(D, lookup), + BIT_TABLE(D, macro), BIT_TABLE(D, memory), BIT_TABLE(D, noutf8), BIT_TABLE(D, pid), @@ -698,7 +700,7 @@ int debug_options_count = nelem(debug_options); uschar debuglog_name[LOG_NAME_SIZE] = {0}; unsigned debug_pretrigger_bsize = 0; uschar * debug_pretrigger_buf = NULL; -unsigned int debug_selector = 0; +unsigned long debug_selector = 0; BOOL debug_startup = FALSE; int delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 }; @@ -1013,7 +1015,7 @@ int log_options_count = nelem(log_options); const uschar *log_ports = NULL; int log_reject_target = 0; -unsigned int log_selector[log_selector_size]; /* initialized in main() */ +unsigned long log_selector[log_selector_size]; /* initialized in main() */ uschar *log_selector_string = NULL; FILE *log_stderr = NULL; uschar *login_sender_address = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index befaf308b..5402fb59e 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -673,7 +673,7 @@ extern int log_notall[]; /* Log options excluded from +all */ extern bit_table log_options[]; /* Table of options */ extern int log_options_count; /* Size of table */ extern int log_reject_target; /* Target log for ACL rejections */ -extern unsigned int log_selector[]; /* Bit map of logging options */ +extern unsigned long log_selector[]; /* Bit map of logging options */ extern uschar *log_selector_string; /* As supplied in the config */ extern FILE *log_stderr; /* Copy of stderr for log use, or NULL */ extern BOOL log_timezone; /* TRUE to include the timezone in log lines */ diff --git a/src/src/local_scan.h b/src/src/local_scan.h index c9d179375..6e63672eb 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -44,7 +44,7 @@ each time a new feature is added (in a way that doesn't break backward compatibility). */ #define LOCAL_SCAN_ABI_VERSION_MAJOR 7 -#define LOCAL_SCAN_ABI_VERSION_MINOR 0 +#define LOCAL_SCAN_ABI_VERSION_MINOR 1 #define LOCAL_SCAN_ABI_VERSION \ LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR @@ -165,7 +165,7 @@ typedef struct recipient_item { /* Global variables that are documented as visible in the function. */ -extern unsigned int debug_selector; /* Debugging bits */ +extern unsigned long debug_selector; /* Debugging bits */ extern int body_linecount; /* Line count in body */ extern int body_zerocount; /* Binary zero count in body */ diff --git a/src/src/log.c b/src/src/log.c index 40bdfcd0c..0220b91bb 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1366,14 +1366,14 @@ Arguments: */ void -bits_clear(unsigned int *selector, size_t selsize, int *bits) +bits_clear(unsigned long * selector, size_t selsize, int * bits) { for(; *bits != -1; ++bits) BIT_CLEAR(selector, selsize, *bits); } void -bits_set(unsigned int *selector, size_t selsize, int *bits) +bits_set(unsigned long * selector, size_t selsize, int * bits) { for(; *bits != -1; ++bits) BIT_SET(selector, selsize, *bits); @@ -1403,7 +1403,7 @@ we treat it as an unknown option: error message to stderr and die. Arguments: selector address of the bit string selsize number of words in the bit string - notall list of bits to exclude from "all" + notall list of bit-numbers to exclude from "all" string the configured string options the table of option names count size of table @@ -1414,11 +1414,12 @@ Returns: nothing on success - bomb out on failure */ void -decode_bits(unsigned int * selector, size_t selsize, int * notall, +decode_bits(unsigned long * selector, size_t selsize, int * notall, const uschar * string, bit_table * options, int count, uschar * which, int flags) { -uschar *errmsg; +uschar * errmsg; + if (!string) return; if (*string == '=') diff --git a/src/src/macros.h b/src/src/macros.h index f6b240322..a1a9cd6c1 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -101,7 +101,7 @@ don't make the file descriptors two-way. */ /* Debugging control */ #define LOG_NAME_SIZE 256 -#define IS_DEBUG(x) (debug_selector & (x)) +#define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) #define DEBUG(x) if (IS_DEBUG(x)) #define HDEBUG(x) if (host_checking || IS_DEBUG(x)) @@ -327,17 +327,21 @@ for having to swallow the rest of an SMTP message is whether the value is /* Bit masks for debug and log selectors */ -/* Assume words are 32 bits wide. Tiny waste of space on 64 bit +/* Assume words are at least 32 bits wide. Tiny waste of space on 64 bit platforms, but this ensures bit vectors always work the same way. */ -#define BITWORDSIZE 32 +#ifdef EXIM_ULONG_BITS + #define BITWORDSIZE EXIM_ULONG_BITS +#else + #define BITWORDSIZE 64 +#endif /* This macro is for single-word bit vectors: the debug selector, and the first word of the log selector. */ #define BIT(n) (1UL << (n)) /* And these are for multi-word vectors. */ -#define BITWORD(n) ( (n) / BITWORDSIZE) -#define BITMASK(n) (1U << (n) % BITWORDSIZE) +#define BITWORD(n) ( (n) / BITWORDSIZE) +#define BITMASK(n) (1UL << (n) % BITWORDSIZE) #define BIT_CLEAR(s,z,n) ((s)[BITWORD(n)] &= ~BITMASK(n)) #define BIT_SET(s,z,n) ((s)[BITWORD(n)] |= BITMASK(n)) @@ -362,9 +366,13 @@ These must match the debug_options table in globals.c . Exim's code assumes in a number of places that the debug_selector is one word, and this is exposed in the local_scan ABI. The D_v and D_local_scan bit -masks are part of the local_scan API so are #defined in local_scan.h */ +masks are part of the local_scan API so are #defined in local_scan.h . + +Thanks to the "one word", debug bits beyond 31 are not available on 32b-int +systems, and coding must account for that. */ -#define DEBUG_BIT(name) Di_##name = IOTA(Di_iota), D_##name = (int)BIT(Di_##name) +#define DEBUG_BIT(name) Di_##name = IOTA(Di_iota), D_##name = (unsigned long)BIT(Di_##name) +#define DEBUG_Z_BIT(name) Di_##name = 0, D_##name = 0 enum { Di_all = -1, @@ -402,8 +410,14 @@ enum { DEBUG_BIT(transport), DEBUG_BIT(uid), DEBUG_BIT(verify), /* 31 */ +#if EXIM_ULONG_BITS > 32 + DEBUG_BIT(macro), /* 33 */ +#else + DEBUG_Z_BIT(macro), +#endif }; + /* Multi-bit debug masks */ #define D_all 0xffffffff diff --git a/src/src/os.c b/src/src/os.c index 4b9d2d1d5..44a53a575 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -12,8 +12,8 @@ # include # include #else -# define IS_DEBUG(x) (debug_selector & (x)) -# define DEBUG(x) if (IS_DEBUG(x)) +# define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) +# define DEBUG(x) if (IS_DEBUG(x)) /* for cppcheck */ #endif #ifndef CS diff --git a/src/src/readconf.c b/src/src/readconf.c index 356321765..e95a2aed3 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -786,7 +786,7 @@ macro_create(const uschar * name, const uschar * val, BOOL command_line) { macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED); -EARLY_DEBUG(D_any, "%s: '%s' '%s'\n", __FUNCTION__, name, val); +EARLY_DEBUG(D_macro, "%s: '%s' '%s'\n", __FUNCTION__, name, val); m->next = NULL; m->command_line = command_line; m->namelen = Ustrlen(name); @@ -979,11 +979,11 @@ if (*s) for (macro_item * m = *s == '_' ? macros : macros_user; m; m = m->next) { int moveby; - DEBUG(D_any) + DEBUG(D_macro) if (f.expansion_test) printf("macro '%s' -> '%s'\n", m->name, m->replacement); else - EARLY_DEBUG(D_any, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, + EARLY_DEBUG(D_macro, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, m->name, (int) Ustrlen(ss)-1, ss); /* Expand the buffer if necessary */ commit 6f268ee4c14cdde79b29809ef25179fb6b60689b Author: Jeremy Harris Date: Tue Jan 20 18:48:15 2026 +0000 Debug: ensure extanded channels propagated Broken-by: bdb65dd6fd1a diff --git a/src/src/child.c b/src/src/child.c index 359b791e8..05f87d856 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -107,7 +107,7 @@ if (!minimal) { if (debug_selector != 0) { - argv[n++] = string_sprintf("-d=0x%x", debug_selector); + argv[n++] = string_sprintf("-d=0x%lx", debug_selector); if (debug_fd > 2) { int flags = fcntl(debug_fd, F_GETFD); diff --git a/src/src/daemon.c b/src/src/daemon.c index a37cc7cc6..607913f6c 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -365,9 +365,8 @@ if (pid == 0) { int queue_only_reason = 0; int old_pool = store_pool; - int save_debug_selector = debug_selector; - BOOL local_queue_only; - BOOL session_local_queue_only; + unsigned long save_debug_selector = debug_selector; + BOOL local_queue_only, session_local_queue_only; #ifdef SA_NOCLDWAIT struct sigaction act; #endif diff --git a/src/src/environment.c b/src/src/environment.c index 9cbd352ec..4b8041f9f 100644 --- a/src/src/environment.c +++ b/src/src/environment.c @@ -42,7 +42,7 @@ if (!keep_environment || !*keep_environment) else if (Ustrcmp(keep_environment, "*") != 0) { rmark reset_point = store_mark(); - unsigned deb = debug_selector; + unsigned long deb = debug_selector; BOOL hc = host_checking; debug_selector = 0; /* quieten this clearout */ host_checking = FALSE; diff --git a/src/src/exim.c b/src/src/exim.c index e11250cc0..6924b4b14 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -4464,10 +4464,10 @@ a debugging feature for finding out what arguments certain MUAs actually use. Don't attempt it if logging is disabled, or if listing variables or if verifying/testing addresses or expansions. */ -if ( (debug_selector & D_any || LOGGING(arguments)) +if ( (IS_DEBUG(D_any) || LOGGING(arguments)) && f.really_exim && !list_options && !checking) { - uschar *p = big_buffer; + uschar * p = big_buffer; Ustrcpy(p, US"cwd= (failed)"); if (!initial_cwd) diff --git a/src/src/rewrite.c b/src/src/rewrite.c index 97c811f41..cf65fc242 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -241,7 +241,7 @@ for (rewrite_rule * rule = rewrite_rules; /* We have a validly rewritten address */ - if (LOGGING(address_rewrite) || debug_selector & D_rewrite) + if (LOGGING(address_rewrite) || IS_DEBUG(D_rewrite)) { const uschar * where = CUS"?"; diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 2dde341f0..35fa5089b 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -620,7 +620,7 @@ for (;;) dsn_envid = string_copy_taint(var + 10, proto_mem); #ifndef COMPILE_UTILITY else if (Ustrncmp(p, "ebug_selector ", 14) == 0) - debug_selector = strtol(CS var + 15, NULL, 0); + debug_selector = strtoul(CS var + 15, NULL, 0); else if (Ustrncmp(p, "ebuglog_name ", 13) == 0) debug_logging_from_spool(var + 14); #endif diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 91b776df2..243db106d 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -232,7 +232,7 @@ tree_walk(acl_var_m, &acl_var_write, fp); if (*debuglog_name) { - fprintf(fp, "-debug_selector 0x%x\n", debug_selector); + fprintf(fp, "-debug_selector 0x%lx\n", debug_selector); fprintf(fp, "-debuglog_name %s\n", debuglog_name); } commit c052ac7dc3c71e083317d8bcd234fa32a0f964ab Author: Jeremy Harris Date: Tue Jan 20 20:20:27 2026 +0000 Debug: add "regex" channel diff --git a/src/src/globals.c b/src/src/globals.c index 90906e923..c4f5064e7 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -655,9 +655,10 @@ uschar *dccifd_options = US"header"; int debug_fd = -1; FILE *debug_file = NULL; int debug_notall[] = { + Di_macro, Di_memory, Di_noutf8, - Di_macro, + Di_regex, -1 }; bit_table debug_options[] = { /* must be in alphabetical order and use @@ -686,6 +687,7 @@ bit_table debug_options[] = { /* must be in alphabetical order and use BIT_TABLE(D, process_info), BIT_TABLE(D, queue_run), BIT_TABLE(D, receive), + BIT_TABLE(D, regex), BIT_TABLE(D, resolver), BIT_TABLE(D, retry), BIT_TABLE(D, rewrite), diff --git a/src/src/macros.h b/src/src/macros.h index a1a9cd6c1..8ab066fac 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -412,8 +412,10 @@ enum { DEBUG_BIT(verify), /* 31 */ #if EXIM_ULONG_BITS > 32 DEBUG_BIT(macro), /* 33 */ + DEBUG_BIT(regex), #else DEBUG_Z_BIT(macro), + DEBUG_Z_BIT(regex), #endif }; diff --git a/src/src/regex_cache.c b/src/src/regex_cache.c index 713da90d5..ab26b8a96 100644 --- a/src/src/regex_cache.c +++ b/src/src/regex_cache.c @@ -52,7 +52,7 @@ int rlen = sizeof(re_req) + klen; re_req * req; int fd, old_pool = store_pool; -DEBUG(D_expand|D_lists) +DEBUG(D_regex) debug_printf_indent("sending RE '%s' to daemon\n", key); store_pool = POOL_MAIN; @@ -68,11 +68,11 @@ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) ssize_t len = daemon_notifier_sockname(&sa_un); if (sendto(fd, req, rlen, 0, (struct sockaddr *)&sa_un, (socklen_t)len) < 0) - DEBUG(D_queue_run) + DEBUG(D_regex) debug_printf("%s: sendto %s\n", __FUNCTION__, strerror(errno)); close(fd); } -else DEBUG(D_queue_run) debug_printf(" socket: %s\n", strerror(errno)); +else DEBUG(D_regex) debug_printf(" socket: %s\n", strerror(errno)); } @@ -81,7 +81,7 @@ regex_from_cache(const uschar * key, BOOL caseless) { tree_node * node = tree_search(caseless ? regex_caseless_cache : regex_cache, key); -DEBUG(D_expand|D_lists) +DEBUG(D_regex) debug_printf_indent("compiled %sRE '%s' %sfound in local cache\n", caseless ? "caseless " : "", key, node ? "" : "not "); @@ -99,8 +99,8 @@ Ustrcpy(node->name, key); node->data.ptr = (void *)cre; if (!tree_insertnode(caseless ? ®ex_caseless_cache : ®ex_cache, node)) - { DEBUG(D_expand|D_lists) debug_printf_indent("duplicate key!\n"); } -else DEBUG(D_expand|D_lists) + { DEBUG(D_regex) debug_printf_indent("duplicate key!\n"); } +else DEBUG(D_regex) debug_printf_indent("compiled RE '%s' saved in local cache\n", key); /* Additionally, if not re-execed and not the daemon, tell the daemon of the RE @@ -204,7 +204,7 @@ if ( flags & MCS_CACHEABLE && (yield = regex_from_cache(key, caseless))) return yield; -DEBUG(D_expand|D_lists) debug_printf_indent("compiling %sRE '%s'\n", +DEBUG(D_regex) debug_printf_indent("compiling %sRE '%s'\n", caseless ? "caseless " : "", pattern); store_pool = POOL_PERM; commit 2d4c73da7de2c0bfc47d5321f158f6620c008b7a Author: Jeremy Harris Date: Wed Jan 21 13:21:27 2026 +0000 More coverage in "-bV" datatype size diagnostics diff --git a/src/src/exim.c b/src/src/exim.c index 6924b4b14..489aa3bd6 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1277,7 +1277,9 @@ if (fixed_never_users[0] > 0) g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid); -g = string_fmt_append(g, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t)); +g = string_fmt_append(g, "Size of off_t:" SIZE_T_FMT + " ptr:" SIZE_T_FMT " long:" SIZE_T_FMT " int:" SIZE_T_FMT "\n", + sizeof(off_t), sizeof(void *), sizeof(long), sizeof(int)); /* Everything else is details which are only worth reporting when debugging. Perhaps the tls_version_report should move into this too. */ diff --git a/src/src/globals.c b/src/src/globals.c index c4f5064e7..142cdde5e 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1453,8 +1453,8 @@ uschar *uucp_from_sender = US"$1"; uschar *verify_mode = NULL; uschar *version_copyright = - US"Copyright (c) University of Cambridge, 1995 - 2018\n" - "(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2025"; + US"Copyright (c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2026\n" + "Copyright (c) University of Cambridge, 1995 - 2018\n"; uschar *version_date = US"?"; uschar *version_cnumber = US"????"; uschar *version_string = US"?"; commit 3ec1c65df8dd1cedb3f77666107a860000dd280b Author: Jeremy Harris Date: Thu Jan 22 18:21:00 2026 +0000 tidying diff --git a/src/src/log.c b/src/src/log.c index 0220b91bb..39ff04378 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -763,27 +763,22 @@ static void set_file_path(void) { int sep = ':'; /* Fixed separator - outside use */ -uschar *t; -const uschar *tt = US LOG_FILE_PATH; +const uschar * t, * tt = US LOG_FILE_PATH; while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE))) - { - if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue; - file_path = string_copy(t); - break; - } + if (Ustrcmp(t, "syslog") != 0 && *t) + { file_path = string_copy(t); break; } } /* Close mainlog, unless we do not see a chance to open the file mainlog later again. This will happen if we log from a transport process (which has dropped privs); something we traditionally avoid, but the introduction of taint-tracking -and resulting detection of errors is makinng harder. */ +and resulting detection of errors is making harder. */ void mainlog_close(void) { -if (mainlogfd < 0 - || !(geteuid() == 0 || geteuid() == exim_uid)) +if (mainlogfd < 0 || !(geteuid() == 0 || geteuid() == exim_uid)) return; (void)close(mainlogfd); mainlogfd = -1; @@ -852,8 +847,7 @@ log_vwrite(unsigned int selector, int flags, const char * format, va_list ap) { int paniclogfd; ssize_t written_len; -gstring gs = { .size = LOG_BUFFER_SIZE-2, .ptr = 0, .s = log_buffer }; -gstring * g = &gs; +gstring gs = { .size = LOG_BUFFER_SIZE-2 }, * g = &gs; /* If panic_recurseflag is set, we have failed to open the panic log. This is the ultimate disaster. First try to write the message to a debug file and/or @@ -881,6 +875,7 @@ if (!log_buffer) fprintf(stderr, "exim: failed to get store for log buffer\n"); exim_exit(EXIT_FAILURE); } +gs.s = log_buffer; /* If we haven't already done so, inspect the setting of log_file_path to determine whether to log to files and/or to syslog. Bits in logging_mode commit c33264393a1c70c92a1fccdfa0640988da26351e Author: Jeremy Harris Date: Thu Jan 22 19:30:43 2026 +0000 Debug: use defined-width type for bitmap diff --git a/src/exim_monitor/em_main.c b/src/exim_monitor/em_main.c index 143de870d..d85cefdba 100644 --- a/src/exim_monitor/em_main.c +++ b/src/exim_monitor/em_main.c @@ -168,7 +168,7 @@ Returns: nothing */ void -log_write(unsigned int selector, int flags, const char *format, ...) +log_write(bitmask_word_t selector, int flags, const char *format, ...) { va_list ap; va_start(ap, format); @@ -179,7 +179,7 @@ va_end(ap); void -log_write_die(unsigned int selector, int flags, const char *format, ...) +log_write_die(bitmask_word_t selector, int flags, const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index 081d1041b..b365643bb 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -207,9 +207,6 @@ else fprintf(new, "#define SSIZE_T_FMT \"%%d\"\n"); #endif -fprintf(new, "#define EXIM_ULONG_BITS %u\n", - sizeof(unsigned long) == 8 ? 64 : 32); - /* Now search the makefile for certain settings */ if (!(base = fopen("Makefile", "rb"))) diff --git a/src/src/child.c b/src/src/child.c index 05f87d856..de08095af 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -107,7 +107,7 @@ if (!minimal) { if (debug_selector != 0) { - argv[n++] = string_sprintf("-d=0x%lx", debug_selector); + argv[n++] = string_sprintf("-d=0x" PR_EXIM_BITMASK, debug_selector); if (debug_fd > 2) { int flags = fcntl(debug_fd, F_GETFD); diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index ba9f50b01..e99b10c16 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -247,4 +247,11 @@ for EXIM_ARITH_MAX and _MIN in OS/oh.h-FOO */ #define SC_EXIM_ARITH "%" SCNi64 /* scanf incl. 0x prefix */ #define SC_EXIM_DEC "%" SCNd64 /* scanf decimal */ +/* Word size for debug and logging channel bitmaps. +Change as above (but expect debugging to become odd). */ +#define bitmask_word_t uint64_t +#define EXIM_BITMAP_WORD_BITS 64 +#define PR_EXIM_BITMASK "%" PRIx64 +#define SC_EXIM_BITMASK "%" SCNx64 + /* End of config.h.defaults */ diff --git a/src/src/daemon.c b/src/src/daemon.c index 607913f6c..bce9bb9f4 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -188,7 +188,7 @@ pid_t pid; union sockaddr_46 interface_sockaddr; EXIM_SOCKLEN_T ifsize = sizeof(interface_sockaddr); int max_for_this_host = 0; -unsigned long save_log_selector = *log_selector; +bitmask_word_t save_log_selector = *log_selector; gstring * whofrom; rmark reset_point = store_mark(); @@ -365,7 +365,7 @@ if (pid == 0) { int queue_only_reason = 0; int old_pool = store_pool; - unsigned long save_debug_selector = debug_selector; + bitmask_word_t save_debug_selector = debug_selector; BOOL local_queue_only, session_local_queue_only; #ifdef SA_NOCLDWAIT struct sigaction act; diff --git a/src/src/environment.c b/src/src/environment.c index 4b8041f9f..58af6b6c3 100644 --- a/src/src/environment.c +++ b/src/src/environment.c @@ -42,7 +42,7 @@ if (!keep_environment || !*keep_environment) else if (Ustrcmp(keep_environment, "*") != 0) { rmark reset_point = store_mark(); - unsigned long deb = debug_selector; + bitmask_word_t deb = debug_selector; BOOL hc = host_checking; debug_selector = 0; /* quieten this clearout */ host_checking = FALSE; diff --git a/src/src/exim.c b/src/src/exim.c index 489aa3bd6..5a756cc4d 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -3982,8 +3982,9 @@ if (debug_selector != 0) testharness_pause_ms(100); /* lets caller finish */ if (debug_selector != D_v) /* -v only doesn't show this */ { - debug_printf("Exim version %s uid=%ld gid=%ld pid=%d D=%x\n", - version_string, (long int)real_uid, (long int)real_gid, (int)getpid(), + debug_printf("Exim version %s uid=%ld gid=%ld pid=" PID_T_FMT + " D=0x" PR_EXIM_BITMASK "\n", + version_string, (long int)real_uid, (long int)real_gid, getpid(), debug_selector); if (!version_printed) show_whats_supported(FALSE); @@ -4290,7 +4291,7 @@ DEBUG(D_any) debug_printf("configuration file is %s\n", config_main_filename); debug_printf("log selectors ="); for (int i = 0; i < log_selector_size; i++) - debug_printf(" %08x", log_selector[i]); + debug_printf(" 0x" PR_EXIM_BITMASK, log_selector[i]); debug_printf("\n"); } diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index c6c884125..1ffedfd95 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -69,7 +69,7 @@ string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, const char * fmt, ...) { return FALSE; } void -log_write(unsigned int selector, int flags, const char *format, ...) +log_write(bitmask_word_t selector, int flags, const char *format, ...) { } const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } @@ -77,7 +77,7 @@ const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) struct global_flags f; -unsigned long log_selector[1]; +bitmask_word_t log_selector[1]; uschar * queue_name; BOOL split_spool_directory; @@ -98,7 +98,7 @@ const uschar *hex_digits = CUS"0123456789abcdef"; * Debug output * *******************/ -unsigned long debug_selector = 0; /* set -1 for debugging */ +bitmask_word_t debug_selector = 0; /* set -1 for debugging */ void debug_printf(const char * fmt, ...) diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 2955861fa..04b3023b7 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -65,7 +65,7 @@ const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } struct global_flags f; -unsigned long log_selector[1]; +bitmask_word_t log_selector[1]; uschar * queue_name; BOOL split_spool_directory; @@ -113,7 +113,7 @@ exit(EXIT_FAILURE); * Debug output * *******************/ -unsigned long debug_selector = 0; /* set -1 for debugging */ +bitmask_word_t debug_selector = 0; /* set -1 for debugging */ void debug_printf(const char * fmt, ...) @@ -195,7 +195,7 @@ Returns: nothing */ void -log_write(unsigned int selector, int flags, const char *format, ...) +log_write(bitmask_word_t selector, int flags, const char *format, ...) { va_list ap; va_start(ap, format); @@ -205,7 +205,7 @@ va_end(ap); } void -log_write_die(unsigned int selector, int flags, const char *format, ...) +log_write_die(bitmask_word_t selector, int flags, const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/src/src/expand.c b/src/src/expand.c index 3c68ab2e9..5e46f7cde 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -9135,7 +9135,7 @@ for (int i = 1; i < argc; i++) argv[i]++; } if (isdigit(argv[i][0])) - debug_selector = Ustrtol(argv[i], NULL, 0); + debug_selector = Ustrtoul(argv[i], NULL, 0); else if (Ustrspn(argv[i], "abcdefghijklmnopqrtsuvwxyz0123456789-.:/") == Ustrlen(argv[i])) diff --git a/src/src/functions.h b/src/src/functions.h index 677972e01..0981f126b 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -302,7 +302,7 @@ extern const uschar *local_part_quote(const uschar *); extern void log_close_all(void); extern int log_open_as_exim(const uschar * const); extern gstring *log_portnum(gstring *, int); -extern void log_write_die(unsigned, int, const char * format, ...) +extern void log_write_die(bitmask_word_t, int, const char * format, ...) PRINTF_FUNCTION(3,4) NORETURN; extern const lookup_info * lookup_with_acq_num(unsigned); diff --git a/src/src/globals.c b/src/src/globals.c index 142cdde5e..58dc8bffd 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -702,7 +702,7 @@ int debug_options_count = nelem(debug_options); uschar debuglog_name[LOG_NAME_SIZE] = {0}; unsigned debug_pretrigger_bsize = 0; uschar * debug_pretrigger_buf = NULL; -unsigned long debug_selector = 0; +bitmask_word_t debug_selector = 0; BOOL debug_startup = FALSE; int delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 }; @@ -1017,7 +1017,7 @@ int log_options_count = nelem(log_options); const uschar *log_ports = NULL; int log_reject_target = 0; -unsigned long log_selector[log_selector_size]; /* initialized in main() */ +bitmask_word_t log_selector[log_selector_size]; /* initialized in main() */ uschar *log_selector_string = NULL; FILE *log_stderr = NULL; uschar *login_sender_address = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 5402fb59e..dca2d0b17 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -673,7 +673,7 @@ extern int log_notall[]; /* Log options excluded from +all */ extern bit_table log_options[]; /* Table of options */ extern int log_options_count; /* Size of table */ extern int log_reject_target; /* Target log for ACL rejections */ -extern unsigned long log_selector[]; /* Bit map of logging options */ +extern bitmask_word_t log_selector[]; /* Bit map of logging options */ extern uschar *log_selector_string; /* As supplied in the config */ extern FILE *log_stderr; /* Copy of stderr for log use, or NULL */ extern BOOL log_timezone; /* TRUE to include the timezone in log lines */ diff --git a/src/src/local_scan.h b/src/src/local_scan.h index 6e63672eb..ad2601c38 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -29,6 +29,7 @@ store.c settings, and the store functions. */ #include +#include #include #include "config.h" #include "mytypes.h" @@ -165,7 +166,7 @@ typedef struct recipient_item { /* Global variables that are documented as visible in the function. */ -extern unsigned long debug_selector; /* Debugging bits */ +extern bitmask_word_t debug_selector; /* Debugging bits */ extern int body_linecount; /* Line count in body */ extern int body_zerocount; /* Binary zero count in body */ @@ -211,7 +212,7 @@ extern void header_add_at_position(BOOL, uschar *, BOOL, int, const char *, . extern void header_remove(int, const uschar *); extern BOOL header_testname(const header_line *, const uschar *, int, BOOL); extern BOOL header_testname_incomplete(const header_line *, const uschar *, int, BOOL); -extern void log_write(unsigned int, int, const char *format, ...) PRINTF_FUNCTION(3,4); +extern void log_write(bitmask_word_t, int, const char *format, ...) PRINTF_FUNCTION(3,4); extern int lss_b64decode(uschar *, uschar **); extern uschar *lss_b64encode(uschar *, int); extern int lss_match_domain(uschar *, uschar *); diff --git a/src/src/log.c b/src/src/log.c index 39ff04378..46d8873da 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -843,7 +843,7 @@ Returns: nothing */ static void -log_vwrite(unsigned int selector, int flags, const char * format, va_list ap) +log_vwrite(bitmask_word_t selector, int flags, const char * format, va_list ap) { int paniclogfd; ssize_t written_len; @@ -1307,7 +1307,7 @@ if (flags & LOG_PANIC) /* The public interface */ void -log_write(unsigned int selector, int flags, const char * format, ...) +log_write(bitmask_word_t selector, int flags, const char * format, ...) { va_list ap; va_start(ap, format); @@ -1320,7 +1320,7 @@ We have this as a wrapper so that we can mark it as never returning, for the benefit of static analysers. */ void -log_write_die(unsigned int selector, int flags, const char * format, ...) +log_write_die(bitmask_word_t selector, int flags, const char * format, ...) { va_list ap; va_start(ap, format); @@ -1361,14 +1361,14 @@ Arguments: */ void -bits_clear(unsigned long * selector, size_t selsize, int * bits) +bits_clear(bitmask_word_t * selector, size_t selsize, int * bits) { for(; *bits != -1; ++bits) BIT_CLEAR(selector, selsize, *bits); } void -bits_set(unsigned long * selector, size_t selsize, int * bits) +bits_set(bitmask_word_t * selector, size_t selsize, int * bits) { for(; *bits != -1; ++bits) BIT_SET(selector, selsize, *bits); @@ -1409,7 +1409,7 @@ Returns: nothing on success - bomb out on failure */ void -decode_bits(unsigned long * selector, size_t selsize, int * notall, +decode_bits(bitmask_word_t * selector, size_t selsize, int * notall, const uschar * string, bit_table * options, int count, uschar * which, int flags) { @@ -1419,12 +1419,14 @@ if (!string) return; if (*string == '=') { - char *end; /* Not uschar */ + int n; memset(selector, 0, sizeof(*selector)*selsize); - *selector = strtoul(CCS string+1, &end, 0); - if (!*end) return; - errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which, - string); + if ( sscanf(CCS string+1, SC_EXIM_BITMASK "%n", selector, &n) == 1 + && !string[1+n]) + return; + + errmsg = string_sprintf("malformed numeric %s_selector setting: %q (n %d, fmt %q)", which, + string, n, SC_EXIM_BITMASK); goto ERROR_RETURN; } @@ -1487,7 +1489,7 @@ else for(;;) if (start >= end) { errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which, - adding? '+' : '-', len, s); + adding ? '+' : '-', len, s); goto ERROR_RETURN; } } /* Loop for selector names */ diff --git a/src/src/macros.h b/src/src/macros.h index 8ab066fac..ea5ca9277 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -329,10 +329,10 @@ for having to swallow the rest of an SMTP message is whether the value is /* Assume words are at least 32 bits wide. Tiny waste of space on 64 bit platforms, but this ensures bit vectors always work the same way. */ -#ifdef EXIM_ULONG_BITS - #define BITWORDSIZE EXIM_ULONG_BITS +#ifdef EXIM_BITMAP_WORD_BITS +# define BITWORDSIZE EXIM_BITMAP_WORD_BITS #else - #define BITWORDSIZE 64 +# define BITWORDSIZE 64 #endif /* This macro is for single-word bit vectors: the debug selector, @@ -410,7 +410,7 @@ enum { DEBUG_BIT(transport), DEBUG_BIT(uid), DEBUG_BIT(verify), /* 31 */ -#if EXIM_ULONG_BITS > 32 +#if BITWORDSIZE > 32 DEBUG_BIT(macro), /* 33 */ DEBUG_BIT(regex), #else diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 35fa5089b..9231a302e 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -620,7 +620,7 @@ for (;;) dsn_envid = string_copy_taint(var + 10, proto_mem); #ifndef COMPILE_UTILITY else if (Ustrncmp(p, "ebug_selector ", 14) == 0) - debug_selector = strtoul(CS var + 15, NULL, 0); + sscanf(CS var + 15, SC_EXIM_BITMASK, &debug_selector); else if (Ustrncmp(p, "ebuglog_name ", 13) == 0) debug_logging_from_spool(var + 14); #endif diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 243db106d..016f7cdd4 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -232,7 +232,7 @@ tree_walk(acl_var_m, &acl_var_write, fp); if (*debuglog_name) { - fprintf(fp, "-debug_selector 0x%lx\n", debug_selector); + fprintf(fp, "-debug_selector 0x" PR_EXIM_BITMASK "\n", debug_selector); fprintf(fp, "-debuglog_name %s\n", debuglog_name); } commit d61563f31ad33c93eae8e1c448475783c437f6e8 Author: Jeremy Harris Date: Thu Jan 22 23:13:10 2026 +0000 Tidying: pid string formatting diff --git a/src/OS/unsupported/os.c-cygwin b/src/OS/unsupported/os.c-cygwin index 56085b857..d9e54d6a8 100644 --- a/src/OS/unsupported/os.c-cygwin +++ b/src/OS/unsupported/os.c-cygwin @@ -55,7 +55,7 @@ int cygwin_setuid(uid_t uid ) if (fakesetugid == 0) { res = setuid(uid); if (cygwin_debug) - fprintf(stderr, "setuid %u %u %d pid: %d\n", + fprintf(stderr, "setuid %u %u %d pid: " PID_T_FMT "\n", uid, getuid(),res, getpid()); } return res; @@ -68,7 +68,7 @@ int cygwin_setgid(gid_t gid ) if (fakesetugid == 0) { res = setgid(gid); if (cygwin_debug) - fprintf(stderr, "setgid %u %u %d pid: %d\n", + fprintf(stderr, "setgid %u %u %d pid: " PID_T_FMT "\n", gid, getgid(), res, getpid()); } return res; diff --git a/src/src/auths/auth-spa.c b/src/src/auths/auth-spa.c index ee69330dd..db62c6859 100644 --- a/src/src/auths/auth-spa.c +++ b/src/src/auths/auth-spa.c @@ -1407,7 +1407,7 @@ spa_build_auth_challenge(SPAAuthRequest * request, SPAAuthChallenge * challenge) { char chalstr[8]; int i; -int p = (int)getpid(); +pid_t p = getpid(); int random_seed = (int)time(NULL) ^ ((p << 16) | p); /* Ensure challenge data is cleared, in case it isn't all used. This diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 44b05465c..1532e2af6 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -173,8 +173,8 @@ int auth_cram_md5_server(auth_instance * ablock, uschar * data) { auth_cram_md5_options_block * ob = ablock->drinst.options_block; -uschar * challenge = string_sprintf("<%d.%ld@%s>", getpid(), - (long int) time(NULL), primary_hostname); +uschar * challenge = string_sprintf("<" PID_T_FMT ".%ld@%s>", + getpid(), (long int) time(NULL), primary_hostname); uschar * clear, * secret; uschar digest[16]; int i, rc, len; diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index c9fdc0ea9..73322a6cd 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -441,7 +441,7 @@ Subsequently, the command was modified to add "secured" and "valid-client- cert" when relevant. ****************************************************************************/ -auth_command = string_sprintf("CPID\t%d\n" +auth_command = string_sprintf("CPID\t" PID_T_FMT "\n" "AUTH\t%d\t%s\tservice=smtp\t%srip=%s\tlip=%s\tnologin\tresp=%s\n", getpid(), crequid, ablock->public_name, auth_extra_data, sender_host_address, diff --git a/src/src/daemon.c b/src/src/daemon.c index bce9bb9f4..d3e84a567 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -493,8 +493,8 @@ if (pid == 0) debug_selector = save_debug_selector; DEBUG(D_any) - debug_printf("Process %d is handling incoming connection from %s\n", - (int)getpid(), sender_fullhost); + debug_printf("Process " PID_T_FMT " is handling incoming connection" + " from %s\n", getpid(), sender_fullhost); /* Now disable debugging permanently if it's required only for the daemon process. */ @@ -538,7 +538,7 @@ if (pid == 0) reset_point = store_mark(); /* Save current store high water point */ DEBUG(D_any) - debug_printf("Process %d is ready for new message\n", (int)getpid()); + debug_printf("Process " PID_T_FMT " is ready for new message\n", getpid()); /* Smtp_setup_msg() returns 0 on QUIT or if the call is from an unacceptable host or if an ACL "drop" command was triggered, -1 on @@ -971,7 +971,7 @@ static BOOL operate_on_pid_file(const enum pid_op operation, const pid_t pid) { char pid_line[sizeof(int) * 3 + 2]; -const int pid_len = snprintf(pid_line, sizeof(pid_line), "%ld\n", (long)pid); +const int pid_len = snprintf(pid_line, sizeof(pid_line), PID_T_FMT "\n", pid); BOOL lines_match = FALSE; uschar * path, * base, * dir; @@ -1144,9 +1144,10 @@ daemon_client_sockname(struct sockaddr_un * sup, uschar ** sname) #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS sup->sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */ return offsetof(struct sockaddr_un, sun_path) + 1 - + snprintf(sup->sun_path+1, sizeof(sup->sun_path)-1, "exim_%d", getpid()); + + snprintf(sup->sun_path+1, sizeof(sup->sun_path)-1, + "exim_" PID_T_FMT, getpid()); #else -*sname = string_sprintf("%s/p_%d", spool_directory, getpid()); +*sname = string_sprintf("%s/p_" PID_T_FMT, spool_directory, getpid()); return offsetof(struct sockaddr_un, sun_path) + snprintf(sup->sun_path, sizeof(sup->sun_path), "%s", CS *sname); #endif @@ -2373,7 +2374,9 @@ if (f.running_in_test_harness || write_pid) || real_uid == root_uid || (real_uid == exim_uid && !override_pid_file_path)) ? PID_WRITE : PID_CHECK; if (!operate_on_pid_file(operation, getpid())) - DEBUG(D_any) debug_printf("%s pid file %s: %s\n", (operation == PID_WRITE) ? "write" : "check", pid_file_path, strerror(errno)); + DEBUG(D_any) debug_printf("%s pid file %s: %s\n", + operation == PID_WRITE ? "write" : "check", + pid_file_path, strerror(errno)); } /* Set up the handler for SIGHUP, which causes a restart of the daemon. */ @@ -2437,8 +2440,8 @@ if (f.inetd_wait_mode) else sprintf(CS p, "with no wait timeout"); - log_write(0, LOG_MAIN, - "exim %s daemon started: pid=%ld, launched with listening socket, %s", + log_write(0, LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT + ", launched with listening socket, %s", version_string, getpid(), big_buffer); set_process_info("daemon(%s): pre-listening socket", version_string); @@ -2544,7 +2547,7 @@ else if (f.daemon_listen) } log_write(0, LOG_MAIN, - "exim %s daemon started: pid=%ld, %s, listening for %s", + "exim %s daemon started: pid=" PID_T_FMT ", %s, listening for %s", version_string, getpid(), qinfo, big_buffer); set_process_info("daemon(%s): %s, listening for %s", version_string, qinfo, big_buffer); @@ -2554,7 +2557,7 @@ else /* no listening sockets, only queue-runs */ { const uschar * s = describe_queue_runners(); log_write(0, LOG_MAIN, - "exim %s daemon started: pid=%ld, %s, not listening for SMTP", + "exim %s daemon started: pid=" PID_T_FMT ", %s, not listening for SMTP", version_string, getpid(), s); set_process_info("daemon(%s): %s, not listening", version_string, s); } @@ -2859,7 +2862,7 @@ for (;;) if (sighup_seen) { - log_write(0, LOG_MAIN, "pid %ld: SIGHUP received: re-exec daemon", + log_write(0, LOG_MAIN, "pid " PID_T_FMT ": SIGHUP received: re-exec daemon", getpid()); close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count); unlink_notifier_socket(); @@ -2868,7 +2871,7 @@ for (;;) sighup_argv[0] = exim_path; exim_nullstd(); execv(CS exim_path, (char *const *)sighup_argv); - log_write_die(0, LOG_MAIN, "pid %ld: exec of %s failed: %s", + log_write_die(0, LOG_MAIN, "pid " PID_T_FMT ": exec of %s failed: %s", getpid(), exim_path, strerror(errno)); /*NOTREACHED*/ } diff --git a/src/src/deliver.c b/src/src/deliver.c index a984ee21e..44e163fa4 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -2240,7 +2240,7 @@ if ( !shadowing addr->return_filename = spool_fname(US"msglog", message_subdir, message_id, - string_sprintf("-%ld-%d", (long)getpid(), return_count++)); + string_sprintf("-" PID_T_FMT "-%d", getpid(), return_count++)); if ((addr->return_file = open_msglog_file(addr->return_filename, 0400, &error)) < 0) { @@ -5919,9 +5919,10 @@ if (!(bounce_recipient = addr_failed->prop.errors_address)) /* Make a subprocess to send a message, using its stdin */ if ((pid = child_open_exim(&fd, US"bounce-message")) < 0) - log_write_die(0, LOG_MAIN, "Process %ld (parent %ld) failed to " + log_write_die(0, LOG_MAIN, + "Process " PID_T_FMT " (parent " PID_T_FMT ") failed to " "create child process to send failure message: %s", - (long)getpid(), (long)getppid(), strerror(errno)); + getpid(), getppid(), strerror(errno)); /* Creation of child succeeded */ @@ -6577,9 +6578,10 @@ if (addr_senddsn) if (pid < 0) /* Creation of child failed */ { - log_write_die(0, LOG_MAIN, "Process %ld (parent %ld) failed to " + log_write_die(0, LOG_MAIN, + "Process " PID_T_FMT " (parent " PID_T_FMT ") failed to " "create child process to send success-dsn message: %s", - (long)getpid(), (long)getppid(), strerror(errno)); + getpid(), getppid(), strerror(errno)); DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); } diff --git a/src/src/exim.c b/src/src/exim.c index 5a756cc4d..a87219920 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -224,7 +224,7 @@ int len; uschar * s; va_list ap; -g = string_fmt_append(&gs, "%5d ", (int)getpid()); +g = string_fmt_append(&gs, PID_T_FMT " ", getpid()); len = gstring_length(g); va_start(ap, format); if (!string_vformat(g, 0, format, ap)) @@ -803,8 +803,8 @@ DEBUG(D_uid) { int group_count, save_errno; gid_t group_list[EXIM_GROUPLIST_SIZE]; - debug_printf("changed uid/gid: %s\n uid=%ld gid=%ld pid=%ld\n", msg, - (long int)geteuid(), (long int)getegid(), (long int)getpid()); + debug_printf("changed uid/gid: %s\n uid=%ld gid=%ld pid=" PID_T_FMT "\n", + msg, (long int)geteuid(), (long int)getegid(), getpid()); group_count = getgroups(nelem(group_list), group_list); save_errno = errno; debug_printf(" auxiliary group list:"); @@ -840,9 +840,9 @@ smtp_fflush(SFF_NO_UNCORK); search_tidyup(); store_exit(); DEBUG(D_any) - debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d " + debug_printf(">>>>>>>>>>>>>>>> Exim pid=" PID_T_FMT " (%s) terminating with rc=%d " ">>>>>>>>>>>>>>>>\n", - (int)getpid(), process_purpose, rc); + getpid(), process_purpose, rc); exit(rc); } @@ -852,9 +852,9 @@ exim_underbar_exit(int rc) { store_exit(); DEBUG(D_any) - debug_printf(">>>>>>>>>>>>>>>> Exim pid=%d (%s) terminating with rc=%d " + debug_printf(">>>>>>>>>>>>>>>> Exim pid=" PID_T_FMT " (%s) terminating with rc=%d " ">>>>>>>>>>>>>>>>\n", - (int)getpid(), process_purpose, rc); + getpid(), process_purpose, rc); _exit(rc); } diff --git a/src/src/exim_lock.c b/src/src/exim_lock.c index f42da23a8..1797fa98b 100644 --- a/src/src/exim_lock.c +++ b/src/src/exim_lock.c @@ -305,7 +305,7 @@ if (use_lockfile) /* Presumably, this must match appendfile.c */ sprintf(hitchname, "%s.%s.%08x.%08x", lockname, primary_hostname, - (unsigned int)now, (unsigned int)getpid()); + (unsigned int)now, (unsigned long)getpid()); if (verbose) printf("exim_lock: lockname = %s\n hitchname = %s\n", lockname, diff --git a/src/src/expand.c b/src/src/expand.c index 5e46f7cde..097e4aa5e 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2004,7 +2004,7 @@ switch (vp->type) return (s = *((uschar **)(val))) ? s : US""; case vtype_pid: - sprintf(CS var_buffer, "%d", (int)getpid()); /* pid */ + sprintf(CS var_buffer, PID_T_FMT, getpid()); /* pid */ return var_buffer; case vtype_load_avg: diff --git a/src/src/functions.h b/src/src/functions.h index 0981f126b..916c1a329 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1311,8 +1311,8 @@ report_time_since(const struct timeval * t0, const uschar * where) # ifdef MEASURE_TIMING struct timeval diff; timesince(&diff, t0); -fprintf(stderr, "%d %s:\t%ld.%06ld\n", - (uint)getpid(), where, (long)diff.tv_sec, (long)diff.tv_usec); +fprintf(stderr, PID_T_FMT " %s:\t%ld.%06ld\n", + getpid(), where, (long)diff.tv_sec, (long)diff.tv_usec); # endif } @@ -1405,7 +1405,7 @@ the generator for it at any time. */ static inline void set_connection_id(void) { -connection_id = string_sprintf("%lu", (u_long)getpid()); +connection_id = string_sprintf(PID_T_FMT, getpid()); } diff --git a/src/src/host.c b/src/src/host.c index 130334793..1bafda996 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -94,7 +94,7 @@ if (random_seed == 0) random_seed = 42; else { - int p = (int)getpid(); + pid_t p = getpid(); random_seed = (int)time(NULL) ^ ((p << 16) | p); } random_seed = 1103515245 * random_seed + 12345; diff --git a/src/src/log.c b/src/src/log.c index 46d8873da..e4fd3aa7f 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1023,7 +1023,7 @@ string_fmt_append_noextend(&gs, "%s ", tod_stamp(tod_log)); if (LOGGING(pid)) { if (!syslog_pid) pid_position[0] = gstring_length(g); /* remember begin … */ - string_fmt_append_noextend(g, "[%ld] ", (long)getpid()); + string_fmt_append_noextend(g, "[" PID_T_FMT "] ", getpid()); if (!syslog_pid) pid_position[1] = gstring_length(g); /* … and end+1 of the PID */ } diff --git a/src/src/miscmods/dkim_transport.c b/src/src/miscmods/dkim_transport.c index 5bce81ad1..1e9a1153c 100644 --- a/src/src/miscmods/dkim_transport.c +++ b/src/src/miscmods/dkim_transport.c @@ -264,7 +264,7 @@ off_t k_file_size; const uschar * errstr; dkim_spool_name = spool_fname(US"input", message_subdir, message_id, - string_sprintf("-%d-K", (int)getpid())); + string_sprintf("-" PID_T_FMT "-K", getpid())); DEBUG(D_transport) debug_printf("dkim signing via file %s\n", dkim_spool_name); diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index cad14b889..59af24ced 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -1564,7 +1564,7 @@ if (!isdirectory) /* cf. exim_lock.c */ lockname = string_sprintf("%s.lock", filename); hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname, - (unsigned int)(time(NULL)), (unsigned int)getpid()); + (unsigned int)(time(NULL)), (unsigned long)getpid()); DEBUG(D_transport) debug_printf("lock name: %s\nhitch name: %s\n", lockname, hitchname); @@ -2419,8 +2419,8 @@ else { DEBUG(D_transport) debug_printf("delivering to new file in %s\n", path); - filename = dataname = - string_sprintf("%s/temp.%d.%s", path, (int)getpid(), primary_hostname); + filename = dataname = string_sprintf("%s/temp." PID_T_FMT ".%s", + path, getpid(), primary_hostname); fd = Uopen(filename, O_WRONLY|O_CREAT, mode); if (fd < 0 && /* failed to open, and */ (errno != ENOENT || /* either not non-exist */ diff --git a/src/src/transports/tf_maildir.c b/src/src/transports/tf_maildir.c index 60716f1a8..fdbe01e71 100644 --- a/src/src/transports/tf_maildir.c +++ b/src/src/transports/tf_maildir.c @@ -527,8 +527,8 @@ else FALSE); (void)gettimeofday(&tv, NULL); - tempname = string_sprintf("%s/tmp/" TIME_T_FMT ".H%luP%lu.%s", - path, tv.tv_sec, tv.tv_usec, (long unsigned) getpid(), primary_hostname); + tempname = string_sprintf("%s/tmp/" TIME_T_FMT ".H%luP" PID_T_FMT ".%s", + path, tv.tv_sec, tv.tv_usec, getpid(), primary_hostname); fd = Uopen(tempname, O_RDWR|O_CREAT|O_EXCL, ob->mode ? ob->mode : 0600); if (fd >= 0) commit c4b6cd19106c7866a0446815a54e8551141512ed Author: Jeremy Harris Date: Fri Jan 23 14:38:26 2026 +0000 Debug: wordsize mods follow-up Broken-by: c33264393a1c diff --git a/src/exim_monitor/em_version.c b/src/exim_monitor/em_version.c index 15b16c10f..aac3788cd 100644 --- a/src/exim_monitor/em_version.c +++ b/src/exim_monitor/em_version.c @@ -9,12 +9,13 @@ #define EM_VERSION_C +#include +#include +#include #include "mytypes.h" #include "store.h" #include "path_max.h" #include "macros.h" -#include -#include #include "version.h" diff --git a/src/src/functions.h b/src/src/functions.h index 916c1a329..3614ebfca 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -140,7 +140,7 @@ extern int bdat_ungetc(int); extern void bdat_flush_data(void); extern void bits_clear(unsigned long *, size_t, int *); -extern void bits_set(unsigned long *, size_t, int *); +extern void bits_set(bitmask_word_t *, size_t, int *); extern void cancel_cutthrough_connection(BOOL, const uschar *); extern gstring *cat_file(FILE *, gstring *, const uschar *); diff --git a/src/src/macros.h b/src/src/macros.h index ea5ca9277..0efe34cc0 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -371,7 +371,16 @@ masks are part of the local_scan API so are #defined in local_scan.h . Thanks to the "one word", debug bits beyond 31 are not available on 32b-int systems, and coding must account for that. */ -#define DEBUG_BIT(name) Di_##name = IOTA(Di_iota), D_##name = (unsigned long)BIT(Di_##name) +#ifndef bitmask_word_t +# define bitmask_word_t uint64_t +#endif + +#define BITMASK_IDX_TO_BIT(idx) ((bitmask_word_t)1 << (idx)) +#define BIT_TABLE_BIT(class, name) \ + class##i_##name = IOTA(class##i_iota), \ + class##_##name = BITMASK_IDX_TO_BIT(class##i_##name) + +#define DEBUG_BIT(name) BIT_TABLE_BIT(D, name) #define DEBUG_Z_BIT(name) Di_##name = 0, D_##name = 0 enum { @@ -455,7 +464,7 @@ and are only ever tested independently, so they do not need bit mask declarations. The Li_all value is recognized specially by decode_bits(). Add also to log_options[] when creating new ones. */ -#define LOG_BIT(name) Li_##name = IOTA(Li_iota), L_##name = BIT(Li_##name) +#define LOG_BIT(name) BIT_TABLE_BIT(L, name) enum logbit { Li_all = -1, commit c58cf949706491e185303796a0193e74188ae035 Author: Jeremy Harris Date: Fri Jan 23 18:25:03 2026 +0000 Fix header collapse in auto-generated bounce message. Bug 3192 diff --git a/src/src/deliver.c b/src/src/deliver.c index 44e163fa4..af10ff8f9 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6110,7 +6110,7 @@ wording. */ else fprintf(fp, "The following text was generated during the delivery " - "attempt%s:\n", (filecount > 1)? "s" : ""); + "attempt%s:\n", filecount > 1 ? "s" : ""); for (address_item * addr = msgchain; addr; addr = nextaddr) { diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 589db7ead..3ddde3e56 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -263,7 +263,7 @@ if (ob->route_list) { int rc; - DEBUG(D_route) debug_printf("route_item = %s\n", route_item); + DEBUG(D_route) debug_printf_indent("route_item = %s\n", route_item); if (!parse_route_item(route_item, &domain, &hostlist, &options)) continue; /* Ignore blank items */ @@ -276,10 +276,7 @@ if (ob->route_list) /* If there was a problem doing the check, defer */ if (rc == DEFER) - { - addr->message = US"lookup defer in route_list"; - return DEFER; - } + { addr->message = US"lookup defer in route_list"; return DEFER; } } if (!route_item) return DECLINE; /* No pattern in the list matched */ diff --git a/src/src/transport.c b/src/src/transport.c index 5d3b8a732..457245cd0 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -834,8 +834,13 @@ for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old) tblock->rewrite_existflags, FALSE))) { len = hh->slen; - if (tctx->options & topt_truncate_headers && len > 998) len = 998; - if (!sendfn(tctx, hh->text, len)) return FALSE; + if (tctx->options & topt_truncate_headers && len > 998) + { + if ( !sendfn(tctx, hh->text, 991) + || !sendfn(tctx, US"\n", 8)) return FALSE; + } + else + if (!sendfn(tctx, hh->text, len)) return FALSE; store_reset(reset_point); continue; /* With the next header line */ } @@ -844,8 +849,13 @@ for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old) /* Either no rewriting rules, or it didn't get rewritten */ len = h->slen; - if (tctx->options & topt_truncate_headers && len > 998) len = 998; - if (!sendfn(tctx, h->text, len)) return FALSE; + if (tctx->options & topt_truncate_headers && len > 998) + { + if ( !sendfn(tctx, h->text, 991) + || !sendfn(tctx, US"\n", 8)) return FALSE; + } + else + if (!sendfn(tctx, h->text, len)) return FALSE; } /* Header removed */ commit c1bdd01d925954872fa7a7ffea10d3d86965a6a0 Author: Jeremy Harris Date: Sun Jan 25 14:27:55 2026 +0000 tidying diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c index ac3e017e9..8a3d02184 100644 --- a/src/src/dnsbl.c +++ b/src/src/dnsbl.c @@ -65,8 +65,8 @@ Returns: OK if lookup succeeded */ static int -one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain, - uschar *prepend, uschar *iplist, BOOL bitmask, int match_type, +one_check_dnsbl(uschar * domain, uschar * domain_txt, uschar * keydomain, + uschar * prepend, uschar * iplist, BOOL bitmask, int match_type, int defer_return) { dns_answer * dnsa = store_get_dns_answer(); @@ -202,17 +202,17 @@ list (introduced by "&"), or a negative bitmask list (introduced by "!&").*/ if (cb->rc == DNS_SUCCEED) { - dns_address * da = NULL; - uschar *addlist = cb->rhs->address; + gstring * addlist = NULL; /* For A and AAAA records, there may be multiple addresses from multiple records. For A6 records (currently not expected to be used) there may be multiple addresses from a single record. */ - for (da = cb->rhs->next; da; da = da->next) - addlist = string_sprintf("%s, %s", addlist, da->address); + for (dns_address * da = cb->rhs; da; da = da->next) + addlist = string_append2_listele_n(addlist, US", ", + da->address, Ustrlen(da->address)); - HDEBUG(D_dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %s)\n", + HDEBUG(D_dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %Y)\n", query, addlist); /* Address list check; this can be either for equality, or via a bitmask. @@ -220,6 +220,7 @@ if (cb->rc == DNS_SUCCEED) if (iplist) { + dns_address * da; for (da = cb->rhs; da; da = da->next) { int ipsep = ','; @@ -315,7 +316,7 @@ if (cb->rc == DNS_SUCCEED) else { BOOL ok = FALSE; - for (da = cb->rhs; da; da = da->next) + for (dns_address * da = cb->rhs; da; da = da->next) { int address[4]; @@ -371,9 +372,9 @@ if (cb->rc == DNS_SUCCEED) } /* $dnslist_* likely apply to the conn not a message, so we want them not - destroyed by reset_store() between messages */ + destroyed by reset_store() between messages. Use the perm pool. */ - dnslist_value = addlist ? string_copy_perm(addlist, FALSE) : NULL; + dnslist_value = addlist ? string_copy_perm(addlist->s, FALSE) : NULL; dnslist_text = cb->text ? string_copy_perm(cb->text, FALSE) : NULL; yield = OK; goto out; @@ -503,10 +504,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) int rc; BOOL bitmask = FALSE; int match_type = 0; - uschar *domain_txt; - uschar *comma; - uschar *iplist; - uschar *key; + uschar * domain_txt, * comma, * iplist, * key; HDEBUG(D_dnsbl) debug_printf("dnslists check: %s\n", domain); commit 57ef5eda41a8c3b3c037d1075f5f6506cd82daed Author: Jeremy Harris Date: Mon Jan 26 10:51:11 2026 +0000 Debug: wordsize mods follow-up Broken-by: c33264393a1c diff --git a/src/src/functions.h b/src/src/functions.h index 3614ebfca..27d1d2504 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -188,7 +188,7 @@ extern void debug_pretrigger_discard(void); extern void debug_print_socket(int); extern void debug_trigger_fire(void); -extern void decode_bits(unsigned long *, size_t, int *, +extern void decode_bits(bitmask_word_t *, size_t, int *, const uschar *, bit_table *, int, uschar *, int); extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); diff --git a/src/src/macros.h b/src/src/macros.h index 0efe34cc0..8600f5a94 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -337,11 +337,11 @@ platforms, but this ensures bit vectors always work the same way. */ /* This macro is for single-word bit vectors: the debug selector, and the first word of the log selector. */ -#define BIT(n) (1UL << (n)) +#define BIT(n) ((bitmask_word_t)1 << (n)) /* And these are for multi-word vectors. */ -#define BITWORD(n) ( (n) / BITWORDSIZE) -#define BITMASK(n) (1UL << (n) % BITWORDSIZE) +#define BITWORD(n) ( (n) / BITWORDSIZE) +#define BITMASK(n) (BIT((n) % BITWORDSIZE)) #define BIT_CLEAR(s,z,n) ((s)[BITWORD(n)] &= ~BITMASK(n)) #define BIT_SET(s,z,n) ((s)[BITWORD(n)] |= BITMASK(n)) commit 8fdbbec22de1bdb8f7cc60c13798050edcafe696 Author: Jeremy Harris Date: Mon Jan 26 10:52:12 2026 +0000 Taint: track the dns answer buffers as being tainted diff --git a/src/src/dns.c b/src/src/dns.c index 6b527ef00..15f4c8cd0 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -376,7 +376,6 @@ if (reset != RESET_NEXT) while (dnss->rrcount-- > 0) { TRACE trace = "Q-namelen"; - /*TTT*/ if ((namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) <0) goto null_return; /* skip name & type & class */ @@ -407,7 +406,6 @@ if (reset != RESET_NEXT) while (dnss->rrcount-- > 0) { TRACE trace = "A-namelen"; - /*TTT*/ if ( (namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) < 0) goto null_return; @@ -442,7 +440,6 @@ if (dnss->rrcount-- <= 0) return NULL; (something safe). */ TRACE trace = "R-namelen"; -/*TTT*/ if ((namelen = dns_rr_expand_taint(dnsa->answer, eom, dnss->aptr, dnss)) < 0) goto null_return; @@ -507,7 +504,7 @@ if (h->nscount && h->aa) for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == (h->ancount ? T_NS : T_SOA)) - return string_copy(rr->name); /*TTT*/ + return string_copy(rr->name); return NULL; } @@ -1061,7 +1058,7 @@ former will work. */ for (int i = 0; i <= dns_cname_loops; i++) { uschar * data; - dns_record cname_rr, type_rr; + dns_record cname_rr = {0}, type_rr = {0}; dns_scan dnss = {0}; /* DNS lookup failures get passed straight back. */ @@ -1075,7 +1072,6 @@ for (int i = 0; i <= dns_cname_loops; i++) contents of any rr blocks returned by dns_next_rr() as they use the same area in the dnsa block. */ - cname_rr.data = type_rr.data = NULL; for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type) @@ -1103,7 +1099,7 @@ for (int i = 0; i <= dns_cname_loops; i++) ) #endif ) - *fully_qualified_name = string_copy_dnsdomain(rr_name); /*TTT*/ + *fully_qualified_name = string_copy_dnsdomain(rr_name); } /* If any data records of the correct type were found, we are done. */ @@ -1127,7 +1123,7 @@ for (int i = 0; i <= dns_cname_loops; i++) } /* DNS data comes from the outside, hence tainted */ - data = store_get(256, GET_TAINTED); /*TTT alloc*/ + data = store_get(256, GET_TAINTED); if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0) { @@ -1359,7 +1355,7 @@ switch (type) /* If it's making an interesting assertion, return this response. */ if (port & 1) { - *fully_qualified_name = namesuff + 1; /*TTT*/ + *fully_qualified_name = namesuff + 1; return DNS_SUCCEED; } } diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c index 8a3d02184..e12a120fa 100644 --- a/src/src/dnsbl.c +++ b/src/src/dnsbl.c @@ -364,8 +364,7 @@ if (cb->rc == DNS_SUCCEED) int len = (rr->data)[0]; if (len > 511) len = 127; store_pool = POOL_PERM; - /*TTT*/ - cb->text = string_copyn_taint(CUS (rr->data+1), len, GET_TAINTED); + cb->text = string_copyn(CUS (rr->data+1), len); store_pool = old_pool; break; } diff --git a/src/src/functions.h b/src/src/functions.h index 27d1d2504..c95ea2dc4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1138,26 +1138,14 @@ return item /* Use store_malloc for DNSA structs, and explicit frees. Using the same pool for them as the strings we proceed to copy from them meant they could not be released, hence blowing 64k for every DNS lookup. That mounted up. With malloc -we do have to take care over marking tainted all copied strings. -A separate pool could be used and could handle taint implicitly - but we would -want to support independent free ops, not limited to stacked alloc/release */ +we do have to special-case taint checking (see store.c). */ +extern dns_answer * store_get_dns_answer_trc(const uschar *, unsigned); #define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__) -static inline dns_answer * -store_get_dns_answer_trc(const uschar * func, unsigned line) -{ -return store_malloc_3(sizeof(dns_answer), CCS func, line); -} - +extern void store_free_dns_answer_trc(dns_answer *, const uschar *, unsigned); #define store_free_dns_answer(dnsa) store_free_dns_answer_trc(dnsa, CUS __FUNCTION__, __LINE__) -static inline void -store_free_dns_answer_trc(dns_answer * dnsa, const uschar * func, unsigned line) -{ -store_free_3(dnsa, CCS func, line); -} - /* Check for an RR being large enough. Return TRUE iff bad. */ static inline BOOL diff --git a/src/src/host.c b/src/src/host.c index 1bafda996..c4ca666cf 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1667,7 +1667,6 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ - /*TTT*/ if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, US rr->data, (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { @@ -2395,7 +2394,7 @@ for (; i >= 0; i--) if (thishostlast == NULL) { if (strcmpic(host->name, rr->name) != 0) - host->name = string_copy_dnsdomain(rr->name); /*TTT*/ + host->name = string_copy_dnsdomain(rr->name); host->address = da->address; host->sort_key = host->mx * 1000 + random_number(500) + randoffset; host->status = hstatus_unknown; @@ -2789,7 +2788,10 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); int port = PORT_NONE; /* MX lookups get PORT_NONE */ const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */ host_item * next; - uschar data[256]; /*TTT*/ + + /* Properly, should be tainted. string_copy_dnsdomain() call below must be + the only outside use if data placed here by dn_expand(). */ + uschar data[256]; if (rr_bad_size(rr, sizeof(uint16_t))) continue; GETSHORT(precedence, s); /* Pointer s is advanced */ @@ -2816,7 +2818,6 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); /* Get the name of the host pointed to. */ - /*TTT*/ if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, (DN_EXPAND_ARG4_TYPE)data, sizeof(data)) < 0) continue; @@ -2858,7 +2859,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); before the first block, copy the first block's data to a new second block. */ next = last ? store_get(sizeof(host_item), GET_UNTAINTED) : host; - next->name = string_copy_dnsdomain(data); /*TTT*/ + next->name = string_copy_dnsdomain(data); next->address = NULL; next->port = port; next->mx = precedence; diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index 80cf2e62a..a17264501 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -140,13 +140,13 @@ int sep = 0, rc, type, failrc = FAIL; const uschar * outsep = CUS"\n", * outsep2 = NULL; uschar * equals, * domain, * found; -dns_answer * dnsa = store_get_dns_answer(); /*TTT alloc */ +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss = {0}; /* Because we're working in the search pool, we try to reclaim as much store as possible later, so we preallocate the result here */ -gstring * yield = string_get_tainted(256, GET_TAINTED); /*TTT alloc*/ +gstring * yield = string_get_tainted(256, GET_TAINTED); /* If the string starts with '>' we change the output separator. If it's followed by ';' or ',' we set the TXT output separator. */ @@ -403,7 +403,6 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) remain = rr->size - ++data_offset; if (chunk_len > remain) chunk_len = remain; - /*TTT*/ yield = string_catn(yield, US ((rr->data) + data_offset), chunk_len); data_offset += chunk_len; @@ -428,7 +427,6 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) if (payload_length > MAX_TLSA_EXPANDED_SIZE) payload_length = MAX_TLSA_EXPANDED_SIZE; - /*TTT*/ yield = string_fmt_append(yield, "%d%c%d%c%d%c%.*H", usage, *outsep2, selector, *outsep2, @@ -442,8 +440,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* NB: this memory is released implicitly by the call gstring_release_unused(yield) below. We used to use a stack-auto, but - I want to track taint wherever possible. The dnsa is not (yet) - allocated using taint-marked memory. */ + I want to track taint wherever possible. */ #define LCL_BUF_SIZE 264 uschar * buf = store_get(LCL_BUF_SIZE, GET_TAINTED); @@ -504,7 +501,6 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) /* GETSHORT() has advanced the pointer to the target domain. */ - /*TTT*/ rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)buf, LCL_BUF_SIZE); @@ -526,7 +522,6 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) p += rc; yield = string_catn(yield, outsep2, 1); - /*TTT*/ rc = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)buf, LCL_BUF_SIZE); if (rc < 0) diff --git a/src/src/miscmods/dkim.c b/src/src/miscmods/dkim.c index 4bd87bbf9..d6858a00c 100644 --- a/src/src/miscmods/dkim.c +++ b/src/src/miscmods/dkim.c @@ -83,7 +83,7 @@ dkim_exim_query_dns_txt(const uschar * name) dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss = {0}; rmark reset_point = store_mark(); -gstring * g = string_get_tainted(256, GET_TAINTED); /*TTT alloc*/ +gstring * g = string_get_tainted(256, GET_TAINTED); lookup_dnssec_authenticated = NULL; if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED) @@ -100,7 +100,6 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); { uschar len = rr->data[rr_offset++]; - /*TTT*/ g = string_catn(g, US(rr->data + rr_offset), len); if (g->ptr >= PDKIM_DNS_TXT_MAX_RECLEN) goto bad; diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index a0cdb8dc6..bc4131071 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -140,8 +140,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; the lib assumes it can free this (it does for srr.rr) - meaning we cannot use pool store. The use of malloc also for T_TXT implies so. */ - uschar * buf = store_malloc(256); /*TTT alloc*/ - /*TTT*/ + uschar * buf = store_malloc(256); if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, (DN_EXPAND_ARG4_TYPE)buf, 256) < 0) continue; @@ -168,11 +167,12 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; if ( !(chunk_len = s[offset++]) || rr->size < offset + chunk_len /* ignore bogus size chunks */ ) break; - g = string_catn(g, s+offset , chunk_len); /*TTT*/ + g = string_catn(g, s+offset , chunk_len); } if (!g) continue; - s = string_copy_malloc(string_from_gstring(g)); /*TTT*/ + /* Again, we lose taint-tracking here */ + s = string_copy_malloc(string_from_gstring(g)); gstring_reset(g); gstring_release_unused(g); DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_lookup '%s'\n", s); @@ -183,7 +183,8 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; case T_AAAA: default: { - uschar * buf = store_malloc(dnsa->answerlen + 1); /*TTT alloc*/ + uschar * buf = store_malloc(dnsa->answerlen + 1); + /* Again, we lose taint-tracking here */ s = memcpy(buf, s, dnsa->answerlen + 1); break; } diff --git a/src/src/store.c b/src/src/store.c index e265acd4c..6478dc3e7 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -210,12 +210,17 @@ static const uschar * poolclass[N_PAIRED_POOLS] = { [POOL_TAINT_SEARCH] = US"tainted", [POOL_TAINT_MESSAGE] = US"tainted", }; + + +static dns_answer * dnsa_tainted = NULL; + #endif static void * internal_store_malloc(size_t, const char *, int); static void internal_store_free(void *, const char *, int linenumber); + /******************************************************************************/ static void @@ -285,6 +290,17 @@ log_write_die(0, LOG_MAIN, return NULL; } + +/******************************************************************************/ +static BOOL +is_tainted_dnsa(const void * p) +{ +#ifndef COMPILE_UTILITY +for (dns_answer * dnsa = dnsa_tainted; dnsa; dnsa = dnsa->next) + if (CS p >= CS dnsa && CS p < CS(dnsa+1)) return TRUE; +#endif +return FALSE; +} /******************************************************************************/ /* Test if a pointer refers to tainted memory. @@ -321,7 +337,7 @@ for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next) for (b = qp->pool.chainbase; b; b = b->next) if (is_pointer_in_block(b, p)) return TRUE; -return FALSE; +return is_tainted_dnsa(p); } @@ -1258,6 +1274,29 @@ n_nonpool_blocks--; internal_store_free(block, func, linenumber); } +/******************************************************************************/ +#ifndef COMPILE_UTILITY +/* Block-handling for dns answers - a bit over 64k each. +We maintain a list for taint-tracking; these are from the outside so always +tainted. Expect less than 3, so a linked-list is fine. */ + +dns_answer * +store_get_dns_answer_trc(const uschar * func, unsigned line) +{ +dns_answer * dnsa = store_malloc_3(sizeof(dns_answer), CCS func, line); +dnsa->next = dnsa_tainted; +return dnsa_tainted = dnsa; +} + +void +store_free_dns_answer_trc(dns_answer * dnsa, const uschar * func, unsigned line) +{ +for (dns_answer ** dp = &dnsa_tainted; *dp; dp = &((*dp)->next)) + if (*dp == dnsa) { *dp = (*dp)->next; break; } +store_free_3(dnsa, CCS func, line); +} +#endif /*COMPILE_UTILITY*/ + /******************************************************************************/ /* Stats output on process exit */ void diff --git a/src/src/string.c b/src/src/string.c index b37606cf3..5e66e0732 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -613,6 +613,8 @@ allow_utf8_domains is set true and UTF-8 characters are used in domain names. Backslash can also be used to escape other characters, though we shouldn't come across them in domain names. +We always return tainted mem, as some callers use stack-auto source buffers. + Argument: the domain name string Returns: copy of string in new store, de-escaped */ @@ -621,7 +623,6 @@ uschar * string_copy_dnsdomain(const uschar * s) { uschar * yield; -/*TTT*/ uschar * ss = yield = store_get(Ustrlen(s) + 1, GET_TAINTED); /* always treat as tainted */ while (*s) diff --git a/src/src/structs.h b/src/src/structs.h index 52b540356..20438bb47 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -770,7 +770,8 @@ typedef struct { /* Structure for holding the result of a DNS query. A touch over 64k big, so take care to release as soon as possible. */ -typedef struct { +typedef struct dns_answer { + struct dns_answer * next; int answerlen; /* length of the answer */ uschar answer[NS_MAXMSG]; /* the answer itself */ } dns_answer; diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 1610387d9..17ee21ef0 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3416,7 +3416,10 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; ) if (rr->type == T_TLSA && rr->size > 3) { const uschar * p = rr->data; -/*XXX need somehow to mark rr and its data as tainted. Doues this mean copying it? *//*TTT*/ +/*XXX need somehow to mark rr and its data as tainted. +Doues this mean copying it? That could actually be preferable, as the 64k +of dns_annwer could be alloc/free within this func. */ +/*TTT*/ uint8_t usage = p[0], sel = p[1], type = p[2]; DEBUG(D_tls) commit b7dda913d7f81dece907c536587b54a16b253e4a Author: Jeremy Harris Date: Sun Jan 25 23:20:23 2026 +0000 DANE: separately alloc the dns answer buffer for TLSA diff --git a/src/src/structs.h b/src/src/structs.h index 20438bb47..ba88f487b 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -827,10 +827,7 @@ typedef struct { #ifdef SUPPORT_DANE BOOL dane:1; /* TLSA says connection must do dane */ - /*TTT alloc*/ - /* Strictly, this should use tainted mem. Also, is rather large - 64k - so - perhaps should be allocated only when needed (for DANE)? */ - dns_answer tlsa_dnsa; /* strictly, this should use tainted mem */ + dns_answer * tlsa_dnsa; #endif } smtp_connect_args; diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 17ee21ef0..04b439950 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -3388,7 +3388,7 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) #ifdef SUPPORT_DANE /* Given our list of RRs from the TLSA lookup, build a lookup block in -GnuTLS-DANE's preferred format. Hang it on the state str for later +GnuTLS-DANE's preferred format. Hang it on the state struct for later use in DANE verification. We point at the dnsa data not copy it, so it must remain valid until @@ -3416,10 +3416,6 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; ) if (rr->type == T_TLSA && rr->size > 3) { const uschar * p = rr->data; -/*XXX need somehow to mark rr and its data as tainted. -Doues this mean copying it? That could actually be preferable, as the 64k -of dns_annwer could be alloc/free within this func. */ -/*TTT*/ uint8_t usage = p[0], sel = p[1], type = p[2]; DEBUG(D_tls) @@ -3441,7 +3437,7 @@ of dns_annwer could be alloc/free within this func. */ } tls_out.tlsa_usage |= 1<size; } @@ -3721,7 +3717,7 @@ set but both tls_verify_hosts and tls_try_verify_hosts are unset. Check only the specified host patterns if one of them is defined */ #ifdef SUPPORT_DANE -if (conn_args->dane && dane_tlsa_load(state, &conn_args->tlsa_dnsa)) +if (conn_args->dane && dane_tlsa_load(state, conn_args->tlsa_dnsa)) { DEBUG(D_tls) debug_printf("TLS: server certificate DANE required\n"); diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 9d3f5af73..72c5c7a46 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -3972,7 +3972,6 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; } found++; - /*TTT*/ switch (DANESSL_add_tlsa(ssl, usage, selector, mdname, p, rr->size - 3)) { default: @@ -4424,7 +4423,7 @@ if (tlsp->sni) #ifdef SUPPORT_DANE if (conn_args->dane) - if (dane_tlsa_load(exim_client_ctx->ssl, host, &conn_args->tlsa_dnsa, errstr) != OK) + if (dane_tlsa_load(exim_client_ctx->ssl, host, conn_args->tlsa_dnsa, errstr) != OK) return FALSE; #endif diff --git a/src/src/tls.c b/src/src/tls.c index 041cca5e9..5c349c2f4 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -850,7 +850,7 @@ exim_sha_init(h, HASH_SHA1); exim_sha_update_string(h, conn_args->host_lbserver); # ifdef SUPPORT_DANE if (conn_args->dane) - exim_sha_update(h, CUS &conn_args->tlsa_dnsa, sizeof(dns_answer)); + exim_sha_update(h, CUS conn_args->tlsa_dnsa, sizeof(dns_answer)); # endif exim_sha_update_string(h, conn_args->host->address); exim_sha_update(h, CUS &conn_args->host->port, sizeof(conn_args->host->port)); diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 7274050f1..836831a49 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2160,7 +2160,11 @@ int rc; if( sx->dane_required || verify_check_given_host(CUSS &ob->hosts_try_dane, sx->conn_args.host) == OK ) - switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required)) + { + if (!sx->conn_args.tlsa_dnsa) + sx->conn_args.tlsa_dnsa = store_get_dns_answer(); + switch (rc = tlsa_lookup(sx->conn_args.host, + sx->conn_args.tlsa_dnsa, sx->dane_required)) { case OK: sx->conn_args.dane = TRUE; #ifdef EXPERIMENTAL_SRV_SMTPS @@ -2182,6 +2186,7 @@ if( sx->dane_required # endif return rc; } + } return OK; } #endif @@ -4050,7 +4055,7 @@ int rc; uschar * message = NULL; -/* Large (12k, 66k if DANE supported). Tainted, for the data buffers */ +/* Large (12k). Tainted, for the data buffers */ smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED); BOOL pass_message = FALSE; commit 697303f0af9f46062d3ebc3b3c336903ef8447cb Author: Jeremy Harris Date: Thu Jan 15 12:17:45 2026 +0000 tidying diff --git a/src/src/functions.h b/src/src/functions.h index c95ea2dc4..2d14d2a58 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -139,7 +139,7 @@ extern BOOL bdat_hasc(void); extern int bdat_ungetc(int); extern void bdat_flush_data(void); -extern void bits_clear(unsigned long *, size_t, int *); +extern void bits_clear(bitmask_word_t *, size_t, int *); extern void bits_set(bitmask_word_t *, size_t, int *); extern void cancel_cutthrough_connection(BOOL, const uschar *); diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index bfcdb22af..d1885069b 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1423,6 +1423,11 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED)) smtp_printf("250 Reset OK\r\n", SP_NO_MORE); break; + case BADARG_CMD: + if (synprot_error(L_smtp_syntax_error, 501, NULL, + US"unexpected argument data") > 0) return; + break; + default: smtp_printf("421 %s\r\n", SP_NO_MORE, message); break; @@ -2888,15 +2893,16 @@ int synprot_error(int type, int code, uschar *data, uschar *errmess) { int yield = -1; +BOOL syntax_error = type == L_smtp_syntax_error; #ifndef DISABLE_EVENT event_raise(event_action, - L_smtp_syntax_error ? US"smtp:fail:syntax" : US"smtp:fail:protocol", + syntax_error ? US"smtp:fail:syntax" : US"smtp:fail:protocol", errmess, NULL); #endif log_write(type, LOG_MAIN, "SMTP %s error in %q %s %s", - type == L_smtp_syntax_error ? "syntax" : "protocol", + syntax_error ? "syntax" : "protocol", string_printing(smtp_cmd_buffer), host_and_ident(TRUE), errmess); GET_OPTION("smtp_max_synprot_errors"); @@ -4051,7 +4057,7 @@ while (done <= 0) { uschar * errmess, * log_msg, * smtp_code; uschar * user_msg = NULL, * recipient = NULL, * hello = NULL; - uschar * s, * ss; + uschar * s; BOOL was_rej_mail = FALSE, was_rcpt = FALSE; int start, end, sender_domain, recipient_domain; int rc, c, dsn_flags; @@ -4079,9 +4085,10 @@ while (done <= 0) done = smtp_handle_acl_fail(ACL_WHERE_AUTH, rc, user_msg, log_msg); else { - smtp_cmd_data = NULL; + uschar * dummy_errmsg; - if (smtp_in_auth(au, &s, &ss) == OK) + smtp_cmd_data = NULL; + if (smtp_in_auth(au, &s, &dummy_errmsg) == OK) { DEBUG(D_auth) debug_printf("tls auth succeeded\n"); } else { commit 02b8b183a16a5bc7e10eb45cfb454002f63400c7 Author: Jeremy Harris Date: Tue Jan 27 00:20:57 2026 +0000 Build: Gnu/HURD types Broken-by: c33264393a1c diff --git a/src/OS/os.h-GNU b/src/OS/os.h-GNU index 2a335bc27..3aba3def5 100644 --- a/src/OS/os.h-GNU +++ b/src/OS/os.h-GNU @@ -1,5 +1,5 @@ /* Exim: OS-specific C header file for GNU/Hurd */ -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ +/* Copyright (c) The Exim Maintainers 2020 - 2026 */ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include @@ -29,4 +29,9 @@ as well as any supplementary groups*/ # define EXIM_HAVE_OPENAT #endif +#ifdef PID_T_FMT +# undef PID_T_FMT +#endif +#define PID_T_FMT "%d" + /* End */ diff --git a/src/src/exim.c b/src/src/exim.c index a87219920..c42bb60d8 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -2824,7 +2824,7 @@ on the second character (the one after '-'), to save some effort. */ /* Use an intermediate variable so that we don't set debugging while decoding the debugging bits. */ - unsigned long selector = D_default; + bitmask_word_t selector = D_default; debug_selector = 0; debug_file = NULL; if (*argrest == 'd') commit be9dbc15f1d9fd6a50e56cdc1e8dca7c0fbb858f Author: Jeremy Harris Date: Sat Jan 31 14:54:12 2026 +0000 Build: handle int-size pid_t diff --git a/src/OS/os.h-FreeBSD b/src/OS/os.h-FreeBSD index 57ea82265..bb596ff0a 100644 --- a/src/OS/os.h-FreeBSD +++ b/src/OS/os.h-FreeBSD @@ -59,11 +59,6 @@ performance on outgoing mail a bit. */ #define OS_SENDFILE extern ssize_t os_sendfile(int, int, off_t *, size_t); -#ifdef PID_T_FMT -# undef PID_T_FMT -#endif -#define PID_T_FMT "%d" - /*******************/ diff --git a/src/OS/os.h-GNU b/src/OS/os.h-GNU index 3aba3def5..448548840 100644 --- a/src/OS/os.h-GNU +++ b/src/OS/os.h-GNU @@ -29,9 +29,4 @@ as well as any supplementary groups*/ # define EXIM_HAVE_OPENAT #endif -#ifdef PID_T_FMT -# undef PID_T_FMT -#endif -#define PID_T_FMT "%d" - /* End */ diff --git a/src/OS/os.h-OpenBSD b/src/OS/os.h-OpenBSD index 19db7189a..e2ef6b597 100644 --- a/src/OS/os.h-OpenBSD +++ b/src/OS/os.h-OpenBSD @@ -42,11 +42,6 @@ typedef struct __res_state *res_state; #define OFF_T_FMT "%lld" #define LONGLONG_T long long int -#ifdef PID_T_FMT -# undef PID_T_FMT -#endif -#define PID_T_FMT "%d" - #ifdef INO_T_FMT # undef INO_T_FMT #endif diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index b365643bb..3ef61735f 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -180,7 +180,10 @@ else fprintf(new, "#endif\n\n"); fprintf(new, "#ifndef PID_T_FMT\n"); -fprintf(new, "# define PID_T_FMT \"%%lu\"\n"); +if (sizeof(pid_t) == sizeof(int)) + fprintf(new, "# define PID_T_FMT \"%%d\"\n"); +else + fprintf(new, "# define PID_T_FMT \"%%lu\"\n"); fprintf(new, "#endif\n\n"); /* And for sizeof() results, size_t, which should with C99 be just %zu, deal commit 84f957f04761159d5047c376638c89dc94207ee9 Author: Jeremy Harris Date: Thu Feb 5 11:03:03 2026 +0000 Build: warn on small wordsize diff --git a/src/src/macros.h b/src/src/macros.h index 8600f5a94..597e44b96 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -423,6 +423,7 @@ enum { DEBUG_BIT(macro), /* 33 */ DEBUG_BIT(regex), #else +# warn BITWORDSIZE <= 32 DEBUG_Z_BIT(macro), DEBUG_Z_BIT(regex), #endif commit 2e50598cfe4ba43717d10680c7bb7162501c95b3 Author: Jeremy Harris Date: Thu Feb 5 11:04:17 2026 +0000 Logging: DSN diff --git a/src/src/deliver.c b/src/src/deliver.c index af10ff8f9..163868597 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -375,7 +375,7 @@ Returns: nothing */ void -deliver_msglog(const char *format, ...) +deliver_msglog(const char * format, ...) { va_list ap; if (!message_logs) return; @@ -1097,6 +1097,20 @@ return g; +static gstring * +delivery_log_dsn(gstring * g, const address_item * addr) +{ +return LOGGING(dsn) + ? dsn_ret || dsn_envid || addr->dsn_flags & rf_dsnflags || addr->dsn_orcpt + ? string_append(g, 2, US" DSN=", + addr->dsn_flags & rf_dsnlasthop ? US"notrouter" + : addr->dsn_aware == dsn_support_unknown ? US"notsmtp" + : addr->dsn_aware == dsn_support_no ? US"notpeer" + : US"yes") + : g + : g; +} + /******************************************************************************/ @@ -1237,12 +1251,14 @@ else g = string_catn(g, US" K", 2); } +g = delivery_log_dsn(g, addr); + #ifndef DISABLE_DKIM - if (addr->dkim_used && LOGGING(dkim_verbose)) - { - g = string_catn(g, US" DKIM=", 6); - g = string_cat(g, addr->dkim_used); - } +if (addr->dkim_used && LOGGING(dkim_verbose)) + { + g = string_catn(g, US" DKIM=", 6); + g = string_cat(g, addr->dkim_used); + } #endif /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */ @@ -1332,6 +1348,8 @@ if (addr->basic_errno > 0) if (addr->host_used) g = d_hostlog(g, addr); +g = delivery_log_dsn(g, addr); + if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); @@ -1409,6 +1427,8 @@ if (LOGGING(protocol_detail) && addr->protocol_sequence) g = d_tlslog(g, addr); #endif +g = delivery_log_dsn(g, addr); + if (addr->basic_errno > 0) g = string_append(g, 2, US" : ", US strerror(addr->basic_errno)); diff --git a/src/src/functions.h b/src/src/functions.h index 2d14d2a58..6af265361 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -107,6 +107,7 @@ extern tree_node *acl_var_create(const uschar *); extern void acl_var_write(uschar *, uschar *, void *); extern gstring * add_dmarc_info_for_log(gstring *); extern void add_driver_info(driver_info **, const driver_info *, size_t); +extern gstring * add_dsn_info_for_log(gstring *, int); extern gstring * add_spf_info_for_log(gstring *); extern gstring * add_tls_info_for_log(gstring *); diff --git a/src/src/globals.c b/src/src/globals.c index 58dc8bffd..3e350e750 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -961,6 +961,7 @@ bit_table log_options[] = { /* must be in alphabetical order, #endif BIT_TABLE(L, dnslist_defer), BIT_TABLE(L, dnssec), + BIT_TABLE(L, dsn), BIT_TABLE(L, etrn), BIT_TABLE(L, host_lookup_failed), BIT_TABLE(L, ident_timeout), diff --git a/src/src/macros.h b/src/src/macros.h index 597e44b96..4d2637d87 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -499,6 +499,7 @@ enum logbit { Li_dmarc, Li_dmarc_verbose, Li_dnssec, + Li_dsn, Li_ident_timeout, Li_incoming_interface, Li_incoming_port, diff --git a/src/src/receive.c b/src/src/receive.c index f1833c5a0..f40b7313f 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -4098,6 +4098,11 @@ if (message_reference) g = add_host_info_for_log(g); g = add_tls_info_for_log(g); +#ifdef SUPPORT_PROXY +if (proxy_session && LOGGING(proxy)) + g = string_append(g, 2, US" PRX=", proxy_local_address); +#endif + if (sender_host_authenticated) { g = string_append(g, 2, US" A=", sender_host_authenticated); @@ -4114,11 +4119,6 @@ if (prdr_requested) g = string_catn(g, US" PRDR", 5); #endif -#ifdef SUPPORT_PROXY -if (proxy_session && LOGGING(proxy)) - g = string_append(g, 2, US" PRX=", proxy_local_address); -#endif - if (chunking_state > CHUNKING_OFFERED) g = string_catn(g, US" K", 2); @@ -4131,6 +4131,9 @@ g = string_fmt_append(g, " S=%d", msg_size); if (LOGGING(8bitmime)) g = string_fmt_append(g, " M8S=%d", body_8bitmime); +if (LOGGING(dsn)) + g = add_dsn_info_for_log(g, ACL_WHERE_DATA); + #ifndef DISABLE_DKIM if (LOGGING(dkim)) { diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index d1885069b..84831ce45 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -160,6 +160,9 @@ static uschar *smtp_data_buffer; static uschar *smtp_cmd_data; static uschar *smtp_resp_buffer; +static uschar * rcpt_orcpt; +static int rcpt_dsn_flags; + /* We need to know the position of RSET, HELO, EHLO, AUTH, and STARTTLS. Their final fields of all except AUTH are forced TRUE at the start of a new message setup, to allow one of each between messages that is not counted as a nonmail @@ -1517,6 +1520,42 @@ return g; #endif } +/* Append DSN information to a log line + +Arguments: + g String under construction: allocated string to extend, or NULL + where ACL cause of call + +Returns: Allocated string or NULL +*/ +gstring * +add_dsn_info_for_log(gstring * g, int where) +{ +BOOL has_orcpt = FALSE, has_notify = FALSE; + +if (where == ACL_WHERE_RCPT) + { + if (rcpt_orcpt) has_orcpt = TRUE; + if (rcpt_dsn_flags) has_notify = TRUE; + } +else if (recipients_list) for (int i = 0; i < recipients_count; i++) + { + has_orcpt |= !!recipients_list[i].orcpt; + has_notify |= !!recipients_list[i].dsn_flags; + } + +if (LOGGING(dsn) && (dsn_ret || dsn_envid || has_orcpt || has_notify)) + { + g = string_catn(g, US" DSN=", 5); + if (dsn_ret) g = string_catn(g, US"ret,", 4); + if (dsn_envid) g = string_catn(g, US"envid,", 6); + if (has_orcpt) g = string_catn(g, US"orcpt,", 6); + if (has_notify) g = string_catn(g, US"notify,", 7); + gstring_trim(g, 1); + } +return g; +} + static gstring * @@ -3113,10 +3152,7 @@ smtp_handle_acl_fail(int where, int rc, uschar * user_msg, uschar * log_msg) { BOOL drop = rc == FAIL_DROP; int codelen = 3; -uschar *smtp_code; -uschar *lognl; -uschar *sender_info = US""; -uschar *what; +uschar * smtp_code, * lognl, * sender_info = US"", * what; if (drop) rc = FAIL; @@ -3263,13 +3299,14 @@ is closing if required and return 2. */ if (log_reject_target) log_write(where == ACL_WHERE_CONNECT ? L_connection_reject : 0, - log_reject_target, "%s%s%#Y%s%#Y%#Y %srejected %s%s", + log_reject_target, "%s%s%#Y%s%#Y%#Y%#Y %srejected %s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), add_tls_info_for_log(NULL), sender_info, add_spf_info_for_log(NULL), add_dmarc_info_for_log(NULL), + add_dsn_info_for_log(NULL, where), rc == FAIL ? US"" : US"temporarily ", what, log_msg); @@ -3285,7 +3322,7 @@ smtp_notquit_exit(US"acl-drop", NULL, NULL); /* An overenthusiastic fail2ban/iptables implimentation has been seen to result in the TCP conn staying open, and retrying, despite this process exiting. A -malicious client could possibly do the same, tying up server netowrking +malicious client could possibly do the same, tying up server networking resources. Close the socket explicitly to try to avoid that (there's a note in the Linux socket(7) manpage, SO_LINGER para, to the effect that exit() without close() results in the socket always lingering). */ @@ -4060,8 +4097,7 @@ while (done <= 0) uschar * s; BOOL was_rej_mail = FALSE, was_rcpt = FALSE; int start, end, sender_domain, recipient_domain; - int rc, c, dsn_flags; - uschar * orcpt = NULL; + int rc, c; gstring * g; #ifdef AUTH_TLS @@ -4317,11 +4353,11 @@ while (done <= 0) tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE)); /* Verify if configured. This doesn't give much security, but it does - make some people happy to be able to do it. If helo_verify_required is set, - (host matches helo_verify_hosts) failure forces rejection. If helo_verify - is set (host matches helo_try_verify_hosts), it does not. This is perhaps - now obsolescent, since the verification can now be requested selectively - at ACL time. */ + make some people happy to be able to do it. If helo_verify_required is + set, (host matches helo_verify_hosts) failure forces rejection. If + helo_verify is set (host matches helo_try_verify_hosts), it does not. + This is perhaps now obsolescent, since the verification can now be + requested selectively at ACL time. */ f.helo_verified = f.helo_verify_failed = sender_helo_dnssec = FALSE; if (fl.helo_verify_required || fl.helo_verify) @@ -4856,8 +4892,7 @@ while (done <= 0) break; /* Handle the two DSN options, but only if configured to do so (which - will have caused "DSN" to be given in the EHLO response). The code - itself is included only if configured in at build time. */ + will have caused "DSN" to be given in the EHLO response). */ case ENV_MAIL_OPT_RET: if (fl.dsn_advertised) @@ -5206,13 +5241,13 @@ while (done <= 0) break; } - /* Set the DSN flags orcpt and dsn_flags from the session*/ - orcpt = NULL; - dsn_flags = 0; + /* Set the DSN flags orcpt and dsn_flags from the session */ + rcpt_orcpt = NULL; + rcpt_dsn_flags = 0; if (fl.esmtp) for(;;) { - uschar *name, *value; + uschar * name, * value; if (!extract_option(&name, &value)) break; @@ -5220,49 +5255,49 @@ while (done <= 0) if (fl.dsn_advertised && strcmpic(name, US"ORCPT") == 0) { /* Check whether orcpt has been already set */ - if (orcpt) + if (rcpt_orcpt) { done = synprot_error(L_smtp_syntax_error, 501, NULL, US"ORCPT can be specified once only"); goto COMMAND_LOOP; } - orcpt = string_copy(value); - DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt); + rcpt_orcpt = string_copy(value); + DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", rcpt_orcpt); } else if (fl.dsn_advertised && strcmpic(name, US"NOTIFY") == 0) { /* Check if the notify flags have been already set */ - if (dsn_flags > 0) + if (rcpt_dsn_flags > 0) { done = synprot_error(L_smtp_syntax_error, 501, NULL, US"NOTIFY can be specified once only"); goto COMMAND_LOOP; } if (strcmpic(value, US"NEVER") == 0) - dsn_flags |= rf_notify_never; + rcpt_dsn_flags |= rf_notify_never; else { - uschar *p = value; - while (*p != 0) + uschar * p = value; + while (*p) { uschar *pp = p; - while (*pp != 0 && *pp != ',') pp++; + while (*pp && *pp != ',') pp++; if (*pp == ',') *pp++ = 0; if (strcmpic(p, US"SUCCESS") == 0) { DEBUG(D_receive) debug_printf("DSN: Setting notify success\n"); - dsn_flags |= rf_notify_success; + rcpt_dsn_flags |= rf_notify_success; } else if (strcmpic(p, US"FAILURE") == 0) { DEBUG(D_receive) debug_printf("DSN: Setting notify failure\n"); - dsn_flags |= rf_notify_failure; + rcpt_dsn_flags |= rf_notify_failure; } else if (strcmpic(p, US"DELAY") == 0) { DEBUG(D_receive) debug_printf("DSN: Setting notify delay\n"); - dsn_flags |= rf_notify_delay; + rcpt_dsn_flags |= rf_notify_delay; } else { @@ -5273,7 +5308,7 @@ while (done <= 0) } p = pp; } - DEBUG(D_receive) debug_printf("DSN Flags: %x\n", dsn_flags); + DEBUG(D_receive) debug_printf("DSN Flags: %x\n", rcpt_dsn_flags); } } @@ -5395,8 +5430,8 @@ while (done <= 0) receive_add_recipient(recipient, -1); /* Set the dsn flags in the recipients_list */ - recipients_list[recipients_count-1].orcpt = orcpt; - recipients_list[recipients_count-1].dsn_flags = dsn_flags; + recipients_list[recipients_count-1].orcpt = rcpt_orcpt; + recipients_list[recipients_count-1].dsn_flags = rcpt_dsn_flags; /* DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 9231a302e..8937496c0 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -245,7 +245,7 @@ local_scan_data = NULL; max_received_linelength = 0; message_linecount = 0; received_protocol = NULL; -received_count = 0; +received_count = recipients_count = 0; recipients_list = NULL; sender_address = NULL; sender_fullhost = NULL; commit 86b804ab3f2ed0acfb4789b5cc171336c1ca0bdd Author: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Thu Feb 5 11:58:28 2026 -0500 Docs: Bugs moved to forgejo Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com> commit 69f2b85553ac6e24c72ee231cb9ff79b67ce520f Author: Jeremy Harris Date: Sun Feb 8 17:12:54 2026 +0000 Debug: more uid info diff --git a/src/src/exim.c b/src/src/exim.c index c42bb60d8..7597abdca 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -803,8 +803,10 @@ DEBUG(D_uid) { int group_count, save_errno; gid_t group_list[EXIM_GROUPLIST_SIZE]; - debug_printf("changed uid/gid: %s\n uid=%ld gid=%ld pid=" PID_T_FMT "\n", - msg, (long int)geteuid(), (long int)getegid(), getpid()); + debug_printf("changed uid/gid: %s\n" + " uid %ld->%ld gid %ld->%ld pid=" PID_T_FMT "\n", + msg, (long)euid, (long)geteuid(), + (long)egid, (long)getegid(), getpid()); group_count = getgroups(nelem(group_list), group_list); save_errno = errno; debug_printf(" auxiliary group list:"); commit c767650d991e8186826a9f255852c01e8a9b9500 Author: Jeremy Harris Date: Mon Feb 9 10:16:07 2026 +0000 Debug: more uid detail diff --git a/src/src/debug.c b/src/src/debug.c index 487531e96..ee44091ff 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -161,7 +161,7 @@ Returns: nothing */ void -debug_print_ids(uschar *s) +debug_print_ids(uschar * s) { debug_printf("%s uid=%ld gid=%ld euid=%ld egid=%ld\n", s, (long int)getuid(), (long int)getgid(), (long int)geteuid(), diff --git a/src/src/deliver.c b/src/src/deliver.c index 163868597..1a9b89635 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -7348,6 +7348,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) } } +//debug_print_ids(US"after system filter:"); /* Scan the recipients list, and for every one that is not in the non- recipients tree, add an addr item to the chain of new addresses. If the pno diff --git a/src/src/log.c b/src/src/log.c index e4fd3aa7f..11d3838b0 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1539,15 +1539,12 @@ if (debug_file) { debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n" "DEBUG: Tag=%q opts=%q\n", tag_name, opts ? opts : US""); - return; + return debug_print_ids(US""); } if (tag_name && (Ustrchr(tag_name, '/') != NULL)) - { - log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", - tag_name); - return; - } + return log_write(0, LOG_MAIN|LOG_PANIC, + "debug tag may not contain a '/' in: %s", tag_name); debug_selector = D_default; if (opts) @@ -1565,6 +1562,8 @@ if ((debug_fd = open_log(lt_debug, tag_name)) != -1) debug_file = fdopen(debug_fd, "w"); else log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log"); + +debug_print_ids(US"debug enabled:"); } @@ -1576,7 +1575,7 @@ if (debug_fd < 0) Ustrncpy(debuglog_name, filename, sizeof(debuglog_name)-1); 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"); + DEBUG(D_deliver) debug_print_ids(US"debug enabled by spoolfile\n"); } /* else DEBUG(D_deliver) diff --git a/src/src/rda.c b/src/src/rda.c index dde001114..e1b30a4fd 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -122,7 +122,7 @@ if (saved_errno == ENOENT) saved_errno = errno; ALARM_CLR(0); - DEBUG(D_route) debug_printf("stat(%s)=%d\n", s, rc); + DEBUG(D_route) debug_printf_indent("stat(%s)=%d\n", s, rc); } if (sigalrm_seen || rc != 0) @@ -133,7 +133,7 @@ if (sigalrm_seen || rc != 0) } *error = string_sprintf("%s does not exist", filename); -DEBUG(D_route) debug_printf("%s\n", *error); +DEBUG(D_route) debug_printf_indent("%s\n", *error); return FILE_NOT_EXIST; } @@ -200,7 +200,7 @@ directory test. */ if (!(fwd = Ufopen(filename, "rb"))) switch(errno) { case ENOENT: /* File does not exist */ - DEBUG(D_route) debug_printf("%s does not exist\n%schecking parent directory\n", + DEBUG(D_route) debug_printf_indent("%s does not exist\n%schecking parent directory\n", filename, options & RDO_ENOTDIR ? "ignore_enotdir set => skip " : ""); *yield = options & RDO_ENOTDIR || rda_exists(filename, error) == FILE_NOT_EXIST @@ -209,14 +209,14 @@ if (!(fwd = Ufopen(filename, "rb"))) switch(errno) case ENOTDIR: /* Something on the path isn't a directory */ if (!(options & RDO_ENOTDIR)) goto DEFAULT_ERROR; - DEBUG(D_route) debug_printf("non-directory on path %s: file assumed not to " + DEBUG(D_route) debug_printf_indent("non-directory on path %s: file assumed not to " "exist\n", filename); *yield = FF_NONEXIST; return NULL; case EACCES: /* Permission denied */ if (!(options & RDO_EACCES)) goto DEFAULT_ERROR; - DEBUG(D_route) debug_printf("permission denied for %s: file assumed not to " + DEBUG(D_route) debug_printf_indent("permission denied for %s: file assumed not to " "exist\n", filename); *yield = FF_NONEXIST; return NULL; @@ -295,7 +295,7 @@ if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size) } filebuf[statbuf.st_size] = 0; -DEBUG(D_route) debug_printf(OFF_T_FMT " %sbytes read from %s\n", +DEBUG(D_route) debug_printf_indent(OFF_T_FMT " %sbytes read from %s\n", statbuf.st_size, is_tainted(filename) ? "(tainted) " : "", filename); (void)fclose(fwd); @@ -343,14 +343,15 @@ rda_extract(const redirect_block * rdata, int options, error_block ** eblockp, int * filtertype) { const uschar * data; +int yield = 0; -if (rdata->isfile) - { - int yield = 0; +expand_level++; + +if (!rdata->isfile) + data = rdata->string; +else if (!(data = rda_get_file_contents(rdata, options, error, &yield))) - return yield; - } -else data = rdata->string; + goto out; *filtertype = f.system_filtering ? FILTER_EXIM : rda_is_filter(data); @@ -362,10 +363,9 @@ expand_forbid that the expander inspects. */ if (*filtertype != FILTER_FORWARD) { - int frc; int old_expand_forbid = expand_forbid; - DEBUG(D_route) debug_printf("data is %s filter program\n", + DEBUG(D_route) debug_printf_indent("data is %s filter program\n", *filtertype == FILTER_EXIM ? "an Exim" : "a Sieve"); /* RDO_FILTER is an "allow" bit */ @@ -373,7 +373,7 @@ if (*filtertype != FILTER_FORWARD) if (!(options & RDO_FILTER)) { *error = US"filtering not enabled"; - return FF_ERROR; + goto ff_error; } expand_forbid = @@ -389,14 +389,14 @@ if (*filtertype != FILTER_FORWARD) if (options & RDO_EXIM_FILTER) { *error = US"Exim filtering not enabled"; - return FF_ERROR; + goto ff_error; } if (!(mi = misc_mod_find(US"exim_filter", NULL))) { *error = US"Exim-filtering not available"; - return FF_ERROR; + goto ff_error; } - frc = (((fn_t *) mi->functions)[EXIM_INTERPRET]) + yield = (((fn_t *) mi->functions)[EXIM_INTERPRET]) (data, options, generated, error); } else @@ -408,32 +408,40 @@ if (*filtertype != FILTER_FORWARD) if (options & RDO_SIEVE_FILTER) { *error = US"Sieve filtering not enabled"; - return FF_ERROR; + goto ff_error; } if (!(mi = misc_mod_find(US"sieve_filter", NULL))) { *error = US"Sieve filtering not available"; - return FF_ERROR; + goto ff_error; } - frc = (((fn_t *) mi->functions)[SIEVE_INTERPRET]) + yield = (((fn_t *) mi->functions)[SIEVE_INTERPRET]) (data, options, sieve, generated, error); } expand_forbid = old_expand_forbid; - return frc; + goto out; } /* Not a filter script */ -DEBUG(D_route) debug_printf("file is not a filter file\n"); +DEBUG(D_route) debug_printf_indent("file is not a filter file\n"); -return parse_forward_list(data, +yield = parse_forward_list(data, options, /* specials that are allowed */ generated, /* where to hang them */ error, /* for errors */ deliver_domain, /* to qualify \name */ include_directory, /* restrain to directory */ eblockp); /* for skipped syntax errors */ + +out: + expand_level--; + return yield; + +ff_error: + yield = FF_ERROR; + goto out; } @@ -565,7 +573,7 @@ uschar *data; uschar *readerror = US""; void (*oldsignal)(int); -DEBUG(D_route) debug_printf("rda_interpret (%s): '%s'\n", +DEBUG(D_route) debug_printf_indent("rda_interpret (%s): '%s'\n", rdata->isfile ? "file" : "string", string_printing(rdata->string)); /* Do the expansions of the file name or data first, while still privileged. */ @@ -580,7 +588,7 @@ if (!(data = expand_string(rdata->string))) rdata->string = data; DEBUG(D_route) - debug_printf("expanded: '%s'%s\n", data, is_tainted(data) ? " (tainted)":""); + debug_printf_indent("expanded: '%s'%s\n", data, is_tainted(data) ? " (tainted)":""); if (rdata->isfile && data[0] != '/') { @@ -644,7 +652,7 @@ if ((pid = exim_fork(US"router-interpret")) == 0) if (ugid->uid != root_uid && ugid->uid != exim_uid) { - DEBUG(D_rewrite) debug_printf("turned off address rewrite logging (not " + DEBUG(D_rewrite) debug_printf_indent("turned off address rewrite logging (not " "root or exim in this process)\n"); BIT_CLEAR(log_selector, log_selector_size, Li_address_rewrite); } @@ -785,7 +793,7 @@ out: exim_underbar_exit(EXIT_SUCCESS); bad: - DEBUG(D_rewrite) debug_printf("rda_interpret: failed write to pipe\n"); + DEBUG(D_rewrite) debug_printf_indent("rda_interpret: failed write to pipe\n"); goto out; } @@ -964,7 +972,7 @@ while ((rc = wait(&status)) != pid) } DEBUG(D_route) - debug_printf("rda_interpret: subprocess yield=%d error=%s\n", yield, *error); + debug_printf_indent("rda_interpret: subprocess yield=%d error=%s\n", yield, *error); if (had_disaster) { @@ -1005,3 +1013,5 @@ goto WAIT_EXIT; } /* End of rda.c */ +/* vi: aw ai sw=2 +*/ commit 0e3c999792b354e7b3e7c8679e58bcca7a47c837 Author: Jeremy Harris Date: Tue Feb 10 12:55:31 2026 +0000 Debug: DSN detail diff --git a/src/src/deliver.c b/src/src/deliver.c index 1a9b89635..6c80ec926 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6561,7 +6561,7 @@ for (const address_item * a = addr_succeed; a; a = a->next) "DSN: orcpt: %s flags: 0x%x\n" "DSN: envid: %s ret: %d\n" "DSN: Final recipient: %s\n" - "DSN: Remote SMTP server supports DSN: %d\n", + "DSN: Remote SMTP server supports DSN: %s\n", a->router ? a->router->drinst.name : US"(unknown)", a->address, sender_address, @@ -6569,7 +6569,7 @@ for (const address_item * a = addr_succeed; a; a = a->next) a->dsn_flags, dsn_envid ? dsn_envid : US"NULL", dsn_ret, a->address, - a->dsn_aware + dsn_aware_names[a->dsn_aware] ); /* send report if next hop not DSN aware or a router flagged "last DSN hop" commit c4025d649a74007d7141d89253018e3f51a4a456 Author: Jeremy Harris Date: Wed Feb 11 11:50:05 2026 +0000 tidying: pid_t diff --git a/src/src/daemon.c b/src/src/daemon.c index d3e84a567..fe9d25e0d 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -721,7 +721,8 @@ if (pid == 0) if (dpid > 0) { release_cutthrough_connection(US"passed for delivery"); - DEBUG(D_any) debug_printf("forked delivery process %d\n", (int)dpid); + DEBUG(D_any) + debug_printf("forked delivery process " PID_T_FMT "\n", dpid); } else { diff --git a/src/src/deliver.c b/src/src/deliver.c index 6c80ec926..e5d43c1a9 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6594,7 +6594,8 @@ if (addr_senddsn) int fd; pid_t pid = child_open_exim(&fd, US"DSN"); - DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %ld\n", (long)pid); + DEBUG(D_deliver) + debug_printf("DSN: child_open_exim returns: " PID_T_FMT "\n", pid); if (pid < 0) /* Creation of child failed */ { diff --git a/src/src/exim.c b/src/src/exim.c index 7597abdca..4d74ffead 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -6231,8 +6231,8 @@ for (BOOL more = TRUE; more; ) while (wait(&status) != pid); if ((status & 0x00ff) != 0) log_write(0, LOG_MAIN|LOG_PANIC, - "process %d crashed with signal %d while delivering %s", - (int)pid, status & 0x00ff, message_id); + "process " PID_T_FMT " crashed with signal %d while delivering %s", + pid, status & 0x00ff, message_id); if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE); } diff --git a/src/src/miscmods/sieve_filter.c b/src/src/miscmods/sieve_filter.c index cb57fa11f..3d1e56f84 100644 --- a/src/src/miscmods/sieve_filter.c +++ b/src/src/miscmods/sieve_filter.c @@ -3030,7 +3030,8 @@ while (*filter->pc) #ifndef COMPILE_SYNTAX_CHECKER if (filter_test == FTEST_NONE) { - int pid, fd; + pid_t pid; + int fd; if ((pid = child_open_exim2(&fd, envelope_from, envelope_from, US"sieve-notify")) >= 1) diff --git a/src/src/moan.c b/src/src/moan.c index e5af5e511..318d7c6aa 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -165,7 +165,7 @@ moan_send_message(const uschar * recipient, int ident, { int written = 0, fd, status, count = 0, size_limit = bounce_return_size_limit; FILE * fp; -int pid; +pid_t pid; #ifdef EXIM_HAVE_DMARC uschar * s, * s2; @@ -198,7 +198,8 @@ if (pid < 0) strerror(errno)); return FALSE; } -else DEBUG(D_any) debug_printf("Child process %d for sending message\n", pid); +else DEBUG(D_any) + debug_printf("Child process " PID_T_FMT " for sending message\n", pid); /* Creation of child succeeded */ @@ -600,7 +601,8 @@ moan_tell_someone(const uschar * who, const address_item * addr, { FILE * f; va_list ap; -int fd, pid = child_open_exim(&fd, US"moan_tell_someone"); +int fd; +pid_t pid = child_open_exim(&fd, US"moan_tell_someone"); if (pid < 0) { @@ -811,7 +813,8 @@ BOOL moan_skipped_syntax_errors(const uschar * rname, const error_block * eblock, const uschar * syntax_errors_to, BOOL some, const uschar * custom) { -int pid, fd; +pid_t pid; +int fd; const uschar * s; FILE * f; @@ -883,3 +886,5 @@ return TRUE; } /* End of moan.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/queue.c b/src/src/queue.c index 46f7f3d57..b63482a43 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -402,7 +402,7 @@ if (!recurse) *p = '\0'; p = big_buffer; - p += sprintf(CS p, "pid=%d", (int)queue_run_pid); + p += sprintf(CS p, "pid=" PID_T_FMT, queue_run_pid); if (*extras) p += sprintf(CS p, " -q%s", extras); @@ -658,7 +658,7 @@ for (int i = queue_run_in_order ? -1 : 0; if (pipe(pfd) < 0) log_write_die(0, LOG_MAIN, "failed to create pipe in queue " - "runner process %d: %s", queue_run_pid, strerror(errno)); + "runner process " PID_T_FMT ": %s", queue_run_pid, strerror(errno)); queue_run_pipe = pfd[pipe_write]; /* To ensure it gets passed on. */ /* Make sure it isn't stdin. This seems unlikely, but just to be on the @@ -703,7 +703,7 @@ single_item_retry: } if (pid < 0) log_write_die(0, LOG_MAIN, "fork of delivery process from " - "queue runner %d failed\n", queue_run_pid); + "queue runner " PID_T_FMT " failed\n", queue_run_pid); /* Close the writing end of the synchronizing pipe in this process, then wait for the first level process to terminate. */ @@ -815,7 +815,8 @@ if (q->queue_2stage) set_process_info("running queue (ph 1): wait-all, child %u/%u", i+1, active); waitpid(qpid[i], NULL, 0); - DEBUG(D_queue_run) debug_printf("q2stage reaped child %d\n", (int)qpid[i]); + DEBUG(D_queue_run) + debug_printf("q2stage reaped child " PID_T_FMT "\n", qpid[i]); } else break; /* should be no holes in table, so we're done */ diff --git a/src/src/rda.c b/src/src/rda.c index e1b30a4fd..bea4ad54c 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -967,7 +967,8 @@ WAIT_EXIT: while ((rc = wait(&status)) != pid) if (rc < 0 && errno == ECHILD) /* Process has vanished */ { - log_write(0, LOG_MAIN, "redirection process %d vanished unexpectedly", pid); + log_write(0, LOG_MAIN, + "redirection process " PID_T_FMT " vanished unexpectedly", pid); goto FINAL_EXIT; } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 84831ce45..35d279c63 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -3976,11 +3976,11 @@ if ((pid = exim_fork(US"etrn-command")) == 0) else { int status; - DEBUG(D_any) debug_printf("waiting for serialized ETRN process %d\n", - (int)pid); + DEBUG(D_any) + debug_printf("waiting for serialized ETRN process " PID_T_FMT "\n", pid); (void)wait(&status); - DEBUG(D_any) debug_printf("serialized ETRN process %d ended\n", - (int)pid); + DEBUG(D_any) + debug_printf("serialized ETRN process " PID_T_FMT " ended\n", pid); } if (smtp_etrn_serialize) enq_end(etrn_serialize_key); diff --git a/src/src/tls.c b/src/src/tls.c index 5c349c2f4..b79828e95 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -820,8 +820,8 @@ do { } while (rc < 0 && errno == EINTR); DEBUG(D_tls) - debug_printf("tls_validate_require_cipher child %d ended: status=0x%x\n", - (int)pid, status); + debug_printf("tls_validate_require_cipher child " PID_T_FMT + " ended: status=0x%x\n", pid, status); signal(SIGCHLD, oldsignal); diff --git a/src/src/transport.c b/src/src/transport.c index 457245cd0..cdf9f1864 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -1325,9 +1325,9 @@ write_pid = (pid_t)(-1); } if (filter_pid < 0) goto TIDY_UP; /* errno set */ -DEBUG(D_transport) - debug_printf("process %d running as transport filter: fd_write=%d fd_read=%d\n", - (int)filter_pid, fd_write, fd_read); +DEBUG(D_transport) debug_printf("process " PID_T_FMT + " running as transport filter: fd_write=%d fd_read=%d\n", + filter_pid, fd_write, fd_read); /* Fork subprocess to write the message to the filter, and return the result via a(nother) pipe. While writing to the filter, we do not do the CRLF, @@ -1381,7 +1381,7 @@ if (write_pid < 0) testharness_pause_ms(250); DEBUG(D_transport) - debug_printf("process %d writing to transport filter\n", (int)write_pid); + debug_printf("process "PID_T_FMT " writing to transport filter\n", write_pid); /* Copy the message from the filter to the output fd. A read error leaves len == -1 and errno set. We need to apply a timeout to the read, to cope with diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index d9d9d7a9d..81152a8e0 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -266,10 +266,8 @@ autoreply_transport_entry( { autoreply_transport_options_block * ob = tblock->drinst.options_block; const uschar * trname = tblock->drinst.name; -int fd, pid, rc; -int cache_fd = -1; -int cache_size = 0; -int add_size = 0; +pid_t pid; +int fd, rc, cache_fd = -1, cache_size = 0, add_size = 0; EXIM_DB * dbm_file = NULL; BOOL file_expand, return_message; const uschar * from, * reply_to, * to, * cc, * bcc, * subject, * headers; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 836831a49..537375e2e 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -3906,18 +3906,19 @@ smtp_proxy_tls(client_conn_ctx * ctx, uschar * buf, size_t bsize, int * pfd, struct pollfd p[2] = {{.fd = ctx->sock, .events = POLLIN}, {.fd = pfd[0], .events = POLLIN}}; void * tls_ctx = ctx->tls_ctx; -int rc, i; +pid_t pid; BOOL send_tls_shutdown = TRUE; acl_level++; close(pfd[1]); -if ((rc = exim_fork(US"tls-proxy"))) - _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS); +if ((pid = exim_fork(US"tls-proxy"))) + _exit(pid < 0 ? EXIT_FAILURE : EXIT_SUCCESS); set_process_info("proxying TLS connection for continued transport to %s\n", host); do { + int rc; time_t time_left = timeout; time_t time_start = time(NULL); @@ -3957,7 +3958,7 @@ do timeout = 5; } else - for (int nbytes = 0; rc - nbytes > 0; nbytes += i) + for (int nbytes = 0, i; rc - nbytes > 0; nbytes += i) if ((i = write(pfd[0], buf + nbytes, rc - nbytes)) < 0) goto done; /* Handle outbound data. We cannot yet combine payload and the TLS-close @@ -3979,7 +3980,7 @@ do shutdown(tls_out.active.sock, SHUT_WR); } else - for (int nbytes = 0; rc - nbytes > 0; nbytes += i) + for (int nbytes = 0, i; rc - nbytes > 0; nbytes += i) if ((i = tls_write(tls_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0) goto done; } @@ -5112,7 +5113,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) smtp_peer_options |= OPTION_TLS; if ((sx->ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0)) { - int pid = exim_fork(US"tls-proxy-interproc"); + pid_t pid = exim_fork(US"tls-proxy-interproc"); if (pid == 0) /* child; fork again to disconnect totally */ { /* does not return */ diff --git a/src/src/verify.c b/src/src/verify.c index be9ea7fe4..a7688d40a 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3603,7 +3603,8 @@ int verify_quota_call(const uschar * rcpt, int pos_cache, int neg_cache, uschar ** msg) { -int pfd[2], pid, save_errno, yield = FAIL; +int pfd[2], save_errno, yield = FAIL; +pid_t pid; void (*oldsignal)(int); const uschar * where = US"socketpair"; commit 48de6fe98d29505ebef85eb8e0be93e5b13b7427 Author: Jeremy Harris Date: Tue Feb 10 22:54:24 2026 +0000 Fix delay of chained message after bounce Broken-by: be5901583f97 diff --git a/src/src/deliver.c b/src/src/deliver.c index e5d43c1a9..5dbdf26c2 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -3759,11 +3759,12 @@ while (!done) dup2((recvd_fd = recv_fd_from_sock(fd)), 0); close(recvd_fd); + /*XXX continue_host_port relies on a preceding A0 record */ DEBUG(D_deliver) debug_printf("continue: fd %d tpt %s host '%s' addr '%s':%d" " seq %d\n", recvd_fd, continue_transport, continue_hostname, - continue_host_address, deliver_host_port, + continue_host_address, continue_host_port, continue_sequence); break; } @@ -6547,8 +6548,8 @@ return child_close(pid, 0) == 0; * Send a success-DSN * *************************************************/ -static void -maybe_send_dsn(const address_item * const addr_succeed) +static BOOL +maybe_send_dsn(const address_item * const addr_succeed, BOOL has_privs) { address_item * addr_senddsn = NULL; @@ -6592,7 +6593,15 @@ for (const address_item * a = addr_succeed; a; a = a->next) if (addr_senddsn) { /* create exim process to send message */ int fd; - pid_t pid = child_open_exim(&fd, US"DSN"); + pid_t pid; + + if (has_privs) + { + exim_setugid(exim_uid, exim_gid, FALSE, US"post-delivery DSN gen"); + has_privs = FALSE; + } + + pid = child_open_exim(&fd, US"DSN"); DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: " PID_T_FMT "\n", pid); @@ -6613,6 +6622,8 @@ if (addr_senddsn) uschar * bound; transport_ctx tctx = {{0}}; + priv_drop_temp(exim_uid, exim_gid); + DEBUG(D_deliver) debug_printf("sending success-dsn to: %s\n", sender_address); @@ -6697,8 +6708,19 @@ if (addr_senddsn) fflush(f); fclose(f); (void) child_close(pid, 0); /* Waits for child to close, no timeout */ + + priv_restore(); } } +return has_privs; +} + +static inline BOOL +drop_privs(const uschar * why, BOOL has_privs) +{ +if (has_privs) + exim_setugid(exim_uid, exim_gid, FALSE, US"post-delivery warn gen"); +return FALSE; } /************************************************* @@ -6747,6 +6769,7 @@ time_t now; address_item * addr_last; uschar * filter_message, * info; open_db dbblock, * dbm_file = NULL; +BOOL has_privs = TRUE; rmark reset_point; CONTINUED_ID: @@ -7349,7 +7372,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) } } -//debug_print_ids(US"after system filter:"); +/* debug_print_ids(US"after system filter:"); */ /* Scan the recipients list, and for every one that is not in the non- recipients tree, add an addr item to the chain of new addresses. If the pno @@ -8465,9 +8488,19 @@ DEBUG(D_deliver) debug_printf(">>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>\n"); cancel_cutthrough_connection(TRUE, US"deliveries are done"); -/* Root privilege is no longer needed */ +/* We used to always drop privs here, from root to exim, but the introduction +of handling a further transport-suggested message requires we retain root. +On the other hand, we want bounce messages to be sent by the Exim user. So, if +there is need to send a response (bounce, warn or DSN) drop at that point and +do a re-exec for the next chained message. +This arises because the reponse (presumably) is labelled with the +reuid not (say) the euid - so we cannot use priv_drop_temp(). */ -exim_setugid(exim_uid, exim_gid, FALSE, US"post-delivery tidying"); +if (addr_failed) /* We will be generating a bounce */ + { + exim_setugid(exim_uid, exim_gid, FALSE, US"post-delivery tidying"); + has_privs = FALSE; + } set_process_info("tidying up after delivering %s", message_id); signal(SIGTERM, SIG_IGN); @@ -8539,90 +8572,94 @@ else if (!f.dont_deliver) /* Send DSN for successful messages if requested */ -maybe_send_dsn(addr_succeed); +has_privs = maybe_send_dsn(addr_succeed, has_privs); /* If any addresses failed, we must send a message to somebody, unless af_ignore_error is set, in which case no action is taken. It is possible for several messages to get sent if there are addresses with different requirements. */ -while (addr_failed) +if (addr_failed) { - const uschar * logtod = tod_stamp(tod_log); - address_item * addr; + has_privs = drop_privs(US"post-delivery bounce gen", has_privs); - /* There are weird cases when logging is disabled in the transport. However, - there may not be a transport (address failed by a router). */ + do + { + const uschar * logtod = tod_stamp(tod_log); + address_item * addr; - f.disable_logging = FALSE; - if (addr_failed->transport) - f.disable_logging = addr_failed->transport->disable_logging; + /* There are weird cases when logging is disabled in the transport. + However, there may not be a transport (address failed by a router). */ - DEBUG(D_deliver) - debug_printf("processing failed address %s\n", addr_failed->address); + f.disable_logging = addr_failed->transport + ? addr_failed->transport->disable_logging : FALSE; - /* There are only two ways an address in a bounce message can get here: + DEBUG(D_deliver) + debug_printf("processing failed address %s\n", addr_failed->address); - (1) When delivery was initially deferred, but has now timed out (in the call - to retry_update() above). We can detect this by testing for - af_retry_timedout. If the address does not have its own errors address, - we arrange to ignore the error. + /* There are only two ways an address in a bounce message can get here: - (2) If delivery failures for bounce messages are being ignored. We can detect - this by testing for af_ignore_error. This will also be set if a bounce - message has been autothawed and the ignore_bounce_errors_after time has - passed. It might also be set if a router was explicitly configured to - ignore errors (errors_to = ""). + (1) When delivery was initially deferred, but has now timed out (in the + call to retry_update() above). We can detect this by testing for + af_retry_timedout. If the address does not have its own errors + address, we arrange to ignore the error. - If neither of these cases obtains, something has gone wrong. Log the - incident, but then ignore the error. */ + (2) If delivery failures for bounce messages are being ignored. We can + detect this by testing for af_ignore_error. This will also be set if a + bounce message has been autothawed and the ignore_bounce_errors_after + time has passed. It might also be set if a router was explicitly + configured to ignore errors (errors_to = ""). - if (sender_address[0] == 0 && !addr_failed->prop.errors_address) - { - if ( !testflag(addr_failed, af_retry_timedout) - && !addr_failed->prop.ignore_error) - log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message " - "failure is neither frozen nor ignored (it's been ignored)"); + If neither of these cases obtains, something has gone wrong. Log the + incident, but then ignore the error. */ - addr_failed->prop.ignore_error = TRUE; - } + if (!*sender_address && !addr_failed->prop.errors_address) + { + if ( !testflag(addr_failed, af_retry_timedout) + && !addr_failed->prop.ignore_error) + log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message " + "failure is neither frozen nor ignored (it's been ignored)"); - /* If the first address on the list has af_ignore_error set, just remove - it from the list, throw away any saved message file, log it, and - mark the recipient done. */ + addr_failed->prop.ignore_error = TRUE; + } - if ( addr_failed->prop.ignore_error - || addr_failed->dsn_flags & rf_dsnflags - && !(addr_failed->dsn_flags & rf_notify_failure) - ) - { - addr = addr_failed; - addr_failed = addr->next; - if (addr->return_filename) Uunlink(addr->return_filename); + /* If the first address on the list has af_ignore_error set, just remove + it from the list, throw away any saved message file, log it, and + mark the recipient done. */ + + if ( addr_failed->prop.ignore_error + || addr_failed->dsn_flags & rf_dsnflags + && !(addr_failed->dsn_flags & rf_notify_failure) + ) + { + addr = addr_failed; + addr_failed = addr->next; + if (addr->return_filename) Uunlink(addr->return_filename); #ifndef DISABLE_EVENT - msg_event_raise(US"msg:fail:delivery", addr); + msg_event_raise(US"msg:fail:delivery", addr); #endif - log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s", - addr->address, - !addr->parent ? US"" : US" <", - !addr->parent ? US"" : addr->parent->address, - !addr->parent ? US"" : US">", - addr->prop.ignore_error - ? US"" : US": RFC 3461 DSN, failure notify not requested"); - - address_done(addr, logtod); - child_done(addr, logtod); - /* Panic-dies on error */ - (void)spool_write_header(message_id, SW_DELIVERING, NULL); - } + log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s", + addr->address, + !addr->parent ? US"" : US" <", + !addr->parent ? US"" : addr->parent->address, + !addr->parent ? US"" : US">", + addr->prop.ignore_error + ? US"" : US": RFC 3461 DSN, failure notify not requested"); - /* Otherwise, handle the sending of a message. Find the error address for - the first address, then send a message that includes all failed addresses - that have the same error address. */ + address_done(addr, logtod); + child_done(addr, logtod); + /* Panic-dies on error */ + (void) spool_write_header(message_id, SW_DELIVERING, NULL); + } - else - send_bounce_message(now, logtod); + /* Otherwise, handle the sending of a message. Find the error address for + the first address, then send a message that includes all failed addresses + that have the same error address. */ + + else + send_bounce_message(now, logtod); + } while (addr_failed); } f.disable_logging = FALSE; /* In case left set */ @@ -8860,11 +8897,14 @@ else if (addr_defer != (address_item *)(+1)) have been. */ if (warning_count < count) + { + has_privs = drop_privs(US"post-delivery warn gen", has_privs); if (send_warning_message(recipients, queue_time, show_time)) { warning_count = count; update_spool = TRUE; /* Ensure spool rewritten */ } + } } } @@ -8907,6 +8947,8 @@ else if (addr_defer != (address_item *)(+1)) else ss++; + has_privs = drop_privs(US"post-delivery freezemsg gen", has_privs); + moan_tell_someone(freeze_tell, addr_defer, US"Message frozen", "Message %s has been frozen%s.\nThe sender is <%s>.\n", message_id, s, sender_address); @@ -8983,22 +9025,46 @@ report_time_since(×tamp_startup, US"delivery end"); /* testcase 0005 */ /* If the transport suggested another message to deliver, go round again. */ if (final_yield == DELIVER_ATTEMPTED_NORMAL && *continue_next_id) - { - addr_defer = addr_failed = addr_succeed = NULL; + if (has_privs) + { + addr_defer = addr_failed = addr_succeed = NULL; - tree_duplicates = NULL; /* discard dups info from old message */ - addr_duplicate = NULL; + tree_duplicates = NULL; /* discard dups info from old message */ + addr_duplicate = NULL; - spool_clear_header_globals(); - deliver_set_expansions(NULL); - deliver_host_address = return_path = bounce_recipient = NULL; + spool_clear_header_globals(); + deliver_set_expansions(NULL); + deliver_host_address = return_path = bounce_recipient = NULL; - store_reset(reset_point); + store_reset(reset_point); - id = string_copyn(continue_next_id, MESSAGE_ID_LENGTH); - continue_next_id[0] = '\0'; - goto CONTINUED_ID; - } + id = string_copyn(continue_next_id, MESSAGE_ID_LENGTH); + continue_next_id[0] = '\0'; + goto CONTINUED_ID; + } + else + { + cutthrough.peer_options = smtp_peer_options; + cutthrough.is_tls = !!continue_proxy_cipher; + cutthrough.snd_ip = sending_ip_address; + cutthrough.snd_port = sending_port; + cutthrough.cipher = continue_proxy_cipher; + cutthrough.sni = continue_proxy_sni; + cutthrough.is_dane = continue_proxy_dane; + cutthrough.transport = US continue_transport; + cutthrough.host.name = continue_hostname; + cutthrough.host.address = continue_host_address; + cutthrough.host.port = continue_host_port; + + transport_do_pass_socket(continue_next_id, 0); + + /* Control never returns here. */ + } + +/* Root privilege is no longer needed */ + +if (has_privs) + exim_setugid(exim_uid, exim_gid, FALSE, US"post-delivery tidying"); /* It is unlikely that there will be any cached resources, since they are released after routing, and in the delivery subprocesses. However, it's @@ -9042,7 +9108,8 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) #ifndef DISABLE_TLS if (cutthrough.is_tls) { - int pfd[2], pid; + int pfd[2]; + pid_t pid; cutthrough.peer_options |= OPTION_TLS; diff --git a/src/src/transport.c b/src/src/transport.c index cdf9f1864..6700cb8b6 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -2036,7 +2036,7 @@ retfalse: *************************************************/ /* Just the regain-root-privilege exec portion. -The sole caller is delivery_re_exec(). */ +Callers: delivery_re_exec(), deliver_message() */ void transport_do_pass_socket(uschar * id, int socket_fd) commit f667087092f23247d9b9196d07e2470b5df0be77 Author: Jeremy Harris Date: Wed Feb 11 14:38:41 2026 +0000 tidying diff --git a/src/src/deliver.c b/src/src/deliver.c index 5dbdf26c2..af817e791 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6622,8 +6622,6 @@ if (addr_senddsn) uschar * bound; transport_ctx tctx = {{0}}; - priv_drop_temp(exim_uid, exim_gid); - DEBUG(D_deliver) debug_printf("sending success-dsn to: %s\n", sender_address); @@ -6708,8 +6706,6 @@ if (addr_senddsn) fflush(f); fclose(f); (void) child_close(pid, 0); /* Waits for child to close, no timeout */ - - priv_restore(); } } return has_privs; diff --git a/src/src/log.c b/src/src/log.c index 11d3838b0..028f75aa0 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1539,7 +1539,8 @@ if (debug_file) { debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n" "DEBUG: Tag=%q opts=%q\n", tag_name, opts ? opts : US""); - return debug_print_ids(US""); + debug_print_ids(US""); + return; } if (tag_name && (Ustrchr(tag_name, '/') != NULL)) commit f9f0152615c628934e95c7ce6d4a2e74286a5e7e Author: Jeremy Harris Date: Fri Feb 6 00:30:05 2026 +0000 tidying diff --git a/src/src/log.c b/src/src/log.c index 028f75aa0..0793b3269 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1544,8 +1544,13 @@ if (debug_file) } if (tag_name && (Ustrchr(tag_name, '/') != NULL)) - return log_write(0, LOG_MAIN|LOG_PANIC, + { + log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", + tag_name); + log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", tag_name); + return; + } debug_selector = D_default; if (opts) commit 46e4e20c3d5ffb0680f36b6cddf5998f80a70ef4 Author: Jeremy Harris Date: Thu Feb 12 15:16:09 2026 +0000 Build: more detail on consistency-check fail diff --git a/src/scripts/source_checks b/src/scripts/source_checks index 8620b27f5..ef1683cf2 100644 --- a/src/scripts/source_checks +++ b/src/scripts/source_checks @@ -13,7 +13,7 @@ do | awk '/{ (US)?"/ {print $2}' \ | awk -F\" '{print $2}' \ | LC_ALL=C sort -c \ - || exit 1 + || { echo "Table $table in $file is not alphabetically ordered" >&2 ; exit 1; } done <<-END readconf.c optionlist_config globals.c optionlist_auths @@ -42,8 +42,7 @@ do perl -e '$/= undef; while (<>) { print $1 if /(?<='$table'\[\])\s*=\s*{\s?(([^}]*)+)}/m }' \ | awk -F\" '/"/ {print $2}' \ | LC_ALL=C sort -c \ - || exit 1 - + || { echo "Table $table in $file is not alphabetically ordered" >&2 ; exit 1; } done <<-END expand.c item_table expand.c op_table_underscore commit 3982394cf435a6e0321ce81cd26269892ee64a7b Author: Jeremy Harris Date: Thu Feb 12 17:25:04 2026 +0000 Fix logged autoreply size. Bug 3197 diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 81152a8e0..ca89534ed 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -567,14 +567,15 @@ if ((pid = child_open_exim(&fd, US"autoreply")) < 0) as the -t option is used. The "headers" stuff *must* be last in case there are newlines in it which might, if placed earlier, screw up other headers. */ +transport_count = 0; fp = fdopen(fd, "wb"); -if (from) fprintf(fp, "From: %s\n", from); -if (reply_to) fprintf(fp, "Reply-To: %s\n", reply_to); -if (to) fprintf(fp, "To: %s\n", to); -if (cc) fprintf(fp, "Cc: %s\n", cc); -if (bcc) fprintf(fp, "Bcc: %s\n", bcc); -if (subject) fprintf(fp, "Subject: %s\n", subject); +if (from) transport_count += fprintf(fp, "From: %s\n", from) + 1; +if (reply_to) transport_count += fprintf(fp, "Reply-To: %s\n", reply_to) + 1; +if (to) transport_count += fprintf(fp, "To: %s\n", to) + 1; +if (cc) transport_count += fprintf(fp, "Cc: %s\n", cc) + 1; +if (bcc) transport_count += fprintf(fp, "Bcc: %s\n", bcc) + 1; +if (subject) transport_count += fprintf(fp, "Subject: %s\n", subject) + 1; /* Generate In-Reply-To from the message_id header; there should always be one, but code defensively. */ @@ -586,24 +587,34 @@ if (h) { message_id = Ustrchr(h->text, ':') + 1; Uskip_whitespace(&message_id); - fprintf(fp, "In-Reply-To: %s", message_id); + transport_count += fprintf(fp, "In-Reply-To: %s", message_id); } +/*XXX byte count? */ moan_write_references(fp, message_id); /* Add an Auto-Submitted: header */ -fprintf(fp, "Auto-Submitted: auto-replied\n"); +transport_count += fprintf(fp, "Auto-Submitted: auto-replied\n") + 1; /* Add any specially requested headers */ -if (headers) fprintf(fp, "%s\n", headers); +if (headers) + { + int i = 1; + transport_count += fprintf(fp, "%s\n", headers); + for (const uschar * s = headers; *s; s++) if (*s == '\n') i++; + transport_count += i; + } + fprintf(fp, "\n"); if (text) { - fprintf(fp, "%s", CS text); - if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n"); + int i = fprintf(fp, "%s", CS text); + if (text[Ustrlen(text)-1] != '\n') { fprintf(fp, "\n"); i++; } + for (const uschar * s = text; *s; s++) if (*s == '\n') i++; + transport_count += i; } if (ff) @@ -612,13 +623,17 @@ if (ff) if (file_expand) { const uschar * s = expand_string(big_buffer); + int i; if (!s) DEBUG(D_transport) debug_printf("error while expanding line from file:\n %s\n %s\n", big_buffer, expand_string_message); - fprintf(fp, "%s", s ? CS s : CS big_buffer); + if (!s) s = big_buffer; + i = fprintf(fp, "%s", CS s); + for (const uschar * t = s; *t; t++) if (*t == '\n') i++; + transport_count += i; } else - fprintf(fp, "%s", CS big_buffer); + transport_count += fprintf(fp, "%s", CS big_buffer) + 1; (void) fclose(ff); } @@ -654,17 +669,17 @@ if (return_message) DELIVER_IN_BUFFER_SIZE; if (fstat(deliver_datafile, &statbuf) == 0 && statbuf.st_size > max) { - fprintf(fp, "\n%s" + transport_count += fprintf(fp, "\n%s" "------ The body of the message is " OFF_T_FMT " characters long; only the first\n" "------ %d or so are included here.\n\n", rubric, statbuf.st_size, - (max/1000)*1000); + (max/1000)*1000) + 5; } - else fprintf(fp, "\n%s\n", rubric); + else + transport_count += fprintf(fp, "\n%s\n", rubric) + 3; } - else fprintf(fp, "\n%s\n", rubric); + else transport_count += fprintf(fp, "\n%s\n", rubric) + 3; fflush(fp); - transport_count = 0; transport_write_message(&tctx, bounce_return_size_limit); } commit a1c6e418abb14297980e705a508b5f32f67ca63a Author: Jeremy Harris Date: Fri Feb 13 11:55:51 2026 +0000 Add daemon job counters to exiwhat. Bug 341 diff --git a/src/src/daemon.c b/src/src/daemon.c index fe9d25e0d..e0f6e2aca 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ +/* Copyright (c) The Exim Maintainers 2020 - 2026 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -43,6 +43,7 @@ static int accept_retry_errno; static BOOL accept_retry_select_failed; static int queue_run_count = 0; /* current runners */ +static const uschar * daemon_process_info = NULL; static unsigned queue_runner_slot_count = 0; static runner_slot * queue_runner_slots = NULL; @@ -751,6 +752,8 @@ else if (smtp_slots) if (smtp_accept_max_per_host) smtp_slots[i].host_address = string_copy_malloc(sender_host_address); smtp_accept_count++; + set_process_info("daemon(%s): [%d+%d] %s", version_string, + smtp_accept_count, queue_run_count, daemon_process_info); break; } DEBUG(D_any) debug_printf("%d SMTP accept process%s running\n", @@ -909,6 +912,8 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) if (--smtp_accept_count < 0) smtp_accept_count = 0; DEBUG(D_any) debug_printf("%d SMTP accept process%s now running\n", smtp_accept_count, smtp_accept_count == 1 ? "" : "es"); + set_process_info("daemon(%s): [%d+%d] %s", version_string, + smtp_accept_count, queue_run_count, daemon_process_info); break; } if (i < smtp_accept_max) continue; /* Found an accepting process */ @@ -928,6 +933,8 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) if (--queue_run_count < 0) queue_run_count = 0; DEBUG(D_any) debug_printf("%d queue-runner process%s now running\n", queue_run_count, queue_run_count == 1 ? "" : "es"); + set_process_info("daemon(%s): [%d+%d] %s", version_string, + smtp_accept_count, queue_run_count, daemon_process_info); for (qrunner ** p = &qrunners, * q = qrunners; q; p = &q->next, q = *p) if (q->name == r->queue_name) @@ -1617,6 +1624,8 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ } DEBUG(D_any) debug_printf("%d queue-runner process%s running\n", queue_run_count, queue_run_count == 1 ? "" : "es"); + set_process_info("daemon(%s): [%d+%d] %s", version_string, + smtp_accept_count, queue_run_count, daemon_process_info); } } } @@ -2434,7 +2443,7 @@ must be set up. */ if (f.inetd_wait_mode) { - uschar *p = big_buffer; + uschar * p = big_buffer; if (inetd_wait_timeout >= 0) sprintf(CS p, "terminating after %d seconds", inetd_wait_timeout); @@ -2444,7 +2453,7 @@ if (f.inetd_wait_mode) log_write(0, LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", launched with listening socket, %s", version_string, getpid(), big_buffer); - set_process_info("daemon(%s): pre-listening socket", version_string); + daemon_process_info = US"pre-listening socket"; /* set up the timeout logic */ sigalrm_seen = TRUE; @@ -2550,8 +2559,8 @@ else if (f.daemon_listen) log_write(0, LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", %s, listening for %s", version_string, getpid(), qinfo, big_buffer); - set_process_info("daemon(%s): %s, listening for %s", - version_string, qinfo, big_buffer); + daemon_process_info = + string_sprintf("%s, listening for %s", qinfo, big_buffer); } else /* no listening sockets, only queue-runs */ @@ -2560,9 +2569,12 @@ else /* no listening sockets, only queue-runs */ log_write(0, LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", %s, not listening for SMTP", version_string, getpid(), s); - set_process_info("daemon(%s): %s, not listening", version_string, s); + daemon_process_info = string_sprintf("%s, not listening", s); } +set_process_info("daemon(%s): [%d+%d] %s", + version_string, smtp_accept_count, queue_run_count, daemon_process_info); + /* Do any work it might be useful to amortize over our children (eg: compile regex) */ commit b329cb2c4c2c3fe9300eca7fd04abdadd41f4d54 Author: Jeremy Harris Date: Fri Feb 13 16:42:45 2026 +0000 exiwhat: compress daemon listener addrs diff --git a/src/src/daemon.c b/src/src/daemon.c index e0f6e2aca..87a4835be 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -2475,6 +2475,7 @@ else if (f.daemon_listen) listings separate. */ for (int j = 0, i; j < 2; j++) + { for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) { /* First time round, look for SMTP ports; second time round, look for @@ -2507,6 +2508,9 @@ else if (f.daemon_listen) else /* check for previously-seen IP */ { ip_address_item * i2; + + /* Look for same-IP combinations of ports */ + for (i2 = addresses; i2 != ipa; i2 = i2->next) if ( host_is_tls_on_connect_port(i2->port) == (j > 0) && Ustrcmp(ipa->address, i2->address) == 0 @@ -2529,6 +2533,39 @@ else if (f.daemon_listen) } } + /* Now look for same-port (or portlist) combinations of IPs */ + + for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next) + if (host_is_tls_on_connect_port(ipa->port) == (j > 0)) + { + const uschar * portlist, * i2_plist; + + if (ipa->log && (portlist = Ustrrchr(ipa->log, ':'))) + { + const uschar * iplist = ipa->log + 1; /* skip leading space */ + int iplen = portlist - iplist; + + for (ip_address_item * i2 = addresses; i2 != ipa; i2 = i2->next) + if ( host_is_tls_on_connect_port(i2->port) == (j > 0) + && i2->log + && (i2_plist = Ustrrchr(i2->log, ':')) + && Ustrcmp(portlist, i2_plist) == 0 + ) + { + BOOL is_list = i2->log[1] == '{'; /*}*/ + const uschar * i2list = i2->log + (is_list ? 2 : 1); + int i2len = i2_plist - i2list - (is_list ? 1 : 0); + + i2->log = string_sprintf(" {%.*s %.*s}%s", + i2len, i2list, iplen, iplist, + portlist); + + ipa->log = NULL; + } + } + } + } + p = big_buffer; for (int j = 0, i; j < 2; j++) { commit ca01bed5ec82761a1b22ca529def1ec47257a72f Author: Jeremy Harris Date: Tue Feb 17 22:24:21 2026 +0000 bounce_charset option. Bug 2281 diff --git a/src/src/deliver.c b/src/src/deliver.c index af817e791..09e753f8f 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -5923,6 +5923,16 @@ fprintf(fp, "%s\n", wrap_header(string_from_gstring(g), 79, 1023, US" ", 1)); * Send a bounce message * *************************************************/ +static uschar * +get_bounce_charset(void) +{ +uschar * charset; +GET_OPTION("bounce_charset"); +return !(charset = expand_string(bounce_charset)) + || Ustrcmp(charset, "us-ascii") != 0 && Ustrcmp(charset, "UTF-8") != 0 + ? US"us-ascii" : charset; +} + /* Find the error address for the first address, then send a message that includes all failed addresses that have the same error address. Note the bounce_recipient is a global so that it can be accessed by $bounce_recipient @@ -6045,9 +6055,10 @@ else to_sender? ": returning message to sender" : ""); /* output human readable part as text/plain section */ + GET_OPTION("bounce_charset"); fprintf(fp, "--%s\n" - "Content-type: text/plain; charset=us-ascii\n\n", - bound); + "Content-type: text/plain; charset=%s\n\n", + bound, get_bounce_charset()); if ((emf_text = next_emf(emf, US"intro"))) fprintf(fp, "%s", CS emf_text); @@ -6418,8 +6429,8 @@ else /* output human readable part as text/plain section */ fprintf(f, "--%s\n" - "Content-type: text/plain; charset=us-ascii\n\n", - bound); + "Content-type: text/plain; charset=%s\n\n", + bound, get_bounce_charset()); if ((wmf_text = next_emf(wmf, US"intro"))) fprintf(f, "%s", CS wmf_text); @@ -6643,11 +6654,11 @@ if (addr_senddsn) "MIME-Version: 1.0\n\n" "--%s\n" - "Content-type: text/plain; charset=us-ascii\n\n" + "Content-type: text/plain; charset=%s\n\n" "This message was created automatically by mail delivery software.\n" " ----- The following addresses had successful delivery notifications -----\n", - bound, bound); + bound, bound, get_bounce_charset()); for (address_item * a = addr_senddsn; a; a = a->next) fprintf(f, "<%s> (relayed %s)\n\n", diff --git a/src/src/globals.c b/src/src/globals.c index 3e350e750..6b85122f7 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -555,6 +555,7 @@ int bsmtp_transaction_linecount = 0; int body_8bitmime = 0; int body_linecount = 0; int body_zerocount = 0; +uschar *bounce_charset = US"us-ascii"; uschar *bounce_message_file = NULL; uschar *bounce_message_text = NULL; const uschar *bounce_recipient = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index dca2d0b17..975867e49 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -372,6 +372,7 @@ extern uschar *big_buffer; /* Used for various temp things */ extern int big_buffer_size; /* Current size (can expand) */ extern int bsmtp_transaction_linecount; /* Start of last transaction */ extern int body_8bitmime; /* sender declared BODY= ; 7=7BIT, 8=8BITMIME */ +extern uschar *bounce_charset; /* value for Content-Type: headers */ extern uschar *bounce_message_file; /* Template file */ extern uschar *bounce_message_text; /* One-liner */ extern const uschar *bounce_recipient; /* When writing an errmsg */ diff --git a/src/src/readconf.c b/src/src/readconf.c index e95a2aed3..3397e7368 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -79,6 +79,7 @@ static optionlist optionlist_config[] = { { "av_scanner", opt_stringptr, {&av_scanner} }, #endif { "bi_command", opt_stringptr, {&bi_command} }, + { "bounce_charset", opt_stringptr, {&bounce_charset} }, { "bounce_message_file", opt_stringptr, {&bounce_message_file} }, { "bounce_message_text", opt_stringptr, {&bounce_message_text} }, { "bounce_return_body", opt_bool, {&bounce_return_body} }, commit aede923bf9a62aa6ce308b03e85c29a5deb7c622 Author: Jeremy Harris Date: Wed Feb 18 14:05:31 2026 +0000 constifying diff --git a/src/src/daemon.c b/src/src/daemon.c index 87a4835be..ede4bf5b7 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -389,7 +389,7 @@ if (pid == 0) if (LOGGING(smtp_connection)) { - uschar * list = hosts_connection_nolog; + const uschar * list = hosts_connection_nolog; memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (list && verify_check_host(&list) == OK) save_log_selector &= ~L_smtp_connection; diff --git a/src/src/functions.h b/src/src/functions.h index 6af265361..35c967fc4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -689,10 +689,10 @@ extern int verify_check_header_address(uschar **, uschar **, int, int, int, uschar *, uschar *, int, int *); extern int verify_check_headers(uschar **); extern int verify_check_header_names_ascii(uschar **); -extern int verify_check_host(uschar **); +extern int verify_check_host(const uschar * const *); extern int verify_check_notblind(BOOL); extern int verify_check_given_host(const uschar **, const host_item *); -extern int verify_check_this_host(const uschar **, unsigned int *, +extern int verify_check_this_host(const uschar * const *, unsigned int *, const uschar*, const uschar *, const uschar **); extern address_item *verify_checked_sender(const uschar *); extern void verify_get_ident(int); diff --git a/src/src/globals.c b/src/src/globals.c index 6b85122f7..acfdfecb4 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -81,15 +81,15 @@ tls_support tls_out = { uschar *dsn_envid = NULL; int dsn_ret = 0; const pcre2_code *regex_DSN = NULL; -uschar *dsn_advertise_hosts = NULL; +const uschar *dsn_advertise_hosts = NULL; #ifndef DISABLE_TLS BOOL gnutls_compat_mode = FALSE; BOOL gnutls_allow_auto_pkcs11 = FALSE; -uschar *hosts_require_alpn = NULL; +const uschar *hosts_require_alpn = NULL; uschar *openssl_options = NULL; const pcre2_code *regex_STARTTLS = NULL; -uschar *tls_advertise_hosts = US"*"; +const uschar *tls_advertise_hosts = US"*"; uschar *tls_alpn = US"smtp:esmtp"; uschar *tls_certificate = NULL; uschar *tls_crl = NULL; @@ -98,7 +98,7 @@ that's the interop problem which has been observed: GnuTLS suggesting a higher bit-count as "NORMAL" (2432) and Thunderbird dropping connection. */ int tls_dh_max_bits = 2236; uschar *tls_dhparam = NULL; -uschar *tls_early_banner_hosts = US""; +const uschar *tls_early_banner_hosts = US""; uschar *tls_eccurve = US"auto"; # ifndef DISABLE_OCSP uschar *tls_ocsp_file = NULL; @@ -108,11 +108,11 @@ uschar *tls_privatekey = NULL; BOOL tls_remember_esmtp = FALSE; uschar *tls_require_ciphers = NULL; # ifndef DISABLE_TLS_RESUME -uschar *tls_resumption_hosts = NULL; +const uschar *tls_resumption_hosts = NULL; # endif -uschar *tls_try_verify_hosts = NULL; +const uschar *tls_try_verify_hosts = NULL; uschar *tls_verify_certificates= US"system"; -uschar *tls_verify_hosts = NULL; +const uschar *tls_verify_hosts = NULL; int tls_watch_fd = -1; time_t tls_watch_trigger_time = (time_t)0; #else /*DISABLE_TLS*/ @@ -526,7 +526,7 @@ uschar *authenticated_fail_id = NULL; uschar *authenticated_id = NULL; uschar *authenticated_sender = NULL; auth_instance *auths = NULL; -uschar *auth_advertise_hosts = US"*"; +const uschar *auth_advertise_hosts = US"*"; auth_instance auth_defaults = { /* All unmentioned elements 0/NULL/FALSE */ 0 }; @@ -575,7 +575,7 @@ int_eximarith_t check_log_space = 10*1024; /* 10K Kbyte == 10MB */ int check_spool_inodes = 100; int_eximarith_t check_spool_space = 10*1024; /* 10K Kbyte == 10MB */ -uschar *chunking_advertise_hosts = US"*"; +const uschar *chunking_advertise_hosts = US"*"; unsigned chunking_datasize = 0; unsigned chunking_data_left = 0; chunking_state_t chunking_state= CHUNKING_NOT_OFFERED; @@ -840,35 +840,35 @@ header_name header_names[] = { int header_names_size = nelem(header_names); -uschar *helo_accept_junk_hosts = NULL; +const uschar *helo_accept_junk_hosts = NULL; uschar *helo_allow_chars = US""; uschar *helo_lookup_domains = US"@ : @[]"; -uschar *helo_try_verify_hosts = NULL; -uschar *helo_verify_hosts = NULL; +const uschar *helo_try_verify_hosts = NULL; +const uschar *helo_verify_hosts = NULL; const uschar *hex_digits = CUS"0123456789abcdef"; uschar *hold_domains = NULL; uschar *host_data = NULL; -uschar *host_lookup = NULL; +const uschar *host_lookup = NULL; uschar *host_lookup_order = US"bydns:byaddr"; uschar *host_lookup_msg = US""; int host_number = 0; uschar *host_number_string = NULL; -uschar *host_reject_connection = NULL; -uschar *hosts_connection_nolog = NULL; +const uschar *host_reject_connection = NULL; +const uschar *hosts_connection_nolog = NULL; #ifdef SUPPORT_PROXY uschar *hosts_proxy = NULL; #endif uschar *hosts_treat_as_local = NULL; -uschar *hosts_require_helo = US"*"; +const uschar *hosts_require_helo = US"*"; #ifdef EXPERIMENTAL_XCLIENT -uschar *hosts_xclient = NULL; +const uschar *hosts_xclient = NULL; #endif tree_node *hostlist_anchor = NULL; int hostlist_count = 0; int ignore_bounce_errors_after = 10*7*24*60*60; /* 10 weeks */ -uschar *ignore_fromline_hosts = NULL; +const uschar *ignore_fromline_hosts = NULL; int inetd_wait_timeout = -1; uschar *initial_cwd = NULL; uschar *interface_address = NULL; @@ -886,7 +886,7 @@ const uschar *letter_digit_hyphen_dot = ".-0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; #ifndef DISABLE_ESMTP_LIMITS -uschar *limits_advertise_hosts = US"*"; +const uschar *limits_advertise_hosts = US"*"; #endif int load_average = -2; uschar *local_from_prefix = NULL; @@ -1103,9 +1103,9 @@ uschar *percent_hack_domains = NULL; const uschar *pid_file_path = US PID_FILE_PATH "\0<--------------Space to patch pid_file_path->"; #ifndef DISABLE_PIPE_CONNECT -uschar *pipe_connect_advertise_hosts = US"*"; +const uschar *pipe_connect_advertise_hosts = US"*"; #endif -uschar *pipelining_advertise_hosts = US"*"; +const uschar *pipelining_advertise_hosts = US"*"; uschar *primary_hostname = NULL; uschar *process_info; int process_info_len = 0; @@ -1187,7 +1187,7 @@ uschar *received_protocol = NULL; struct timeval received_time = { 0, 0 }; struct timeval received_time_complete = { 0, 0 }; uschar *recipient_data = NULL; -uschar *recipient_unqualified_hosts = NULL; +const uschar *recipient_unqualified_hosts = NULL; uschar *recipient_verify_failure = NULL; int recipients_count = 0; recipient_item *recipients_list = NULL; @@ -1222,7 +1222,7 @@ int retry_maximum_timeout = 0; /* set from retry config */ retry_config *retries = NULL; const uschar *return_path = NULL; int rewrite_existflags = 0; -uschar *rfc1413_hosts = US"@[]"; +const uschar *rfc1413_hosts = US"@[]"; int rfc1413_query_timeout = 0; uid_t root_gid = ROOT_GID; uid_t root_uid = ROOT_UID; @@ -1288,7 +1288,7 @@ uschar *sender_rate = NULL; uschar *sender_rate_limit = NULL; uschar *sender_rate_period = NULL; uschar *sender_rcvhost = NULL; -uschar *sender_unqualified_hosts = NULL; +const uschar *sender_unqualified_hosts = NULL; uschar *sender_verify_failure = NULL; address_item *sender_verified_list = NULL; address_item *sender_verified_failed = NULL; @@ -1302,7 +1302,7 @@ int slow_lookup_log = 0; /* millisecs, zero disables */ int smtp_accept_count = 0; int smtp_accept_max = 20; int smtp_accept_max_nonmail= 10; -uschar *smtp_accept_max_nonmail_hosts = US"*"; +const uschar *smtp_accept_max_nonmail_hosts = US"*"; uschar *smtp_accept_max_per_connection = US"1000"; uschar *smtp_accept_max_per_host = NULL; int smtp_accept_queue = 0; @@ -1333,12 +1333,12 @@ int smtp_max_unknown_commands = 3; const uschar *smtp_notquit_reason = NULL; unsigned smtp_peer_options = 0; unsigned smtp_peer_options_wrap= 0; -uschar *smtp_ratelimit_hosts = NULL; +const uschar *smtp_ratelimit_hosts = NULL; uschar *smtp_ratelimit_mail = NULL; uschar *smtp_ratelimit_rcpt = NULL; int smtp_receive_timeout = 5*60; uschar *smtp_receive_timeout_s = NULL; -uschar *smtp_reserve_hosts = NULL; +const uschar *smtp_reserve_hosts = NULL; int smtp_rlm_base = 0; double smtp_rlm_factor = 0.0; int smtp_rlm_limit = 0; @@ -1348,7 +1348,7 @@ double smtp_rlr_factor = 0.0; int smtp_rlr_limit = 0; int smtp_rlr_threshold = INT_MAX; #ifdef SUPPORT_I18N -uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */ +const uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */ #endif #ifdef WITH_CONTENT_SCAN @@ -1467,7 +1467,7 @@ const uschar *warnmsg_delay = NULL; const uschar *warnmsg_recipients = NULL; #ifndef DISABLE_WELLKNOWN -uschar *wellknown_advertise_hosts = NULL; +const uschar *wellknown_advertise_hosts = NULL; uschar *wellknown_response = NULL; #endif diff --git a/src/src/globals.h b/src/src/globals.h index 975867e49..f121b7609 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -95,7 +95,7 @@ extern tls_support tls_out; #ifndef DISABLE_TLS extern BOOL gnutls_compat_mode; /* Less security, more compatibility */ extern BOOL gnutls_allow_auto_pkcs11; /* Let GnuTLS autoload PKCS11 modules */ -extern uschar *hosts_require_alpn; /* Mandatory ALPN successful nogitiation */ +extern const uschar *hosts_require_alpn; /* Mandatory ALPN successful nogitiation */ extern uschar *openssl_options; /* OpenSSL compatibility options */ extern const pcre2_code *regex_STARTTLS; /* For recognizing STARTTLS settings */ extern uschar *tls_alpn; /* ALPN names acceptable */ @@ -103,7 +103,7 @@ extern uschar *tls_certificate; /* Certificate file */ extern uschar *tls_crl; /* CRL File */ extern int tls_dh_max_bits; /* don't accept higher lib suggestions */ extern uschar *tls_dhparam; /* DH param file */ -extern uschar *tls_early_banner_hosts; /* use Early Data for SMTP banner */ +extern const uschar *tls_early_banner_hosts; /* use Early Data for SMTP banner */ extern uschar *tls_eccurve; /* EC curve */ # ifndef DISABLE_OCSP extern uschar *tls_ocsp_file; /* OCSP stapling proof file */ @@ -113,20 +113,20 @@ extern uschar *tls_privatekey; /* Private key file */ extern BOOL tls_remember_esmtp; /* For YAEB */ extern uschar *tls_require_ciphers; /* So some can be avoided */ # ifndef DISABLE_TLS_RESUME -extern uschar *tls_resumption_hosts; /* TLS session resumption */ +extern const uschar *tls_resumption_hosts; /* TLS session resumption */ # endif -extern uschar *tls_try_verify_hosts; /* Optional client verification */ +extern const uschar *tls_try_verify_hosts; /* Optional client verification */ extern uschar *tls_verify_certificates;/* Path for certificates to check */ -extern uschar *tls_verify_hosts; /* Mandatory client verification */ +extern const uschar *tls_verify_hosts; /* Mandatory client verification */ extern int tls_watch_fd; /* for inotify of creds files */ extern time_t tls_watch_trigger_time; /* non-0: triggered */ #endif -extern uschar *tls_advertise_hosts; /* host for which TLS is advertised */ +const extern uschar *tls_advertise_hosts; /* host for which TLS is advertised */ extern uschar *dsn_envid; /* DSN envid string */ extern int dsn_ret; /* DSN ret type*/ extern const pcre2_code *regex_DSN; /* For recognizing DSN settings */ -extern uschar *dsn_advertise_hosts; /* host for which TLS is advertised */ +extern const uschar *dsn_advertise_hosts; /* host for which TLS is advertised */ /* Input-reading functions for messages, so we can use special ones for incoming TCP/IP. */ @@ -344,7 +344,7 @@ extern uschar *authenticated_id; /* ID that was authenticated */ extern uschar *authenticated_sender; /* From AUTH on MAIL */ extern BOOL authentication_failed; /* TRUE if AUTH was tried and failed */ extern uschar *authenticator_name; /* for debug and error messages */ -extern uschar *auth_advertise_hosts; /* Only advertise to these */ +extern const uschar *auth_advertise_hosts; /* Only advertise to these */ extern auth_info *auths_available; /* List of available auth mechanisms */ extern auth_instance *auths; /* Chain of instantiated auths */ extern auth_instance auth_defaults; /* Default values */ @@ -394,7 +394,7 @@ extern int_eximarith_t check_log_space; /* Minimum for message acceptance */ extern BOOL check_rfc2047_length; /* Check RFC 2047 encoded string length */ extern int check_spool_inodes; /* Minimum for message acceptance */ extern int_eximarith_t check_spool_space; /* Minimum for message acceptance */ -extern uschar *chunking_advertise_hosts; /* RFC 3030 CHUNKING */ +extern const uschar *chunking_advertise_hosts; /* RFC 3030 CHUNKING */ extern unsigned chunking_datasize; extern unsigned chunking_data_left; extern chunking_state_t chunking_state; @@ -608,27 +608,27 @@ extern int header_maxsize; /* Max total length for header */ extern int header_line_maxsize; /* Max for an individual line */ extern header_name header_names[]; /* Table of header names */ extern int header_names_size; /* Number of entries */ -extern uschar *helo_accept_junk_hosts; /* Allowed to use junk arg */ +extern const uschar *helo_accept_junk_hosts; /* Allowed to use junk arg */ extern uschar *helo_allow_chars; /* Rogue chars to allow in HELO/EHLO */ extern uschar *helo_lookup_domains; /* If these given, lookup host name */ -extern uschar *helo_try_verify_hosts; /* Soft check HELO argument for these */ -extern uschar *helo_verify_hosts; /* Hard check HELO argument for these */ +extern const uschar *helo_try_verify_hosts; /* Soft check HELO argument for these */ +extern const uschar *helo_verify_hosts; /* Hard check HELO argument for these */ extern const uschar *hex_digits; /* Used in several places */ extern uschar *hold_domains; /* Hold up deliveries to these */ extern uschar *host_data; /* Obtained from lookup in ACL */ -extern uschar *host_lookup; /* For which IP addresses are always looked up */ +extern const uschar *host_lookup; /* For which IP addresses are always looked up */ extern BOOL host_lookup_deferred; /* TRUE if lookup deferred */ extern BOOL host_lookup_failed; /* TRUE if lookup failed */ extern uschar *host_lookup_order; /* Order of host lookup types */ extern uschar *host_lookup_msg; /* Text for why it failed */ extern int host_number; /* For sharing spools */ extern uschar *host_number_string; /* For expanding */ -extern uschar *host_reject_connection; /* Reject these hosts */ -extern uschar *hosts_connection_nolog; /* Limits the logging option */ -extern uschar *hosts_require_helo; /* check for HELO/EHLO before MAIL */ +extern const uschar *host_reject_connection; /* Reject these hosts */ +extern const uschar *hosts_connection_nolog; /* Limits the logging option */ +extern const uschar *hosts_require_helo; /* check for HELO/EHLO before MAIL */ extern uschar *hosts_treat_as_local; /* For routing */ #ifdef EXPERIMENTAL_XCLIENT -extern uschar *hosts_xclient; /* Allow XCLIENT command for specified hosts */ +extern const uschar *hosts_xclient; /* Allow XCLIENT command for specified hosts */ #endif extern tree_node *hostlist_anchor; /* Tree of defined host lists */ extern int hostlist_count; /* Number defined */ @@ -636,7 +636,7 @@ extern int hostlist_count; /* Number defined */ extern int ignore_bounce_errors_after; /* Keep them for this time. */ extern BOOL ignore_fromline_local; /* Local SMTP ignore fromline */ -extern uschar *ignore_fromline_hosts; /* Hosts permitted to send "From " */ +extern const uschar *ignore_fromline_hosts; /* Hosts permitted to send "From "*/ extern int inetd_wait_timeout; /* Timeout for inetd wait mode */ extern uschar *initial_cwd; /* The directory we where in at startup */ extern uschar *iterate_item; /* Item from iterate list */ @@ -648,7 +648,7 @@ extern int keep_malformed; /* Time to keep malformed messages */ extern const uschar *letter_digit_hyphen_dot; /* Legitimate DNS host name chars */ #ifndef DISABLE_ESMTP_LIMITS -extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */ +extern const uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */ #endif extern int load_average; /* Most recently read load average */ extern BOOL local_from_check; /* For adding Sender: (global value) */ @@ -774,9 +774,9 @@ extern pcre2_compile_context * pcre_mlc_cmp_ctx; extern uschar *percent_hack_domains; /* Local domains for which '% operates */ extern const uschar *pid_file_path; /* For writing daemon pids */ #ifndef DISABLE_PIPE_CONNECT -extern uschar *pipe_connect_advertise_hosts; /* for banner/EHLO pipelining */ +extern const uschar *pipe_connect_advertise_hosts; /* for banner/EHLO pipelining */ #endif -extern uschar *pipelining_advertise_hosts; /* As it says */ +extern const uschar *pipelining_advertise_hosts; /* As it says */ #ifndef DISABLE_PRDR extern BOOL prdr_enable; /* As it says */ extern BOOL prdr_requested; /* Connecting mail server wants PRDR */ @@ -855,7 +855,7 @@ extern int received_headers_max; /* Max count of Received: headers */ extern struct timeval received_time; /* Time the message started to be received */ extern struct timeval received_time_complete; /* Time the message completed reception */ extern uschar *recipient_data; /* lookup data for recipients */ -extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */ +extern const uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */ extern uschar *recipient_verify_failure; /* What went wrong */ extern int recipients_list_max; /* Maximum number fitting in list */ extern uschar *recipients_max; /* Max permitted */ @@ -894,7 +894,7 @@ extern int retry_maximum_timeout; /* The maximum timeout */ extern const uschar *return_path; /* Return path for a message */ extern BOOL return_path_remove; /* Remove return-path headers */ extern int rewrite_existflags; /* Indicate which headers have rewrites */ -extern uschar *rfc1413_hosts; /* RFC hosts */ +extern const uschar *rfc1413_hosts; /* RFC hosts */ extern int rfc1413_query_timeout; /* Timeout on RFC 1413 calls */ /* extern BOOL rfc821_domains; */ /* If set, syntax is 821, not 822 => being abolished */ extern uid_t root_gid; /* The gid for root */ @@ -927,7 +927,7 @@ extern uschar *sender_rate; /* Sender rate computed by ACL */ extern uschar *sender_rate_limit; /* Configured rate limit */ extern uschar *sender_rate_period; /* Configured smoothing period */ extern uschar *sender_rcvhost; /* Host data for Received: */ -extern uschar *sender_unqualified_hosts; /* Permitted unqualified senders */ +extern const uschar *sender_unqualified_hosts; /* Permitted unqualified senders */ extern uschar *sender_verify_failure; /* What went wrong */ extern address_item *sender_verified_list; /* Saved chain of sender verifies */ extern address_item *sender_verified_failed; /* The one that caused denial */ @@ -941,7 +941,7 @@ extern int smtp_accept_count; /* Count of connections */ extern BOOL smtp_accept_keepalive; /* Set keepalive on incoming */ extern int smtp_accept_max; /* Max SMTP connections */ extern int smtp_accept_max_nonmail;/* Max non-mail commands in one con */ -extern uschar *smtp_accept_max_nonmail_hosts; /* Limit non-mail cmds from these hosts */ +extern const uschar *smtp_accept_max_nonmail_hosts; /* Limit non-mail cmds from these hosts */ extern uschar *smtp_accept_max_per_connection; /* Max msgs per connection */ extern uschar *smtp_accept_max_per_host; /* Max SMTP cons from one IP addr */ extern int smtp_accept_queue; /* Queue after so many connections */ @@ -972,12 +972,12 @@ extern int smtp_max_unknown_commands; /* As it says */ extern uschar *smtp_names[]; /* decode for command codes */ extern const uschar *smtp_notquit_reason; /* Global for disconnect reason */ extern int smtp_out_fd; /* Incoming SMTP output file */ -extern uschar *smtp_ratelimit_hosts; /* Rate limit these hosts */ +extern const uschar *smtp_ratelimit_hosts; /* Rate limit these hosts */ extern uschar *smtp_ratelimit_mail; /* Parameters for MAIL limiting */ extern uschar *smtp_ratelimit_rcpt; /* Parameters for RCPT limiting */ extern int smtp_receive_timeout; /* Applies to each received line */ extern uschar *smtp_receive_timeout_s; /* ... expandable version */ -extern uschar *smtp_reserve_hosts; /* Hosts for reserved slots */ +extern const uschar *smtp_reserve_hosts; /* Hosts for reserved slots */ extern BOOL smtp_return_error_details; /* TRUE to return full info */ extern int smtp_rlm_base; /* Base interval for MAIL rate limit */ extern double smtp_rlm_factor; /* Factor for MAIL rate limit */ @@ -990,7 +990,7 @@ extern int smtp_rlr_threshold; /* Threshold for RCPT rate limit */ extern unsigned smtp_peer_options; /* Global flags for passed connections */ extern unsigned smtp_peer_options_wrap; /* stacked version hidden by TLS */ #ifdef SUPPORT_I18N -extern uschar *smtputf8_advertise_hosts; /* ingress control */ +extern const uschar *smtputf8_advertise_hosts; /* ingress control */ #endif #ifdef WITH_CONTENT_SCAN @@ -1085,7 +1085,7 @@ extern uschar *version_string; /* Version string */ extern int warning_count; /* Delay warnings sent for this msg */ #ifndef DISABLE_WELLKNOWN -extern uschar *wellknown_advertise_hosts;/* Allow WELLKNOWN command for specified hosts */ +extern const uschar *wellknown_advertise_hosts; /* Allow WELLKNOWN command for specified hosts */ extern uschar *wellknown_response; /* SMTP response for WELLKNOWN verb */ #endif diff --git a/src/src/verify.c b/src/src/verify.c index a7688d40a..931aff6e2 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -3326,8 +3326,9 @@ determined from the IP address, the result is FAIL unless the item "+allow_unknown" was met earlier in the list, in which case OK is returned. */ int -verify_check_this_host(const uschar **listptr, unsigned int *cache_bits, - const uschar *host_name, const uschar *host_address, const uschar **valueptr) +verify_check_this_host(const uschar * const * listptr, + unsigned int * cache_bits, const uschar * host_name, + const uschar * host_address, const uschar ** valueptr) { int rc; unsigned int *local_cache_bits = cache_bits; @@ -3394,7 +3395,7 @@ Returns: the yield of verify_check_this_host(), */ int -verify_check_host(uschar **listptr) +verify_check_host(const uschar * const * listptr) { return verify_check_this_host(CUSS listptr, sender_host_cache, NULL, sender_host_address ? sender_host_address : US"", NULL); commit d04dacc83e57a342b2b6dea7ec434a4c53e116aa Author: Jeremy Harris Date: Wed Feb 18 13:28:16 2026 +0000 tidying diff --git a/src/src/daemon.c b/src/src/daemon.c index ede4bf5b7..9fac96428 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -189,7 +189,6 @@ pid_t pid; union sockaddr_46 interface_sockaddr; EXIM_SOCKLEN_T ifsize = sizeof(interface_sockaddr); int max_for_this_host = 0; -bitmask_word_t save_log_selector = *log_selector; gstring * whofrom; rmark reset_point = store_mark(); @@ -374,6 +373,7 @@ if (pid == 0) smtp_accept_count++; /* So that it includes this process */ set_connection_id(); + memset(sender_host_cache, 0, sizeof(sender_host_cache)); /* Log the connection if requested. In order to minimize the cost (because this is going to happen for every @@ -390,9 +390,8 @@ if (pid == 0) if (LOGGING(smtp_connection)) { const uschar * list = hosts_connection_nolog; - memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (list && verify_check_host(&list) == OK) - save_log_selector &= ~L_smtp_connection; + log_selector[0] &= ~L_smtp_connection; /*XXX assumes word-of-bit */ else if (LOGGING(connection_id)) log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y " "Ci=%s (TCP/IP connection count = %d)", @@ -408,10 +407,6 @@ if (pid == 0) log_write(0, LOG_MAIN, "listen backlog %d I=[%s]:%d", smtp_listen_backlog, interface_address, interface_port); - /* May have been modified for the subprocess */ - - *log_selector = save_log_selector; - /* Get the local interface address into permanent store */ store_pool = POOL_PERM; diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 35d279c63..bdbe61d56 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -2855,10 +2855,6 @@ else /* not already sent */ this synchronisation check is disabled. */ #ifndef DISABLE_PIPE_CONNECT - fl.pipe_connect_acceptable = - sender_host_address - && verify_check_host(&pipe_connect_advertise_hosts) == OK; - if (!check_sync(WBR_DATA_ONLY)) if (fl.pipe_connect_acceptable) f.smtp_in_early_pipe_used = TRUE; commit e386f312398285a94848457ca86f3de0f4e9d0ae Author: Bernard Quatermass Date: Wed Feb 18 16:20:21 2026 +0000 Update project URLs commit 287ed9fb10be0324c3cfcc5760cc05916c1ad072 Author: Jeremy Harris Date: Thu Feb 19 13:44:18 2026 +0000 Debug: note empty list elements diff --git a/src/src/macros.h b/src/src/macros.h index 4d2637d87..07d5e0003 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1107,6 +1107,7 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE }; #define UTF8_RIGHT_TRIANGLE "\xE2\x96\xB6" #define UTF8_LIGHT_SHADE "\xE2\x96\x91" #define UTF8_L_ARROW_HOOK "\xE2\x86\xA9" +#define UTF8_COMB_BRIDGE_BELOW "\xCC\xAA" /* Options on tls_close */ diff --git a/src/src/string.c b/src/src/string.c index 5e66e0732..90b9ec503 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -1714,10 +1714,20 @@ while (*fp) gstring * zg = NULL; int p = precision; + if (!*s) /* output something distinctive for an empty input */ + { + zg = string_catn(zg, CUS "e" UTF8_COMB_BRIDGE_BELOW + "m" UTF8_COMB_BRIDGE_BELOW + "p" UTF8_COMB_BRIDGE_BELOW + "t" UTF8_COMB_BRIDGE_BELOW + "y" UTF8_COMB_BRIDGE_BELOW, 15); + if (precision >= 0) precision += 15; + } + /* If a precision was given, we can handle embedded NULs. Take it as applying to the input and expand it for the transformed result */ - for ( ; precision >= 0 || *s; s++) + else for ( ; precision >= 0 || *s; s++) if (p >= 0 && --p < 0) break; else switch (*s) commit 434eed8bce1e73e3175ef83a1feb6f07ec59c7bb Author: Jeremy Harris Date: Fri Feb 20 16:31:06 2026 +0000 Debug: rework for small-wordsize platforms diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 699f485c1..945c7c38d 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -237,7 +237,8 @@ macro_predef: $(OBJ_MACRO) $(FE)$(LNCC) -o $@ $(LFLAGS) $(OBJ_MACRO) macro.c: macro_predef - ./macro_predef > macro.c + ./macro_predef > tmpfile + mv tmpfile $@ # This target is recognized specially by GNU make. It records those targets # that do not correspond to files that are being built and which should diff --git a/src/OS/os.c-Linux b/src/OS/os.c-Linux index b7cd4e53a..ad1cb855b 100644 --- a/src/OS/os.c-Linux +++ b/src/OS/os.c-Linux @@ -139,7 +139,7 @@ while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", last = next; } - DEBUG(D_interface) + DEBUG(interface) debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, devname); } diff --git a/src/OS/unsupported/os.c-IRIX b/src/OS/unsupported/os.c-IRIX index 67725322b..f9f75a425 100644 --- a/src/OS/unsupported/os.c-IRIX +++ b/src/OS/unsupported/os.c-IRIX @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX6 b/src/OS/unsupported/os.c-IRIX6 index 67725322b..f9f75a425 100644 --- a/src/OS/unsupported/os.c-IRIX6 +++ b/src/OS/unsupported/os.c-IRIX6 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX632 b/src/OS/unsupported/os.c-IRIX632 index 67725322b..f9f75a425 100644 --- a/src/OS/unsupported/os.c-IRIX632 +++ b/src/OS/unsupported/os.c-IRIX632 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-IRIX65 b/src/OS/unsupported/os.c-IRIX65 index 67725322b..f9f75a425 100644 --- a/src/OS/unsupported/os.c-IRIX65 +++ b/src/OS/unsupported/os.c-IRIX65 @@ -106,7 +106,7 @@ for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s\n", last->address); } } diff --git a/src/OS/unsupported/os.c-cygwin b/src/OS/unsupported/os.c-cygwin index d9e54d6a8..92cff1eec 100644 --- a/src/OS/unsupported/os.c-cygwin +++ b/src/OS/unsupported/os.c-cygwin @@ -357,7 +357,7 @@ static BOOL LoadNtdll() "RtlNtStatusToDosError"))) return TRUE; - DEBUG(D_load) + DEBUG(load) debug_printf("perf: load: %u (Windows)\n", GetLastError()); return FALSE; } @@ -381,18 +381,18 @@ static BOOL ReadStat(unsigned long long int *Time100nsPtr, if ((ret = NtQuerySystemInformation(SystemBasicInformation, (PVOID) &sbi, sizeof sbi, NULL)) != STATUS_SUCCESS) { - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n", RtlNtStatusToDosError(ret)); } else if (!(spt = (PSYSTEM_PROCESSOR_TIMES) alloca(sizeof(spt[0]) * sbi.NumberProcessors))) { - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: alloca: errno %d (%s)\n", errno, strerror(errno)); } else if ((ret = NtQuerySystemInformation(SystemProcessorTimes, (PVOID) spt, sizeof spt[0] * sbi.NumberProcessors, NULL)) != STATUS_SUCCESS) { - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n", RtlNtStatusToDosError(ret)); } @@ -472,12 +472,12 @@ int os_getloadavg() if ((new = !cygwin_load.handle)) { cygwin_load.handle = CreateFileMapping (INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, sizeof(cygwin_perf_t), NULL); - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: CreateFileMapping: handle %p\n", (void *) cygwin_load.handle); } cygwin_load.perf = (cygwin_perf_t *) MapViewOfFile (cygwin_load.handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: MapViewOfFile: addr %p\n", (void *) cygwin_load.perf); if (new && cygwin_load.perf) InitLoadAvg(cygwin_load.perf); @@ -493,7 +493,7 @@ int os_getloadavg() results in an immediate delivery .*/ if (InterlockedCompareExchange(&cygwin_load.perf->Lock, 1, 0)) { - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: Lock busy\n"); return 0; } @@ -512,7 +512,7 @@ int os_getloadavg() cygwin_load.perf->IdleCount = IdleCount; cygwin_load.perf->LastCounter = CurrCounter; cygwin_load.perf->LastLoad = value; - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: New load average %d\n", value); } else { /* Something bad happened. @@ -523,7 +523,7 @@ int os_getloadavg() } } else - DEBUG(D_load) + DEBUG(load) debug_printf("Perf: Old load average %d\n", cygwin_load.perf->LastLoad); cygwin_load.perf->Lock = 0; return cygwin_load.perf->LastLoad; diff --git a/src/scripts/source_checks b/src/scripts/source_checks index ef1683cf2..a7013f98c 100644 --- a/src/scripts/source_checks +++ b/src/scripts/source_checks @@ -17,9 +17,7 @@ do done <<-END readconf.c optionlist_config globals.c optionlist_auths - globals.c debug_options globals.c header_names - globals.c log_options expand.c item_table std-crypto.c dh_constants transport.c optionlist_transports @@ -44,6 +42,8 @@ do | LC_ALL=C sort -c \ || { echo "Table $table in $file is not alphabetically ordered" >&2 ; exit 1; } done <<-END + globals.c debug_chan_names + globals.c log_chan_names expand.c item_table expand.c op_table_underscore expand.c op_table_main diff --git a/src/src/acl.c b/src/src/acl.c index b236eb2de..17d9904d1 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1321,7 +1321,7 @@ if (host_lookup_failed) /* Need to do a lookup */ -HDEBUG(D_acl) +HDEBUG(acl) debug_printf_indent("looking up host name to force name/address consistency check\n"); if ((rc = host_name_lookup()) != OK) @@ -1392,7 +1392,7 @@ for (dns_record * rr = dns_next_rr(dnsa, dnss, reset); { /* If the client IP address matches the target IP address, it's good! */ - DEBUG(D_acl) debug_printf_indent("CSA target address is %s\n", da->address); + DEBUG(acl) debug_printf_indent("CSA target address is %s\n", da->address); if (strcmpic(sender_host_address, da->address) == 0) return CSA_OK; } @@ -1525,7 +1525,7 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); GETSHORT(weight, p); GETSHORT(port, p); - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("CSA priority=%d weight=%d port=%d\n", priority, weight, port); /* Check the CSA version number */ @@ -1565,7 +1565,7 @@ for (rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p, (DN_EXPAND_ARG4_TYPE)target, TARGET_SIZE); - DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target); + DEBUG(acl) debug_printf_indent("CSA target is %s\n", target); break; } @@ -1856,7 +1856,7 @@ switch(vp->value) *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s", csa_reason_string[rc]); csa_status = csa_status_string[rc]; - DEBUG(D_acl) debug_printf_indent("CSA result %s\n", csa_status); + DEBUG(acl) debug_printf_indent("CSA result %s\n", csa_status); rc = csa_return_code[rc]; goto OUT; @@ -2184,7 +2184,7 @@ else if (verify_sender_address) rc = sender_vaddr->special_action; *basic_errno = sender_vaddr->basic_errno; } - HDEBUG(D_acl) debug_printf_indent("using cached sender verify result\n"); + HDEBUG(acl) debug_printf_indent("using cached sender verify result\n"); } /* Do a new verification, and cache the result. The cache is used to avoid @@ -2231,12 +2231,12 @@ else if (verify_sender_address) rc = verify_address(sender_vaddr, -1, verify_options, callout, callout_overall, callout_connect, se_mailfrom, pm_mailfrom, &routed); - HDEBUG(D_acl) debug_printf_indent("----------- end verify ------------\n"); + HDEBUG(acl) debug_printf_indent("----------- end verify ------------\n"); if (rc != OK) *basic_errno = sender_vaddr->basic_errno; else - DEBUG(D_acl) + DEBUG(acl) if (Ustrcmp(sender_vaddr->address, verify_sender_address) != 0) debug_printf_indent("sender %s verified ok as %s\n", verify_sender_address, sender_vaddr->address); @@ -2246,7 +2246,7 @@ else if (verify_sender_address) } else { - DEBUG(D_acl) debug_printf_indent(" null sender\n"); + DEBUG(acl) debug_printf_indent(" null sender\n"); rc = OK; } @@ -2285,7 +2285,7 @@ else addr2 = *addr; rc = verify_address(&addr2, -1, verify_options|vopt_is_recipient, callout, callout_overall, callout_connect, se_mailfrom, pm_mailfrom, NULL); - HDEBUG(D_acl) debug_printf_indent("----------- end verify ------------\n"); + HDEBUG(acl) debug_printf_indent("----------- end verify ------------\n"); *basic_errno = addr2.basic_errno; *log_msgptr = addr2.message; @@ -2305,7 +2305,7 @@ if ( rc == DEFER || callout_defer_ok && *basic_errno == ERRNO_CALLOUTDEFER ) ) { - HDEBUG(D_acl) debug_printf_indent("verify defer overridden by %s\n", + HDEBUG(acl) debug_printf_indent("verify defer overridden by %s\n", defer_ok? "defer_ok" : "callout_defer_ok"); rc = OK; } @@ -2604,7 +2604,7 @@ key = string_sprintf("%s/%s/%s%s", unique == NULL ? "" : "unique/", key); -HDEBUG(D_acl) +HDEBUG(acl) debug_printf_indent("ratelimit condition count=%.0f %.1f/%s\n", count, limit, key); /* See if we have already computed the rate by looking in the relevant tree. @@ -2647,7 +2647,7 @@ if ((t = tree_search(*anchor, key))) rc = (dbd->rate < limit)? FAIL : OK; store_pool = old_pool; sender_rate = string_sprintf("%.1f", dbd->rate); - HDEBUG(D_acl) + HDEBUG(acl) debug_printf_indent("ratelimit found pre-computed rate %s\n", sender_rate); return rc; } @@ -2659,7 +2659,7 @@ if (!(dbm = dbfn_open(US"ratelimit", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) { store_pool = old_pool; sender_rate = NULL; - HDEBUG(D_acl) debug_printf_indent("ratelimit database not available\n"); + HDEBUG(acl) debug_printf_indent("ratelimit database not available\n"); *log_msgptr = US"ratelimit database not available"; return DEFER; } @@ -2671,7 +2671,7 @@ gettimeofday(&tv, NULL); if (dbdb) { /* Locate the basic ratelimit block inside the DB data. */ - HDEBUG(D_acl) debug_printf_indent("ratelimit found key in database\n"); + HDEBUG(acl) debug_printf_indent("ratelimit found key in database\n"); dbd = &dbdb->dbd; /* Forget the old Bloom filter if it is too old, so that we count each @@ -2681,7 +2681,7 @@ if (dbdb) if(unique && tv.tv_sec > dbdb->bloom_epoch + period) { - HDEBUG(D_acl) debug_printf_indent("ratelimit discarding old Bloom filter\n"); + HDEBUG(acl) debug_printf_indent("ratelimit discarding old Bloom filter\n"); dbdb = NULL; } @@ -2689,7 +2689,7 @@ if (dbdb) if(unique && dbdb_size < sizeof(*dbdb)) { - HDEBUG(D_acl) debug_printf_indent("ratelimit discarding undersize Bloom filter\n"); + HDEBUG(acl) debug_printf_indent("ratelimit discarding undersize Bloom filter\n"); dbdb = NULL; } } @@ -2702,14 +2702,14 @@ if (!dbdb) if (!unique) { /* No Bloom filter. This basic ratelimit block is initialized below. */ - HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n"); + HDEBUG(acl) debug_printf_indent("ratelimit creating new rate data block\n"); dbdb_size = sizeof(*dbd); dbdb = store_get(dbdb_size, GET_UNTAINTED); } else { int extra; - HDEBUG(D_acl) debug_printf_indent("ratelimit creating new Bloom filter\n"); + HDEBUG(acl) debug_printf_indent("ratelimit creating new Bloom filter\n"); /* See the long comment below for an explanation of the magic number 2. The filter has a minimum size in case the rate limit is very small; @@ -2793,7 +2793,7 @@ if (unique && !readonly) /* Scan the bits corresponding to this event. A zero bit means we have not seen it before. Ensure all bits are set to record this event. */ - HDEBUG(D_acl) debug_printf_indent("ratelimit checking uniqueness of %s\n", unique); + HDEBUG(acl) debug_printf_indent("ratelimit checking uniqueness of %s\n", unique); seen = TRUE; for (n = 0; n < 8; n++, hash += hinc) @@ -2811,11 +2811,11 @@ if (unique && !readonly) if (seen) { - HDEBUG(D_acl) debug_printf_indent("ratelimit event found in Bloom filter\n"); + HDEBUG(acl) debug_printf_indent("ratelimit event found in Bloom filter\n"); count = 0.0; } else - HDEBUG(D_acl) debug_printf_indent("ratelimit event added to Bloom filter\n"); + HDEBUG(acl) debug_printf_indent("ratelimit event added to Bloom filter\n"); } /* If there was no previous ratelimit data block for this key, initialize @@ -2824,7 +2824,7 @@ is what would be computed by the code below for an infinite interval. */ if (!dbd) { - HDEBUG(D_acl) debug_printf_indent("ratelimit initializing new key's rate data\n"); + HDEBUG(acl) debug_printf_indent("ratelimit initializing new key's rate data\n"); dbd = &dbdb->dbd; dbd->gen.time_stamp = tv.tv_sec; dbd->time_usec = tv.tv_usec; @@ -2925,11 +2925,11 @@ neither leaky nor strict are set, so we do not do any updates. */ if ((rc == FAIL && leaky) || strict) { dbfn_write(dbm, key, dbdb, dbdb_size); - HDEBUG(D_acl) debug_printf_indent("ratelimit db updated\n"); + HDEBUG(acl) debug_printf_indent("ratelimit db updated\n"); } else { - HDEBUG(D_acl) debug_printf_indent("ratelimit db not updated: %s\n", + HDEBUG(acl) debug_printf_indent("ratelimit db not updated: %s\n", readonly? "readonly mode" : "over the limit, but leaky"); } @@ -2949,7 +2949,7 @@ order to ensure that it is done using the correct storage pool. */ store_pool = old_pool; sender_rate = string_sprintf("%.1f", dbd->rate); -HDEBUG(D_acl) +HDEBUG(acl) debug_printf_indent("ratelimit computed rate %s\n", sender_rate); return rc; @@ -3039,7 +3039,7 @@ while ((ele = string_nextinlist(&list, &slash, NULL, 0))) if (!(dbm = dbfn_open(US"seen", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) { - HDEBUG(D_acl) debug_printf_indent("database for 'seen' not available\n"); + HDEBUG(acl) debug_printf_indent("database for 'seen' not available\n"); *log_msgptr = US"database for 'seen' not available"; return DEFER; } @@ -3054,18 +3054,18 @@ if (dbd) /* an existing record */ yield = OK; if (mode == SEEN_READONLY) - { HDEBUG(D_acl) debug_printf_indent("seen db not written (readonly)\n"); } + { HDEBUG(acl) debug_printf_indent("seen db not written (readonly)\n"); } else if (mode == SEEN_WRITE || !before) { dbd->gen.time_stamp = now; dbfn_write(dbm, key, dbd, sizeof(*dbd)); - HDEBUG(D_acl) debug_printf_indent("seen db written (update)\n"); + HDEBUG(acl) debug_printf_indent("seen db written (update)\n"); } else if (diff >= refresh) { dbd->gen.time_stamp = now - interval; dbfn_write(dbm, key, dbd, sizeof(*dbd)); - HDEBUG(D_acl) debug_printf_indent("seen db written (refresh)\n"); + HDEBUG(acl) debug_printf_indent("seen db written (refresh)\n"); } } else @@ -3074,10 +3074,10 @@ else { dbdata_seen d = {.gen = {.time_stamp = now}}; dbfn_write(dbm, key, &d, sizeof(*dbd)); - HDEBUG(D_acl) debug_printf_indent("seen db written (create)\n"); + HDEBUG(acl) debug_printf_indent("seen db written (create)\n"); } else - HDEBUG(D_acl) debug_printf_indent("seen db not written (readonly)\n"); + HDEBUG(acl) debug_printf_indent("seen db not written (readonly)\n"); } dbfn_close(dbm); @@ -3161,7 +3161,7 @@ if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN) return DEFER; } -HDEBUG(D_acl) +HDEBUG(acl) debug_printf_indent("udpsend [%s]:%d %s\n", h->address, portnum, arg); /*XXX this could better use sendto */ @@ -3184,7 +3184,7 @@ if (r < len) return DEFER; } -HDEBUG(D_acl) +HDEBUG(acl) debug_printf_indent("udpsend %d bytes\n", r); return OK; @@ -3319,11 +3319,11 @@ for (; cb; cb = cb->next) case of rejection. They are expanded later. */ case ACLC_MESSAGE: - HDEBUG(D_acl) debug_printf_indent(" message: %s\n", cb->arg); + HDEBUG(acl) debug_printf_indent(" message: %s\n", cb->arg); user_message = cb->arg; continue; case ACLC_LOG_MESSAGE: - HDEBUG(D_acl) debug_printf_indent("l_message: %s\n", cb->arg); + HDEBUG(acl) debug_printf_indent("l_message: %s\n", cb->arg); log_message = cb->arg; continue; /* The endpass "condition" just sets a flag to show it occurred. This is @@ -3350,7 +3350,7 @@ for (; cb; cb = cb->next) /* Show condition, and expanded condition if it's different */ - HDEBUG(D_acl) + HDEBUG(acl) { int lhswidth = 0; debug_printf_indent("check %s%s %n", @@ -3720,7 +3720,7 @@ for (; cb; cb = cb->next) ignored = US"repeated"; else if (cutthrough.callout_hold_only) { - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent(" cutthrough request upgrades callout hold\n"); cutthrough.callout_hold_only = FALSE; cutthrough.delivery = TRUE; /* control accepted */ @@ -3749,7 +3749,7 @@ for (; cb; cb = cb->next) } } - DEBUG(D_acl) if (ignored) + DEBUG(acl) if (ignored) debug_printf(" cutthrough request ignored on %s item\n", ignored); } break; @@ -3837,11 +3837,11 @@ for (; cb; cb = cb->next) } else { - HDEBUG(D_acl) debug_printf_indent("delay modifier requests %d-second delay\n", + HDEBUG(acl) debug_printf_indent("delay modifier requests %d-second delay\n", delay); if (host_checking) { - HDEBUG(D_acl) + HDEBUG(acl) debug_printf_indent("delay skipped in -bh checking mode\n"); } @@ -3870,7 +3870,7 @@ for (; cb; cb = cb->next) n = 1; } if (poll(&p, n, delay*1000) > 0) - HDEBUG(D_acl) debug_printf_indent("delay cancelled by peer close\n"); + HDEBUG(acl) debug_printf_indent("delay cancelled by peer close\n"); } #else /* Lacking POLLRDHUP it appears to be impossible to detect that a @@ -4471,7 +4471,7 @@ if (acl_level > 20) if (!s) { - HDEBUG(D_acl) debug_printf_indent("ACL is NULL: implicit DENY\n"); + HDEBUG(acl) debug_printf_indent("ACL is NULL: implicit DENY\n"); return FAIL; } @@ -4517,11 +4517,11 @@ if (Ustrchr(ss, ' ') == NULL) { if (!(acl = (acl_block *)(t->data.ptr))) { - HDEBUG(D_acl) debug_printf_indent("ACL %q is empty: implicit DENY\n", ss); + HDEBUG(acl) debug_printf_indent("ACL %q is empty: implicit DENY\n", ss); return FAIL; } acl_name = string_sprintf("ACL %s", ss); - HDEBUG(D_acl) debug_printf_indent("using ACL %q\n", ss); + HDEBUG(acl) debug_printf_indent("using ACL %q\n", ss); } else if (*ss == '/') @@ -4554,7 +4554,7 @@ if (Ustrchr(ss, ' ') == NULL) (void)close(fd); acl_name = string_sprintf("ACL %s", ss); - HDEBUG(D_acl) debug_printf_indent("read ACL from file %s\n", ss); + HDEBUG(acl) debug_printf_indent("read ACL from file %s\n", ss); } } @@ -4594,7 +4594,7 @@ while ((acl_current = acl)) config_filename = acl->srcfile; config_lineno = acl->srcline; - HDEBUG(D_acl) + HDEBUG(acl) { debug_printf_indent("processing %s %q", acl_name, verbs[acl->verb]); if (config_lineno) debug_printf(" (%s %d)", config_filename, config_lineno); @@ -4614,7 +4614,7 @@ while ((acl_current = acl)) switch (cond) { case DEFER: - HDEBUG(D_acl) debug_printf_indent("%s: condition test deferred in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test deferred in %s\n", verbs[acl->verb], acl_name); if (basic_errno != ERRNO_CALLOUTDEFER) { @@ -4629,17 +4629,17 @@ while ((acl_current = acl)) default: /* Paranoia */ case ERROR: - HDEBUG(D_acl) debug_printf_indent("%s: condition test error in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test error in %s\n", verbs[acl->verb], acl_name); return ERROR; case OK: - HDEBUG(D_acl) debug_printf_indent("%s: condition test succeeded in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test succeeded in %s\n", verbs[acl->verb], acl_name); break; case FAIL: - HDEBUG(D_acl) debug_printf_indent("%s: condition test failed in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test failed in %s\n", verbs[acl->verb], acl_name); break; @@ -4647,12 +4647,12 @@ while ((acl_current = acl)) DISCARD can happen only for an "accept" or "discard" verb. */ case DISCARD: - HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"discard\" in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test yielded \"discard\" in %s\n", verbs[acl->verb], acl_name); break; case FAIL_DROP: - HDEBUG(D_acl) debug_printf_indent("%s: condition test yielded \"drop\" in %s\n", + HDEBUG(acl) debug_printf_indent("%s: condition test yielded \"drop\" in %s\n", verbs[acl->verb], acl_name); break; } @@ -4666,12 +4666,12 @@ while ((acl_current = acl)) case ACL_ACCEPT: if (cond == OK || cond == DISCARD) { - HDEBUG(D_acl) debug_printf_indent("end of %s: ACCEPT\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: ACCEPT\n", acl_name); return cond; } if (endpass_seen) { - HDEBUG(D_acl) debug_printf_indent("accept: endpass encountered - denying access\n"); + HDEBUG(acl) debug_printf_indent("accept: endpass encountered - denying access\n"); return cond; } break; @@ -4679,7 +4679,7 @@ while ((acl_current = acl)) case ACL_DEFER: if (cond == OK) { - HDEBUG(D_acl) debug_printf_indent("end of %s: DEFER\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: DEFER\n", acl_name); if (acl_quit_check) goto badquit; f.acl_temp_details = TRUE; return DEFER; @@ -4689,7 +4689,7 @@ while ((acl_current = acl)) case ACL_DENY: if (cond == OK) { - HDEBUG(D_acl) debug_printf_indent("end of %s: DENY\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: DENY\n", acl_name); if (acl_quit_check) goto badquit; return FAIL; } @@ -4698,13 +4698,13 @@ while ((acl_current = acl)) case ACL_DISCARD: if (cond == OK || cond == DISCARD) { - HDEBUG(D_acl) debug_printf_indent("end of %s: DISCARD\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: DISCARD\n", acl_name); if (acl_quit_check) goto badquit; return DISCARD; } if (endpass_seen) { - HDEBUG(D_acl) + HDEBUG(acl) debug_printf_indent("discard: endpass encountered - denying access\n"); return cond; } @@ -4713,7 +4713,7 @@ while ((acl_current = acl)) case ACL_DROP: if (cond == OK) { - HDEBUG(D_acl) debug_printf_indent("end of %s: DROP\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: DROP\n", acl_name); if (acl_quit_check) goto badquit; return FAIL_DROP; } @@ -4722,7 +4722,7 @@ while ((acl_current = acl)) case ACL_REQUIRE: if (cond != OK) { - HDEBUG(D_acl) debug_printf_indent("end of %s: not OK\n", acl_name); + HDEBUG(acl) debug_printf_indent("end of %s: not OK\n", acl_name); if (acl_quit_check) goto badquit; return cond; } @@ -4760,7 +4760,7 @@ while ((acl_current = acl)) /* We have reached the end of the ACL. This is an implicit DENY. */ -HDEBUG(D_acl) debug_printf_indent("end of %s: implicit DENY\n", acl_name); +HDEBUG(acl) debug_printf_indent("end of %s: implicit DENY\n", acl_name); return FAIL; badquit: @@ -4965,12 +4965,12 @@ switch (where) else if (cutthrough.delivery) if (rc != OK) { - HDEBUG(D_acl) debug_printf_indent( + HDEBUG(acl) debug_printf_indent( "ignore cutthrough request; ACL did not accept\n"); } else if (rcpt_count <= cutthrough.nrcpt) { - HDEBUG(D_acl) debug_printf_indent( + HDEBUG(acl) debug_printf_indent( "ignore cutthrough request; nonfirst message\n"); } else if ( (rc = open_cutthrough_connection(addr, cutthrough.tpt_sender)) @@ -4986,7 +4986,7 @@ switch (where) } else { - HDEBUG(D_acl) debug_printf_indent("cutthrough defer; will spool\n"); + HDEBUG(acl) debug_printf_indent("cutthrough defer; will spool\n"); rc = OK; } diff --git a/src/src/auths/call_saslauthd.c b/src/src/auths/call_saslauthd.c index b5735fc6c..eb6604e2a 100644 --- a/src/src/auths/call_saslauthd.c +++ b/src/src/auths/call_saslauthd.c @@ -45,22 +45,22 @@ uschar *reply = NULL; if (service == NULL) service = US""; if (realm == NULL) realm = US""; -DEBUG(D_auth) +DEBUG(auth) debug_printf("Running saslauthd authentication for user %q \n", username); switch (saslauthd_verify_password(username, password, service, realm, (const uschar **)(&reply))) { case PWCHECK_OK: - DEBUG(D_auth) debug_printf("saslauthd: success (%s)\n", reply); + DEBUG(auth) debug_printf("saslauthd: success (%s)\n", reply); return OK; case PWCHECK_NO: - DEBUG(D_auth) debug_printf("saslauthd: access denied (%s)\n", reply); + DEBUG(auth) debug_printf("saslauthd: access denied (%s)\n", reply); return FAIL; default: - DEBUG(D_auth) debug_printf("saslauthd: query failed (%s)\n", reply); + DEBUG(auth) debug_printf("saslauthd: query failed (%s)\n", reply); *errptr = reply; return ERROR; } diff --git a/src/src/auths/check_serv_cond.c b/src/src/auths/check_serv_cond.c index 739efff43..bcada237f 100644 --- a/src/src/auths/check_serv_cond.c +++ b/src/src/auths/check_serv_cond.c @@ -64,7 +64,7 @@ auth_check_some_cond(auth_instance * ablock, { uschar * cond; -HDEBUG(D_auth) +HDEBUG(auth) { debug_printf("%s authenticator %s:\n", ablock->drinst.name, label); for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i]) @@ -85,7 +85,7 @@ server_condition will be OK and otherwise will typically be FAIL. */ if (!condition) return unset; cond = expand_string(condition); -HDEBUG(D_auth) +HDEBUG(auth) if (!cond) debug_printf("expansion failed: %s\n", expand_string_message); else diff --git a/src/src/auths/cram_md5.c b/src/src/auths/cram_md5.c index 1532e2af6..56a40b9b8 100644 --- a/src/src/auths/cram_md5.c +++ b/src/src/auths/cram_md5.c @@ -228,7 +228,7 @@ if (secret == NULL) compute_cram_md5(secret, challenge, digest); -HDEBUG(D_auth) +HDEBUG(auth) { debug_printf("CRAM-MD5: user name = %s\n", auth_vars[0]); debug_printf(" challenge = %s\n", challenge); diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index 0ccb1f5fe..356fc6e50 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -160,7 +160,7 @@ if (sasl_listmech(conn, NULL, "", ":", "", CCSS &list, &len, NULL) != SASL_OK) sep = ':'; listptr = list; -HDEBUG(D_auth) +HDEBUG(auth) { debug_printf("Initialised Cyrus SASL service=%q fqdn=%q realm=%q\n", ob->server_service, expanded_hostname, realm_expanded); @@ -185,7 +185,7 @@ if (!buffer) store_reset(rs_point); -HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", a->name, ablock->public_name); +HDEBUG(auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", a->name, ablock->public_name); /* make sure that if we get here then we're allowed to advertise. */ ablock->server = TRUE; @@ -219,7 +219,7 @@ unsigned int inlen, outlen; input = data; inlen = Ustrlen(data); -HDEBUG(D_auth) debug = string_copy(data); +HDEBUG(auth) debug = string_copy(data); hname = expand_string(ob->server_hostname); if (hname && ob->server_realm) @@ -247,7 +247,7 @@ if ((rc = sasl_server_init(cbs, "exim")) != SASL_OK) rc = sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL, NULL, NULL, 0, &conn); -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("Initialised Cyrus SASL server connection; service=%q fqdn=%q realm=%q\n", ob->server_service, hname, realm_expanded); @@ -262,20 +262,20 @@ if (tls_in.cipher) { if ((rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits)) != SASL_OK) { - HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", + HDEBUG(auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", tls_in.bits, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF"; sasl_done(); return DEFER; } else - HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits); + HDEBUG(auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits); /*XXX Set channel-binding here with sasl_channel_binding_t / SASL_CHANNEL_BINDING Unclear what the "name" element does though, ditto the "critical" flag. */ } else - HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); + HDEBUG(auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); /* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed @@ -308,7 +308,7 @@ for (int i = 0; i < 2; ++i) if ((rc = sasl_setprop(conn, propnum, address_port)) != SASL_OK) { - HDEBUG(D_auth) + HDEBUG(auth) { const char * s_err = sasl_errdetail(conn); debug_printf("Failed to set %s SASL property: [%d] %s\n", @@ -316,7 +316,7 @@ for (int i = 0; i < 2; ++i) } break; } - HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n", + HDEBUG(auth) debug_printf("Cyrus SASL set %s hostport to: %s\n", label, address_port); } @@ -325,7 +325,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) if (firsttime) { firsttime = 0; - HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,%q)\n", ob->server_mech, debug); + HDEBUG(auth) debug_printf("Calling sasl_server_start(%s,%q)\n", ob->server_mech, debug); rc = sasl_server_start(conn, CS ob->server_mech, inlen ? CS input : NULL, inlen, CCSS &output, &outlen); } @@ -344,7 +344,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) } inlen = Ustrlen(input); - HDEBUG(D_auth) debug = string_copy_taint(input, GET_TAINTED); + HDEBUG(auth) debug = string_copy_taint(input, GET_TAINTED); if (inlen) { if ((clen = b64decode(input, &clear, GET_TAINTED)) < 0) @@ -357,7 +357,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) inlen = clen; } - HDEBUG(D_auth) debug_printf("Calling sasl_server_step(%q)\n", debug); + HDEBUG(auth) debug_printf("Calling sasl_server_step(%q)\n", debug); rc = sasl_server_step(conn, CS input, inlen, CCSS &output, &outlen); } @@ -375,7 +375,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) if ((sasl_getprop(conn, SASL_USERNAME, (const void **)&out2)) != SASL_OK) { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL library will not tell us the username: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s): " @@ -395,7 +395,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) case SASL_NOAUTHZ: case SASL_ENCRYPT: case SASL_EXPIRED: case SASL_DISABLED: case SASL_NOUSER: /* these are considered permanent failure codes */ - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL permanent failure: %s", auname, ob->server_mech, @@ -409,7 +409,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) available for this user. If it wasn't available at all, we shouldn't have got here in the first place... */ - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech); @@ -418,13 +418,13 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) return DEFER; case SASL_OK: - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, auth_vars[0]); if ((rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)))!= SASL_OK) { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL library will not tell us the SSF: %s\n", sasl_errstring(rc, NULL, NULL)); log_write(0, LOG_REJECT, "%s authenticator (%s): " @@ -435,11 +435,11 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) return FAIL; } negotiated_ssf = *negotiated_ssf_ptr; - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf); if (negotiated_ssf > 0) { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf); log_write(0, LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL SSF %d not supported by Exim", auname, ob->server_mech, negotiated_ssf); @@ -459,7 +459,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) /* Anything else is a temporary failure, and we'll let SASL print out * the error string for us */ - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL)); diff --git a/src/src/auths/dovecot.c b/src/src/auths/dovecot.c index 73322a6cd..9b2819293 100644 --- a/src/src/auths/dovecot.c +++ b/src/src/auths/dovecot.c @@ -110,7 +110,7 @@ if (!ablock->public_name) ablock->public_name = a->name; if (ob->server_socket) ablock->server = TRUE; -else DEBUG(D_auth) +else DEBUG(auth) debug_printf("Dovecot auth driver: no server_socket for %s\n", ablock->public_name); ablock->client = FALSE; @@ -159,7 +159,7 @@ if (n <= nptrs) *ptrs = last_sub_start; else { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("dovecot: warning: too many results from tab-splitting;" " saw %d fields, room for %d\n", n, nptrs); n = nptrs; @@ -251,7 +251,7 @@ dc_write(client_conn_ctx * cctx, const uschar * s) { int len = Ustrlen(s), res; -HDEBUG(D_auth) debug_printf(" DOVECOT>> '%s'\n", s); +HDEBUG(auth) debug_printf(" DOVECOT>> '%s'\n", s); res = #ifndef DISABLE_TLS cctx->tls_ctx ? tls_write(cctx->tls_ctx, s, len, FALSE) : @@ -279,7 +279,7 @@ host_item host; client_conn_ctx cctx = {.sock = -1, .tls_ctx = NULL}; BOOL found = FALSE, have_mech_line = FALSE; -HDEBUG(D_auth) debug_printf("dovecot authentication\n"); +HDEBUG(auth) debug_printf("dovecot authentication\n"); if (!data) { @@ -336,11 +336,11 @@ for (;;) OUT("authentication socket protocol line too long"); *p = '\0'; - HDEBUG(D_auth) debug_printf(" DOVECOT<< '%s'\n", buffer); + HDEBUG(auth) debug_printf(" DOVECOT<< '%s'\n", buffer); nargs = strcut(buffer, args, nelem(args)); - HDEBUG(D_auth) debug_strcut(args, nargs, nelem(args)); + HDEBUG(auth) debug_strcut(args, nargs, nelem(args)); /* Code below rewritten by Kirill Miazine (km@krot.org). Only check commands that Exim will need. Original code also failed if Dovecot server sent unknown @@ -364,7 +364,7 @@ for (;;) VERSION_MAJOR, VERSION_MINOR); if (dc_write(&cctx, version_command) < 0) - HDEBUG(D_auth) debug_printf("error sending version_command: %s\n", + HDEBUG(auth) debug_printf("error sending version_command: %s\n", strerror(errno)); } else if (Ustrcmp(args[0], US"MECH") == 0) @@ -448,7 +448,7 @@ auth_command = string_sprintf("CPID\t" PID_T_FMT "\n" interface_address, data); if (dc_write(&cctx, auth_command) < 0) - HDEBUG(D_auth) debug_printf("error sending auth_command: %s\n", + HDEBUG(auth) debug_printf("error sending auth_command: %s\n", strerror(errno)); while (1) @@ -463,9 +463,9 @@ while (1) } buffer[Ustrlen(buffer) - 1] = 0; - HDEBUG(D_auth) debug_printf(" DOVECOT<< '%s'\n", buffer); + HDEBUG(auth) debug_printf(" DOVECOT<< '%s'\n", buffer); nargs = strcut(buffer, args, nelem(args)); - HDEBUG(D_auth) debug_strcut(args, nargs, nelem(args)); + HDEBUG(auth) debug_strcut(args, nargs, nelem(args)); if (Uatoi(args[1]) != crequid) OUT("authentication socket connection id mismatch"); @@ -549,7 +549,7 @@ if (cctx.sock >= 0) /* Expand server_condition as an authorization check */ if (ret == OK) ret = auth_check_serv_cond(ablock); -HDEBUG(D_auth) debug_printf("dovecot auth ret: %s\n", rc_names[ret]); +HDEBUG(auth) debug_printf("dovecot auth ret: %s\n", rc_names[ret]); return ret; } diff --git a/src/src/auths/get_data.c b/src/src/auths/get_data.c index 20f36bb82..515fcde0b 100644 --- a/src/src/auths/get_data.c +++ b/src/src/auths/get_data.c @@ -34,17 +34,17 @@ else int len; if ((len = b64decode(data, &clear, GET_TAINTED)) < 0) return BAD64; - DEBUG(D_auth) debug_printf("auth input decode:"); + DEBUG(auth) debug_printf("auth input decode:"); for (const uschar * end = clear + len; clear < end && expand_nmax < EXPAND_MAXN; ) { - DEBUG(D_auth) debug_printf(" '%s'", clear); + DEBUG(auth) debug_printf(" '%s'", clear); if (expand_nmax < AUTH_VARS) auth_vars[expand_nmax] = clear; expand_nstring[++expand_nmax] = clear; while (*clear) clear++; expand_nlength[expand_nmax] = clear++ - expand_nstring[expand_nmax]; } - DEBUG(D_auth) debug_printf("\n"); + DEBUG(auth) debug_printf("\n"); } return OK; } @@ -86,7 +86,7 @@ while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF) } if (p > 0 && big_buffer[p-1] == '\r') p--; big_buffer[p] = 0; -DEBUG(D_receive) debug_printf("SMTP<< %s\n", big_buffer); +DEBUG(receive) debug_printf("SMTP<< %s\n", big_buffer); if (Ustrcmp(big_buffer, "*") == 0) return CANCELLED; *aptr = big_buffer; return OK; @@ -249,7 +249,7 @@ if (clear_len < 0) "response %q", save_bad); return CANCELLED; } - DEBUG(D_auth) debug_printf("bad b64 decode for '%s';" + DEBUG(auth) debug_printf("bad b64 decode for '%s';" " ignoring due to client_ignore_invalid_base64\n", save_bad); clear = string_copy(US""); } diff --git a/src/src/auths/gsasl.c b/src/src/auths/gsasl.c index ad4c9b479..3f9432bdf 100644 --- a/src/src/auths/gsasl.c +++ b/src/src/auths/gsasl.c @@ -202,7 +202,7 @@ if (!gsasl_ctx) /* We don't need this except to log it for debugging. */ -HDEBUG(D_auth) if (!once) +HDEBUG(auth) if (!once) { if ((rc = gsasl_server_mechlist(gsasl_ctx, &once)) != GSASL_OK) log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " @@ -233,7 +233,7 @@ else if( ob->server_mech */ ablock->server = FALSE; - HDEBUG(D_auth) debug_printf("%s authenticator: " + HDEBUG(auth) debug_printf("%s authenticator: " "Need server_condition for %s mechanism\n", a->name, ob->server_mech); } @@ -245,7 +245,7 @@ if ( !ob->server_realm && STREQIC(ob->server_mech, US"DIGEST-MD5")) { ablock->server = FALSE; - HDEBUG(D_auth) debug_printf("%s authenticator: " + HDEBUG(auth) debug_printf("%s authenticator: " "Need server_realm for %s mechanism\n", a->name, ob->server_mech); } @@ -266,19 +266,19 @@ struct callback_exim_state *cb_state = if (!cb_state) { - HDEBUG(D_auth) debug_printf("gsasl callback (%d) not from our server/client processing\n", prop); + HDEBUG(auth) debug_printf("gsasl callback (%d) not from our server/client processing\n", prop); #ifdef CHANNELBIND_HACK if (prop == GSASL_CB_TLS_UNIQUE) { uschar * s; if ((s = gsasl_callback_hook_get(ctx))) /* Gross hack for early lib vers */ { - HDEBUG(D_auth) debug_printf("GSASL_CB_TLS_UNIQUE from ctx hook\n"); + HDEBUG(auth) debug_printf("GSASL_CB_TLS_UNIQUE from ctx hook\n"); gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CS s); } else { - HDEBUG(D_auth) debug_printf("GSASL_CB_TLS_UNIQUE! dummy for now\n"); + HDEBUG(auth) debug_printf("GSASL_CB_TLS_UNIQUE! dummy for now\n"); gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, ""); } return GSASL_OK; @@ -287,7 +287,7 @@ if (!cb_state) return GSASL_NO_CALLBACK; } -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("GNU SASL Callback entered, prop=%d (loop prop=%d)\n", prop, callback_loop); @@ -296,7 +296,7 @@ if (callback_loop > 0) /* Most likely is that we were asked for property FOO, and to expand the string we asked for property BAR to put into an auth variable, but property BAR is not supplied for this mechanism. */ - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Loop, asked for property %d while handling property %d\n", prop, callback_loop); return GSASL_NO_CALLBACK; @@ -370,7 +370,7 @@ return CUS string_sprintf("(unknown prop: %d)", (int)prop); static void preload_prop(Gsasl_session * sctx, Gsasl_property propcode, const uschar * val) { -DEBUG(D_auth) debug_printf("preloading prop %s val %s\n", +DEBUG(auth) debug_printf("preloading prop %s val %s\n", gsasl_prop_code_to_name(propcode), val); gsasl_property_set(sctx, propcode, CCS val); } @@ -392,7 +392,7 @@ Gsasl_session * sctx = NULL; struct callback_exim_state cb_state; int rc, auth_result, exim_error, exim_error_override; -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("GNU SASL: initialising session for %s, mechanism %s\n", auname, ob->server_mech); @@ -402,7 +402,7 @@ if (tls_in.channelbinding && ob->server_channelbinding) # ifndef DISABLE_TLS_RESUME if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED) { /* per RFC 7677 section 4 */ - HDEBUG(D_auth) debug_printf( + HDEBUG(auth) debug_printf( "channel binding not usable on resumed TLS without extended-master-secret"); return FAIL; } @@ -421,7 +421,7 @@ if ((rc = gsasl_server_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK { auth_defer_msg = string_sprintf("GNU SASL: session start failure: %s (%s)", gsasl_strerror_name(rc), gsasl_strerror(rc)); - HDEBUG(D_auth) debug_printf("%s\n", auth_defer_msg); + HDEBUG(auth) debug_printf("%s\n", auth_defer_msg); return DEFER; } /* Hereafter: gsasl_finish(sctx) please */ @@ -472,7 +472,7 @@ if (tls_in.channelbinding) */ if (ob->server_channelbinding) { - HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n", + HDEBUG(auth) debug_printf("Auth %s: Enabling channel-binding\n", auname); # ifndef CHANNELBIND_HACK preload_prop(sctx, @@ -484,12 +484,12 @@ if (tls_in.channelbinding) # endif } else - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Auth %s: Not enabling channel-binding (data available)\n", auname); } else - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Auth %s: no channel-binding data available\n", auname); #endif @@ -520,7 +520,7 @@ do { case GSASL_NO_PASSCODE: case GSASL_NO_PIN: case GSASL_BASE64_ERROR: - HDEBUG(D_auth) debug_printf("GNU SASL permanent error: %s (%s)\n", + HDEBUG(auth) debug_printf("GNU SASL permanent error: %s (%s)\n", gsasl_strerror_name(rc), gsasl_strerror(rc)); log_write(0, LOG_REJECT, "%s authenticator (%s):\n " "GNU SASL permanent failure: %s (%s)", @@ -533,7 +533,7 @@ do { default: auth_defer_msg = string_sprintf("GNU SASL temporary error: %s (%s)", gsasl_strerror_name(rc), gsasl_strerror(rc)); - HDEBUG(D_auth) debug_printf("%s\n", auth_defer_msg); + HDEBUG(auth) debug_printf("%s\n", auth_defer_msg); exim_error_override = DEFER; goto STOP_INTERACTION; } @@ -556,7 +556,7 @@ do { STOP_INTERACTION: auth_result = rc; -HDEBUG(D_auth) +HDEBUG(auth) { const uschar * s; if ((s = CUS gsasl_property_fast(sctx, GSASL_SCRAM_ITER))) @@ -580,7 +580,7 @@ if (exim_error != OK) if (auth_result != GSASL_OK) { - HDEBUG(D_auth) debug_printf("authentication returned %s (%s)\n", + HDEBUG(auth) debug_printf("authentication returned %s (%s)\n", gsasl_strerror_name(auth_result), gsasl_strerror(auth_result)); if (exim_error_override != OK) return exim_error_override; /* might be DEFER */ @@ -623,7 +623,7 @@ set_exim_authvar_from_prop(Gsasl_session * sctx, Gsasl_property prop) uschar * propval = US gsasl_property_fast(sctx, prop); int i = expand_nmax, j = i + 1; propval = propval ? string_copy(propval) : US""; -HDEBUG(D_auth) debug_printf("auth[%d] <= %s'%s'\n", +HDEBUG(auth) debug_printf("auth[%d] <= %s'%s'\n", j, gsasl_prop_code_to_name(prop), propval); expand_nstring[j] = propval; expand_nlength[j] = Ustrlen(propval); @@ -653,17 +653,17 @@ static int prop_from_option(Gsasl_session * sctx, Gsasl_property prop, const uschar * option) { -HDEBUG(D_auth) debug_printf(" %s\n", gsasl_prop_code_to_name(prop)); +HDEBUG(auth) debug_printf(" %s\n", gsasl_prop_code_to_name(prop)); if (option) { set_exim_authvars_from_a_az_r_props(sctx); option = expand_string(option); - HDEBUG(D_auth) debug_printf(" '%s'\n", option); + HDEBUG(auth) debug_printf(" '%s'\n", option); if (*option) gsasl_property_set(sctx, prop, CCS option); return GSASL_OK; } -HDEBUG(D_auth) debug_printf(" option not set\n"); +HDEBUG(auth) debug_printf(" option not set\n"); return GSASL_NO_CALLBACK; } @@ -676,7 +676,7 @@ char * tmps; uschar * s; int cbrc = GSASL_NO_CALLBACK; -HDEBUG(D_auth) debug_printf("GNU SASL callback %s for %s/%s as server\n", +HDEBUG(auth) debug_printf("GNU SASL callback %s for %s/%s as server\n", gsasl_prop_code_to_name(prop), ablock->drinst.name, ablock->public_name); for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL; @@ -697,7 +697,7 @@ switch (prop) case GSASL_VALIDATE_EXTERNAL: if (!ablock->server_condition) { - HDEBUG(D_auth) debug_printf("No server_condition supplied, to validate EXTERNAL\n"); + HDEBUG(auth) debug_printf("No server_condition supplied, to validate EXTERNAL\n"); cbrc = GSASL_AUTHENTICATION_ERROR; break; } @@ -711,7 +711,7 @@ switch (prop) case GSASL_VALIDATE_ANONYMOUS: if (!ablock->server_condition) { - HDEBUG(D_auth) debug_printf("No server_condition supplied, to validate ANONYMOUS\n"); + HDEBUG(auth) debug_printf("No server_condition supplied, to validate ANONYMOUS\n"); cbrc = GSASL_AUTHENTICATION_ERROR; break; } @@ -772,17 +772,17 @@ switch (prop) if (!(s = ob->server_password)) { - HDEBUG(D_auth) debug_printf("option not set\n"); + HDEBUG(auth) debug_printf("option not set\n"); break; } if (!(tmps = CS expand_string(s))) { sasl_error_should_defer = !f.expand_string_forcedfail; - HDEBUG(D_auth) debug_printf("server_password expansion failed, so " + HDEBUG(auth) debug_printf("server_password expansion failed, so " "can't tell GNU SASL library the password for %s\n", auth_vars[0]); return GSASL_AUTHENTICATION_ERROR; } - HDEBUG(D_auth) debug_printf(" set\n"); + HDEBUG(auth) debug_printf(" set\n"); gsasl_property_set(sctx, GSASL_PASSWORD, tmps); /* This is inadequate; don't think Exim's store stacks are geared @@ -794,11 +794,11 @@ switch (prop) break; default: - HDEBUG(D_auth) debug_printf(" Unrecognised callback: %d\n", prop); + HDEBUG(auth) debug_printf(" Unrecognised callback: %d\n", prop); cbrc = GSASL_NO_CALLBACK; } -HDEBUG(D_auth) debug_printf("Returning %s (%s)\n", +HDEBUG(auth) debug_printf("Returning %s (%s)\n", gsasl_strerror_name(cbrc), gsasl_strerror(cbrc)); return cbrc; @@ -823,7 +823,7 @@ if (!(s = expand_string(val)) || !(flags & PROP_OPTIONAL) && !*s) } if (*s) { - HDEBUG(D_auth) debug_printf("%s: set %s = '%s'\n", __FUNCTION__, + HDEBUG(auth) debug_printf("%s: set %s = '%s'\n", __FUNCTION__, gsasl_prop_code_to_name(prop), s); gsasl_property_set(sctx, prop, CS s); } @@ -853,7 +853,7 @@ uschar * s; BOOL initial = TRUE; int rc, yield = FAIL; -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("GNU SASL: initialising session for %s, mechanism %s\n", auname, ob->server_mech); @@ -885,7 +885,7 @@ if ((rc = gsasl_client_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK { string_format(buffer, buffsize, "GNU SASL: session start failure: %s (%s)", gsasl_strerror_name(rc), gsasl_strerror(rc)); - HDEBUG(D_auth) debug_printf("%s\n", buffer); + HDEBUG(auth) debug_printf("%s\n", buffer); return ERROR; } @@ -908,7 +908,7 @@ if ( !set_client_prop(sctx, GSASL_PASSWORD, ob->client_password, if (tls_out.channelbinding) if (ob->client_channelbinding) { - HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n", + HDEBUG(auth) debug_printf("Auth %s: Enabling channel-binding\n", auname); # ifndef CHANNELBIND_HACK preload_prop(sctx, @@ -920,7 +920,7 @@ if (tls_out.channelbinding) # endif } else - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("Auth %s: Not enabling channel-binding (data available)\n", auname); #endif @@ -997,14 +997,14 @@ return yield; static int client_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_instance *ablock) { -HDEBUG(D_auth) debug_printf("GNU SASL callback %s for %s/%s as client\n", +HDEBUG(auth) debug_printf("GNU SASL callback %s for %s/%s as client\n", gsasl_prop_code_to_name(prop), ablock->drinst.name, ablock->public_name); switch (prop) { #ifdef EXIM_GSASL_HAVE_EXPORTER case GSASL_CB_TLS_EXPORTER: /* Should never get called for this, as pre-set */ if (!tls_out.channelbind_exporter) break; - HDEBUG(D_auth) debug_printf(" filling in\n"); + HDEBUG(auth) debug_printf(" filling in\n"); gsasl_property_set(sctx, GSASL_CB_TLS_EXPORTER, CCS tls_out.channelbinding); return GSASL_OK; #endif @@ -1012,7 +1012,7 @@ switch (prop) #ifdef EXIM_GSASL_HAVE_EXPORTER if (tls_out.channelbind_exporter) break; #endif - HDEBUG(D_auth) debug_printf(" filling in\n"); + HDEBUG(auth) debug_printf(" filling in\n"); gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding); return GSASL_OK; case GSASL_SCRAM_SALTED_PASSWORD: @@ -1020,7 +1020,7 @@ switch (prop) uschar * client_spassword = ((auth_gsasl_options_block *) ablock->drinst.options_block)->client_spassword; uschar dummy[4]; - HDEBUG(D_auth) if (!client_spassword) + HDEBUG(auth) if (!client_spassword) debug_printf(" client_spassword option unset\n"); if (client_spassword) { @@ -1036,7 +1036,7 @@ switch (prop) break; } default: - HDEBUG(D_auth) + HDEBUG(auth) debug_printf(" not providing one\n"); break; } diff --git a/src/src/auths/heimdal_gssapi.c b/src/src/auths/heimdal_gssapi.c index 1c79112c3..a2b2cd49f 100644 --- a/src/src/auths/heimdal_gssapi.c +++ b/src/src/auths/heimdal_gssapi.c @@ -135,14 +135,14 @@ ablock->client = FALSE; if (!ob->server_service || !*ob->server_service) { - HDEBUG(D_auth) debug_printf("heimdal: missing server_service\n"); + HDEBUG(auth) debug_printf("heimdal: missing server_service\n"); return; } if ((krc = krb5_init_context(&context))) { int kerr = errno; - HDEBUG(D_auth) debug_printf("heimdal: failed to initialise krb5 context: %s\n", + HDEBUG(auth) debug_printf("heimdal: failed to initialise krb5 context: %s\n", strerror(kerr)); return; } @@ -150,24 +150,24 @@ if ((krc = krb5_init_context(&context))) if (ob->server_keytab) { k_keytab_typed_name = CCS string_sprintf("file:%s", expand_string(ob->server_keytab)); - HDEBUG(D_auth) debug_printf("heimdal: using keytab %s\n", k_keytab_typed_name); + HDEBUG(auth) debug_printf("heimdal: using keytab %s\n", k_keytab_typed_name); if ((krc = krb5_kt_resolve(context, k_keytab_typed_name, &keytab))) { - HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_resolve", context, krc); + HDEBUG(auth) exim_heimdal_error_debug("krb5_kt_resolve", context, krc); return; } } else { - HDEBUG(D_auth) debug_printf("heimdal: using system default keytab\n"); + HDEBUG(auth) debug_printf("heimdal: using system default keytab\n"); if ((krc = krb5_kt_default(context, &keytab))) { - HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_default", context, krc); + HDEBUG(auth) exim_heimdal_error_debug("krb5_kt_default", context, krc); return; } } -HDEBUG(D_auth) +HDEBUG(auth) { /* http://www.h5l.org/manual/HEAD/krb5/krb5_keytab_intro.html */ if ((krc = krb5_kt_start_seq_get(context, keytab, &cursor))) @@ -193,7 +193,7 @@ HDEBUG(D_auth) } if ((krc = krb5_kt_close(context, keytab))) - HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_close", context, krc); + HDEBUG(auth) exim_heimdal_error_debug("krb5_kt_close", context, krc); krb5_free_context(context); @@ -249,7 +249,7 @@ uschar requested_qop; store_reset_point = store_mark(); -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("heimdal: initialising auth context for %s\n", ablock->drinst.name); /* Construct our gss_name_t gserver describing ourselves */ @@ -272,7 +272,7 @@ if (ob->server_keytab) if (GSS_ERROR(maj_stat)) return exim_gssapi_error_defer(store_reset_point, maj_stat, min_stat, "registering keytab %q", keytab); - HDEBUG(D_auth) debug_printf("heimdal: using keytab %q\n", keytab); + HDEBUG(auth) debug_printf("heimdal: using keytab %q\n", keytab); } /* Acquire our credentials */ @@ -290,7 +290,7 @@ if (GSS_ERROR(maj_stat)) maj_stat = gss_release_name(&min_stat, &gserver); -HDEBUG(D_auth) debug_printf("heimdal: have server credentials.\n"); +HDEBUG(auth) debug_printf("heimdal: have server credentials.\n"); /* Loop talking to client */ step = 0; @@ -317,12 +317,12 @@ while (step < 4) { if (handled_empty_ir) { - HDEBUG(D_auth) debug_printf("gssapi: repeated empty input, grr.\n"); + HDEBUG(auth) debug_printf("gssapi: repeated empty input, grr.\n"); error_out = BAD64; goto ERROR_OUT; } - HDEBUG(D_auth) debug_printf("gssapi: missing initial response, nudging.\n"); + HDEBUG(auth) debug_printf("gssapi: missing initial response, nudging.\n"); if ((error_out = auth_get_data(&from_client, US"", 0)) != OK) goto ERROR_OUT; handled_empty_ir = TRUE; @@ -330,7 +330,7 @@ while (step < 4) } /* We should now have the opening data from the client, base64-encoded. */ step += 1; - HDEBUG(D_auth) debug_printf("heimdal: have initial client data\n"); + HDEBUG(auth) debug_printf("heimdal: have initial client data\n"); break; case 1: @@ -372,10 +372,10 @@ while (step < 4) if (maj_stat == GSS_S_COMPLETE) { step += 1; - HDEBUG(D_auth) debug_printf("heimdal: GSS complete\n"); + HDEBUG(auth) debug_printf("heimdal: GSS complete\n"); } else - HDEBUG(D_auth) debug_printf("heimdal: need more data\n"); + HDEBUG(auth) debug_printf("heimdal: need more data\n"); break; case 2: @@ -406,7 +406,7 @@ while (step < 4) goto ERROR_OUT; } - HDEBUG(D_auth) debug_printf("heimdal SASL: requesting QOP with no security layers\n"); + HDEBUG(auth) debug_printf("heimdal SASL: requesting QOP with no security layers\n"); error_out = auth_get_data(&from_client, gbufdesc_out.value, gbufdesc_out.length); @@ -436,7 +436,7 @@ while (step < 4) } if (gbufdesc_out.length < 4) { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("gssapi: final message too short; " "need flags, buf sizes and optional authzid\n"); error_out = FAIL; @@ -446,7 +446,7 @@ while (step < 4) requested_qop = (CS gbufdesc_out.value)[0]; if (!(requested_qop & 0x01)) { - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("gssapi: client requested security layers (%x)\n", (unsigned int) requested_qop); error_out = FAIL; @@ -496,11 +496,11 @@ while (step < 4) expand_nmax = 2; expand_nlength[2] = expand_nlength[1]; auth_vars[1] = expand_nstring[2] = string_copyn(expand_nstring[1], expand_nlength[1]); - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("heimdal SASL: empty authzid, set to dup of GSSAPI display name\n"); } - HDEBUG(D_auth) + HDEBUG(auth) debug_printf("heimdal SASL: happy with client request\n" " auth1 (verified GSSAPI display-name): %q\n" " auth2 (unverified SASL requested authzid): %q\n", @@ -549,7 +549,7 @@ OM_uint32 msgcontext = 0; gss_buffer_desc status_string; gstring * g = NULL; -HDEBUG(D_auth) +HDEBUG(auth) { va_start(ap, format); g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, format, ap); @@ -565,7 +565,7 @@ do { if (!auth_defer_msg) auth_defer_msg = string_copy(US status_string.value); - HDEBUG(D_auth) debug_printf("heimdal %Y: %.*s\n", + HDEBUG(auth) debug_printf("heimdal %Y: %.*s\n", g, (int)status_string.length, CS status_string.value); gss_release_buffer(&min_stat, &status_string); @@ -591,7 +591,7 @@ auth_heimdal_gssapi_client( uschar *buffer, /* buffer for reading response */ int buffsize) /* size of buffer */ { -HDEBUG(D_auth) +HDEBUG(auth) debug_printf("Client side NOT IMPLEMENTED: you should not see this!\n"); /* NOT IMPLEMENTED */ return FAIL; diff --git a/src/src/auths/pwcheck.c b/src/src/auths/pwcheck.c index cd8ed1e10..8856fcce3 100644 --- a/src/src/auths/pwcheck.c +++ b/src/src/auths/pwcheck.c @@ -111,7 +111,7 @@ int saslauthd_verify_password(const uschar *userid, int s, r; struct sockaddr_un srvaddr; - DEBUG(D_auth) + DEBUG(auth) debug_printf("saslauthd userid='%s' servicename='%s'" " realm='%s'\n", userid, service, realm ); @@ -129,7 +129,7 @@ int saslauthd_verify_password(const uschar *userid, sizeof(srvaddr.sun_path)); r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); if (r == -1) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Cannot connect to saslauthd daemon (at '%s'): %s\n", CYRUS_SASLAUTHD_SOCKET, strerror(errno)); *reply = string_sprintf("cannot connect to saslauthd daemon at " @@ -139,14 +139,14 @@ int saslauthd_verify_password(const uschar *userid, } if ( write_string(s, userid, Ustrlen(userid)) < 0) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Failed to send userid to saslauthd daemon \n"); (void)close(s); return PWCHECK_FAIL; } if ( write_string(s, password, Ustrlen(password)) < 0) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Failed to send password to saslauthd daemon \n"); (void)close(s); return PWCHECK_FAIL; @@ -155,21 +155,21 @@ int saslauthd_verify_password(const uschar *userid, memset((void *)password, 0, Ustrlen(password)); if ( write_string(s, service, Ustrlen(service)) < 0) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Failed to send service name to saslauthd daemon \n"); (void)close(s); return PWCHECK_FAIL; } if ( write_string(s, realm, Ustrlen(realm)) < 0) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Failed to send realm to saslauthd daemon \n"); (void)close(s); return PWCHECK_FAIL; } if ( read_string(s, &daemon_reply ) < 2) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("Corrupted answer '%s' received. \n", daemon_reply); (void)close(s); return PWCHECK_FAIL; @@ -177,7 +177,7 @@ int saslauthd_verify_password(const uschar *userid, (void)close(s); - DEBUG(D_auth) + DEBUG(auth) debug_printf("Answer '%s' received. \n", daemon_reply); *reply = daemon_reply; diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c index 3e2cccde9..4b7f9cc95 100644 --- a/src/src/auths/spa.c +++ b/src/src/auths/spa.c @@ -156,7 +156,7 @@ if (!*data && auth_get_no64_data(&data, US"NTLM supported") != OK) if (spa_base64_to_bits(CS &request, sizeof(request), CCS data) < 0) { - DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in " + DEBUG(auth) debug_printf("auth_spa_server(): bad base64 data in " "request: %s\n", data); return FAIL; } @@ -172,7 +172,7 @@ if (auth_get_no64_data(&data, msgbuf) != OK) /* dump client response */ if (spa_base64_to_bits(CS &response, sizeof(response), CCS data) < 0) { - DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in " + DEBUG(auth) debug_printf("auth_spa_server(): bad base64 data in " "response: %s\n", data); return FAIL; } @@ -201,7 +201,7 @@ that causes failure if the size of msgbuf is exceeded. ****/ || (p = (CS responseptr) + off) + len*2 >= CS (responseptr+1) ) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("auth_spa_server(): bad uUser spec in response\n"); return FAIL; } @@ -233,13 +233,13 @@ debug_print_string(ablock->server_debug_string); /* customized debug */ if (!(clearpass = expand_string(ob->spa_serverpassword))) if (f.expand_string_forcedfail) { - DEBUG(D_auth) debug_printf("auth_spa_server(): forced failure while " + DEBUG(auth) debug_printf("auth_spa_server(): forced failure while " "expanding spa_serverpassword\n"); return FAIL; } else { - DEBUG(D_auth) debug_printf("auth_spa_server(): error while expanding " + DEBUG(auth) debug_printf("auth_spa_server(): error while expanding " "spa_serverpassword: %s\n", expand_string_message); return DEFER; } @@ -254,7 +254,7 @@ spa_smb_nt_encrypt(clearpass, challenge.challengeData, ntRespData); off = IVAL(&responseptr->ntResponse.offset,0); if (off >= sizeof(SPAAuthResponse) - 24) { - DEBUG(D_auth) + DEBUG(auth) debug_printf("auth_spa_server(): bad ntRespData spec in response\n"); return FAIL; } diff --git a/src/src/child.c b/src/src/child.c index de08095af..8796b4354 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -69,15 +69,14 @@ Returns: if CEE_RETURN_ARGV is given, returns a pointer to argv; */ uschar ** -child_exec_exim(int exec_type, BOOL kill_v, int *pcount, BOOL minimal, +child_exec_exim(int exec_type, BOOL kill_v, int * pcount, BOOL minimal, int acount, ...) { -int first_special = -1; -int n = 0; -int extra = pcount ? *pcount : 0; +int first_special = -1, n = 0, extra = pcount ? *pcount : 0; uschar **argv; -argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), GET_UNTAINTED); +argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), + GET_UNTAINTED); /* In all case, the list starts out with the path, any macros, and a changed config file. */ @@ -99,15 +98,11 @@ was involved, so we do pass it on. */ if (!minimal) { - if (debug_selector == D_v) - { - if (!kill_v) argv[n++] = US"-v"; - } - else - { - if (debug_selector != 0) + if (ANY_DEBUG) + if (DEBUG_BIT(BIT_TABLE_IDX_NONVERB)) { - argv[n++] = string_sprintf("-d=0x" PR_EXIM_BITMASK, debug_selector); + argv[n++] = string_from_gstring(debug_selector_dump(NULL)); + if (debug_fd > 2) { int flags = fcntl(debug_fd, F_GETFD); @@ -117,12 +112,14 @@ if (!minimal) close(debug_fd); } } - } + else + if (!kill_v) argv[n++] = US"-v"; + if (debug_pretrigger_buf) { argv[n++] = US"-dp"; argv[n++] = string_sprintf("0x%x", debug_pretrigger_bsize); } if (dtrigger_selector != 0) argv[n++] = string_sprintf("-dt=0x%x", dtrigger_selector); - DEBUG(D_any) + DEBUG(any) { argv[n++] = US"-MCd"; argv[n++] = US process_purpose; @@ -163,7 +160,7 @@ if (exec_type == CEE_RETURN_ARGV) failure. We know that there will always be at least one extra option in the call when exec() is done here, so it can be used to add to the panic data. */ -DEBUG(D_exec) debug_print_argv(CUSS argv); +DEBUG(exec) debug_print_argv(CUSS argv); exim_nullstd(); /* Make sure std{in,out,err} exist */ execv(CS argv[0], (char *const *)argv); @@ -379,14 +376,14 @@ if (pid == 0) if (newgid && setgid(*newgid) < 0) { - DEBUG(D_any) debug_printf("failed to set gid=%ld in subprocess: %s\n", + DEBUG(any) debug_printf("failed to set gid=%ld in subprocess: %s\n", (long int)(*newgid), strerror(errno)); goto CHILD_FAILED; } if (newuid && setuid(*newuid) < 0) { - DEBUG(D_any) debug_printf("failed to set uid=%ld in subprocess: %s\n", + DEBUG(any) debug_printf("failed to set uid=%ld in subprocess: %s\n", (long int)(*newuid), strerror(errno)); goto CHILD_FAILED; } @@ -395,7 +392,7 @@ if (pid == 0) if (wd && Uchdir(wd) < 0) { - DEBUG(D_any) debug_printf("failed to chdir to %s: %s\n", wd, + DEBUG(any) debug_printf("failed to chdir to %s: %s\n", wd, strerror(errno)); goto CHILD_FAILED; } @@ -407,7 +404,7 @@ if (pid == 0) if (make_leader && setpgid(0,0) < 0) { - DEBUG(D_any) debug_printf("failed to set group leader in subprocess: %s\n", + DEBUG(any) debug_printf("failed to set group leader in subprocess: %s\n", strerror(errno)); goto CHILD_FAILED; } @@ -555,3 +552,5 @@ return yield; } /* End of child.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/daemon.c b/src/src/daemon.c index 9fac96428..c63a10838 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -142,7 +142,7 @@ static void unlink_notifier_socket(void) { #ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS -DEBUG(D_any) debug_printf("unlinking notifier socket %s\n", notifier_socket_name); +DEBUG(any) debug_printf("unlinking notifier socket %s\n", notifier_socket_name); Uunlink(notifier_socket_name); #endif } @@ -197,7 +197,7 @@ rmark reset_point = store_mark(); the remote port. */ sender_host_address = host_ntoa(-1, accepted, NULL, &sender_host_port); -DEBUG(D_any) debug_printf("Connection request from %s port %d\n", +DEBUG(any) debug_printf("Connection request from %s port %d\n", sender_host_address, sender_host_port); /* Set up the output stream, check the socket has duplicated, and set up the @@ -226,7 +226,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr), } interface_address = host_ntoa(-1, &interface_sockaddr, NULL, &interface_port); -DEBUG(D_interface) debug_printf("interface address=%s port=%d\n", +DEBUG(interface) debug_printf("interface address=%s port=%d\n", interface_address, interface_port); /* Build a string identifying the remote host and, if requested, the port and @@ -250,7 +250,7 @@ it might take some time. */ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max) { - DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n", + DEBUG(any) debug_printf("rejecting SMTP connection: count=%d max=%d\n", smtp_accept_count, smtp_accept_max); smtp_printf("421 Too many concurrent SMTP connections; " "please try again later.\r\n", SP_NO_MORE); @@ -270,7 +270,7 @@ if (smtp_load_reserve >= 0) load_average = OS_GETLOADAVG(); if (!smtp_reserve_hosts && load_average > smtp_load_reserve) { - DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n", + DEBUG(any) debug_printf("rejecting SMTP connection: load average = %.2f\n", (double)load_average/1000.0); smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, @@ -339,7 +339,7 @@ if ( smtp_slots if (host_accept_count >= max_for_this_host) { - DEBUG(D_any) debug_printf("rejecting SMTP connection: too many from this " + DEBUG(any) debug_printf("rejecting SMTP connection: too many from this " "IP address: count=%d max=%d\n", host_accept_count, max_for_this_host); smtp_printf("421 Too many concurrent SMTP connections " @@ -363,10 +363,8 @@ pid = exim_fork(US"daemon-accept"); if (pid == 0) { - int queue_only_reason = 0; - int old_pool = store_pool; - bitmask_word_t save_debug_selector = debug_selector; - BOOL local_queue_only, session_local_queue_only; + int queue_only_reason = 0, old_pool = store_pool; + BOOL is_any_debug = FALSE, local_queue_only, session_local_queue_only; #ifdef SA_NOCLDWAIT struct sigaction act; #endif @@ -390,8 +388,9 @@ if (pid == 0) if (LOGGING(smtp_connection)) { const uschar * list = hosts_connection_nolog; + if (list && verify_check_host(&list) == OK) - log_selector[0] &= ~L_smtp_connection; /*XXX assumes word-of-bit */ + logging_modify_channels(US"-smtp_connection"); else if (LOGGING(connection_id)) log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y " "Ci=%s (TCP/IP connection count = %d)", @@ -483,19 +482,27 @@ if (pid == 0) finding the id, but turn it on again afterwards so that information about the incoming connection is output. */ - if (f.debug_daemon) debug_selector = 0; + if (f.debug_daemon) + { + is_any_debug = !!ANY_DEBUG; + bit_clear(debug_selector, BIT_TABLE_IDX_NONZERO); + } + verify_get_ident(IDENT_PORT); host_build_sender_fullhost(); - debug_selector = save_debug_selector; - DEBUG(D_any) + if (f.debug_daemon && is_any_debug) + bit_set(debug_selector, BIT_TABLE_IDX_NONZERO); + + DEBUG(any) debug_printf("Process " PID_T_FMT " is handling incoming connection" " from %s\n", getpid(), sender_fullhost); /* Now disable debugging permanently if it's required only for the daemon process. */ - if (f.debug_daemon) debug_selector = 0; + if (f.debug_daemon && is_any_debug) + bit_clear(debug_selector, BIT_TABLE_IDX_NONZERO); /* If there are too many child processes for immediate delivery, set the session_local_queue_only flag, which is initialized from the @@ -533,7 +540,7 @@ if (pid == 0) message_id[0] = 0; /* Clear out any previous message_id */ reset_point = store_mark(); /* Save current store high water point */ - DEBUG(D_any) + DEBUG(any) debug_printf("Process " PID_T_FMT " is ready for new message\n", getpid()); /* Smtp_setup_msg() returns 0 on QUIT or if the call is from an @@ -563,7 +570,7 @@ if (pid == 0) /*XXX should we pause briefly, hoping that the client will be the active TCP closer hence get the TCP_WAIT endpoint? */ - DEBUG(D_receive) debug_printf("SMTP>>(close on process exit)\n"); + DEBUG(receive) debug_printf("SMTP>>(close on process exit)\n"); exim_underbar_exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); } @@ -582,7 +589,7 @@ if (pid == 0) /* Show the recipients when debugging */ - DEBUG(D_receive) + DEBUG(receive) { if (sender_address) debug_printf("Sender: %s\n", sender_address); @@ -717,8 +724,7 @@ if (pid == 0) if (dpid > 0) { release_cutthrough_connection(US"passed for delivery"); - DEBUG(D_any) - debug_printf("forked delivery process " PID_T_FMT "\n", dpid); + DEBUG(any) debug_printf("forked delivery process " PID_T_FMT "\n", dpid); } else { @@ -751,7 +757,7 @@ else if (smtp_slots) smtp_accept_count, queue_run_count, daemon_process_info); break; } - DEBUG(D_any) debug_printf("%d SMTP accept process%s running\n", + DEBUG(any) debug_printf("%d SMTP accept process%s running\n", smtp_accept_count, smtp_accept_count == 1 ? "" : "es"); } @@ -879,7 +885,7 @@ pid_t pid; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - DEBUG(D_any) + DEBUG(any) { debug_printf("child %ld ended: status=0x%x\n", (long)pid, status); #ifdef WCOREDUMP @@ -905,7 +911,7 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) store_free(sp->host_address); *sp = empty_smtp_slot; if (--smtp_accept_count < 0) smtp_accept_count = 0; - DEBUG(D_any) debug_printf("%d SMTP accept process%s now running\n", + DEBUG(any) debug_printf("%d SMTP accept process%s now running\n", smtp_accept_count, smtp_accept_count == 1 ? "" : "es"); set_process_info("daemon(%s): [%d+%d] %s", version_string, smtp_accept_count, queue_run_count, daemon_process_info); @@ -926,7 +932,7 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) r->pid = 0; /* free up the slot */ if (--queue_run_count < 0) queue_run_count = 0; - DEBUG(D_any) debug_printf("%d queue-runner process%s now running\n", + DEBUG(any) debug_printf("%d queue-runner process%s now running\n", queue_run_count, queue_run_count == 1 ? "" : "es"); set_process_info("daemon(%s): [%d+%d] %s", version_string, smtp_accept_count, queue_run_count, daemon_process_info); @@ -1053,7 +1059,7 @@ if (operation == PID_WRITE) if (base_fd < 0) goto cleanup; if (fchmod(base_fd, base_mode) != 0) goto cleanup; if (write(base_fd, pid_line, pid_len) != pid_len) goto cleanup; - DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path); + DEBUG(any) debug_printf("pid written to %s\n", pid_file_path); } } else @@ -1090,7 +1096,7 @@ delete_pid_file(void) { const BOOL success = operate_on_pid_file(PID_DELETE, getppid()); -DEBUG(D_any) +DEBUG(any) debug_printf("delete pid file %s %s: %s\n", pid_file_path, success ? "success" : "failure", strerror(errno)); @@ -1106,7 +1112,7 @@ daemon_die(void) { pid_t pid; -DEBUG(D_any) debug_printf("SIGTERM/SIGINT seen\n"); +DEBUG(any) debug_printf("SIGTERM/SIGINT seen\n"); #if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)) tls_watch_invalidate(); #endif @@ -1184,22 +1190,22 @@ ssize_t len; if (!f.notifier_socket_en) { - DEBUG(D_any) debug_printf("-oY used so not creating notifier socket\n"); + DEBUG(any) debug_printf("-oY used so not creating notifier socket\n"); return; } if (override_local_interfaces && !override_pid_file_path) { - DEBUG(D_any) + DEBUG(any) debug_printf("-oX used without -oP so not creating notifier socket\n"); return; } if (!notifier_socket || !*notifier_socket) { - DEBUG(D_any) debug_printf("no name for notifier socket\n"); + DEBUG(any) debug_printf("no name for notifier socket\n"); return; } -DEBUG(D_any) debug_printf("creating notifier socket\n"); +DEBUG(any) debug_printf("creating notifier socket\n"); #ifdef SOCK_CLOEXEC if ((fd = socket(PF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) @@ -1213,9 +1219,9 @@ if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) len = daemon_notifier_sockname(&sa_un); #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS -DEBUG(D_any) debug_printf(" @%s\n", sa_un.sun_path+1); +DEBUG(any) debug_printf(" @%s\n", sa_un.sun_path+1); #else /* filesystem-visible and persistent; will neeed removal */ -DEBUG(D_any) debug_printf(" %s\n", sa_un.sun_path); +DEBUG(any) debug_printf(" %s\n", sa_un.sun_path); #endif if (bind(fd, (const struct sockaddr *)&sa_un, (socklen_t)len) < 0) @@ -1277,7 +1283,7 @@ if (sz >= sizeof(buf)) return; #ifdef notdef debug_printf("addrlen %d\n", msg.msg_namelen); #endif -DEBUG(D_queue_run) +DEBUG(queue_run) if (msg.msg_namelen > 0) { BOOL abstract = !*sa_un.sun_path; @@ -1313,14 +1319,14 @@ for (struct cmsghdr * cp = CMSG_FIRSTHDR(&msg); struct ucred * cr = (struct ucred *) CMSG_DATA(cp); if (cr->uid && cr->uid != exim_uid) { - DEBUG(D_queue_run) debug_printf("%s: sender creds pid %ld uid %d gid %d\n", + DEBUG(queue_run) debug_printf("%s: sender creds pid %ld uid %d gid %d\n", __FUNCTION__, (long)cr->pid, (int)cr->uid, (int)cr->gid); } # elif defined(LOCAL_CREDS) /* BSD-ish */ struct sockcred * cr = (struct sockcred *) CMSG_DATA(cp); if (cr->sc_uid && cr->sc_uid != exim_uid) { - DEBUG(D_queue_run) debug_printf("%s: sender creds pid ??? uid %d gid %d\n", + DEBUG(queue_run) debug_printf("%s: sender creds pid ??? uid %d gid %d\n", __FUNCTION__, (int)cr->sc_uid, (int)cr->sc_gid); } # endif @@ -1334,7 +1340,7 @@ switch (buf[0]) #ifndef DISABLE_QUEUE_RAMP case NOTIFY_MSG_QRUN: /* this should be a message_id */ - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("%s: qrunner trigger: %s\n", __FUNCTION__, buf+1); memcpy(queuerun_msgid, buf+1, MESSAGE_ID_LENGTH+1); @@ -1353,7 +1359,7 @@ switch (buf[0]) uschar qsbuf[16]; int len = snprintf(CS qsbuf, sizeof(qsbuf), "%u", queue_count_cached()); - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("%s: queue size request: %s\n", __FUNCTION__, qsbuf); if (sendto(daemon_notifier_fd, qsbuf, len, 0, @@ -1379,7 +1385,7 @@ time_t resignal_interval = inetd_wait_timeout; if (last_connection_time == (time_t)0) { - DEBUG(D_any) + DEBUG(any) debug_printf("inetd wait timeout expired, but still not seen first message, ignoring\n"); } else @@ -1387,11 +1393,11 @@ else time_t now = time(NULL); if (now == (time_t)-1) { - DEBUG(D_any) debug_printf("failed to get time: %s\n", strerror(errno)); + DEBUG(any) debug_printf("failed to get time: %s\n", strerror(errno)); } else if ((now - last_connection_time) >= inetd_wait_timeout) { - DEBUG(D_any) + DEBUG(any) debug_printf("inetd wait timeout %d expired, ending daemon\n", inetd_wait_timeout); log_write(0, LOG_MAIN, "exim %s daemon terminating, inetd wait timeout reached.\n", @@ -1455,7 +1461,7 @@ Return the number of seconds until the next due runner. static int daemon_qrun(int local_queue_run_max, struct pollfd * fd_polls, int listen_socket_count) { -DEBUG(D_any) debug_printf("%s received\n", +DEBUG(any) debug_printf("%s received\n", #ifndef DISABLE_QUEUE_RAMP *queuerun_msgid ? "qrun notification" : #endif @@ -1509,7 +1515,8 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ leave the above message, because it ties up with the "child ended" debugging messages. */ - if (f.debug_daemon) debug_selector = 0; + if (f.debug_daemon) debug_modify_channel(US"=0"); +; /* Close any open listening sockets in the child */ @@ -1617,7 +1624,7 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ queue_run_count++; break; } - DEBUG(D_any) debug_printf("%d queue-runner process%s running\n", + DEBUG(any) debug_printf("%d queue-runner process%s running\n", queue_run_count, queue_run_count == 1 ? "" : "es"); set_process_info("daemon(%s): [%d+%d] %s", version_string, smtp_accept_count, queue_run_count, daemon_process_info); @@ -1751,7 +1758,7 @@ process_purpose = US"daemon"; /* If any debugging options are set, turn on the D_pid bit so that all debugging lines get the pid added. */ -DEBUG(D_any|D_v) debug_selector |= D_pid; +DEBUG(any|v) debug_modify_channel(US"+pid"); /* Get any requested dynamic-load modules loaded */ @@ -1789,7 +1796,7 @@ if (f.inetd_wait_mode) debug_logging_activate(US"-wait", NULL); } - DEBUG(D_any) debug_printf("running in inetd wait mode\n"); + DEBUG(any) debug_printf("running in inetd wait mode\n"); /* As per below, when creating sockets ourselves, we handle tcp_nodelay for our own buffering; we assume though that inetd set the socket REUSEADDR. */ @@ -1928,7 +1935,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) if (new_smtp_port) { daemon_smtp_port = string_from_gstring(new_smtp_port); - DEBUG(D_any) debug_printf("daemon_smtp_port overridden by -oX:\n %s\n", + DEBUG(any) debug_printf("daemon_smtp_port overridden by -oX:\n %s\n", daemon_smtp_port); } @@ -1936,7 +1943,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) { local_interfaces = string_from_gstring(new_local_interfaces); local_iface_source = US"-oX data"; - DEBUG(D_any) debug_printf("local_interfaces overridden by -oX:\n %s\n", + DEBUG(any) debug_printf("local_interfaces overridden by -oX:\n %s\n", local_interfaces); } } @@ -2263,7 +2270,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) if (ip_bind(fd, af, ipa->address, ipa->port) >= 0) break; if (check_special_case(errno, addresses, ipa, TRUE)) { - DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 " + DEBUG(any) debug_printf("wildcard IPv4 bind() failed after IPv6 " "listen() success; EADDRINUSE ignored\n"); (void)close(fd); goto SKIP_SOCKET; @@ -2286,7 +2293,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) sleep(daemon_startup_sleep); } - DEBUG(D_any) + DEBUG(any) if (wildcard) debug_printf("listening on all interfaces (IPv%c) port %d\n", af == AF_INET6 ? '6' : '4', ipa->port); @@ -2302,7 +2309,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) && setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &smtp_connect_backlog, sizeof(smtp_connect_backlog))) { - DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); + DEBUG(any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); f.tcp_fastopen_ok = FALSE; } #endif @@ -2312,7 +2319,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) if ( f.tcp_fastopen_ok && setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on))) { - DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); + DEBUG(any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno)); f.tcp_fastopen_ok = FALSE; } #endif @@ -2332,7 +2339,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) ? af == AF_INET6 ? US"(any IPv6)" : US"(any IPv4)" : ipa->address, strerror(errno)); - DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 " + DEBUG(any) debug_printf("wildcard IPv4 listen() failed after IPv6 " "listen() success; EADDRINUSE ignored\n"); (void)close(fd); @@ -2379,7 +2386,7 @@ if (f.running_in_test_harness || write_pid) || real_uid == root_uid || (real_uid == exim_uid && !override_pid_file_path)) ? PID_WRITE : PID_CHECK; if (!operate_on_pid_file(operation, getpid())) - DEBUG(D_any) debug_printf("%s pid file %s: %s\n", + DEBUG(any) debug_printf("%s pid file %s: %s\n", operation == PID_WRITE ? "write" : "check", pid_file_path, strerror(errno)); } @@ -2644,7 +2651,7 @@ closes the log afterwards, for the same reason. */ log_close_all(); -DEBUG(D_any) debug_print_ids(US"daemon running with"); +DEBUG(any) debug_print_ids(US"daemon running with"); /* Any messages accepted via this route are going to be SMTP. */ @@ -2691,7 +2698,7 @@ for (;;) int lcount; BOOL select_failed = FALSE; - DEBUG(D_any) debug_printf("Listening...\n"); + DEBUG(any) debug_printf("Listening...\n"); /* In rare cases we may have had a SIGCHLD signal in the time between setting the handler (below) and getting back here. If so, pretend that the @@ -2786,7 +2793,7 @@ for (;;) if ( smtp_backlog_monitor > 0 && getsockopt(p->fd, SOL_SOCKET, SO_LISTENQLEN, &backlog, &blen) == 0) { - DEBUG(D_interface) + DEBUG(interface) debug_printf("listen fd %d queue curr %d\n", p->fd, backlog); smtp_listen_backlog = backlog; } @@ -2801,7 +2808,7 @@ for (;;) if ( smtp_backlog_monitor > 0 && getsockopt(p->fd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0) { - DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n", + DEBUG(interface) debug_printf("listen fd %d queue max %u curr %u\n", p->fd, ti.tcpi_sacked, ti.tcpi_unacked); smtp_listen_backlog = ti.tcpi_unacked; } diff --git a/src/src/dane-openssl.c b/src/src/dane-openssl.c index fb2527958..354bc7e90 100644 --- a/src/src/dane-openssl.c +++ b/src/src/dane-openssl.c @@ -909,7 +909,7 @@ if (gens) continue; if (!(dane->mhost = OPENSSL_strdup(certid))) matched = -1; - DEBUG(D_tls) debug_printf("Dane name_check: matched SAN %s\n", certid); + DEBUG(tls) debug_printf("Dane name_check: matched SAN %s\n", certid); break; } } @@ -925,7 +925,7 @@ if (!got_altname) char *certid = parse_subject_name(cert); if (certid != 0 && *certid && (matched = match_name(certid, dane)) != 0) { - DEBUG(D_tls) debug_printf("Dane name_check: matched SN %s\n", certid); + DEBUG(tls) debug_printf("Dane name_check: matched SN %s\n", certid); dane->mhost = OPENSSL_strdup(certid); } if (certid) @@ -948,7 +948,7 @@ dane_selector_list issuer_rrs = dane->selectors[DANESSL_USAGE_PKIX_TA]; dane_selector_list leaf_rrs = dane->selectors[DANESSL_USAGE_PKIX_EE]; int matched = 0; -DEBUG(D_tls) debug_printf("Dane verify_chain\n"); +DEBUG(tls) debug_printf("Dane verify_chain\n"); /* Restore OpenSSL's internal_verify() as the signature check function */ X509_STORE_CTX_set_verify(ctx, dane->verify); @@ -1008,7 +1008,7 @@ else */ if (leaf_rrs) matched = match(leaf_rrs, xn, 0); - if (matched) DEBUG(D_tls) debug_printf("Dane verify_chain: matched EE\n"); + if (matched) DEBUG(tls) debug_printf("Dane verify_chain: matched EE\n"); if (!matched && issuer_rrs) for (n = chain_length-1; !matched && n >= 0; --n) @@ -1017,7 +1017,7 @@ else if (n > 0 || X509_check_issued(xn, xn) == X509_V_OK) matched = match(issuer_rrs, xn, n); } - if (matched) DEBUG(D_tls) debug_printf("Dane verify_chain: matched %s\n", + if (matched) DEBUG(tls) debug_printf("Dane verify_chain: matched %s\n", n>0 ? "CA" : "selfisssued EE"); if (!matched) @@ -1077,7 +1077,7 @@ int (*cb)(int, X509_STORE_CTX *) = X509_STORE_CTX_get_verify_cb(ctx); X509 *cert = X509_STORE_CTX_get0_cert(ctx); int matched; -DEBUG(D_tls) debug_printf("Dane verify_cert\n"); +DEBUG(tls) debug_printf("Dane verify_cert\n"); if (ssl_idx < 0) ssl_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); @@ -1234,7 +1234,7 @@ DANESSL_cleanup(SSL *ssl) { ssl_dane *dane; -DEBUG(D_tls) debug_printf("Dane lib-cleanup\n"); +DEBUG(tls) debug_printf("Dane lib-cleanup\n"); if (dane_idx < 0 || !(dane = SSL_get_ex_data(ssl, dane_idx))) return; @@ -1373,7 +1373,7 @@ dane_cert_list xlist = 0; dane_pkey_list klist = 0; const EVP_MD *md = 0; -DEBUG(D_tls) debug_printf("Dane add-tlsa: usage %u sel %u mdname %q\n", +DEBUG(tls) debug_printf("Dane add-tlsa: usage %u sel %u mdname %q\n", usage, selector, mdname); if(dane_idx < 0 || !(dane = SSL_get_ex_data(ssl, dane_idx))) @@ -1560,7 +1560,7 @@ DANESSL_init(SSL *ssl, const char *sni_domain, const char **hostnames) { ssl_dane *dane; -DEBUG(D_tls) debug_printf("Dane ssl_init\n"); +DEBUG(tls) debug_printf("Dane ssl_init\n"); if (dane_idx < 0) { DANEerr(DANESSL_F_INIT, DANESSL_R_LIBRARY_INIT); @@ -1632,7 +1632,7 @@ Return int DANESSL_CTX_init(SSL_CTX *ctx) { -DEBUG(D_tls) debug_printf("Dane ctx-init\n"); +DEBUG(tls) debug_printf("Dane ctx-init\n"); if (dane_idx >= 0) { SSL_CTX_set_cert_verify_callback(ctx, verify_cert, 0); @@ -1723,7 +1723,7 @@ DANESSL_library_init(void) { static CRYPTO_ONCE once = CRYPTO_ONCE_STATIC_INIT; -DEBUG(D_tls) debug_printf("Dane lib-init\n"); +DEBUG(tls) debug_printf("Dane lib-init\n"); (void) CRYPTO_THREAD_run_once(&once, dane_init); #if defined(LN_sha256) diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 64807a7b8..7c0351a4f 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -136,7 +136,7 @@ lock that times out. */ lock_data.l_type = rdonly ? F_RDLCK : F_WRLCK; lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0; -DEBUG(D_hints_lookup|D_retry|D_route|D_deliver) +DEBUG(hints_lookup|retry|route|deliver) debug_printf_indent("locking %s\n", filename); sigalrm_seen = FALSE; @@ -155,7 +155,7 @@ if (rc < 0) return FALSE; } -DEBUG(D_hints_lookup) debug_printf_indent("locked %s\n", filename); +DEBUG(hints_lookup) debug_printf_indent("locked %s\n", filename); return TRUE; } @@ -184,7 +184,7 @@ dbfn_open(const uschar * name, int flags, open_db * dbblock, int save_errno, dlen, flen; uschar dirname[PATHLEN], filename[PATHLEN]; -DEBUG(D_hints_lookup) acl_level++; +DEBUG(hints_lookup) acl_level++; /* The first thing to do is to open a separate file on which to lock. This ensures that Exim has exclusive use of the database before it even tries to @@ -213,7 +213,7 @@ else flen, name); if (!lockfile_take(dbblock, filename, flags == O_RDONLY, panic)) { - DEBUG(D_hints_lookup) acl_level--; + DEBUG(hints_lookup) acl_level--; return NULL; } } @@ -236,7 +236,7 @@ dbblock->dbptr = dbblock->readonly && !exim_lockfile_needed() if (!dbblock->dbptr && errno == ENOENT && flags & O_CREAT) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("%s appears not to exist: trying to create\n", filename); dbblock->dbptr = exim_dbopen(filename, dirname, flags, EXIMDB_MODE); } @@ -254,7 +254,7 @@ if (!dbblock->dbptr) log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s", filename)); else - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("%s\n", CS string_open_failed("DB file %s", filename)); (void)close(dbblock->lockfd); @@ -265,7 +265,7 @@ if (!dbblock->dbptr) /* Pass back the block containing the opened database handle and the open fd for the lock. */ -DEBUG(D_hints_lookup) acl_level--; +DEBUG(hints_lookup) acl_level--; return dbblock; } @@ -281,7 +281,7 @@ dbfn_open_multi(const uschar * name, int flags, open_db * dbblock) int save_errno, dlen; uschar dirname[PATHLEN], filename[PATHLEN]; -DEBUG(D_hints_lookup) acl_level++; +DEBUG(hints_lookup) acl_level++; dbblock->lockfd = -1; dbblock->readonly = (flags & O_ACCMODE) == O_RDONLY; @@ -294,7 +294,7 @@ priv_drop_temp(exim_uid, exim_gid); dbblock->dbptr = exim_dbopen_multi(filename, dirname, flags & O_ACCMODE, EXIMDB_MODE); if (!dbblock->dbptr && errno == ENOENT && flags & O_CREAT) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("%s appears not to exist: trying to create\n", filename); dbblock->dbptr = exim_dbopen_multi(filename, dirname, flags, EXIMDB_MODE); } @@ -312,14 +312,14 @@ if (!dbblock->dbptr) log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s", filename)); else - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("%s\n", CS string_open_failed("DB file %s", filename)); dbblock = NULL; } /* Pass back the block containing the opened database handle */ -DEBUG(D_hints_lookup) acl_level--; +DEBUG(hints_lookup) acl_level--; return dbblock; } @@ -328,14 +328,14 @@ return dbblock; BOOL dbfn_transaction_start(open_db * dbp) { -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_transaction_start\n"); +DEBUG(hints_lookup) debug_printf_indent("dbfn_transaction_start\n"); if (!dbp->readonly) return exim_dbtransaction_start(dbp->dbptr); return FALSE; } void dbfn_transaction_commit(open_db * dbp) { -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_transaction_commit\n"); +DEBUG(hints_lookup) debug_printf_indent("dbfn_transaction_commit\n"); if (!dbp->readonly) exim_dbtransaction_commit(dbp->dbptr); } @@ -363,7 +363,7 @@ else exim_dbclose(dbp->dbptr); if (*fdp >= 0) (void)close(*fdp); -DEBUG(D_hints_lookup) +DEBUG(hints_lookup) debug_printf_indent("closed hints database%s\n", *fdp < 0 ? "" : " and lockfile"); *fdp = -1; @@ -374,7 +374,7 @@ void dbfn_close_multi(open_db * dbp) { exim_dbclose_multi(dbp->dbptr); -DEBUG(D_hints_lookup) +DEBUG(hints_lookup) debug_printf_indent("closed hints database\n"); } @@ -425,7 +425,7 @@ BOOL tainted; memcpy(key_copy, key, klen); -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%.*W\n", klen, key); +DEBUG(hints_lookup) debug_printf_indent("dbfn_read: key=%.*W\n", klen, key); exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ exim_datum_init(&result_datum); /* to be cleared before use. */ @@ -434,12 +434,12 @@ exim_datum_size_set(&key_datum, klen); if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) { - DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: null return\n"); + DEBUG(hints_lookup) debug_printf_indent("dbfn_read: null return\n"); return NULL; } dlen = exim_datum_size_get(&result_datum); -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); +DEBUG(hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); if (hintsdb) { @@ -447,13 +447,13 @@ if (hintsdb) if (dlen < sizeof(dbdata_generic)) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("dbfn_read: bad record size %u\n", dlen); return NULL; } if (gp->version != HINTS_VERSION) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("dbfn_read: bad record version %u\n", gp->version); return NULL; } @@ -557,7 +557,7 @@ gptr->version = HINTS_VERSION; gptr->tainted = is_tainted(ptr); gptr->time_stamp = time(NULL); -DEBUG(D_hints_lookup) +DEBUG(hints_lookup) debug_printf_indent("dbfn_write: key=%s datalen %d\n", key, length); exim_datum_init(&key_datum); /* Some DBM libraries require the datum */ @@ -590,14 +590,14 @@ int klen = Ustrlen(key) + 1, rc; uschar * key_copy = store_get(klen, key); EXIM_DATUM key_datum; -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key); +DEBUG(hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key); memcpy(key_copy, key, klen); exim_datum_init(&key_datum); /* Some DBM libraries require clearing */ exim_datum_data_set(&key_datum, key_copy); exim_datum_size_set(&key_datum, klen); rc = exim_dbdel(dbblock->dbptr, &key_datum); -DEBUG(D_hints_lookup) if (rc != EXIM_DBPUTB_OK) +DEBUG(hints_lookup) if (rc != EXIM_DBPUTB_OK) debug_printf_indent(" exim_dbdel: fail\n"); return rc; } @@ -631,7 +631,7 @@ dbfn_scan(open_db *dbblock, BOOL start, EXIM_CURSOR **cursor) EXIM_DATUM key_datum, value_datum; uschar *yield; -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n"); +DEBUG(hints_lookup) debug_printf_indent("dbfn_scan\n"); /* Some dbm require an initialization */ @@ -684,7 +684,8 @@ if (argc != 2) /* Initialize */ spool_directory = argv[1]; -debug_selector = D_all - D_memory; +debug_modify_channel(US""); +debug_modify_channel(US"+all-memory"); debug_file = stderr; big_buffer = malloc(big_buffer_size); diff --git a/src/src/dcc.c b/src/src/dcc.c index 8af6c3cda..9341607b7 100644 --- a/src/src/dcc.c +++ b/src/src/dcc.c @@ -37,15 +37,15 @@ static int flushbuffer int rsp; rsp = write(socket, buffer->s, buffer->ptr); -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: flushbuffer(): Result of the write() = %d\n", rsp); if(rsp < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: flushbuffer(): Error writing buffer to socket: %s\n", strerror(errno)); return errno; } -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: flushbuffer(): Wrote buffer to socket:\n%.*s\n", buffer->ptr, buffer->s); return 0; } @@ -132,21 +132,21 @@ if (((override_client_ip = expand_string(US"$acl_m_dcc_override_client_ip")) != (override_client_ip[0] != '\0')) { Ustrncpy(client_ip, override_client_ip, sizeof(client_ip)-1); - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Client IP (overridden): %s\n", client_ip); } else if(sender_host_address) { /* else if $sender_host_address is available use that? */ Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1); - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Client IP (sender_host_address): %s\n", client_ip); } else { /* sender_host_address is NULL which means it comes from localhost */ Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1); - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Client IP (default): %s\n", client_ip); } /* build options block */ @@ -176,7 +176,7 @@ if(Ustrcmp(sockip, "")) serv_addr_in.sin_port = htons(portnr); if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); /* if we cannot create the socket, defer the mail */ @@ -186,7 +186,7 @@ if(Ustrcmp(sockip, "")) /* Now connecting the socket (INET) */ if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); /* if we cannot contact the socket, defer the mail */ @@ -202,7 +202,7 @@ else Ustrncpy(US serv_addr.sun_path, sockpath, sizeof(serv_addr.sun_path)); if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); /* if we cannot create the socket, defer the mail */ @@ -212,7 +212,7 @@ else /* Now connecting the socket (UNIX) */ if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); /* if we cannot contact the socket, defer the mail */ @@ -221,14 +221,14 @@ else } } /* the socket is open, now send the options to dccifd*/ -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: -----------------------------------\nDCC: Socket opened; now sending input\n" "DCC: -----------------------------------\n"); /* let's send each of the recipients to dccifd */ for (int i = 0; i < recipients_count; i++) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: recipient = %s\n",recipients_list[i].address); dcc_headers = string_append(dcc_headers, 2, recipients_list[i].address, "\n"); } @@ -236,7 +236,7 @@ for (int i = 0; i < recipients_count; i++) dcc_headers = string_catn(dcc_headers, US"\n", 1); /* Now we send the input buffer */ -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: ***********************************\nDCC: Sending options:\n%Y" "DCC: ***********************************\n", dcc_headers); if (flushbuffer(sockfd, dcc_headers) != 0) @@ -247,7 +247,7 @@ if (flushbuffer(sockfd, dcc_headers) != 0) /* now send the message */ /* First send the headers */ -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: ***********************************\nDCC: Sending headers:\n"); sendbuf = string_get(8192); sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen); @@ -257,7 +257,7 @@ while((mail_headers=mail_headers->next)) /* a blank line separates header from body */ sendbuf = string_catn(sendbuf, US"\r\n", 2); gstring_release_unused(sendbuf); -DEBUG(D_acl) +DEBUG(acl) debug_printf("%YDCC: ***********************************\n", sendbuf); if (flushbuffer(sockfd, sendbuf) != 0) { @@ -266,7 +266,7 @@ if (flushbuffer(sockfd, sendbuf) != 0) } /* now send the body */ -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: ***********************************\nDCC: Writing body:\n"); (void)fseek(data_file, spool_data_start_offset(message_id), SEEK_SET); @@ -278,13 +278,13 @@ while((filebuf.ptr = fread(filebuf.s, 1, filebuf.size, data_file)) > 0) (void)fclose(data_file); return retval; } -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: ***********************************\n"); /* shutdown() the socket */ if(shutdown(sockfd, SHUT_WR) < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno)); log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno)); /* If there is a problem with the shutdown() @@ -292,7 +292,7 @@ if(shutdown(sockfd, SHUT_WR) < 0) (void)fclose(data_file); return retval; } -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: Input sent.\n" "DCC: +++++++++++++++++++++++++++++++++++\n" "DCC: Now receiving output from server\n" @@ -321,7 +321,7 @@ dcc_header_str = string_get(DCC_HEADER_LIMIT + 2); while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) { /* make the answer 0-terminated. only needed for debug_printf */ - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Length of the output buffer is: %d\nDCC: Output buffer is:\n" "DCC: -----------------------------------\n%.*s\n" "DCC: -----------------------------------\n", dcc_resplen, dcc_resplen, big_buffer); @@ -345,14 +345,14 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) switch (big_buffer[bufoffset]) { case 'A': - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = A\treturning OK\n"); dcc_return_text = US"Mail accepted by DCC"; dcc_result = US"A"; retval = OK; break; case 'R': - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = R\treturning FAIL\n"); dcc_return_text = US"Rejected by DCC"; dcc_result = US"R"; @@ -365,7 +365,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) sender_host_address, sender_address); break; case 'S': - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = S\treturning OK\n"); dcc_return_text = US"Not all recipients accepted by DCC"; /* Since we're in an ACL we want a global result so we accept for all */ @@ -373,14 +373,14 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) retval = OK; break; case 'G': - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = G\treturning FAIL\n"); dcc_return_text = US"Greylisted by DCC"; dcc_result = US"G"; retval = FAIL; break; case 'T': - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = T\treturning DEFER\n"); dcc_return_text = US"Temporary error with DCC"; dcc_result = US"T"; @@ -388,7 +388,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer); break; default: - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Overall result = something else\treturning DEFER\n"); dcc_return_text = US"Unknown DCC response"; dcc_result = US"T"; @@ -401,7 +401,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) { /* We're on the first line but not on the first character, * there must be something wrong. */ - DEBUG(D_acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0" + DEBUG(acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0" " character is %c - This is wrong!\n", line, bufoffset, big_buffer[bufoffset]); log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer); } @@ -425,7 +425,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) if (gstring_length(dcc_header_str) + dcc_resplen > DCC_HEADER_LIMIT) { dcc_resplen = DCC_HEADER_LIMIT - gstring_length(dcc_header_str); - DEBUG(D_acl) debug_printf("DCC: We got more output than we can store" + DEBUG(acl) debug_printf("DCC: We got more output than we can store" "in the X-DCC header. Truncating at 120 characters.\n"); } dcc_header_str = string_catn(dcc_header_str, &big_buffer[bufoffset], dcc_resplen); @@ -435,7 +435,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) /* fail on read error */ if(dcc_resplen < 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Error reading from socket: %s\n", strerror(errno)); (void)fclose(data_file); return retval; @@ -446,7 +446,7 @@ dcc_header_str = string_catn(dcc_header_str, US"\n", 1); (void) string_from_gstring(dcc_header_str); /* Now let's sum up what we've got. */ -DEBUG(D_acl) +DEBUG(acl) debug_printf("\nDCC: --------------------------\nDCC: Overall result = %d\n" "DCC: X-DCC header: %YReturn message: %s\nDCC: dcc_result: %s\n", retval, dcc_header_str, dcc_return_text, dcc_result); @@ -463,7 +463,7 @@ if(!(Ustrncmp(dcc_header_str->s, "X-DCC", 5))) } } else - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: Wrong format of the X-DCC header: %Y\n", dcc_header_str); /* check if we should add additional headers passed in acl_m_dcc_add_header */ @@ -476,14 +476,14 @@ if (dcc_direct_add_header) if (dcc_xtra_hdrs->s[dcc_xtra_hdrs->ptr - 1] != '\n') dcc_xtra_hdrs = string_catn(dcc_xtra_hdrs, US"\n", 1); header_add(' ', "%s", string_from_gstring(dcc_xtra_hdrs)); - DEBUG(D_acl) + DEBUG(acl) debug_printf("DCC: adding additional headers in $acl_m_dcc_add_header: %Y", dcc_xtra_hdrs); } } dcc_ok = 1; /* Now return to exim main process */ -DEBUG(D_acl) +DEBUG(acl) debug_printf("DCC: Before returning to exim main process:\nDCC: return_text = %s - retval = %d\n" "DCC: dcc_result = %s\n", dcc_return_text, retval, dcc_result); diff --git a/src/src/debug.c b/src/src/debug.c index ee44091ff..1c45d2586 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -138,14 +138,14 @@ void debug_print_string(uschar *debug_string) { if (!debug_string) return; -HDEBUG(D_any|D_v) +HDEBUG(any|v) { uschar * s = expand_string(debug_string); if (!s) debug_printf("failed to expand debug_output %q: %s\n", debug_string, expand_string_message); - else if (s[0] != 0) - debug_printf("%s%s", s, (s[Ustrlen(s)-1] == '\n')? "" : "\n"); + else if (*s) + debug_printf("%s%s", s, s[Ustrlen(s)-1] == '\n' ? "" : "\n"); } } @@ -230,7 +230,7 @@ timestamp buffer, which may contain something useful. (This was a bug fix: the if (debug_ptr == debug_buffer) { - DEBUG(D_timestamp) + DEBUG(timestamp) { struct timeval now; time_t tmp; @@ -244,12 +244,12 @@ if (debug_ptr == debug_buffer) t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000)); } - DEBUG(D_pid) + DEBUG(pid) debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid()); /* Set up prefix if outputting for host checking and not debugging */ - if (host_checking && debug_selector == 0) + if (host_checking && !ANY_DEBUG) debug_ptr = Ustpcpy(debug_ptr, US">>> "); debug_prefix_length = debug_ptr - debug_buffer; @@ -258,7 +258,7 @@ if (debug_ptr == debug_buffer) if (indent > 0) { for (int i = indent >> 2; i > 0; i--) - DEBUG(D_noutf8) + DEBUG(noutf8) { debug_ptr = Ustpcpy(debug_ptr, US" !"); debug_prefix_length += 4; @@ -501,4 +501,80 @@ debug_pretrigger_discard(); } +/******************************************************************************/ + +BOOL +is_debug(const uschar * channels) +{ +int sep = '|'; +uschar buf[64]; /* static buffer to avoid allocs */ +const uschar * chan; + +/* The "any" request is special (and somewhat a misnomer). +Check its summary bit. */ + +while (chan = string_nextinlist(&channels, &sep, buf, sizeof(buf))) + { + unsigned bit = + Ustrcmp(chan, "any") == 0 + ? BIT_TABLE_IDX_IS_ANY + : chan_name_to_idx(chan, Ustrlen(chan), + debug_chan_names, debug_options_count); + if (bit && DEBUG_BIT(bit)) return TRUE; + } +return FALSE; +} + +void +debug_decode_bits(bitmask_word_t ** selector, const uschar * string, int flags) +{ +if (!*selector) + { + size_t len = sizeof(bitmask_word_t) * DEBUG_SELECTOR_SIZE; + *selector = store_get_perm(len, GET_UNTAINTED); + memset(*selector, 0, len); + } + +decode_bits(*selector, DEBUG_SELECTOR_SIZE, debug_notall_names, string, + debug_chan_names, debug_options_count, DCB_DEBUG | flags); +} + +void +debug_modify_channel(const uschar * string) +{ +debug_decode_bits(&debug_selector, string, 0); +} + +void +debug_set_default_bits(bitmask_word_t ** selector) +{ +debug_decode_bits(selector, US"=0", 0); +debug_decode_bits(selector, debug_defaults, 0); +} + +BOOL +debug_disable(void) +{ +BOOL is_debugging = !!ANY_DEBUG; +bit_clear(debug_selector, BIT_TABLE_IDX_NONZERO); +return is_debugging; +} + +void +debug_enable(void) +{ +bit_set(debug_selector, BIT_TABLE_IDX_NONZERO); +} + +gstring * +debug_selector_dump(gstring * g) +{ +g = string_fmt_append(g, "-d=0x" PR_EXIM_BITMASK, debug_selector[0]); +for (int i = 1; i < DEBUG_SELECTOR_SIZE; i++) + g = string_fmt_append(g, ",0x" PR_EXIM_BITMASK, debug_selector[i]); +return g; +} + /* End of debug.c */ +/* vi: ai aw sw=2 + */ diff --git a/src/src/deliver.c b/src/src/deliver.c index 09e753f8f..55ccf1b45 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -721,7 +721,7 @@ while (addr->parent) if (aa) continue; deliver_msglog("%s %s: children all complete\n", now, addr->address); - DEBUG(D_deliver) debug_printf("%s: children all complete\n", addr->address); + DEBUG(deliver) debug_printf("%s: children all complete\n", addr->address); } } @@ -847,7 +847,7 @@ event_raise(const uschar * action, const uschar * event, const uschar * ev_data, if (action) { const uschar * s; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("Event(%s): event_action=|%s| delivery_IP=%s\n", event, action, deliver_host_address); @@ -868,7 +868,7 @@ if (action) if (s && *s) { - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("Event(%s): event_action returned %q\n", event, s); if (errnop) *errnop = ERRNO_EVENT; @@ -1480,7 +1480,7 @@ uschar * now = tod_stamp(tod_log); uschar * driver_kind = NULL; uschar * driver_name = NULL; -DEBUG(D_deliver) +DEBUG(deliver) debug_printf("post-process %s (%s)\n", addr->address, rc_names[result]); /* Set up driver kind and name for logging. Disable logging if the router or @@ -1615,7 +1615,7 @@ if (result == OK) last child to complete. */ address_done(addr, now); - DEBUG(D_deliver) debug_printf("%s delivered\n", addr->address); + DEBUG(deliver) debug_printf("%s delivered\n", addr->address); if (!addr->parent) deliver_msglog("%s %s: %s%s succeeded\n", now, addr->address, @@ -2056,7 +2056,7 @@ uschar * s = string_sprintf("%s/%s", if (tree_search(tree_nonrecipients, s) != 0) { - DEBUG(D_deliver|D_route|D_transport) + DEBUG(deliver|route|transport) debug_printf("%s was previously delivered (%s transport): discarded\n", addr->address, addr->transport->drinst.name); if (!testing) child_done(addr, tod_stamp(tod_log)); @@ -2359,7 +2359,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0) string_sprintf("local delivery to %s <%s> transport=%s", addr->local_part, addr->address, addr->transport->drinst.name)); - DEBUG(D_deliver) + DEBUG(deliver) { debug_printf(" home=%s current=%s\n", deliver_home, working_directory); for (address_item * batched = addr->next; batched; batched = batched->next) @@ -2570,7 +2570,7 @@ if (!shadowing) testharness_pause_ms(300); - DEBUG(D_deliver) debug_printf("journalling %s", big_buffer); + DEBUG(deliver) debug_printf("journalling %s", big_buffer); len = Ustrlen(big_buffer); if (write(journal_fd, big_buffer, len) != len) log_write(0, LOG_MAIN|LOG_PANIC, "failed to update journal for %s: %s", @@ -2627,7 +2627,7 @@ if (addr->special_action == SPECIAL_WARN) int fd; pid_t ch_pid; - DEBUG(D_deliver) debug_printf("Warning message requested by transport\n"); + DEBUG(deliver) debug_printf("Warning message requested by transport\n"); if (!(warn_message = expand_string(warn_message))) log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %q (warning " @@ -2688,7 +2688,7 @@ if (max_parallel > 0) unsigned running; if (!(running = enq_start(serialize_key, max_parallel))) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("skipping tpt %s because concurrency limit %u reached\n", trname, max_parallel); do @@ -2746,7 +2746,7 @@ while (addr_local) addr_local = addr->next; addr->next = NULL; - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf("--------> %s <--------\n", addr->address); /* An internal disaster if there is no transport. Should not occur! */ @@ -2912,11 +2912,11 @@ while (addr_local) if (continue_retry_db && continue_retry_db != (open_db *)-1) { - DEBUG(D_hints_lookup) debug_printf("using cached retry hintsdb handle\n"); + DEBUG(hints_lookup) debug_printf("using cached retry hintsdb handle\n"); dbm_file = continue_retry_db; } else if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE))) - DEBUG(D_deliver|D_retry|D_hints_lookup) + DEBUG(deliver|retry|hints_lookup) debug_printf("no retry data available\n"); addr2 = addr; @@ -2951,7 +2951,7 @@ while (addr_local) retry time has come, or if it has passed its cutoff time, delivery will go ahead. */ - DEBUG(D_retry) + DEBUG(retry) { debug_printf("retry record exists: age=%s ", readconf_printtime(now - retry_record->gen.time_stamp)); @@ -2975,7 +2975,7 @@ while (addr_local) retry_record, now); } } - else DEBUG(D_retry) debug_printf("no retry record exists\n"); + else DEBUG(retry) debug_printf("no retry record exists\n"); } /* This address is to be delivered. Leave it on the chain. */ @@ -3005,7 +3005,7 @@ while (addr_local) if (dbm_file != continue_retry_db) { dbfn_close(dbm_file); dbm_file = NULL; } else - DEBUG(D_hints_lookup) debug_printf("retaining retry hintsdb handle\n"); + DEBUG(hints_lookup) debug_printf("retaining retry hintsdb handle\n"); /* If there are no addresses left on the chain, they all deferred. Loop for the next set of addresses. */ @@ -3094,7 +3094,7 @@ while (addr_local) const uschar * s_trname = stp->drinst.name; int save_count = transport_count; - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf(">>>>>>>>>>>>>>>> Shadow delivery >>>>>>>>>>>>>>>>\n"); deliver_local(shadow_addr, TRUE); @@ -3117,12 +3117,12 @@ while (addr_local) ? US"unknown error" : US""); - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf("%s shadow transport returned %s for %s\n", s_trname, rc_to_string(sresult), shadow_addr->address); } - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf(">>>>>>>>>>>>>>>> End shadow delivery >>>>>>>>>>>>>>>>\n"); transport_count = save_count; /* Restore original transport count */ @@ -3146,7 +3146,7 @@ while (addr_local) int result = addr2->transport_return; nextaddr = addr2->next; - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf("%s transport returned %s for %s\n", trname, rc_to_string(result), addr2->address); @@ -3274,7 +3274,7 @@ while ( *aptr if (!*aptr) *aptr = moved; } -DEBUG(D_deliver) +DEBUG(deliver) { debug_printf("remote addresses after sorting:\n"); for (address_item * addr = addr_remote; addr; addr = addr->next) @@ -3352,7 +3352,7 @@ same channel (pipe). */ -DEBUG(D_deliver) debug_printf("reading pipe for subprocess %ld (%s)\n", +DEBUG(deliver) debug_printf("reading pipe for subprocess %ld (%s)\n", (long)p->pid, eop? "ended" : "not ended yet"); while (!done) @@ -3365,7 +3365,7 @@ while (!done) size_t required = PIPE_HEADER_SIZE; /* first the pipehaeder, later the data */ ssize_t got; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("expect %lu bytes (pipeheader) from tpt process %ld\n", (u_long)required, (long)pid); @@ -3384,7 +3384,7 @@ while (!done) } pipeheader[PIPE_HEADER_SIZE] = '\0'; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("got %ld bytes (pipeheader) '%c' from transport process %ld\n", (long) got, *id, (long)pid); @@ -3403,7 +3403,7 @@ while (!done) } } - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("expect %lu bytes (pipedata) from transport process %ld\n", (u_long)required, (long)pid); @@ -3453,7 +3453,7 @@ while (!done) case 'R': if (!addr) goto ADDR_MISMATCH; - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf("reading retry information for %s from subprocess\n", ptr+1); @@ -3464,7 +3464,7 @@ while (!done) { if (!(r->flags & rf_delete)) break; /* It was not "delete" */ *rp = r->next; /* Excise a delete item */ - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf(" existing delete item dropped\n"); } @@ -3484,13 +3484,13 @@ while (!done) memcpy(&r->more_errno, ptr, sizeof(r->more_errno)); ptr += sizeof(r->more_errno); r->message = *ptr ? string_copy(ptr) : NULL; - DEBUG(D_deliver|D_retry) debug_printf(" added %s item\n", + DEBUG(deliver|retry) debug_printf(" added %s item\n", r->flags & rf_delete ? "delete" : "retry"); } else { - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf(" delete item not added: non-delete item exists\n"); ptr++; while(*ptr++); @@ -3600,7 +3600,7 @@ while (!done) if (!addr) goto ADDR_MISMATCH; memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware)); ptr += sizeof(addr->dsn_aware); - DEBUG(D_deliver) debug_printf("DSN: addr->dsn_aware = %d (%s)\n", + DEBUG(deliver) debug_printf("DSN: addr->dsn_aware = %d (%s)\n", addr->dsn_aware, dsn_aware_names[addr->dsn_aware]); break; @@ -3656,7 +3656,7 @@ while (!done) #endif case '0': /* results of trying to send to this address */ - DEBUG(D_deliver) debug_printf("A0 %s tret %d (%s)\n", + DEBUG(deliver) debug_printf("A0 %s tret %d (%s)\n", addr->address, *ptr, rc_names[*ptr]); addr->transport_return = *ptr++; addr->special_action = *ptr++; @@ -3736,19 +3736,19 @@ while (!done) { case '0': /* End marker */ done = TRUE; - DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr); + DEBUG(deliver) debug_printf("Z0%c item read\n", *ptr); break; case '1': /* Suggested continuation message */ Ustrncpy(continue_next_id, ptr, MESSAGE_ID_LENGTH); continue_sequence = atoi(CS ptr + MESSAGE_ID_LENGTH + 1); - DEBUG(D_deliver) debug_printf("continue_next_id: %s seq %d\n", + DEBUG(deliver) debug_printf("continue_next_id: %s seq %d\n", continue_next_id, continue_sequence); break; case '2': /* Continued transport, host & addr */ { int recvd_fd; - DEBUG(D_any) if (Ustrcmp(process_purpose, "continued-delivery") != 0) + DEBUG(any) if (Ustrcmp(process_purpose, "continued-delivery") != 0) debug_printf("%s becomes continued-delivery\n", process_purpose); process_purpose = US"continued-delivery"; continue_transport = string_copy(ptr); while (*ptr++) ; @@ -3760,7 +3760,7 @@ while (!done) close(recvd_fd); /*XXX continue_host_port relies on a preceding A0 record */ - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("continue: fd %d tpt %s host '%s' addr '%s':%d" " seq %d\n", recvd_fd, continue_transport, continue_hostname, @@ -3953,7 +3953,7 @@ while (addr) addr->host_list = addr->fallback_hosts; addr->next = addr_fallback; addr_fallback = addr; - DEBUG(D_deliver) debug_printf("%s queued for fallback host(s)\n", addr->address); + DEBUG(deliver) debug_printf("%s queued for fallback host(s)\n", addr->address); } /* If msg is set (=> unexpected problem), set it in the address before @@ -4078,7 +4078,7 @@ for (;;) /* Normally we do not repeat this loop */ { if (errno != ECHILD) continue; /* Repeats the waitpid() */ - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("waitpid() returned -1/ECHILD: checking explicitly " "for process existence\n"); @@ -4086,7 +4086,7 @@ for (;;) /* Normally we do not repeat this loop */ { if ((pid = parlist[poffset].pid) != 0 && kill(pid, 0) == 0) { - DEBUG(D_deliver) debug_printf("process %ld still exists: assume " + DEBUG(deliver) debug_printf("process %ld still exists: assume " "stolen by strace\n", (long)pid); break; /* With poffset set */ } @@ -4094,7 +4094,7 @@ for (;;) /* Normally we do not repeat this loop */ if (poffset >= remote_max_parallel) { - DEBUG(D_deliver) debug_printf("*** no delivery children found\n"); + DEBUG(deliver) debug_printf("*** no delivery children found\n"); return NULL; /* This is the error return */ } } @@ -4104,7 +4104,7 @@ for (;;) /* Normally we do not repeat this loop */ subprocess, but there are no completed subprocesses. See if any pipes are ready with any data for reading. */ - DEBUG(D_deliver) debug_printf("polling subprocess pipes\n"); + DEBUG(deliver) debug_printf("polling subprocess pipes\n"); for (poffset = 0; poffset < remote_max_parallel; poffset++) if (parlist[poffset].pid != 0) @@ -4180,7 +4180,7 @@ the process in pid has been wait()ed for. */ PROCESS_DONE: -DEBUG(D_deliver) +DEBUG(deliver) { if (status == 0) debug_printf("remote delivery process %ld ended\n", (long)pid); @@ -4315,7 +4315,7 @@ if (PIPE_HEADER_SIZE != snprintf(CS pipe_header, PIPE_HEADER_SIZE+1, "%c%c%05ld" id, subid, (long)size)) log_write_die(0, LOG_MAIN, "header snprintf failed\n"); -DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%ld,final:%s\n", +DEBUG(deliver) debug_printf("header write id:%c,subid:%c,size:%ld,final:%s\n", id, subid, (long)size, pipe_header); if ((ret = writev(fd, iov, 2)) != total_len) @@ -4404,7 +4404,7 @@ for (int delivery_count = 0; addr_remote; delivery_count++) addr_remote = addr->next; addr->next = NULL; - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf("--------> %s <--------\n", addr->address); /* If no transport has been set, there has been a big screw-up somewhere. */ @@ -4448,7 +4448,7 @@ So look out for the place it gets used. if (tp->expand_multi_domain) deliver_set_expansions(addr); - if (exp_bool(addr, US"transport", tp->drinst.name, D_transport, + if (exp_bool(addr, US"transport", tp->drinst.name, IS_DEBUG(transport), US"multi_domain", tp->multi_domain, tp->expand_multi_domain, &multi_domain) != OK) { @@ -4562,8 +4562,8 @@ Does that also apply to address_data? && ( !multi_domain || ( ( (void)(!tp->expand_multi_domain || ((void)deliver_set_expansions(next), 1)), - exp_bool(addr, - US"transport", next->transport->drinst.name, D_transport, + exp_bool(addr, US"transport", next->transport->drinst.name, + IS_DEBUG(transport), US"multi_domain", next->transport->multi_domain, next->transport->expand_multi_domain, &md) == OK ) @@ -4660,7 +4660,7 @@ Does that also apply to address_data? if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only) { - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("lazy-callout-close: have conn still open from verification\n"); continue_transport = cutthrough.transport; continue_hostname = string_copy(cutthrough.host.name); @@ -4719,7 +4719,7 @@ Does that also apply to address_data? if (!ok) { - DEBUG(D_deliver) debug_printf("not suitable for continue_transport (%s)\n", + DEBUG(deliver) debug_printf("not suitable for continue_transport (%s)\n", Ustrcmp(continue_transport, tp->drinst.name) != 0 ? string_sprintf("tpt %s vs %s", continue_transport, tp->drinst.name) : string_sprintf("no host matching %s", continue_hostname)); @@ -4730,7 +4730,7 @@ Does that also apply to address_data? for (next = addr; ; next = next->next) { next->host_list = next->fallback_hosts; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("%s queued for fallback host(s)\n", next->address); if (!next->next) break; } @@ -4742,7 +4742,7 @@ Does that also apply to address_data? { for (next = addr; ; next = next->next) { - DEBUG(D_deliver) debug_printf(" %s to def list\n", next->address); + DEBUG(deliver) debug_printf(" %s to def list\n", next->address); if (!next->next) break; } next->next = addr_defer; @@ -4771,7 +4771,7 @@ parmax * tpt-max is exceeded? */ { f.continue_more = TRUE; break; } } } - else DEBUG(D_deliver) + else DEBUG(deliver) debug_printf( "not reached parallelism limit (%d/%d) so not setting continue_more\n", parcount+1, remote_max_parallel); @@ -4909,8 +4909,8 @@ do_remote_deliveries par_reduce par_wait par_read_pipe /* Show pids on debug output if parallelism possible */ - if (parmax > 1 && (parcount > 0 || addr_remote)) - DEBUG(D_any|D_v) debug_selector |= D_pid; + if (parmax > 1 && (parcount > 0 || addr_remote)) DEBUG(any|v) + debug_modify_channel(US"+pid"); /* Reset the random number generator, so different processes don't all have the same sequence. In the test harness we want different, but @@ -5147,7 +5147,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe #ifndef DISABLE_DKIM if (addr->dkim_used && LOGGING(dkim_verbose)) { - DEBUG(D_deliver) debug_printf("dkim used: %s\n", addr->dkim_used); + DEBUG(deliver) debug_printf("dkim used: %s\n", addr->dkim_used); ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->dkim_used) + 1; rmt_dlv_checked_write(fd, 'A', '4', big_buffer, ptr - big_buffer); } @@ -5155,7 +5155,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe if (testflag(addr, af_new_conn) || testflag(addr, af_cont_conn)) { - DEBUG(D_deliver) debug_printf("%scontinued-connection\n", + DEBUG(deliver) debug_printf("%scontinued-connection\n", testflag(addr, af_new_conn) ? "non-" : ""); big_buffer[0] = testflag(addr, af_new_conn) ? BIT(1) : BIT(2); rmt_dlv_checked_write(fd, 'A', '3', big_buffer, 1); @@ -5167,9 +5167,9 @@ do_remote_deliveries par_reduce par_wait par_read_pipe ptr = big_buffer; if (proxy_local_address) { - DEBUG(D_deliver) debug_printf("proxy_local_address '%s'\n", proxy_local_address); + DEBUG(deliver) debug_printf("proxy_local_address '%s'\n", proxy_local_address); ptr = big_buffer + sprintf(CS ptr, "%.128s", proxy_local_address) + 1; - DEBUG(D_deliver) debug_printf("proxy_local_port %d\n", proxy_local_port); + DEBUG(deliver) debug_printf("proxy_local_port %d\n", proxy_local_port); memcpy(ptr, &proxy_local_port, sizeof(proxy_local_port)); ptr += sizeof(proxy_local_port); } @@ -5183,11 +5183,11 @@ do_remote_deliveries par_reduce par_wait par_read_pipe /*um, are they really per-addr? Other per-conn stuff is not (auth, tls). But host_used is! */ if (addr->smtp_greeting) { - DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting); + DEBUG(deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting); ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->smtp_greeting) + 1; if (addr->helo_response) { - DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response); + DEBUG(deliver) debug_printf("helo_response '%s'\n", addr->helo_response); ptr += sprintf(CS ptr, "%.128s", addr->helo_response) + 1; } else @@ -5198,7 +5198,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe /* The rest of the information goes in an 'A0' item. */ #ifdef notdef - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("%s %s for MAIL\n", addr->special_action == '=' ? "initial RCPT" : addr->special_action == '-' ? "additional RCPT" : "?", @@ -5499,7 +5499,7 @@ if (percent_hack_domains) addr->unique = string_copy(new_address); addr->domain = deliver_domain; addr->cc_local_part = local_part; - DEBUG(D_deliver) debug_printf("%%-hack changed address to: %s\n", + DEBUG(deliver) debug_printf("%%-hack changed address to: %s\n", addr->address); } } @@ -5751,7 +5751,7 @@ unsigned cnt; if (!s) return; -DEBUG(D_deliver) +DEBUG(deliver) debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message); /* search first ": ". we assume to find the remote-MTA answer there */ @@ -5765,7 +5765,7 @@ while (*s) { if (cnt > 950) /* RFC line length limit: 998 */ { - DEBUG(D_deliver) debug_printf("print_dsn_diagnostic_code() truncated line\n"); + DEBUG(deliver) debug_printf("print_dsn_diagnostic_code() truncated line\n"); fputs("[truncated]", f); break; } @@ -5817,7 +5817,7 @@ while ((addr = *anchor)) anchor = &addr->next; else if ((tnode = tree_search(tree_duplicates, addr->unique))) { - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf("%s is a duplicate address: discarded\n", addr->unique); *anchor = addr->next; addr->dupof = tnode->data.ptr; @@ -5867,7 +5867,7 @@ int qt; if ( f.running_in_test_harness && *fudged_queue_times && (qt = readconf_readtime(fudged_queue_times, '/', FALSE)) >= 0) { - DEBUG(D_deliver) debug_printf("fudged queue_times = %s\n", + DEBUG(deliver) debug_printf("fudged queue_times = %s\n", fudged_queue_times); return qt; } @@ -5972,7 +5972,7 @@ else address_item * msgchain = NULL, ** pmsgchain = &msgchain; address_item * handled_addr = NULL; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("sending error message to: %s\n", bounce_recipient); /* Scan the addresses for all that have the same errors address, removing @@ -6567,7 +6567,7 @@ address_item * addr_senddsn = NULL; for (const address_item * a = addr_succeed; a; a = a->next) { /* af_ignore_error not honored here. it's not an error */ - DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n" + DEBUG(deliver) debug_printf("DSN: processing router : %s\n" "DSN: processing successful delivery address: %s\n" "DSN: Sender_address: %s\n" "DSN: orcpt: %s flags: 0x%x\n" @@ -6598,7 +6598,7 @@ for (const address_item * a = addr_succeed; a; a = a->next) addr_senddsn->next = addr_next; } else - DEBUG(D_deliver) debug_printf("DSN: not sending DSN success message\n"); + DEBUG(deliver) debug_printf("DSN: not sending DSN success message\n"); } if (addr_senddsn) @@ -6614,8 +6614,7 @@ if (addr_senddsn) pid = child_open_exim(&fd, US"DSN"); - DEBUG(D_deliver) - debug_printf("DSN: child_open_exim returns: " PID_T_FMT "\n", pid); + DEBUG(deliver) debug_printf("DSN: child_open_exim returns: " PID_T_FMT "\n", pid); if (pid < 0) /* Creation of child failed */ { @@ -6624,7 +6623,7 @@ if (addr_senddsn) "create child process to send success-dsn message: %s", getpid(), getppid(), strerror(errno)); - DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); + DEBUG(deliver) debug_printf("DSN: child_open_exim failed\n"); } else /* Creation of child succeeded */ { @@ -6633,12 +6632,12 @@ if (addr_senddsn) uschar * bound; transport_ctx tctx = {{0}}; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("sending success-dsn to: %s\n", sender_address); /* build unique id for MIME boundary */ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand()); - DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound); + DEBUG(deliver) debug_printf("DSN: MIME boundary: %s\n", bound); if (errors_reply_to) fprintf(f, "Reply-To: %s\n", errors_reply_to); @@ -6802,9 +6801,9 @@ D_queue_run is set or in verbose mode. */ set_process_info("%s", info); -if ( !(debug_selector & D_process_info) - && (debug_selector & (D_deliver|D_queue_run|D_v)) - ) +DEBUG(process_info) + ; +else DEBUG(deliver|queue_run|v) debug_printf("%s\n", info); /* Ensure that we catch any subprocesses that are created. Although Exim @@ -6941,7 +6940,7 @@ Otherwise it might be needed again. */ int n = Ustrlen(big_buffer); big_buffer[n-1] = 0; tree_add_nonrecipient(big_buffer); - DEBUG(D_deliver) debug_printf("Previously delivered address %s taken from " + DEBUG(deliver) debug_printf("Previously delivered address %s taken from " "journal file\n", big_buffer); } rewind(jread); @@ -7129,7 +7128,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) redirect.pw = NULL; redirect.modemask = 0; - DEBUG(D_deliver|D_filter) debug_printf("running system filter\n"); + DEBUG(deliver|filter) debug_printf("running system filter\n"); rc = rda_interpret( &redirect, /* Where the data is */ @@ -7148,7 +7147,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) &filtertype, /* Will always be set to FILTER_EXIM for this call */ US"system filter"); /* For error messages */ - DEBUG(D_deliver|D_filter) debug_printf("system filter returned %d\n", rc); + DEBUG(deliver|filter) debug_printf("system filter returned %d\n", rc); if (rc == FF_ERROR || rc == FF_NONEXIST) { @@ -7370,7 +7369,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) /* Either a non-pfr delivery, or we found a transport */ - DEBUG(D_deliver|D_filter) + DEBUG(deliver|filter) debug_printf("system filter added %s\n", p->address); addr_last = p; @@ -7420,7 +7419,7 @@ if (process_recipients != RECIP_IGNORE) { new->prop.utf8_downcvt = message_utf8_downconvert == 1; new->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1; - DEBUG(D_deliver) debug_printf("utf8, downconvert %s\n", + DEBUG(deliver) debug_printf("utf8, downconvert %s\n", new->prop.utf8_downcvt ? "yes" : new->prop.utf8_downcvt_maybe ? "ifneeded" : "no"); @@ -7435,7 +7434,7 @@ if (process_recipients != RECIP_IGNORE) new->dsn_flags = r->dsn_flags & rf_dsnflags; new->dsn_orcpt = r->orcpt; - DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: 0x%x\n", + DEBUG(deliver) debug_printf("DSN: set orcpt: %s flags: 0x%x\n", new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags); switch (process_recipients) @@ -7537,7 +7536,7 @@ if (process_recipients != RECIP_IGNORE) } } -DEBUG(D_deliver) +DEBUG(deliver) { debug_printf("Delivery address list:\n"); for (address_item * p = addr_new; p; p = p->next) @@ -7613,7 +7612,7 @@ while (addr_new) /* Loop until all addresses dealt with */ if (continue_retry_db) { - DEBUG(D_hints_lookup) debug_printf("using cached retry hintsdb handle\n"); + DEBUG(hints_lookup) debug_printf("using cached retry hintsdb handle\n"); dbm_file = continue_retry_db; } else if (!exim_lockfile_needed()) @@ -7625,7 +7624,7 @@ while (addr_new) /* Loop until all addresses dealt with */ dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE); if (!dbm_file) - DEBUG(D_deliver|D_retry|D_route|D_hints_lookup) + DEBUG(deliver|retry|route|hints_lookup) debug_printf("no retry data available\n"); /* Scan the current batch of new addresses, to handle pipes, files and @@ -7640,7 +7639,7 @@ while (addr_new) /* Loop until all addresses dealt with */ addr = addr_new; addr_new = addr->next; - DEBUG(D_deliver|D_retry|D_route) + DEBUG(deliver|retry|route) { debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf("Considering: %s\n", addr->address); @@ -7689,7 +7688,7 @@ while (addr_new) /* Loop until all addresses dealt with */ else if ((tnode = tree_search(tree_duplicates, addr->unique))) { - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf("%s is a duplicate address: discarded\n", addr->address); addr->dupof = tnode->data.ptr; addr->next = addr_duplicate; @@ -7697,13 +7696,13 @@ while (addr_new) /* Loop until all addresses dealt with */ continue; } - DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique); + DEBUG(deliver|route) debug_printf("unique = %s\n", addr->unique); /* Check for previous delivery */ if (tree_search(tree_nonrecipients, addr->unique)) { - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf("%s was previously delivered: discarded\n", addr->address); child_done(addr, tod_stamp(tod_log)); continue; @@ -7780,7 +7779,7 @@ while (addr_new) /* Loop until all addresses dealt with */ /* Pipe, file, or autoreply delivery is to go ahead as a normal local delivery. */ - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf_indent("queued for %s transport\n", addr->transport->drinst.name); addr->next = addr_local; addr_local = addr; @@ -7854,11 +7853,11 @@ while (addr_new) /* Loop until all addresses dealt with */ for (uschar * p = Ustrrchr(addr->unique, '@'); *p; p++) *p = tolower(*p); - DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique); + DEBUG(deliver|route) debug_printf("unique = %s\n", addr->unique); if (tree_search(tree_nonrecipients, addr->unique)) { - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf("%s was previously delivered: discarded\n", addr->unique); child_done(addr, tod_stamp(tod_log)); continue; @@ -7870,7 +7869,7 @@ while (addr_new) /* Loop until all addresses dealt with */ the sender attached, because this form is used by the smtp transport after a 4xx response to RCPT when address_retry_include_sender is true. */ - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) { debug_printf_indent("checking router retry status\n"); acl_level++; @@ -7886,7 +7885,7 @@ while (addr_new) /* Loop until all addresses dealt with */ && now - domain_retry_record->gen.time_stamp > retry_data_expire ) { - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf_indent("domain retry record present but expired\n"); domain_retry_record = NULL; /* Ignore if too old */ } @@ -7896,7 +7895,7 @@ while (addr_new) /* Loop until all addresses dealt with */ && now - address_retry_record->gen.time_stamp > retry_data_expire ) { - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf_indent("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ } @@ -7909,14 +7908,14 @@ while (addr_new) /* Loop until all addresses dealt with */ if ( address_retry_record && now - address_retry_record->gen.time_stamp > retry_data_expire) { - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) debug_printf_indent("address retry record present but expired\n"); address_retry_record = NULL; /* Ignore if too old */ } } } - DEBUG(D_deliver|D_retry) + DEBUG(deliver|retry) { if (!domain_retry_record) debug_printf_indent("no domain retry record\n"); @@ -8030,7 +8029,7 @@ while (addr_new) /* Loop until all addresses dealt with */ setflag(addr, af_dr_retry_exists); addr->next = addr_route; addr_route = addr; - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf("%s: queued for routing\n", addr->address); } } @@ -8043,7 +8042,7 @@ while (addr_new) /* Loop until all addresses dealt with */ if (exim_lockfile_needed()) { dbfn_close(dbm_file); continue_retry_db = dbm_file = NULL; } else - DEBUG(D_hints_lookup) debug_printf("retaining retry hintsdb handle\n"); + DEBUG(hints_lookup) debug_printf("retaining retry hintsdb handle\n"); /* If queue_domains is set, we don't even want to try routing addresses in those domains. During queue runs, queue_domains is forced to be unset. @@ -8153,7 +8152,7 @@ while (addr_new) /* Loop until all addresses dealt with */ && tree_search(tree_nonrecipients, addr_r->unique) != 0 ) { - DEBUG(D_deliver|D_route) debug_printf("%s was previously delivered: " + DEBUG(deliver|route) debug_printf("%s was previously delivered: " "discarded\n", addr_r->address); if (addr_remote == addr_r) addr_remote = addr_r->next; else if (addr_local == addr_r) addr_local = addr_r->next; @@ -8199,7 +8198,7 @@ while (addr_new) /* Loop until all addresses dealt with */ copyflag(addr2, addr_r, af_hide_child); copyflag(addr2, addr_r, af_local_host_removed); - DEBUG(D_deliver|D_route) + DEBUG(deliver|route) debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" "routing %s\n" "Routing for %s copied from %s\n", @@ -8211,7 +8210,7 @@ while (addr_new) /* Loop until all addresses dealt with */ /* Debugging: show the results of the routing */ -DEBUG(D_deliver|D_retry|D_route) +DEBUG(deliver|retry|route) { debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf("After routing:\n Local deliveries:\n"); @@ -8315,7 +8314,7 @@ delivery, test continue_sequence rather than continue_transport. */ if (continue_sequence > 1 && addr_local) { - DEBUG(D_deliver|D_retry|D_route) + DEBUG(deliver|retry|route) debug_printf("deferring local deliveries due to continued-transport\n"); if (addr_defer) { @@ -8423,7 +8422,7 @@ if (!regex_IGNOREQUOTA) if (addr_local) { - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf(">>>>>>>>>>>>>>>> Local deliveries >>>>>>>>>>>>>>>>\n"); do_local_deliveries(); f.disable_logging = FALSE; @@ -8447,7 +8446,7 @@ if (f.queue_run_local) if (addr_remote) { - DEBUG(D_deliver|D_transport) + DEBUG(deliver|transport) debug_printf(">>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>>\n"); /* Precompile some regex that are used to recognize parameters in response @@ -8478,7 +8477,7 @@ if (addr_remote) if (addr_fallback && !mua_wrapper) { - DEBUG(D_deliver) debug_printf("Delivering to fallback hosts\n"); + DEBUG(deliver) debug_printf("Delivering to fallback hosts\n"); addr_remote = addr_fallback; addr_fallback = NULL; if (remote_sort_domains) sort_remote_deliveries(); @@ -8491,7 +8490,7 @@ if (addr_remote) /* All deliveries are now complete. Ignore SIGTERM during this tidying up phase, to minimize cases of half-done things. */ -DEBUG(D_deliver) +DEBUG(deliver) debug_printf(">>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>\n"); cancel_cutthrough_connection(TRUE, US"deliveries are done"); @@ -8677,7 +8676,7 @@ DELIVERY_TIDYUP: if (dbm_file) /* Can only be continue_retry_db */ { - DEBUG(D_hints_lookup) debug_printf("final close of cached retry db\n"); + DEBUG(hints_lookup) debug_printf("final close of cached retry db\n"); dbfn_close_multi(continue_retry_db); continue_retry_db = dbm_file = NULL; } @@ -8825,7 +8824,7 @@ else if (addr_defer != (address_item *)(+1)) if ( rnum >= recipients_count && t < recipients_count && Ustrcmp(otaddr->address, otaddr->parent->address) != 0) { - DEBUG(D_deliver) debug_printf("one_time: adding %s in place of %s\n", + DEBUG(deliver) debug_printf("one_time: adding %s in place of %s\n", otaddr->address, otaddr->parent->address); receive_add_recipient(otaddr->address, t); recipients_list[recipients_count-1].errors_to = otaddr->prop.errors_address; @@ -8891,7 +8890,7 @@ else if (addr_defer != (address_item *)(+1)) count += extra; } - DEBUG(D_deliver) + DEBUG(deliver) { debug_printf("time on queue = %s id %s addr %s\n", readconf_printtime(queue_time), message_id, addr_defer->address); @@ -8974,7 +8973,7 @@ else if (addr_defer != (address_item *)(+1)) was more than one address being delivered, the header_change update is done earlier, in case one succeeds and then something crashes. */ - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("delivery deferred: update_spool=%d header_rewritten=%d\n", update_spool, f.header_rewritten); @@ -9024,7 +9023,7 @@ to try delivery. */ (void)close(deliver_datafile); deliver_datafile = -1; -DEBUG(D_deliver) debug_printf("end delivery of %s\n", id); +DEBUG(deliver) debug_printf("end delivery of %s\n", id); #ifdef MEASURE_TIMING report_time_since(×tamp_startup, US"delivery end"); /* testcase 0005 */ #endif diff --git a/src/src/dns.c b/src/src/dns.c index 15f4c8cd0..ce152535a 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -62,7 +62,7 @@ if (stat(CS utilname, &statbuf) >= 0) int infd, outfd, rc; uschar *argv[5]; - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) using fakens\n", + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) using fakens\n", name, dns_text_type(type)); argv[0] = utilname; @@ -105,17 +105,17 @@ if (stat(CS utilname, &statbuf) >= 0) case 3: h_errno = NO_RECOVERY; return -1; case 4: h_errno = NO_DATA; return -1; case 5: /* Pass on to res_search() */ - DEBUG(D_dns) debug_printf_indent("fakens returned PASS_ON\n"); + DEBUG(dns) debug_printf_indent("fakens returned PASS_ON\n"); } } else { - DEBUG(D_dns) debug_printf_indent("fakens (%s) not found\n", utilname); + DEBUG(dns) debug_printf_indent("fakens (%s) not found\n", utilname); } /* fakens utility not found, or it returned "pass on" */ -DEBUG(D_dns) debug_printf_indent("passing %s on to res_search()\n", domain); +DEBUG(dns) debug_printf_indent("passing %s on to res_search()\n", domain); return res_search(CS domain, C_IN, type, answerptr, size); } @@ -144,10 +144,10 @@ res_state resp = os_get_dns_resolver_res(); if ((resp->options & RES_INIT) == 0) { - DEBUG(D_resolver) resp->options |= RES_DEBUG; /* For Cygwin */ + DEBUG(resolver) resp->options |= RES_DEBUG; /* For Cygwin */ os_put_dns_resolver_res(resp); res_init(); - DEBUG(D_resolver) resp->options |= RES_DEBUG; + DEBUG(resolver) resp->options |= RES_DEBUG; os_put_dns_resolver_res(resp); } @@ -164,13 +164,13 @@ if (dns_use_edns0 >= 0) resp->options |= RES_USE_EDNS0; else resp->options &= ~RES_USE_EDNS0; - DEBUG(D_resolver) + DEBUG(resolver) debug_printf_indent("Coerced resolver EDNS0 support %s.\n", dns_use_edns0 ? "on" : "off"); } #else if (dns_use_edns0 >= 0) - DEBUG(D_resolver) + DEBUG(resolver) debug_printf_indent("Unable to %sset EDNS0 without resolver support.\n", dns_use_edns0 ? "" : "un"); #endif @@ -186,7 +186,7 @@ if (dns_dnssec_ok >= 0) { if (dns_use_edns0 == 0 && dns_dnssec_ok != 0) { - DEBUG(D_resolver) + DEBUG(resolver) debug_printf_indent("CONFLICT: dns_use_edns0 forced false, dns_dnssec_ok forced true, ignoring latter!\n"); } else @@ -195,17 +195,17 @@ if (dns_dnssec_ok >= 0) resp->options |= RES_USE_DNSSEC; else resp->options &= ~RES_USE_DNSSEC; - DEBUG(D_resolver) debug_printf_indent("Coerced resolver DNSSEC support %s.\n", + DEBUG(resolver) debug_printf_indent("Coerced resolver DNSSEC support %s.\n", dns_dnssec_ok ? "on" : "off"); } } # else if (dns_dnssec_ok >= 0) - DEBUG(D_resolver) + DEBUG(resolver) debug_printf_indent("Unable to %sset DNSSEC without resolver support.\n", dns_dnssec_ok ? "" : "un"); if (use_dnssec) - DEBUG(D_resolver) + DEBUG(resolver) debug_printf_indent("Unable to set DNSSEC without resolver support.\n"); # endif #endif /* DISABLE_DNSSEC */ @@ -358,7 +358,7 @@ int namelen; char * trace = NULL; #ifdef rr_trace -# define TRACE DEBUG(D_dns) +# define TRACE DEBUG(dns) #else # define TRACE if (FALSE) #endif @@ -527,7 +527,7 @@ BOOL dns_is_secure(const dns_answer * dnsa) { #ifdef DISABLE_DNSSEC -DEBUG(D_dns) +DEBUG(dns) debug_printf_indent("DNSSEC support disabled at build-time; dns_is_secure() false\n"); return FALSE; #else @@ -555,7 +555,7 @@ if ( !h->aa ) return FALSE; -DEBUG(D_dns) debug_printf_indent("DNS faked the AD bit " +DEBUG(dns) debug_printf_indent("DNS faked the AD bit " "(got AA and matched with dns_trust_aa (%s in %s))\n", auth_name, dns_trust_aa); @@ -679,7 +679,7 @@ else (void)tree_insertnode(&tree_dns_fails, new); } -DEBUG(D_dns) debug_printf_indent(" %s neg-cache entry for %s, ttl %d\n", +DEBUG(dns) debug_printf_indent(" %s neg-cache entry for %s, ttl %d\n", previous ? "update" : "writing", node_name, expiry ? (int)(expiry - time(NULL)) : -1); e->expiry = expiry; @@ -706,7 +706,7 @@ e = previous->data.ptr; val = e->data.val; rc = e->expiry && e->expiry <= time(NULL) ? -1 : val; -DEBUG(D_dns) debug_printf_indent("DNS lookup of %.255s (%s): %scached value %s%s\n", +DEBUG(dns) debug_printf_indent("DNS lookup of %.255s (%s): %scached value %s%s\n", name, dns_text_type(type), rc == -1 ? "" : "using ", dns_rc_names[val], @@ -744,12 +744,12 @@ if ( h->qr == 1 /* a response */ && ntohs(h->ancount) == 0 /* no answer records */ && ntohs(h->nscount) >= 1) /* authority records */ { - DEBUG(D_dns) debug_printf_indent("faking res_search(%s) response length as %d\n", + DEBUG(dns) debug_printf_indent("faking res_search(%s) response length as %d\n", dns_text_type(type), (int)sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); return TRUE; } -DEBUG(D_dns) debug_printf_indent("DNS: couldn't fake dnsa len\n"); +DEBUG(dns) debug_printf_indent("DNS: couldn't fake dnsa len\n"); /* Maybe we should just do a second lookup for an SOA? */ return FALSE; } @@ -796,7 +796,7 @@ if (fake_dnsa_len_for_fail(dnsa, type)) return time(NULL) + ttl; } -DEBUG(D_dns) debug_printf_indent("DNS: no SOA record found for neg-TTL\n"); +DEBUG(dns) debug_printf_indent("DNS: no SOA record found for neg-TTL\n"); return 0; } @@ -856,11 +856,11 @@ if ((rc = dns_fail_cache_hit(name, type)) > 0) { const uschar * alabel; uschar * errstr = NULL; - DEBUG(D_dns) if (string_is_utf8(name)) + DEBUG(dns) if (string_is_utf8(name)) debug_printf_indent("convert utf8 '%s' to alabel for for lookup\n", name); if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr) { - DEBUG(D_dns) debug_printf_indent( + DEBUG(dns) debug_printf_indent( "DNS name '%s' utf8 conversion to alabel failed: %s\n", name, errstr); f.host_find_failed_syntax = TRUE; return DNS_NOMATCH; @@ -888,7 +888,7 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT) dns_pattern_init(); if (!regex_match(regex_check_dns_names, name, -1, NULL)) { - DEBUG(D_dns) + DEBUG(dns) debug_printf_indent("DNS name syntax check failed: %s (%s)\n", name, dns_text_type(type)); f.host_find_failed_syntax = TRUE; @@ -921,7 +921,7 @@ dnsa->answerlen = f.running_in_test_harness if (dnsa->answerlen > (int) sizeof(dnsa->answer)) { - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) resulted in overlong packet" + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) resulted in overlong packet" " (size %d), truncating to %u.\n", name, dns_text_type(type), dnsa->answerlen, (unsigned int) sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); @@ -930,12 +930,12 @@ if (dnsa->answerlen > (int) sizeof(dnsa->answer)) if (dnsa->answerlen < 0) switch (h_errno) { case HOST_NOT_FOUND: - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave HOST_NOT_FOUND\n" + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) gave HOST_NOT_FOUND\n" "returning DNS_NOMATCH\n", name, dns_text_type(type)); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); case TRY_AGAIN: - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave TRY_AGAIN\n", + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) gave TRY_AGAIN\n", name, dns_text_type(type)); /* Cut this out for various test programs */ @@ -967,10 +967,10 @@ if (dnsa->answerlen < 0) switch (h_errno) if (rc != OK) { - DEBUG(D_dns) debug_printf_indent("returning DNS_AGAIN\n"); + DEBUG(dns) debug_printf_indent("returning DNS_AGAIN\n"); return dns_fail_return(name, type, 0, DNS_AGAIN); } - DEBUG(D_dns) debug_printf_indent("%s is in dns_again_means_nonexist: returning " + DEBUG(dns) debug_printf_indent("%s is in dns_again_means_nonexist: returning " "DNS_NOMATCH\n", name); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); @@ -979,22 +979,22 @@ if (dnsa->answerlen < 0) switch (h_errno) #endif case NO_RECOVERY: - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_RECOVERY\n" + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_RECOVERY\n" "returning DNS_FAIL\n", name, dns_text_type(type)); return dns_fail_return(name, type, 0, DNS_FAIL); case NO_DATA: - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_DATA\n" + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) gave NO_DATA\n" "returning DNS_NODATA\n", name, dns_text_type(type)); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NODATA); default: - DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) gave unknown DNS error %d\n" + DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) gave unknown DNS error %d\n" "returning DNS_FAIL\n", name, dns_text_type(type), h_errno); return dns_fail_return(name, type, 0, DNS_FAIL); } -DEBUG(D_dns) debug_printf_indent("DNS lookup of %s (%s) succeeded\n", +DEBUG(dns) debug_printf_indent("DNS lookup of %s (%s) succeeded\n", name, dns_text_type(type)); return DNS_SUCCEED; @@ -1142,7 +1142,7 @@ for (int i = 0; i <= dns_cname_loops; i++) if (!dns_is_secure(dnsa)) secure_so_far = FALSE; - DEBUG(D_dns) debug_printf_indent("CNAME found: change to %s\n", name); + DEBUG(dns) debug_printf_indent("CNAME found: change to %s\n", name); } /* Loop back to do another lookup */ /* Control reaches here after 10 times round the CNAME loop. Something isn't @@ -1261,7 +1261,7 @@ switch (type) dns_record * rr; dns_scan dnss = {0}; - DEBUG(D_dns) debug_printf_indent("CSA lookup of %s\n", name); + DEBUG(dns) debug_printf_indent("CSA lookup of %s\n", name); srvname = string_sprintf("_client._smtp.%s", name); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); @@ -1299,7 +1299,7 @@ switch (type) limit = 3; } - DEBUG(D_dns) debug_printf_indent("CSA TLD %s\n", tld); + DEBUG(dns) debug_printf_indent("CSA TLD %s\n", tld); /* Do not perform the search if the top level or 2nd level domains do not exist. This is quite common, and when it occurs all the search queries would @@ -1326,7 +1326,7 @@ switch (type) if (--namesuff <= name) return DNS_NOMATCH; while (*namesuff != '.'); - DEBUG(D_dns) debug_printf_indent("CSA parent search at %s\n", namesuff + 1); + DEBUG(dns) debug_printf_indent("CSA parent search at %s\n", namesuff + 1); srvname = string_sprintf("_client._smtp.%s", namesuff + 1); rc = dns_lookup(dnsa, srvname, T_SRV, NULL); diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c index e12a120fa..297f1ba07 100644 --- a/src/src/dnsbl.c +++ b/src/src/dnsbl.c @@ -97,7 +97,7 @@ if ( (t = tree_search(dnsbl_cache, query)) /* Previous lookup was cached */ { - HDEBUG(D_dnsbl) debug_printf("dnslists: using result of previous lookup\n"); + HDEBUG(dnsbl) debug_printf("dnslists: using result of previous lookup\n"); } /* If not cached from a previous lookup, we must do a DNS lookup, and @@ -111,7 +111,7 @@ else if (t) { - HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; "); + HDEBUG(dnsbl) debug_printf("cached data found but past valid time; "); } else @@ -124,7 +124,7 @@ else /* Do the DNS lookup . */ - HDEBUG(D_dnsbl) debug_printf("new DNS lookup for %s\n", query); + HDEBUG(dnsbl) debug_printf("new DNS lookup for %s\n", query); cb->rc = dns_basic_lookup(dnsa, query, T_A); cb->text_set = FALSE; cb->text = NULL; @@ -190,7 +190,7 @@ else } store_pool = old_pool; - HDEBUG(D_dnsbl) debug_printf("dnslists: wrote cache entry, ttl=%d\n", + HDEBUG(dnsbl) debug_printf("dnslists: wrote cache entry, ttl=%d\n", (int)(cb->expiry - time(NULL))); } @@ -212,7 +212,7 @@ if (cb->rc == DNS_SUCCEED) addlist = string_append2_listele_n(addlist, US", ", da->address, Ustrlen(da->address)); - HDEBUG(D_dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %Y)\n", + HDEBUG(dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %Y)\n", query, addlist); /* Address list check; this can be either for equality, or via a bitmask. @@ -285,7 +285,7 @@ if (cb->rc == DNS_SUCCEED) if ((match_type == MT_NOT || match_type == MT_ALL) != (da == NULL)) { - HDEBUG(D_dnsbl) + HDEBUG(dnsbl) { uschar *res = NULL; switch(match_type) @@ -394,7 +394,7 @@ if (cb->rc != DNS_NOMATCH && cb->rc != DNS_NODATA) /* No entry was found in the DNS; continue for next domain */ -HDEBUG(D_dnsbl) +HDEBUG(dnsbl) { debug_printf("DNS lookup for %s failed\n", query); debug_printf("=> that means %s is not listed at %s\n", @@ -493,7 +493,7 @@ if (!(s = expand_string(s))) list, expand_string_message); return f.search_find_defer ? DEFER : ERROR; } -HDEBUG(D_acl) if (s != list) debug_printf_indent("expanded list: %s\n", s); +HDEBUG(acl) if (s != list) debug_printf_indent("expanded list: %s\n", s); list = s; /* Loop through all the domains supplied, until something matches */ @@ -505,7 +505,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) int match_type = 0; uschar * domain_txt, * comma, * iplist, * key; - HDEBUG(D_dnsbl) debug_printf("dnslists check: %s\n", domain); + HDEBUG(dnsbl) debug_printf("dnslists check: %s\n", domain); /* Deal with special values that change the behaviour on defer */ @@ -609,7 +609,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) { dnslist_domain = domain_txt ? string_copy_perm(domain_txt, FALSE) : NULL; dnslist_matched = string_copy_perm(sender_host_address, FALSE); - HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n", + HDEBUG(dnsbl) debug_printf("=> that means %s is listed at %s\n", sender_host_address, dnslist_domain); } if (rc != FAIL) return rc; /* OK or DEFER */ @@ -641,7 +641,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) { dnslist_domain = domain_txt ? string_copy_perm(domain_txt, FALSE) :NULL; dnslist_matched = keydomain ? string_copy_perm(keydomain, FALSE) : NULL; - HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n", + HDEBUG(dnsbl) debug_printf("=> that means %s is listed at %s\n", keydomain, dnslist_domain); return OK; } diff --git a/src/src/drtables.c b/src/src/drtables.c index ec2c4c33a..3bb55ea91 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -171,14 +171,14 @@ if (!(dl = mod_open(name, US"lookup", errstr))) info = (lookup_module_info *) dlsym(dl, "_lookup_module_info"); if ((errormsg = dlerror())) { - EARLY_DEBUG(D_any, "%s does not appear to be a lookup module (%s)\n", name, errormsg); + EARLY_DEBUG(any, "%s does not appear to be a lookup module (%s)\n", name, errormsg); log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)", name, errormsg); dlclose(dl); return FALSE; } if (info->magic != LOOKUP_MODULE_INFO_MAGIC) { - EARLY_DEBUG(D_any, "Lookup module %s is not compatible with this version of Exim\n", name); + EARLY_DEBUG(any, "Lookup module %s is not compatible with this version of Exim\n", name); log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim", name); dlclose(dl); return FALSE; @@ -186,11 +186,11 @@ if (info->magic != LOOKUP_MODULE_INFO_MAGIC) addlookupmodule(info); if (debug_startup) - { EARLY_DEBUG(D_lookup, "Loaded %q (%d lookup type%s)\n", + { EARLY_DEBUG(lookup, "Loaded %q (%d lookup type%s)\n", name, info->lookupcount, info->lookupcount > 1 ? "s" : ""); } else - DEBUG(D_lookup) debug_printf_indent("Loaded module %q\n", name); + DEBUG(lookup) debug_printf_indent("Loaded module %q\n", name); return TRUE; } @@ -304,17 +304,17 @@ misc_module_list = mi; if (mi->init) { - EARLY_DEBUG(D_any, "Module init: %q\n", mi->name); + EARLY_DEBUG(any, "Module init: %q\n", mi->name); expand_level++; if (!mi->init(mi)) - EARLY_DEBUG(D_any, "module init call failed for %q\n", mi->name); + EARLY_DEBUG(any, "module init call failed for %q\n", mi->name); expand_level--; } if (mi->lib_vers_report) - DEBUG(D_any) debug_printf_indent("%Y", mi->lib_vers_report(NULL)); + DEBUG(any) debug_printf_indent("%Y", mi->lib_vers_report(NULL)); -/* EARLY_DEBUG(D_any, "added %q\n", mi->name); */ +/* EARLY_DEBUG(any, "added %q\n", mi->name); */ } @@ -329,10 +329,10 @@ void * dl; struct misc_module_info * mi; const char * errormsg; -EARLY_DEBUG(D_any, "Loading module %q\n", name); +EARLY_DEBUG(any, "Loading module %q\n", name); if (!(dl = mod_open(name, US"miscmod", errstr))) { - if (errstr && *errstr) EARLY_DEBUG(D_any, " mod_open: %s\n", *errstr); + if (errstr && *errstr) EARLY_DEBUG(any, " mod_open: %s\n", *errstr); return NULL; } @@ -340,7 +340,7 @@ mi = (struct misc_module_info *) dlsym(dl, CS string_sprintf("%s_module_info", name)); if ((errormsg = dlerror())) { - EARLY_DEBUG(D_any, "%s does not appear to be a '%s' module (%s)\n", + EARLY_DEBUG(any, "%s does not appear to be a '%s' module (%s)\n", name, name, errormsg); log_write(0, LOG_MAIN|LOG_PANIC, "%s does not contain the expected module info symbol (%s)", name, errormsg); @@ -349,13 +349,13 @@ if ((errormsg = dlerror())) } if (mi->dyn_magic != MISC_MODULE_MAGIC) { - EARLY_DEBUG(D_any, "Module %s is not compatible with this version of Exim\n", name); + EARLY_DEBUG(any, "Module %s is not compatible with this version of Exim\n", name); log_write(0, LOG_MAIN|LOG_PANIC, "Module %s is not compatible with this version of Exim", name); dlclose(dl); return FALSE; } -EARLY_DEBUG(D_lookup, "Loaded module %q\n", name); +EARLY_DEBUG(lookup, "Loaded module %q\n", name); misc_mod_add(mi); return mi; } @@ -483,13 +483,13 @@ lookup_list_init_done = TRUE; for (lookup_module_info ** avi = avail_static_lookups; *avi; avi++) addlookupmodule(*avi); -DEBUG(D_lookup) debug_printf_indent("Total %d built-in lookups\n", lookup_list_count); +DEBUG(lookup) debug_printf_indent("Total %d built-in lookups\n", lookup_list_count); #ifdef LOOKUP_MODULE_DIR if (!(dd = open_module_dir())) { - EARLY_DEBUG(D_lookup, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); + EARLY_DEBUG(lookup, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); } @@ -502,7 +502,7 @@ else const pcre2_code * regex_islookupmod = regex_must_compile( US"(lsearch|ldap|nis)_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE); - EARLY_DEBUG(D_lookup, "Loading lookup modules from %s\n", LOOKUP_MODULE_DIR); + EARLY_DEBUG(lookup, "Loading lookup modules from %s\n", LOOKUP_MODULE_DIR); while ((ent = readdir(dd))) if (regex_match_and_setup(regex_islookupmod, US ent->d_name, 0, 0)) { @@ -511,13 +511,13 @@ else countmodules++; else { - EARLY_DEBUG(D_any, "%s\n", errstr); + EARLY_DEBUG(any, "%s\n", errstr); log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr); } } } -EARLY_DEBUG(D_lookup, "Loaded %d dynamic lookup modules\n", countmodules); +EARLY_DEBUG(lookup, "Loaded %d dynamic lookup modules\n", countmodules); #endif } diff --git a/src/src/enq.c b/src/src/enq.c index 372607daf..9dab03ac3 100644 --- a/src/src/enq.c +++ b/src/src/enq.c @@ -42,7 +42,7 @@ dbdata_serialize new_record; open_db dbblock; open_db * dbm_file; -DEBUG(D_transport) debug_printf("check serialized: %s\n", key); +DEBUG(transport) debug_printf("check serialized: %s\n", key); /* Open and lock the waiting information database. */ @@ -58,7 +58,7 @@ if (serial_record && time(NULL) - serial_record->gen.time_stamp < 6*60*60) if (serial_record->count >= lim) { dbfn_close(dbm_file); - DEBUG(D_transport) debug_printf("outstanding serialization record for %s\n", + DEBUG(transport) debug_printf("outstanding serialization record for %s\n", key); return 0; } @@ -69,7 +69,7 @@ else /* We can proceed - insert a new record or update the old one. */ -DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n", +DEBUG(transport) debug_printf("write serialization record for %s val %d\n", key, new_record.count); dbfn_write(dbm_file, key, &new_record, (int)sizeof(dbdata_serialize)); dbfn_close(dbm_file); @@ -98,7 +98,7 @@ open_db dbblock; open_db *dbm_file; dbdata_serialize *serial_record; -DEBUG(D_transport) debug_printf("end serialized: %s\n", key); +DEBUG(transport) debug_printf("end serialized: %s\n", key); if ( !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)) || !(serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize))) @@ -106,13 +106,13 @@ if ( !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)) return; if (--serial_record->count > 0) { - DEBUG(D_transport) debug_printf("write serialization record for %s val %d\n", + DEBUG(transport) debug_printf("write serialization record for %s val %d\n", key, serial_record->count); dbfn_write(dbm_file, key, serial_record, (int)sizeof(dbdata_serialize)); } else { - DEBUG(D_transport) debug_printf("remove serialization record for %s\n", key); + DEBUG(transport) debug_printf("remove serialization record for %s\n", key); dbfn_delete(dbm_file, key); } dbfn_close(dbm_file); diff --git a/src/src/environment.c b/src/src/environment.c index 58af6b6c3..d768dee43 100644 --- a/src/src/environment.c +++ b/src/src/environment.c @@ -42,9 +42,9 @@ if (!keep_environment || !*keep_environment) else if (Ustrcmp(keep_environment, "*") != 0) { rmark reset_point = store_mark(); - bitmask_word_t deb = debug_selector; - BOOL hc = host_checking; - debug_selector = 0; /* quieten this clearout */ + BOOL hc = host_checking, dbg; + + dbg = debug_disable(); /* quieten this clearout */ host_checking = FALSE; if (environ) for (uschar ** p = USS environ; *p; /* see below */) @@ -64,14 +64,18 @@ else if (Ustrcmp(keep_environment, "*") != 0) else if (os_unsetenv(name) == 0) p = USS environ; /* RESTART from the beginning */ else - { debug_selector = deb; host_checking = hc; return FALSE; } + { + host_checking = hc; + if (dbg) debug_enable(); + return FALSE; + } } } - debug_selector = deb; host_checking = hc; + if (dbg) debug_enable(); store_reset(reset_point); } -DEBUG(D_expand) +DEBUG(expand) { debug_printf("environment after trimming:\n"); if (environ) for (uschar ** p = USS environ; *p; p++) @@ -86,7 +90,7 @@ if (add_environment) for (const uschar * p; p = string_nextinlist(&envlist, &sep, NULL, 0); ) { - DEBUG(D_expand) debug_printf("adding %s\n", p); + DEBUG(expand) debug_printf("adding %s\n", p); putenv(CS p); } store_pool = old_pool; @@ -97,3 +101,6 @@ tls_clean_env(); return TRUE; } + +/* vi: aw ai sw=2 +*/ diff --git a/src/src/exim.c b/src/src/exim.c index 4d74ffead..d7c64f8a4 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -160,7 +160,7 @@ if ((yield = (res >= 0))) } expand_nmax--; } -else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any) +else if (res != PCRE2_ERROR_NOMATCH) DEBUG(any) { uschar errbuf[128]; pcre2_get_error_message(res, errbuf, sizeof(errbuf)); @@ -234,7 +234,7 @@ if (!string_vformat(g, 0, format, ap)) } g = string_catn(g, US"\n", 1); process_info_len = len_string_from_gstring(g, &s); -DEBUG(D_process_info) debug_printf("set_process_info: %s", process_info); +DEBUG(process_info) debug_printf("set_process_info: %s", process_info); va_end(ap); } @@ -587,7 +587,7 @@ while (exim_tvcmp(&now_tv, prev_tv) <= 0) itval.it_value.tv_sec -= 1; } - DEBUG(D_transport|D_receive) + DEBUG(transport|receive) { if (!f.running_in_test_harness) { @@ -733,9 +733,12 @@ if (smtp_input) } else { - (void)close(0); /* stdin */ - if ((debug_selector & D_resolver) == 0) (void)close(1); /* stdout */ - if (debug_selector == 0) /* stderr */ + (void)close(0); /* stdin */ + DEBUG(resolver) + ; + else + (void)close(1); /* stdout */ + if (!ANY_DEBUG) /* stderr */ { if (!f.synchronous_delivery) { @@ -799,7 +802,7 @@ if (euid == root_uid || euid != uid || egid != gid || igflag) /* Debugging output included uid/gid and all groups */ -DEBUG(D_uid) +DEBUG(uid) { int group_count, save_errno; gid_t group_list[EXIM_GROUPLIST_SIZE]; @@ -812,8 +815,7 @@ DEBUG(D_uid) debug_printf(" auxiliary group list:"); if (group_count > 0) for (int i = 0; i < group_count; i++) debug_printf(" %d", (int)group_list[i]); - else if (group_count < 0) - debug_printf(" ", strerror(save_errno)); + else if (group_count < 0) debug_printf(" ", strerror(save_errno)); else debug_printf(" "); debug_printf("\n"); } @@ -841,7 +843,7 @@ exim_exit(int rc) smtp_fflush(SFF_NO_UNCORK); search_tidyup(); store_exit(); -DEBUG(D_any) +DEBUG(any) debug_printf(">>>>>>>>>>>>>>>> Exim pid=" PID_T_FMT " (%s) terminating with rc=%d " ">>>>>>>>>>>>>>>>\n", getpid(), process_purpose, rc); @@ -853,7 +855,7 @@ void exim_underbar_exit(int rc) { store_exit(); -DEBUG(D_any) +DEBUG(any) debug_printf(">>>>>>>>>>>>>>>> Exim pid=" PID_T_FMT " (%s) terminating with rc=%d " ">>>>>>>>>>>>>>>>\n", getpid(), process_purpose, rc); @@ -1046,7 +1048,7 @@ show_db_version(gstring * g) { g = string_cat(g, US"Hints DB:\n"); #ifdef DB_VERSION_STRING -DEBUG(D_any) +DEBUG(any) { g = string_fmt_append(g, " Library version: BDB: Compile: %s\n", DB_VERSION_STRING); g = string_fmt_append(g, " Runtime: %s\n", @@ -1129,7 +1131,7 @@ the main pool. */ store_pool = POOL_MAIN; reset_point = store_mark(); -DEBUG(D_any) {} else g = show_db_version(g); +DEBUG(any) {} else g = show_db_version(g); g = string_cat(g, US"Support for:"); #ifdef WITH_CONTENT_SCAN @@ -1285,7 +1287,8 @@ g = string_fmt_append(g, "Size of off_t:" SIZE_T_FMT /* Everything else is details which are only worth reporting when debugging. Perhaps the tls_version_report should move into this too. */ -DEBUG(D_any) + +DEBUG(any) { /* clang defines __GNUC__ (at least, for me) so test for it first */ @@ -1517,7 +1520,7 @@ if (dlhandle) *fn_addhist_ptr = (void(*)(const char*))dlsym(dlhandle, "add_history"); } else - DEBUG(D_any) debug_printf("failed to load readline: %s\n", dlerror()); + DEBUG(any) debug_printf("failed to load readline: %s\n", dlerror()); return dlhandle; } @@ -1732,7 +1735,7 @@ for (macro_item * m = macros_user; m; m = m->next) if (m->command_line) if (!regex_match(regex_whitelisted_macro, m->replacement, len, NULL)) return FALSE; } -DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n"); +DEBUG(any) debug_printf("macros_trusted overridden to true by whitelisting\n"); return TRUE; #endif } @@ -2006,7 +2009,7 @@ if (!(log_buffer = US malloc(LOG_BUFFER_SIZE))) /* Initialize the default log options. */ -bits_set(log_selector, log_selector_size, log_default); +logging_set_defaults(); /* Set log_stderr to stderr, provided that stderr exists. This gets reset to NULL when the daemon is run and the file is closed. We have to use this @@ -2220,6 +2223,10 @@ unprivileged = (real_uid != root_uid && original_euid != root_uid); int old_pool = store_pool; store_pool = POOL_PERM; +/* Allocate an empty bitmask for debug channels */ + +debug_modify_channel(US""); + /* Scan the program's arguments. Some can be dealt with right away; others are simply recorded for checking and handling afterwards. Do a high-level switch on the second character (the one after '-'), to save some effort. */ @@ -2542,7 +2549,7 @@ on the second character (the one after '-'), to save some effort. */ else { list_options = TRUE; - debug_selector |= D_v; + debug_modify_channel(US"+v"); debug_file = stderr; } break; @@ -2809,6 +2816,7 @@ on the second character (the one after '-'), to save some effort. */ /* -dS: enable startup-time debugging (before the config is read) */ /* Another debug channel per "-d" would be nicer, but we're at 32 already */ + /*XXX*/ else if (Ustrcmp(argrest, "S") == 0) debug_startup = TRUE; @@ -2826,17 +2834,19 @@ on the second character (the one after '-'), to save some effort. */ /* Use an intermediate variable so that we don't set debugging while decoding the debugging bits. */ - bitmask_word_t selector = D_default; - debug_selector = 0; + bitmask_word_t * selector = NULL; + debug_file = NULL; if (*argrest == 'd') { f.debug_daemon = TRUE; argrest++; } + + debug_set_default_bits(&selector); if (*argrest) - decode_bits(&selector, 1, debug_notall, argrest, - debug_options, debug_options_count, US"debug", 0); + debug_decode_bits(&selector, argrest, 0); + debug_selector = selector; } break; @@ -3330,7 +3340,7 @@ on the second character (the one after '-'), to save some effort. */ if (!*argrest) { f.dont_deliver = TRUE; - debug_selector |= D_v; + debug_modify_channel(US"+v"); debug_file = stderr; } else badarg = TRUE; @@ -3854,12 +3864,12 @@ on the second character (the one after '-'), to save some effort. */ break; - /* -v: verify things - this is a very low-level debugging */ + /* -v: verbose - this is a very gentle-level debugging */ case 'v': if (!*argrest) { - debug_selector |= D_v; + debug_modify_channel(US"+v"); debug_file = stderr; } else badarg = TRUE; @@ -3976,18 +3986,18 @@ if ( (smtp_input || extract_recipients || recipients_arg < argc) child processes. It should, of course, be 2 for stderr. Also, force the daemon to run in the foreground. */ -if (debug_selector != 0) +if (ANY_DEBUG) { debug_file = stderr; debug_fd = fileno(debug_file); f.background_daemon = FALSE; testharness_pause_ms(100); /* lets caller finish */ - if (debug_selector != D_v) /* -v only doesn't show this */ + + if (DEBUG_BIT(BIT_TABLE_IDX_NONVERB)) /* -v only doesn't show this */ { - debug_printf("Exim version %s uid=%ld gid=%ld pid=" PID_T_FMT - " D=0x" PR_EXIM_BITMASK "\n", + debug_printf("Exim version %s uid=%ld gid=%ld pid=" PID_T_FMT " %Y\n", version_string, (long int)real_uid, (long int)real_gid, getpid(), - debug_selector); + debug_selector_dump(NULL)); if (!version_printed) show_whats_supported(FALSE); } @@ -4001,7 +4011,7 @@ change some of these limits. */ if (unprivileged) { - DEBUG(D_any) debug_print_ids(US"Exim has no root privilege:"); + DEBUG(any) debug_print_ids(US"Exim has no root privilege:"); } else { @@ -4116,15 +4126,14 @@ recompile each time, or to patch in an actual configuration file name and other values (such as the path name). If running in the test harness, pretend that configuration file changes and macro definitions haven't happened. */ -if (( /* EITHER */ - (!f.trusted_config || /* Config changed, or */ - !macros_trusted(opt_D_used)) && /* impermissible macros and */ - real_uid != root_uid && /* Not root, and */ - !f.running_in_test_harness /* Not fudged */ - ) || /* OR */ - f.expansion_test /* expansion testing */ - || /* OR */ - filter_test != FTEST_NONE) /* Filter testing */ +if ( ( /* EITHER */ + ( !f.trusted_config /* Config changed */ + || !macros_trusted(opt_D_used)) /* or impermissible macros */ + && real_uid != root_uid /* and Not root */ + && !f.running_in_test_harness /* and Not fudged */ + ) + || f.expansion_test /* OR expansion testing */ + || filter_test != FTEST_NONE) /* OR Filter testing */ { setgroups(group_count, group_list); exim_setugid(real_uid, real_gid, FALSE, @@ -4285,10 +4294,10 @@ if (checking && commandline_checks_require_admin && !f.admin_user) /* Handle the decoding of logging options. */ -decode_bits(log_selector, log_selector_size, log_notall, - log_selector_string, log_options, log_options_count, US"log", 0); +decode_bits(log_selector, log_selector_size, log_notall_names, + log_selector_string, log_chan_names, log_options_count, DCB_LOG); -DEBUG(D_any) +DEBUG(any) { debug_printf("configuration file is %s\n", config_main_filename); debug_printf("log selectors ="); @@ -4374,7 +4383,7 @@ EXIM_TMPDIR by the build scripts. uschar * newp = store_malloc(Ustrlen(EXIM_TMPDIR) + 8); sprintf(CS newp, "TMPDIR=%s", EXIM_TMPDIR); *p = newp; - DEBUG(D_any) debug_printf("reset TMPDIR=%s in environment\n", EXIM_TMPDIR); + DEBUG(any) debug_printf("reset TMPDIR=%s in environment\n", EXIM_TMPDIR); } #endif @@ -4415,7 +4424,7 @@ else *newp = NULL; environ = CSS new; tzset(); - DEBUG(D_any) debug_printf("Reset TZ to %s: time is %s\n", timezone_string, + DEBUG(any) debug_printf("Reset TZ to %s: time is %s\n", timezone_string, tod_stamp(tod_log)); } } @@ -4469,7 +4478,7 @@ a debugging feature for finding out what arguments certain MUAs actually use. Don't attempt it if logging is disabled, or if listing variables or if verifying/testing addresses or expansions. */ -if ( (IS_DEBUG(D_any) || LOGGING(arguments)) +if ( (IS_DEBUG(any) || LOGGING(arguments)) && f.really_exim && !list_options && !checking) { uschar * p = big_buffer; @@ -4549,7 +4558,7 @@ if (bi_option) setgroups(group_count, group_list); exim_setugid(real_uid, real_gid, FALSE, US"running bi_command"); - DEBUG(D_exec) debug_printf("exec '%.256s' %s%.256s%s\n", bi_argv[0], + DEBUG(exec) debug_printf("exec '%.256s' %s%.256s%s\n", bi_argv[0], bi_argv[1] ? "'" : "", bi_argv[1] ? bi_argv[1] : US"", bi_argv[1] ? "'" : ""); @@ -4559,7 +4568,7 @@ if (bi_option) } else { - DEBUG(D_any) debug_printf("-bi used but bi_command not set; exiting\n"); + DEBUG(any) debug_printf("-bi used but bi_command not set; exiting\n"); exit(EXIT_SUCCESS); } } @@ -4568,8 +4577,8 @@ if (bi_option) configuration file. We leave these prints here to ensure that syslog setup, logfile setup, and so on has already happened. */ -if (f.trusted_caller) DEBUG(D_any) debug_printf("trusted user\n"); -if (f.admin_user) DEBUG(D_any) debug_printf("admin user\n"); +if (f.trusted_caller) DEBUG(any) debug_printf("trusted user\n"); +if (f.admin_user) DEBUG(any) debug_printf("admin user\n"); /* Only an admin user may start the daemon or force a queue run in the default configuration, but the queue run restriction can be relaxed. Only an admin @@ -4581,7 +4590,8 @@ count. Only an admin user can use the test interface to scan for email if (!f.admin_user) { - BOOL debugset = (debug_selector & ~D_v) != 0; + BOOL debugset = !!DEBUG_BIT(BIT_TABLE_IDX_NONVERB); + if ( deliver_give_up || f.daemon_listen || malware_test_file || count_queue && queue_list_requires_admin || list_queue && queue_list_requires_admin @@ -4638,7 +4648,7 @@ if (flag_G) if (f.trusted_caller) { f.suppress_local_fixups = f.suppress_local_fixups_default = TRUE; - DEBUG(D_acl) debug_printf("suppress_local_fixups forced on by -G\n"); + DEBUG(acl) debug_printf("suppress_local_fixups forced on by -G\n"); } else exim_fail("permission denied (-G requires a trusted user)"); @@ -4735,7 +4745,7 @@ if ( !unprivileged /* originally had root AND */ else { int rv; - DEBUG(D_any) debug_printf("dropping to exim gid; retaining priv uid\n"); + DEBUG(any) debug_printf("dropping to exim gid; retaining priv uid\n"); rv = setgid(exim_gid); /* Impact of failure is that some stuff might end up with an incorrect group. We track this for failures from root, since any attempt to change privilege @@ -4746,7 +4756,7 @@ else if (!(unprivileged || removed_privilege)) exim_fail("changing group failed: %s", strerror(errno)); else - DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n", + DEBUG(any) debug_printf("changing group to %ld failed: %s\n", (long int)exim_gid, strerror(errno)); } @@ -5148,14 +5158,14 @@ for (i = 0;;) expand_nmax = -1; if (new_name) { - DEBUG(D_receive) debug_printf("user name %q extracted from " + DEBUG(receive) debug_printf("user name %q extracted from " "gecos field %q\n", new_name, name); name = new_name; } - else DEBUG(D_receive) debug_printf("failed to expand gecos_name string " + else DEBUG(receive) debug_printf("failed to expand gecos_name string " "%q: %s\n", gecos_name, expand_string_message); } - else DEBUG(D_receive) debug_printf("gecos_pattern %q did not match " + else DEBUG(receive) debug_printf("gecos_pattern %q did not match " "gecos field %q\n", gecos_pattern, name); store_free((void *)re); } @@ -5207,7 +5217,7 @@ read in from the spool. */ originator_uid = real_uid; originator_gid = real_gid; -DEBUG(D_receive) debug_printf("originator: uid=%d gid=%d login=%s name=%s\n", +DEBUG(receive) debug_printf("originator: uid=%d gid=%d login=%s name=%s\n", (int)originator_uid, (int)originator_gid, originator_login, originator_name); /* Run in daemon and/or queue-running mode. The function daemon_go() never @@ -5324,7 +5334,7 @@ if (sender_address && *sender_address && sender_address_domain == 0) sender_address = string_sprintf("%s@%s", local_part_quote(sender_address), qualify_domain_sender); -DEBUG(D_receive) debug_printf("sender address = %s\n", sender_address); +DEBUG(receive) debug_printf("sender address = %s\n", sender_address); /* Handle a request to verify a list of addresses, or test them for delivery. This must follow the setting of the sender address, since routers can be @@ -5339,16 +5349,16 @@ if (verify_address_mode || f.address_test_mode) if (verify_address_mode) { if (!verify_as_sender) flags |= vopt_is_recipient; - DEBUG(D_verify) debug_print_ids(US"Verifying:"); + DEBUG(verify) debug_print_ids(US"Verifying:"); } else { flags |= vopt_is_recipient; - debug_selector |= D_v; + debug_modify_channel(US"+v"); debug_file = stderr; debug_fd = fileno(debug_file); - DEBUG(D_verify) debug_print_ids(US"Address testing:"); + DEBUG(verify) debug_print_ids(US"Address testing:"); } if (recipients_arg < argc) /* addresses on cmdline */ @@ -5552,11 +5562,9 @@ if (host_checking) set_connection_id(); memset(sender_host_cache, 0, sizeof(sender_host_cache)); + if (verify_check_host(&hosts_connection_nolog) == OK) - { - BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection); - BIT_CLEAR(log_selector, log_selector_size, Li_smtp_no_mail); - } + logging_modify_channels(US"-smtp_connection -smtp_no_mail"); log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); /* NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails, @@ -5748,11 +5756,9 @@ if (smtp_input) memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (verify_check_host(&hosts_connection_nolog) == OK) - { - BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection); - BIT_CLEAR(log_selector, log_selector_size, Li_smtp_no_mail); - } + logging_modify_channels(US"-smtp_connection -smtp_no_mail"); log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); + if (!smtp_start_session()) exim_exit(EXIT_SUCCESS); } @@ -5937,7 +5943,7 @@ for (BOOL more = TRUE; more; ) if ( recipients_max_expanded > 0 && ++rcount > recipients_max_expanded && !extract_recipients) { - DEBUG(D_all) debug_printf("excess reipients (max %d)\n", + DEBUG(all) debug_printf("excess reipients (max %d)\n", recipients_max_expanded); if (error_handling == ERRORS_STDERR) @@ -5975,7 +5981,7 @@ for (BOOL more = TRUE; more; ) if (!recipient) { - DEBUG(D_all) debug_printf("bad recipient address %q: %s\n", + DEBUG(all) debug_printf("bad recipient address %q: %s\n", string_printing(list[i]), errmess); if (error_handling == ERRORS_STDERR) @@ -6005,7 +6011,7 @@ for (BOOL more = TRUE; more; ) /* Show the recipients when debugging */ - DEBUG(D_receive) + DEBUG(receive) { if (sender_address) debug_printf("Sender: %s\n", sender_address); if (recipients_list) @@ -6092,7 +6098,7 @@ for (BOOL more = TRUE; more; ) if (chdir("/")) /* Get away from wherever the user is running this from */ { - DEBUG(D_receive) debug_printf("chdir(\"/\") failed\n"); + DEBUG(receive) debug_printf("chdir(\"/\") failed\n"); exim_exit(EXIT_FAILURE); } diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 1ffedfd95..ef5953700 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -98,7 +98,9 @@ const uschar *hex_digits = CUS"0123456789abcdef"; * Debug output * *******************/ -bitmask_word_t debug_selector = 0; /* set -1 for debugging */ +bitmask_word_t * debug_selector = {0}; /* set -1 for debugging */ + +inline BOOL is_debug(const uschar * channels) { return TRUE; } void debug_printf(const char * fmt, ...) diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index 04b3023b7..cb7fb75aa 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -113,7 +113,9 @@ exit(EXIT_FAILURE); * Debug output * *******************/ -bitmask_word_t debug_selector = 0; /* set -1 for debugging */ +bitmask_word_t * debug_selector = {0}; /* set -1 for debugging */ + +inline BOOL is_debug(const uschar * channels) { return TRUE; } void debug_printf(const char * fmt, ...) @@ -473,7 +475,7 @@ if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL; dlen = exim_datum_size_get(&result_datum); -DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); +DEBUG(hints_lookup) debug_printf_indent("dbfn_read: size %u return\n", dlen); if (length) *length = dlen; /* Hintsdb uses store the taint of the payload of the value in the value. @@ -486,13 +488,13 @@ else dbdata_generic * gp = (dbdata_generic *) exim_datum_data_get(&result_datum); if (dlen < sizeof(dbdata_generic)) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("dbfn_read: bad record size %u\n", dlen); return NULL; } if (gp->version != HINTS_VERSION) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("dbfn_read: bad record version %u; deleting\n", gp->version); return NULL; diff --git a/src/src/expand.c b/src/src/expand.c index 097e4aa5e..8da904d59 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1731,7 +1731,7 @@ else uschar * error, * decoded = rfc2047_decode2(rawhdr, check_rfc2047_length, charset, '?', NULL, newsize, &error); if (error) - DEBUG(D_any) debug_printf("*** error in RFC 2047 decoding: %s\n" + DEBUG(any) debug_printf("*** error in RFC 2047 decoding: %s\n" " input was: %s\n", error, rawhdr); return decoded ? decoded : rawhdr; } @@ -1837,7 +1837,7 @@ uschar * sname; if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { - DEBUG(D_expand) debug_printf(" socket: %s\n", strerror(errno)); + DEBUG(expand) debug_printf(" socket: %s\n", strerror(errno)); return NULL; } @@ -1861,7 +1861,7 @@ if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; } if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1) { - DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n"); + DEBUG(expand) debug_printf("no daemon response; using local evaluation\n"); len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached()); } else if ((len = recv(fd, buf, sizeof(buf), 0)) < 0) @@ -1879,7 +1879,7 @@ bad2: #endif bad: close(fd); - DEBUG(D_expand) debug_printf(" %s: %s\n", where, strerror(errno)); + DEBUG(expand) debug_printf(" %s: %s\n", where, strerror(errno)); return NULL; } @@ -2361,7 +2361,7 @@ while (i < nsub) acl_arg[i++] = NULL; } -DEBUG(D_expand) +DEBUG(expand) debug_printf_indent("expanding: acl: %s arg: %s%s\n", sub[0], acl_narg>0 ? acl_arg[0] : US"", @@ -2461,7 +2461,7 @@ for (item = s; *list = *s ? s+1 : s; if (item == s) return NULL; item = string_copyn(item, s - item); -DEBUG(D_expand) debug_printf_indent(" json ele: '%s'\n", item); +DEBUG(expand) debug_printf_indent(" json ele: '%s'\n", item); return US item; } @@ -2510,7 +2510,7 @@ if (!name[0]) "but found \"%.16s\"", s); return -1; } -DEBUG(D_expand) debug_printf_indent("cond: %s\n", name); +DEBUG(expand) debug_printf_indent("cond: %s\n", name); if (opname) *opname = string_copy(name); @@ -2797,9 +2797,9 @@ switch(cond_type = identify_operator(&s, &opname)) { const uschar *errp; const uschar **errpp; - DEBUG(D_expand) errpp = &errp; else errpp = 0; + DEBUG(expand) errpp = &errp; else errpp = 0; if (0 == (rc = string_is_ip_addressX(sub[0], NULL, errpp))) - DEBUG(D_expand) debug_printf("failed: %s\n", errp); + DEBUG(expand) debug_printf("failed: %s\n", errp); *yield = ( cond_type == ECOND_ISIP ? rc != 0 : cond_type == ECOND_ISIP4 ? rc == 4 : rc == 6) == testfor; @@ -3029,7 +3029,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (!(sub[i] = expand_string_internal(s+1, flags, &s, resetok, &textonly))) goto failout; if (textonly) sub_textonly |= BIT(i); - DEBUG(D_expand) if (i == 1 && !sub2_honour_dollar && Ustrchr(sub[1], '$')) + DEBUG(expand) if (i == 1 && !sub2_honour_dollar && Ustrchr(sub[1], '$')) debug_printf_indent("WARNING: the second arg is NOT expanded," " for security reasons\n"); if (*s++ != '}') goto COND_FAILED_CURLY_END; @@ -3042,7 +3042,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (sub[i][0] == 0) { num[i] = 0; - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("empty string cast to zero for numerical comparison\n"); } else @@ -3228,7 +3228,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (sublen == 24) { uschar *coded = b64encode(CUS digest, 16); - DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n" + DEBUG(auth) debug_printf("crypteq: using MD5+B64 hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+5); tempcond = (Ustrcmp(coded, sub[1]+5) == 0); } @@ -3237,13 +3237,13 @@ switch(cond_type = identify_operator(&s, &opname)) uschar coded[36]; for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); coded[32] = 0; - DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n" + DEBUG(auth) debug_printf("crypteq: using MD5+hex hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+5); tempcond = (strcmpic(coded, sub[1]+5) == 0); } else { - DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: " + DEBUG(auth) debug_printf("crypteq: length for MD5 not 24 or 32: " "fail\n crypted=%s\n", sub[1]+5); tempcond = FALSE; } @@ -3265,7 +3265,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (sublen == 28) { uschar *coded = b64encode(CUS digest, 20); - DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n" + DEBUG(auth) debug_printf("crypteq: using SHA1+B64 hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+6); tempcond = (Ustrcmp(coded, sub[1]+6) == 0); } @@ -3274,13 +3274,13 @@ switch(cond_type = identify_operator(&s, &opname)) uschar coded[44]; for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]); coded[40] = 0; - DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n" + DEBUG(auth) debug_printf("crypteq: using SHA1+hex hashing\n" " subject=%s\n crypted=%s\n", coded, sub[1]+6); tempcond = (strcmpic(coded, sub[1]+6) == 0); } else { - DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: " + DEBUG(auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: " "fail\n crypted=%s\n", sub[1]+6); tempcond = FALSE; } @@ -3318,7 +3318,7 @@ switch(cond_type = identify_operator(&s, &opname)) #define STR(s) # s #define XSTR(s) STR(s) - DEBUG(D_auth) debug_printf("crypteq: using %s()\n" + DEBUG(auth) debug_printf("crypteq: using %s()\n" " subject=%s\n crypted=%s\n", which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16", coded, sub[1]); @@ -3351,7 +3351,7 @@ switch(cond_type = identify_operator(&s, &opname)) uschar * save_iterate_item = iterate_item; int (*compare)(const uschar *, const uschar *); - DEBUG(D_expand) debug_printf_indent("condition: %s item: %s\n", opname, sub[0]); + DEBUG(expand) debug_printf_indent("condition: %s item: %s\n", opname, sub[0]); /* grab any listsep spec, then expand the list */ @@ -3365,7 +3365,7 @@ switch(cond_type = identify_operator(&s, &opname)) while ((iterate_item = string_nextinlist(&list, &sep, NULL, 0))) { - DEBUG(D_expand) debug_printf_indent(" compare %s\n", iterate_item); + DEBUG(expand) debug_printf_indent(" compare %s\n", iterate_item); if (compare(sub[0], iterate_item) == 0) { tempcond = TRUE; @@ -3452,7 +3452,7 @@ switch(cond_type = identify_operator(&s, &opname)) int sep; uschar *save_iterate_item = iterate_item; - DEBUG(D_expand) debug_printf_indent("condition: %s\n", opname); + DEBUG(expand) debug_printf_indent("condition: %s\n", opname); /* First expand the list, apart from a leading change-of-separator on non-json lists */ @@ -3513,7 +3513,7 @@ switch(cond_type = identify_operator(&s, &opname)) goto failout; } - DEBUG(D_expand) debug_printf_indent("%s: $item = %q\n", opname, iterate_item); + DEBUG(expand) debug_printf_indent("%s: $item = %q\n", opname, iterate_item); if (!eval_condition(sub[1], resetok, &tempcond)) { expand_string_message = string_sprintf("%s inside %q condition", @@ -3521,7 +3521,7 @@ switch(cond_type = identify_operator(&s, &opname)) iterate_item = save_iterate_item; goto failout; } - DEBUG(D_expand) debug_printf_indent("%s: condition evaluated to %s\n", opname, + DEBUG(expand) debug_printf_indent("%s: condition evaluated to %s\n", opname, tempcond? "true":"false"); if (yield) *yield = (tempcond == testfor); @@ -3577,7 +3577,7 @@ switch(cond_type = identify_operator(&s, &opname)) len = t2 - t; } } - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("considering %s: %s\n", ourname, len ? t : US""); /* logic for the lax case from expand_check_condition(), which also does expands, and the logic is both short and stable enough that there should @@ -3605,7 +3605,7 @@ switch(cond_type = identify_operator(&s, &opname)) "value %q", t); goto failout; } - DEBUG(D_expand) debug_printf_indent("%s: condition evaluated to %s\n", ourname, + DEBUG(expand) debug_printf_indent("%s: condition evaluated to %s\n", ourname, boolvalue? "true":"false"); if (yield) *yield = (boolvalue == testfor); next = s; goto out; @@ -3640,7 +3640,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT, md, pcre_gen_mtc_ctx) < 0) { - DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n"); + DEBUG(expand) debug_printf("no match for SRS'd local-part pattern\n"); goto srs_result; } ovec = pcre2_get_ovector_pointer(md); @@ -3651,7 +3651,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL) { quoting = 1; break; } if (quoting) - DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); + DEBUG(expand) debug_printf_indent("auto-quoting local part\n"); /* Record the (quoted, if needed) decoded recipient as $srs_recipient */ @@ -3686,7 +3686,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (((now.tv_sec - d) & 0x3ff) > 10) /* days since SRS generated */ { - DEBUG(D_expand) debug_printf("SRS too old\n"); + DEBUG(expand) debug_printf("SRS too old\n"); goto srs_result; } } @@ -3695,7 +3695,7 @@ switch(cond_type = identify_operator(&s, &opname)) if (ovec[3]-ovec[2] != 4) { - DEBUG(D_expand) debug_printf("SRS checksum wrong size\n"); + DEBUG(expand) debug_printf("SRS checksum wrong size\n"); goto srs_result; } @@ -3705,7 +3705,7 @@ switch(cond_type = identify_operator(&s, &opname)) hmac_md5(sub[1], srs_recipient, cksum, sizeof(cksum)); if (Ustrncmp(cksum, sub[0] + ovec[2], 4) != 0) { - DEBUG(D_expand) debug_printf("SRS checksum mismatch\n"); + DEBUG(expand) debug_printf("SRS checksum mismatch\n"); goto srs_result; } } @@ -4065,7 +4065,7 @@ hash_source = string_catn(NULL, key_num, 1); hash_source = string_catn(hash_source, daystamp, 3); hash_source = string_cat(hash_source, address); -DEBUG(D_expand) +DEBUG(expand) debug_printf_indent("prvs: hash source is '%Y'\n", hash_source); memset(innerkey, 0x36, 64); @@ -4163,18 +4163,18 @@ return yield; static inline void eval_dbg_op_2(const uschar * op, int_eximarith_t a, int_eximarith_t b) { -DEBUG(D_expand) +DEBUG(expand) debug_printf_indent("eval " PR_EXIM_ARITH " %s " PR_EXIM_ARITH, a, op, b); } static inline void eval_dbg_res(int_eximarith_t res) { -DEBUG(D_expand) debug_printf(" => " PR_EXIM_ARITH "\n", res); +DEBUG(expand) debug_printf(" => " PR_EXIM_ARITH "\n", res); } static inline void eval_dbg(const uschar * op, int_eximarith_t res) { -DEBUG(D_expand) +DEBUG(expand) debug_printf_indent("eval '%s' res: " PR_EXIM_ARITH "\n", op, res); } @@ -4329,7 +4329,7 @@ if (!*error) if (y == -1 && x == EXIM_ARITH_MIN && op != '*') { - DEBUG(D_expand) + DEBUG(expand) debug_printf("Integer exception dodging: " PR_EXIM_ARITH "%c-1 coerced to " PR_EXIM_ARITH "\n", EXIM_ARITH_MIN, op, EXIM_ARITH_MAX); x = EXIM_ARITH_MAX; @@ -4686,7 +4686,7 @@ else if (!opt_perl_started) uschar * initerror; typedef uschar * (*fn_t)(const uschar *); - DEBUG(D_any) debug_printf_indent("Starting Perl interpreter\n"); + DEBUG(any) debug_printf_indent("Starting Perl interpreter\n"); if ((initerror = (((fn_t *) mi->functions)[PERL_STARTUP]) (startup_pl))) { expand_string_message = @@ -4803,7 +4803,7 @@ while (*s) /* known to be untainted */ if (flags & ESI_EXISTS_ONLY && gstring_length(yield) > 0) break; - DEBUG(D_expand) + DEBUG(expand) { debug_printf_indent("%V%V%s: %W\n", first ? "/" : "K", @@ -4830,7 +4830,7 @@ while (*s) /* known to be untainted */ const uschar * t = s + 2; for (s = t; *s ; s++) if (*s == '\\' && s[1] == 'N') break; - DEBUG(D_expand) + DEBUG(expand) debug_expansion_interim(US"protected", t, (int)(s - t), flags); if (!(flags & ESI_SKIPPING)) yield = string_catn(yield, t, s - t); @@ -4839,7 +4839,7 @@ while (*s) /* known to be untainted */ else { uschar ch[1]; - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("%Vbackslashed: '\\%c'\n", "K", s[1]); ch[0] = string_interpret_escape(&s); if (!(flags & ESI_SKIPPING)) @@ -4861,7 +4861,7 @@ while (*s) /* known to be untainted */ for (const uschar * t = s+1; *t && *t != '$' && *t != '}' && *t != '\\'; t++) i++; - DEBUG(D_expand) debug_expansion_interim(US"text", s, i, flags); + DEBUG(expand) debug_expansion_interim(US"text", s, i, flags); if (!(flags & ESI_SKIPPING)) yield = string_catn(yield, s, i); @@ -4949,13 +4949,13 @@ while (*s) /* known to be untainted */ if (flags & ESI_SKIPPING) { - DEBUG(D_expand) + DEBUG(expand) debug_expansion_interim(US"var", name, Ustrlen(name), flags); } else { int len = Ustrlen(value); - DEBUG(D_expand) debug_expansion_interim(US"value", value, len, flags); + DEBUG(expand) debug_expansion_interim(US"value", value, len, flags); if (!yield && newsize != 0) { yield = g; @@ -4976,7 +4976,7 @@ while (*s) /* known to be untainted */ s = read_cnumber(&n, s); if (n >= 0 && n <= expand_nmax) { - DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); + DEBUG(expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); if (!(flags & ESI_SKIPPING)) yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); } @@ -5005,7 +5005,7 @@ while (*s) /* known to be untainted */ } if (n >= 0 && n <= expand_nmax) { - DEBUG(D_expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); + DEBUG(expand) debug_expansion_interim(US"value", expand_nstring[n], expand_nlength[n], flags); if (!(flags & ESI_SKIPPING)) yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); } @@ -5061,7 +5061,7 @@ while (*s) /* known to be untainted */ { case OK: case FAIL: - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("acl expansion yield: %s\n", user_msg); if (user_msg) yield = string_cat(yield, user_msg); @@ -5119,7 +5119,7 @@ while (*s) /* known to be untainted */ if (!(next_s = eval_condition(s, &resetok, flags & ESI_SKIPPING ? NULL : &cond))) goto EXPAND_FAILED; /* message already set */ - DEBUG(D_expand) + DEBUG(expand) { debug_expansion_interim(US"condition", s, (int)(next_s - s), flags); debug_expansion_interim(US"result", @@ -5529,7 +5529,7 @@ while (*s) /* known to be untainted */ uschar * hash = string_copyn(expand_nstring[3],expand_nlength[3]); uschar * domain = string_copyn(expand_nstring[5],expand_nlength[5]); - DEBUG(D_expand) + DEBUG(expand) { debug_printf_indent("prvscheck localpart: %s\n", local_part); debug_printf_indent("prvscheck key number: %s\n", key_num); @@ -5563,8 +5563,8 @@ while (*s) /* known to be untainted */ goto EXPAND_FAILED; } - DEBUG(D_expand) debug_printf_indent("prvscheck: received hash is %s\n", hash); - DEBUG(D_expand) debug_printf_indent("prvscheck: own hash is %s\n", p); + DEBUG(expand) debug_printf_indent("prvscheck: received hash is %s\n", hash); + DEBUG(expand) debug_printf_indent("prvscheck: own hash is %s\n", p); if (Ustrcmp(p,hash) == 0) { @@ -5582,18 +5582,18 @@ while (*s) /* known to be untainted */ if (iexpire >= inow) { prvscheck_result = US"1"; - DEBUG(D_expand) debug_printf_indent("prvscheck: success, $prvscheck_result set to 1\n"); + DEBUG(expand) debug_printf_indent("prvscheck: success, $prvscheck_result set to 1\n"); } else { prvscheck_result = NULL; - DEBUG(D_expand) debug_printf_indent("prvscheck: signature expired, $prvscheck_result unset\n"); + DEBUG(expand) debug_printf_indent("prvscheck: signature expired, $prvscheck_result unset\n"); } } else { prvscheck_result = NULL; - DEBUG(D_expand) debug_printf_indent("prvscheck: hash failure, $prvscheck_result unset\n"); + DEBUG(expand) debug_printf_indent("prvscheck: hash failure, $prvscheck_result unset\n"); } /* Now expand the final argument. We leave this till now so that @@ -5799,7 +5799,7 @@ while (*s) /* known to be untainted */ SOCK_FAIL: if (*s != '{') goto EXPAND_FAILED; /*}*/ - DEBUG(D_any) debug_printf("%s\n", expand_string_message); + DEBUG(any) debug_printf("%s\n", expand_string_message); if (!(arg = expand_string_internal(s+1, ESI_BRACE_ENDS | ESI_HONOR_DOLLAR, &s, &resetok, NULL))) goto EXPAND_FAILED; @@ -5862,7 +5862,7 @@ while (*s) /* known to be untainted */ } else { - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("args string for ${run} expand before split\n"); if (!(arg = expand_string_internal(s, ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL))) @@ -6171,7 +6171,7 @@ while (*s) /* known to be untainted */ *p++ = hex_digits[finalhash[i] & 0x0f]; } - DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n", + DEBUG(any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n", sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex); yield = string_catn(yield, finalhash_hex, hashlen*2); @@ -6246,7 +6246,7 @@ while (*s) /* known to be untainted */ } /* Match - set up for expanding the replacement. */ - DEBUG(D_expand) debug_printf_indent("%s: match\n", name); + DEBUG(expand) debug_printf_indent("%s: match\n", name); if (n == 0) n = EXPAND_MAXN + 1; expand_nmax = 0; @@ -6761,7 +6761,7 @@ while (*s) /* known to be untainted */ goto EXPAND_FAILED_CURLY; /*}*/ } - DEBUG(D_expand) debug_printf_indent("%s: evaluate input list\n", name); + DEBUG(expand) debug_printf_indent("%s: evaluate input list\n", name); /* Check for a list-sep spec before expansion */ sep = matchlist_parse_sep(&s); @@ -6784,7 +6784,7 @@ while (*s) /* known to be untainted */ expand_string_message = US"missing '{' for second arg of reduce"; goto EXPAND_FAILED_CURLY; /*}*/ } - DEBUG(D_expand) debug_printf_indent("reduce: initial result list\n"); + DEBUG(expand) debug_printf_indent("reduce: initial result list\n"); t = expand_string_internal(s, ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | flags, &s, &resetok, NULL); if (!t) goto EXPAND_FAILED; @@ -6812,7 +6812,7 @@ while (*s) /* known to be untainted */ condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using the normal internal expansion function. */ - DEBUG(D_expand) debug_printf_indent("%s: find end of conditionn\n", name); + DEBUG(expand) debug_printf_indent("%s: find end of conditionn\n", name); if (item_type != EITEM_FILTER) temp = expand_string_internal(s, ESI_BRACE_ENDS | ESI_HONOR_DOLLAR | ESI_SKIPPING, &s, &resetok, NULL); @@ -6851,7 +6851,7 @@ while (*s) /* known to be untainted */ { *outsep = (uschar)sep; /* Separator as a string */ - DEBUG(D_expand) debug_printf_indent("%s: $item = '%s' $value = '%s'\n", + DEBUG(expand) debug_printf_indent("%s: $item = '%s' $value = '%s'\n", name, iterate_item, lookup_value); if (item_type == EITEM_FILTER) @@ -6869,7 +6869,7 @@ while (*s) /* known to be untainted */ goto EXPAND_FAILED; } lookup_value = save_value; - DEBUG(D_expand) debug_printf_indent("%s: condition is %s\n", name, + DEBUG(expand) debug_printf_indent("%s: condition is %s\n", name, condresult? "true":"false"); if (condresult) temp = iterate_item; /* TRUE => include this item */ @@ -7045,7 +7045,7 @@ while (*s) /* known to be untainted */ const uschar * srcfield, * dstitem; gstring * newlist = NULL, * newkeylist = NULL; - DEBUG(D_expand) debug_printf_indent("%s: $item = %q\n", name, srcitem); + DEBUG(expand) debug_printf_indent("%s: $item = %q\n", name, srcitem); /* extract field for comparisons */ iterate_item = srcitem; @@ -7110,8 +7110,8 @@ while (*s) /* known to be untainted */ dstlist = newlist->s; dstkeylist = newkeylist->s; - DEBUG(D_expand) debug_printf_indent("%s: dstlist = %q\n", name, dstlist); - DEBUG(D_expand) debug_printf_indent("%s: dstkeylist = %q\n", name, dstkeylist); + DEBUG(expand) debug_printf_indent("%s: dstlist = %q\n", name, dstlist); + DEBUG(expand) debug_printf_indent("%s: dstkeylist = %q\n", name, dstkeylist); } if (dstlist) @@ -7312,7 +7312,7 @@ while (*s) /* known to be untainted */ if ((quoted = Ustrchr(ss, '"') != NULL)) { gstring * h = NULL; - DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n"); + DEBUG(expand) debug_printf_indent("auto-quoting local part\n"); while (*ss) /* de-quote */ { while (*ss && *ss != '"') h = string_catn(h, ss++, 1); @@ -7338,7 +7338,7 @@ while (*s) /* known to be untainted */ yield = string_cat(yield, sub[2]); } else - DEBUG(D_expand) debug_printf_indent("null return_path for srs-encode\n"); + DEBUG(expand) debug_printf_indent("null return_path for srs-encode\n"); break; } @@ -7349,7 +7349,7 @@ while (*s) /* known to be untainted */ } /* EITEM_* switch */ /*NOTREACHED*/ - DEBUG(D_expand) /* only if not the sole expansion of the line */ + DEBUG(expand) /* only if not the sole expansion of the line */ if (yield && (expansion_start > 0 || *s)) debug_expansion_interim(US"item-res", yield->s + expansion_start, yield->ptr - expansion_start, @@ -8240,7 +8240,7 @@ NOT_ITEM: ; goto EXPAND_FAILED; } yield = string_cat(yield, s); - DEBUG(D_expand) debug_printf_indent("yield: '%Y'\n", yield); + DEBUG(expand) debug_printf_indent("yield: '%Y'\n", yield); break; } @@ -8556,7 +8556,7 @@ NOT_ITEM: ; goto EXPAND_FAILED; } /* EOP_* switch */ - DEBUG(D_expand) + DEBUG(expand) { const uschar * res = string_from_gstring(yield); const uschar * s = res + expansion_start; @@ -8658,7 +8658,7 @@ left != NULL, return a pointer to the endpoint in the source string. */ if (resetok) gstring_release_unused(yield); else if (resetok_p) *resetok_p = FALSE; - DEBUG(D_expand) + DEBUG(expand) { BOOL tainted = is_tainted(res); debug_printf_indent("%Vexpanded: %.*W\n", @@ -8703,7 +8703,7 @@ that is a bad idea, because expand_string_message is in dynamic store. */ EXPAND_FAILED: if (left) *left = s; -DEBUG(D_expand) +DEBUG(expand) { debug_printf_indent("%Vfailed to expand: %s\n", "K", orig_string); debug_printf_indent("%Verror message: %s\n", @@ -8851,7 +8851,7 @@ to find at all). */ if (isspace(*s)) if (Uskip_whitespace(&s) == '\0') { - DEBUG(D_expand) + DEBUG(expand) debug_printf_indent("treating blank string as number 0\n"); return 0; } @@ -8902,7 +8902,7 @@ Arguments: addr address being routed mtype the module type mname the module name - dbg_opt debug selectors + dbg output debugging oname the option name bvalue the router's boolean value svalue the router's string value @@ -8914,31 +8914,30 @@ Returns: OK value placed in rvalue int exp_bool(address_item * addr, - const uschar * mtype, const uschar * mname, unsigned dbg_opt, + const uschar * mtype, const uschar * mname, BOOL dbg, uschar * oname, BOOL bvalue, const uschar * svalue, BOOL * rvalue) { const uschar * expanded; -DEBUG(D_expand) debug_printf_indent("try option %s\n", oname); +DEBUG(expand) debug_printf_indent("try option %s\n", oname); if (!svalue) { *rvalue = bvalue; return OK; } if (!(expanded = expand_string(svalue))) { if (f.expand_string_forcedfail) { - DEBUG(dbg_opt) debug_printf("expansion of %q forced failure\n", oname); + if(dbg) debug_printf("expansion of %q forced failure\n", oname); *rvalue = bvalue; return OK; } addr->message = string_sprintf("failed to expand %q in %s %s: %s", oname, mname, mtype, expand_string_message); - DEBUG(dbg_opt) debug_printf("%s\n", addr->message); + if(dbg) debug_printf("%s\n", addr->message); return DEFER; } -DEBUG(dbg_opt) debug_printf("expansion of %q yields %q\n", oname, - expanded); +if(dbg) debug_printf("expansion of %q yields %q\n", oname, expanded); if (strcmpic(expanded, US"true") == 0 || strcmpic(expanded, US"yes") == 0) *rvalue = TRUE; @@ -9121,7 +9120,7 @@ int main(int argc, uschar **argv) { uschar buffer[1024]; -debug_selector = D_v; +debug_modify_channel(US"+v"); debug_file = stderr; debug_fd = fileno(debug_file); big_buffer = malloc(big_buffer_size); @@ -9135,7 +9134,7 @@ for (int i = 1; i < argc; i++) argv[i]++; } if (isdigit(argv[i][0])) - debug_selector = Ustrtoul(argv[i], NULL, 0); + debug_selector[0] = Ustrtoul(argv[i], NULL, 0); else if (Ustrspn(argv[i], "abcdefghijklmnopqrtsuvwxyz0123456789-.:/") == Ustrlen(argv[i])) diff --git a/src/src/functions.h b/src/src/functions.h index 35c967fc4..13fa362a4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -140,12 +140,12 @@ extern BOOL bdat_hasc(void); extern int bdat_ungetc(int); extern void bdat_flush_data(void); -extern void bits_clear(bitmask_word_t *, size_t, int *); -extern void bits_set(bitmask_word_t *, size_t, int *); - extern void cancel_cutthrough_connection(BOOL, const uschar *); extern gstring *cat_file(FILE *, gstring *, const uschar *); extern gstring *cat_file_tls(void *, gstring *, const uschar *); +extern unsigned chan_name_to_idx(const uschar *, unsigned, + const uschar * const *, unsigned); + extern void check_deliver_addrs_not_freed(void (*)(const uschar*, const uschar*, void*), void *); extern int check_host(void *, const uschar *, const uschar **, uschar **); extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...); @@ -175,6 +175,9 @@ extern ssize_t daemon_notifier_sockname(struct sockaddr_un *); extern int dcc_process(uschar **); #endif +extern BOOL debug_disable(void); +extern void debug_decode_bits(bitmask_word_t **, const uschar *, int); + extern void debug_logging_activate(const uschar *, const uschar *); extern void debug_logging_from_spool(const uschar *); extern void debug_logging_stop(BOOL); @@ -187,10 +190,13 @@ extern void debug_vprintf(int, const char *, va_list); extern void debug_pretrigger_setup(const uschar *); extern void debug_pretrigger_discard(void); extern void debug_print_socket(int); +extern gstring * debug_selector_dump(gstring *); +extern void debug_set_default_bits(bitmask_word_t **); +extern void debug_enable(void); extern void debug_trigger_fire(void); -extern void decode_bits(bitmask_word_t *, size_t, int *, - const uschar *, bit_table *, int, uschar *, int); +extern void decode_bits(bitmask_word_t *, size_t, const uschar * const *, + const uschar *, const uschar * const *, int, int); extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); extern address_item *deliver_make_addr(const uschar *, BOOL); @@ -234,7 +240,7 @@ extern void exim_setugid(uid_t, gid_t, BOOL, const uschar *); extern void exim_underbar_exit(int) NORETURN; extern void exim_wait_tick(struct timeval *, int); extern int exp_bool(address_item *, - const uschar *, const uschar *, unsigned, uschar *, BOOL bvalue, + const uschar *, const uschar *, BOOL, uschar *, BOOL, const uschar *, BOOL *); extern BOOL expand_check_condition(const uschar *, const uschar *, const uschar *); extern uschar *expand_file_big_buffer(const uschar *); @@ -305,6 +311,8 @@ extern int log_open_as_exim(const uschar * const); extern gstring *log_portnum(gstring *, int); extern void log_write_die(bitmask_word_t, int, const char * format, ...) PRINTF_FUNCTION(3,4) NORETURN; +extern void logging_modify_channels(const uschar *); +extern void logging_set_defaults(void); extern const lookup_info * lookup_with_acq_num(unsigned); extern gstring *lookup_dynamic_supported(gstring *); @@ -711,6 +719,21 @@ extern uschar *xtextencode(const uschar *, int); extern int xtextdecode(const uschar *, uschar **); +/******************************************************************************/ +/* Bit-manipulation in multi-word vectors. */ + +static inline void +bit_clear(bitmask_word_t * tbl, unsigned bitnum) +{ tbl[BITWORD(bitnum)] &= ~BITMASK(bitnum); } + +static inline void +bit_set(bitmask_word_t * tbl, unsigned bitnum) +{ tbl[BITWORD(bitnum)] |= BITMASK(bitnum); } + +static inline bitmask_word_t +bit_test(bitmask_word_t * tbl, unsigned bitnum) +{ return tbl[BITWORD(bitnum)] & BITMASK(bitnum); } + /******************************************************************************/ /* Predicate: if an address is in a tainted pool. By extension, a variable pointing to this address is tainted. @@ -1404,18 +1427,18 @@ static inline pid_t exim_fork(const unsigned char * purpose) { pid_t pid; -DEBUG(D_any) +DEBUG(any) debug_printf_indent("%s forking for %s\n", process_purpose, purpose); if ((pid = fork()) == 0) { f.daemon_listen = FALSE; process_purpose = purpose; - DEBUG(D_any) debug_printf_indent("postfork: %s\n", purpose); + DEBUG(any) debug_printf_indent("postfork: %s\n", purpose); } else { testharness_pause_ms(100); /* let child work */ - DEBUG(D_any) debug_printf_indent("%s forked for %s: %d\n", + DEBUG(any) debug_printf_indent("%s forked for %s: %d\n", process_purpose, purpose, (int)pid); } return pid; @@ -1465,7 +1488,7 @@ store_pool = old_pool; static inline void smtp_debug_cmd(const uschar * buf, int mode) { -HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP%c> %s\n", +HDEBUG(transport|acl|v) debug_printf_indent(" SMTP%c> %s\n", mode == SCMD_BUFFER ? '|' : mode == SCMD_MORE ? '+' : '>', buf); # ifndef DISABLE_CLIENT_CMD_LOG @@ -1549,9 +1572,9 @@ is_multiple_qrun(void) return qrunners && (qrunners->interval > 0 || qrunners->next); } - # endif /* !COMPILE_UTILITY */ + /******************************************************************************/ #endif /* !MACRO_PREDEF */ diff --git a/src/src/globals.c b/src/src/globals.c index acfdfecb4..0d47bfbfb 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -655,55 +655,74 @@ uschar *dccifd_options = US"header"; int debug_fd = -1; FILE *debug_file = NULL; -int debug_notall[] = { - Di_macro, - Di_memory, - Di_noutf8, - Di_regex, - -1 + +/* List of names for debug channels. Must be in alphabetical order. +The initial few entries are dummies. */ + +const uschar * const debug_chan_names[] = { + [BIT_TABLE_IDX_USABLE] = US"acl", /* 4 */ + US"auth", + US"deliver", + US"dns", + US"dnsbl", /* 8 */ + US"exec", + US"expand", + US"filter", + US"hints_lookup", + US"host_lookup", + US"ident", + US"interface", + US"lists", /* 16 */ + US"load", + US"local_scan", + US"lookup", + US"macro", + US"memory", + US"noutf8", + US"pid", + US"process_info", /* 24 */ + US"queue_run", + US"receive", + US"regex", + US"resolver", + US"retry", + US"rewrite", + US"route", + US"timestamp", /* 32 */ + US"tls", + US"transport", + US"uid", + US"v", + US"verify", }; -bit_table debug_options[] = { /* must be in alphabetical order and use - only the enum values from macros.h */ - BIT_TABLE(D, acl), - BIT_TABLE(D, all), - BIT_TABLE(D, auth), - BIT_TABLE(D, deliver), - BIT_TABLE(D, dns), - BIT_TABLE(D, dnsbl), - BIT_TABLE(D, exec), - BIT_TABLE(D, expand), - BIT_TABLE(D, filter), - BIT_TABLE(D, hints_lookup), - BIT_TABLE(D, host_lookup), - BIT_TABLE(D, ident), - BIT_TABLE(D, interface), - BIT_TABLE(D, lists), - BIT_TABLE(D, load), - BIT_TABLE(D, local_scan), - BIT_TABLE(D, lookup), - BIT_TABLE(D, macro), - BIT_TABLE(D, memory), - BIT_TABLE(D, noutf8), - BIT_TABLE(D, pid), - BIT_TABLE(D, process_info), - BIT_TABLE(D, queue_run), - BIT_TABLE(D, receive), - BIT_TABLE(D, regex), - BIT_TABLE(D, resolver), - BIT_TABLE(D, retry), - BIT_TABLE(D, rewrite), - BIT_TABLE(D, route), - BIT_TABLE(D, timestamp), - BIT_TABLE(D, tls), - BIT_TABLE(D, transport), - BIT_TABLE(D, uid), - BIT_TABLE(D, verify), + +int debug_options_count = nelem(debug_chan_names); + +/* Channel settings for "default" debug (just a "-d" used) */ + +const uschar * debug_defaults = + US "+all" + "-expand" + "-filter" + "-interface" + "-load" + "-local_scan" + "-memory" + "-noutf8" + "-pid" + "-timestamp" + "-resolver"; + +/* List of debug channels that we exclude from "all" */ + +const uschar * const debug_notall_names[] = { + US"macro", US"memory", US"noutf8", US"regex", NULL }; -int debug_options_count = nelem(debug_options); + uschar debuglog_name[LOG_NAME_SIZE] = {0}; unsigned debug_pretrigger_bsize = 0; uschar * debug_pretrigger_buf = NULL; -bitmask_word_t debug_selector = 0; +bitmask_word_t * debug_selector = NULL; BOOL debug_startup = FALSE; int delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 }; @@ -909,117 +928,149 @@ tree_node *localpartlist_anchor= NULL; int localpartlist_count = 0; uschar *log_buffer = NULL; -int log_default[] = { /* for initializing log_selector */ - Li_acl_warn_skipped, - Li_connection_reject, - Li_delay_delivery, - Li_dkim, - Li_dnslist_defer, - Li_etrn, - Li_host_lookup_failed, - Li_lost_incoming_connection, - Li_outgoing_interface, /* see d_log_interface in deliver.c */ - Li_msg_id, - Li_queue_run, - Li_queue_time_exclusive, - Li_rejected_header, - Li_retry_defer, - Li_sender_verify_fail, - Li_size_reject, - Li_skip_delivery, - Li_smtp_confirmation, - Li_tls_certificate_verified, - Li_tls_cipher, - -1 +const uschar * log_default_names[] = { /* for initializing log_selector */ + US"acl_warn_skipped", + US"connection_reject", + US"delay_delivery", + US"dkim", + US"dnslist_defer", + US"etrn", + US"host_lookup_failed", + US"lost_incoming_connection", + US"outgoing_interface", /* see d_log_interface in deliver.c */ + US"msg_id", + US"queue_run", + US"queue_time_exclusive", + US"rejected_header", + US"retry_defer", + US"sender_verify_fail", + US"size_reject", + US"skip_delivery", + US"smtp_confirmation", + US"tls_certificate_verified", + US"tls_cipher", }; +int log_default_count = nelem(log_default_names); uschar *log_file_path = US LOG_FILE_PATH "\0<--------------Space to patch log_file_path->"; -int log_notall[] = { - -1 +const uschar * const log_notall_names[] = { NULL }; + +/* Table for selectors for log_write() calls. +Must have names that are in both enum logwrite_bit and logging_test_bit. */ + +#define BIT_TABLE(chan) {.name = US #chan, .logchan_bit = Lt_##chan } + +bit_table logwrite_options[] = { + BIT_TABLE(address_rewrite), + BIT_TABLE(all_parents), + BIT_TABLE(connection_reject), + BIT_TABLE(delay_delivery), + BIT_TABLE(dnslist_defer), + BIT_TABLE(etrn), + BIT_TABLE(host_lookup_failed), + BIT_TABLE(lost_incoming_connection), + BIT_TABLE(queue_run), + BIT_TABLE(retry_defer), + BIT_TABLE(size_reject), + BIT_TABLE(skip_delivery), + BIT_TABLE(smtp_connection), + BIT_TABLE(smtp_incomplete_transaction), + BIT_TABLE(smtp_protocol_error), + BIT_TABLE(smtp_syntax_error), }; -bit_table log_options[] = { /* must be in alphabetical order, - with definitions from enum logbit. */ - BIT_TABLE(L, 8bitmime), - BIT_TABLE(L, acl_warn_skipped), - BIT_TABLE(L, address_rewrite), - BIT_TABLE(L, all), - BIT_TABLE(L, all_parents), - BIT_TABLE(L, arguments), - BIT_TABLE(L, connection_id), - BIT_TABLE(L, connection_reject), - BIT_TABLE(L, delay_delivery), - BIT_TABLE(L, deliver_time), - BIT_TABLE(L, delivery_size), +#undef BIT_TABLE +int logwrite_options_count = nelem(logwrite_options); + + +/* List of names for logging channels. Must be in alphabetical order. +Must match enum logging_test_bit (macros.h). +This is a superset of logwrite_options[]. +The initial few entries are dummies. */ + +#define LOG_CHAN(name) [Lt_##name] = US #name + +const uschar * const log_chan_names[] = { + LOG_CHAN(8bitmime), + LOG_CHAN(acl_warn_skipped), + LOG_CHAN(address_rewrite), + [Lt_DUMMY_all] = US"all", + LOG_CHAN(all_parents), + LOG_CHAN(arguments), + LOG_CHAN(connection_id), + LOG_CHAN(connection_reject), + LOG_CHAN(delay_delivery), + LOG_CHAN(deliver_time), + LOG_CHAN(delivery_size), #ifndef DISABLE_DKIM - BIT_TABLE(L, dkim), - BIT_TABLE(L, dkim_verbose), + LOG_CHAN(dkim), + LOG_CHAN(dkim_verbose), #endif #ifdef EXIM_HAVE_DMARC - BIT_TABLE(L, dmarc), - BIT_TABLE(L, dmarc_verbose), + LOG_CHAN(dmarc), + LOG_CHAN(dmarc_verbose), #endif - BIT_TABLE(L, dnslist_defer), - BIT_TABLE(L, dnssec), - BIT_TABLE(L, dsn), - BIT_TABLE(L, etrn), - BIT_TABLE(L, host_lookup_failed), - BIT_TABLE(L, ident_timeout), - BIT_TABLE(L, incoming_interface), - BIT_TABLE(L, incoming_port), - BIT_TABLE(L, lost_incoming_connection), - BIT_TABLE(L, millisec), - BIT_TABLE(L, msg_id), - BIT_TABLE(L, msg_id_created), - BIT_TABLE(L, outgoing_interface), - BIT_TABLE(L, outgoing_port), - BIT_TABLE(L, pid), - BIT_TABLE(L, pipelining), - BIT_TABLE(L, protocol_detail), + LOG_CHAN(dnslist_defer), + LOG_CHAN(dnssec), + LOG_CHAN(dsn), + LOG_CHAN(etrn), + LOG_CHAN(host_lookup_failed), + LOG_CHAN(ident_timeout), + LOG_CHAN(incoming_interface), + LOG_CHAN(incoming_port), + LOG_CHAN(lost_incoming_connection), + LOG_CHAN(millisec), + LOG_CHAN(msg_id), + LOG_CHAN(msg_id_created), + LOG_CHAN(outgoing_interface), + LOG_CHAN(outgoing_port), + LOG_CHAN(pid), + LOG_CHAN(pipelining), + LOG_CHAN(protocol_detail), #if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS) - BIT_TABLE(L, proxy), + LOG_CHAN(proxy), #endif - BIT_TABLE(L, queue_run), - BIT_TABLE(L, queue_time), - BIT_TABLE(L, queue_time_exclusive), - BIT_TABLE(L, queue_time_overall), - BIT_TABLE(L, receive_time), - BIT_TABLE(L, received_recipients), - BIT_TABLE(L, received_sender), - BIT_TABLE(L, rejected_header), - { US"rejected_headers", Li_rejected_header }, - BIT_TABLE(L, retry_defer), - BIT_TABLE(L, return_path_on_delivery), - BIT_TABLE(L, sender_on_delivery), - BIT_TABLE(L, sender_verify_fail), - BIT_TABLE(L, size_reject), - BIT_TABLE(L, skip_delivery), - BIT_TABLE(L, smtp_confirmation), - BIT_TABLE(L, smtp_connection), - BIT_TABLE(L, smtp_incomplete_transaction), - BIT_TABLE(L, smtp_mailauth), - BIT_TABLE(L, smtp_no_mail), - BIT_TABLE(L, smtp_protocol_error), - BIT_TABLE(L, smtp_syntax_error), + LOG_CHAN(queue_run), + LOG_CHAN(queue_time), + LOG_CHAN(queue_time_exclusive), + LOG_CHAN(queue_time_overall), + LOG_CHAN(receive_time), + LOG_CHAN(received_recipients), + LOG_CHAN(received_sender), + LOG_CHAN(rejected_header), + LOG_CHAN(retry_defer), + LOG_CHAN(return_path_on_delivery), + LOG_CHAN(sender_on_delivery), + LOG_CHAN(sender_verify_fail), + LOG_CHAN(size_reject), + LOG_CHAN(skip_delivery), + LOG_CHAN(smtp_confirmation), + LOG_CHAN(smtp_connection), + LOG_CHAN(smtp_incomplete_transaction), + LOG_CHAN(smtp_mailauth), + LOG_CHAN(smtp_no_mail), + LOG_CHAN(smtp_protocol_error), + LOG_CHAN(smtp_syntax_error), #ifdef EXIM_HAVE_SPF - BIT_TABLE(L, spf), - BIT_TABLE(L, spf_verbose), + LOG_CHAN(spf), + LOG_CHAN(spf_verbose), #endif - BIT_TABLE(L, subject), - BIT_TABLE(L, tls_certificate_verified), - BIT_TABLE(L, tls_cipher), - BIT_TABLE(L, tls_on_connect), - BIT_TABLE(L, tls_peerdn), - BIT_TABLE(L, tls_resumption), - BIT_TABLE(L, tls_sni), - BIT_TABLE(L, unknown_in_list), + LOG_CHAN(subject), + LOG_CHAN(tls_certificate_verified), + LOG_CHAN(tls_cipher), + LOG_CHAN(tls_on_connect), + LOG_CHAN(tls_peerdn), + LOG_CHAN(tls_resumption), + LOG_CHAN(tls_sni), + LOG_CHAN(unknown_in_list), }; -int log_options_count = nelem(log_options); +#undef LOG_CHAN +int log_options_count = nelem(log_chan_names); const uschar *log_ports = NULL; int log_reject_target = 0; -bitmask_word_t log_selector[log_selector_size]; /* initialized in main() */ +bitmask_word_t log_selector[log_selector_size]; /* initialized from main() */ uschar *log_selector_string = NULL; FILE *log_stderr = NULL; uschar *login_sender_address = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index f121b7609..b0c1dd44a 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -476,10 +476,14 @@ extern uschar *dccifd_address; /* address of the dccifd daemon */ extern uschar *dccifd_options; /* options for the dccifd daemon */ #endif +extern const uschar * const debug_chan_names[]; /* channel names */ +extern const uschar * debug_defaults; /* chans for "-d" */ +extern const uschar * const debug_notall_names[]; /* chans not in "all" */ +extern bitmask_word_t * debug_selector; /* Debugging bits */ + + extern int debug_fd; /* The fd for debug_file */ extern FILE *debug_file; /* Where to write debugging info */ -extern int debug_notall[]; /* Debug options excluded from +all */ -extern bit_table debug_options[]; /* Table of debug options */ extern int debug_options_count; /* Size of table */ extern unsigned debug_pretrigger_bsize; extern uschar *debug_pretrigger_buf; /* circular buffer for precapture */ @@ -667,11 +671,12 @@ extern uid_t local_user_uid; /* As it says; may be set in routers */ extern tree_node *localpartlist_anchor;/* Tree of defined localpart lists */ extern int localpartlist_count; /* Number defined */ extern uschar *log_buffer; /* For constructing log entries */ -extern int log_default[]; /* Initialization list for log_selector */ +extern const uschar * log_default_names[]; /* Init list for log_selector */ +extern int log_default_count; /* Size of table */ extern uschar *log_file_path; /* If unset, use default */ extern const uschar *log_ports; /* If set, port numbers to log */ -extern int log_notall[]; /* Log options excluded from +all */ -extern bit_table log_options[]; /* Table of options */ +extern const uschar * const log_chan_names[]; /* Table of options */ +extern const uschar * const log_notall_names[]; /* chans not in "all" */ extern int log_options_count; /* Size of table */ extern int log_reject_target; /* Target log for ACL rejections */ extern bitmask_word_t log_selector[]; /* Bit map of logging options */ @@ -679,6 +684,8 @@ extern uschar *log_selector_string; /* As supplied in the config */ extern FILE *log_stderr; /* Copy of stderr for log use, or NULL */ extern BOOL log_timezone; /* TRUE to include the timezone in log lines */ extern uschar *login_sender_address; /* The actual sender address */ +extern bit_table logwrite_options[]; /* Options usable for logwrite() */ +extern int logwrite_options_count; /* Size of table */ extern tree_node *lookups_tree; /* Tree of available lookups */ extern unsigned lookup_list_count; /* Number of entries in the list */ extern uschar *lookup_dnssec_authenticated; /* AD status of dns lookup */ diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index 9a65d8b19..dbce3dbaa 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -110,7 +110,7 @@ exim_dbopen(const uschar * name, const uschar * dirname, int flags, unsigned mode) { void * dbp; -DEBUG(D_hints_lookup) +DEBUG(hints_lookup) debug_printf_indent("EXIM_DBOPEN: file <%s> dir <%s> flags=%s\n", name, dirname, flags == O_RDONLY ? "O_RDONLY" @@ -125,7 +125,7 @@ if (is_tainted(name) || is_tainted(dirname)) else dbp = exim_dbopen__(name, dirname, flags, mode); -DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp); +DEBUG(hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", dbp); return dbp; } @@ -134,7 +134,7 @@ exim_dbopen_multi(const uschar * name, const uschar * dirname, int flags, unsigned mode) { void * dbp; -DEBUG(D_hints_lookup) +DEBUG(hints_lookup) debug_printf_indent("EXIM_DBOPEN_MULTI: file <%s> dir <%s> flags=%s\n", name, dirname, flags == O_RDONLY ? "O_RDONLY" @@ -149,20 +149,20 @@ if (is_tainted(name) || is_tainted(dirname)) else dbp = exim_dbopen_multi__(name, dirname, flags, mode); -DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN_MULTI: %p\n", dbp); +DEBUG(hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN_MULTI: %p\n", dbp); return dbp; } static inline void exim_dbclose(EXIM_DB * dbp) { -DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp); +DEBUG(hints_lookup) debug_printf_indent("EXIM_DBCLOSE(%p)\n", dbp); exim_dbclose__(dbp); } static inline void exim_dbclose_multi(EXIM_DB * dbp) { -DEBUG(D_hints_lookup) debug_printf_indent("EXIM_DBCLOSE_MULTI(%p)\n", dbp); +DEBUG(hints_lookup) debug_printf_indent("EXIM_DBCLOSE_MULTI(%p)\n", dbp); exim_dbclose_multi__(dbp); } diff --git a/src/src/hintsdb/hints_bdb.h b/src/src/hintsdb/hints_bdb.h index 85e8984ec..5a5065302 100644 --- a/src/src/hintsdb/hints_bdb.h +++ b/src/src/hintsdb/hints_bdb.h @@ -119,7 +119,7 @@ if (db_create(&b, dbp, 0) == 0) mode) == 0 ) return dbp; - else DEBUG(D_hints_lookup) + else DEBUG(hints_lookup) debug_printf_indent("bdb_open(flags 0x%x mode %04o) %s\n", flags, mode, strerror(errno)); diff --git a/src/src/hintsdb/hints_gdbm.h b/src/src/hintsdb/hints_gdbm.h index 34df8c84f..11a2e655e 100644 --- a/src/src/hintsdb/hints_gdbm.h +++ b/src/src/hintsdb/hints_gdbm.h @@ -63,7 +63,7 @@ if (dbp) if (dbp->gdbm) return dbp; - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("gdbm_open(flags 0x%x mode %04o) %s\n", flags, mode, strerror(errno)); free(dbp); diff --git a/src/src/hintsdb/hints_ndbm.h b/src/src/hintsdb/hints_ndbm.h index ceee975e1..2a28509c7 100644 --- a/src/src/hintsdb/hints_ndbm.h +++ b/src/src/hintsdb/hints_ndbm.h @@ -62,7 +62,7 @@ else if ((res = dbm_open(CS name, flags, mode))) return res; else - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("ndbm_open(flags 0x%x mode %04o) %s\n", flags, mode, strerror(errno)); return NULL; diff --git a/src/src/hintsdb/hints_sqlite.h b/src/src/hintsdb/hints_sqlite.h index 1772a85c7..13c409214 100644 --- a/src/src/hintsdb/hints_sqlite.h +++ b/src/src/hintsdb/hints_sqlite.h @@ -55,7 +55,7 @@ if ((ret = sqlite3_open_v2(CCS name, &dbp, sflags, NULL)) == SQLITE_OK) /* in case we are migrating, drop the old table, return code not needed */ (void) sqlite3_exec(dbp, "DROP TABLE IF EXISTS tbl;", NULL, NULL, NULL); } -else DEBUG(D_hints_lookup) +else DEBUG(hints_lookup) debug_printf_indent("sqlite_open(flags 0x%x mode %04o) %s\n", flags, mode, sqlite3_errmsg(dbp)); return ret == SQLITE_OK ? dbp : NULL; @@ -115,7 +115,7 @@ if (SQLITE_OK != sqlite3_prepare_v2(dbp, query, strlen(query), &stmt, NULL)) } # ifdef SQL_DEBUG -DEBUG(D_hints_lookup) debug_printf_indent("prepared SQL: %s\n", sqlite3_sql(stmt)); +DEBUG(hints_lookup) debug_printf_indent("prepared SQL: %s\n", sqlite3_sql(stmt)); # endif stmt = exim_sqlbind_blob(dbp, stmt, &bindcol, key); @@ -124,7 +124,7 @@ stmt = exim_sqlbind_blob(dbp, stmt, &bindcol, data); # ifdef SQL_DEBUG if (stmt) { - DEBUG(D_hints_lookup) debug_printf_indent("expanded SQL: %s\n", sqlite3_expanded_sql(stmt)); + DEBUG(hints_lookup) debug_printf_indent("expanded SQL: %s\n", sqlite3_expanded_sql(stmt)); } # endif @@ -223,7 +223,7 @@ static inline int exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data) { # ifdef SQL_DEBUG -DEBUG(D_hints_lookup) debug_printf_indent(EXIM_DBTYPE " put: key:%.*W data:%.*W\n", key->len, key->data, data->len, data->data ); +DEBUG(hints_lookup) debug_printf_indent(EXIM_DBTYPE " put: key:%.*W data:%.*W\n", key->len, key->data, data->len, data->data ); # endif (void) exim_s_dbp(dbp, key, data, "INSERT OR REPLACE INTO tblblob (ky, dat) VALUES(?, ?)"); return 0; @@ -261,7 +261,7 @@ EXIM_CURSOR * cursor; cursor = exim_sqlprep(dbp, "SELECT ky FROM tblblob ORDER BY ky", NULL, NULL ); if (!cursor) return NULL; # ifdef SQL_DEBUG -DEBUG(D_hints_lookup) debug_printf_indent("prepared query: %s\n", sqlite3_sql(cursor)); +DEBUG(hints_lookup) debug_printf_indent("prepared query: %s\n", sqlite3_sql(cursor)); # endif return cursor; diff --git a/src/src/hintsdb/hints_tdb.h b/src/src/hintsdb/hints_tdb.h index 388904a55..ac6f62395 100644 --- a/src/src/hintsdb/hints_tdb.h +++ b/src/src/hintsdb/hints_tdb.h @@ -43,12 +43,12 @@ exim_dbopen__(const uschar * name, const uschar * dirname, int flags, EXIM_DB * db = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode); int e; -DEBUG(D_hints_lookup) if (!db) +DEBUG(hints_lookup) if (!db) debug_printf_indent("tdb_open(flags 0x%x mode %04o) %s\n", flags, mode, strerror(errno)); if (!db || tdb_transaction_start(db) == 0) return db; e = errno; -DEBUG(D_hints_lookup) if (db) +DEBUG(hints_lookup) if (db) debug_printf_indent("tdb_transaction_start: %s\n", tdb_errorstr(db)); tdb_close(db); errno = e; @@ -60,7 +60,7 @@ exim_dbopen_multi__(const uschar * name, const uschar * dirname, int flags, unsigned mode) { EXIM_DB * db = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode); -DEBUG(D_hints_lookup) if (!db) +DEBUG(hints_lookup) if (!db) debug_printf_indent("tdb_open(flags 0x%x mode %04o) %s\n", flags, mode, strerror(errno)); return db; @@ -79,7 +79,7 @@ static inline BOOL exim_dbtransaction_start(EXIM_DB * db) { BOOL ok = tdb_transaction_start(db) == 0; -DEBUG(D_hints_lookup) if (!ok) +DEBUG(hints_lookup) if (!ok) debug_printf_indent("tdb_transaction_start: %s\n", tdb_errorstr(db)); return ok; } @@ -88,7 +88,7 @@ static inline void exim_dbtransaction_commit(EXIM_DB * db) { BOOL ok = tdb_transaction_commit(db) == 0; -DEBUG(D_hints_lookup) if (!ok) +DEBUG(hints_lookup) if (!ok) debug_printf_indent("tdb_transaction_commit: %s\n", tdb_errorstr(db)); return; } @@ -100,7 +100,7 @@ static inline int exim_dbput(EXIM_DB * dbp, EXIM_DATUM * key, EXIM_DATUM * data) { int rc = tdb_store(dbp, *key, *data, TDB_REPLACE); -DEBUG(D_hints_lookup) if (rc != 0) +DEBUG(hints_lookup) if (rc != 0) debug_printf_indent("tdb_store: %s\n", tdb_errorstr(dbp)); return rc; } @@ -162,7 +162,7 @@ static inline void exim_dbclose_multi__(EXIM_DB * db) { int rc = tdb_close(db); -DEBUG(D_hints_lookup) if (rc != 0) +DEBUG(hints_lookup) if (rc != 0) debug_printf_indent("tdb_close: %s\n", tdb_errorstr(db)); } @@ -170,10 +170,10 @@ static inline void exim_dbclose__(EXIM_DB * db) { int rc = tdb_transaction_commit(db); -DEBUG(D_hints_lookup) if (rc != 0) +DEBUG(hints_lookup) if (rc != 0) debug_printf_indent("tdb_transaction_commit: %s\n", tdb_errorstr(db)); rc = tdb_close(db); -DEBUG(D_hints_lookup) if (rc != 0) +DEBUG(hints_lookup) if (rc != 0) debug_printf_indent("tdb_close: %s\n", tdb_errorstr(db)); } diff --git a/src/src/host.c b/src/src/host.c index c4ca666cf..5f8f985d4 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -187,7 +187,7 @@ struct hostent *yield; dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss = {0}; -DEBUG(D_host_lookup) +DEBUG(host_lookup) debug_printf_indent("using host_fake_gethostbyname for %s (%s)\n", name, af == AF_INET ? "IPv4" : "IPv6"); @@ -418,7 +418,7 @@ else if (Ustrchr(h->name, ':') == p) h->name = string_copyn(h->name, p - h->name); else return PORT_NONE; -DEBUG(D_route|D_host_lookup) debug_printf_indent("host=%s port=%d\n", h->name, port); +DEBUG(route|host_lookup) debug_printf_indent("host=%s port=%d\n", h->name, port); return port; } @@ -588,7 +588,7 @@ sender_rcvhost = string_copy_perm(rcvhost, TRUE); store_reset(reset_point); -DEBUG(D_host_lookup) +DEBUG(host_lookup) { debug_printf_indent("sender_fullhost = %s\n", sender_fullhost); debug_printf_indent("sender_rcvhost = %s\n", sender_rcvhost); @@ -795,7 +795,7 @@ if (!local_interface_data) else { local_interface_data = add_unique_interface(local_interface_data, ipa); - DEBUG(D_interface) + DEBUG(interface) { debug_printf_indent("Configured local interface: address=%s", ipa->address); if (ipa->port != 0) debug_printf(" port=%d", ipa->port); @@ -1361,13 +1361,13 @@ FOUND_LOCAL: if (!prev) { - HDEBUG(D_host_lookup) debug_printf_indent(h->mx >= 0 + HDEBUG(host_lookup) debug_printf_indent(h->mx >= 0 ? "local host has lowest MX\n" : "local host found for non-MX address\n"); return HOST_FOUND_LOCAL; } -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) { debug_printf_indent("local host in host list - removed hosts:\n"); for (h = prev->next; h != last->next; h = h->next) @@ -1413,7 +1413,7 @@ while (host != *lastptr) if (h->next->address != NULL && Ustrcmp(h->next->address, host->address) == 0) { - DEBUG(D_host_lookup) debug_printf_indent("duplicate IP address %s (MX=%d) " + DEBUG(host_lookup) debug_printf_indent("duplicate IP address %s (MX=%d) " "removed\n", host->address, h->next->mx); if (h->next == *lastptr) *lastptr = h; h->next = h->next->next; @@ -1495,7 +1495,7 @@ if ( slow_lookup_log if (!hosts) { - HDEBUG(D_host_lookup) debug_printf_indent("IP address lookup failed: h_errno=%d\n", + HDEBUG(host_lookup) debug_printf_indent("IP address lookup failed: h_errno=%d\n", h_errno); return (h_errno == TRY_AGAIN || h_errno == NO_RECOVERY) ? DEFER : FAIL; } @@ -1506,7 +1506,7 @@ empty string; in others as a single dot. */ if (!hosts->h_name || !hosts->h_name[0] || hosts->h_name[0] == '.') { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("IP address lookup yielded an empty name: " "treated as non-existent host name\n"); return FAIL; @@ -1596,7 +1596,7 @@ dns_scan dnss = {0}; sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) debug_printf_indent("looking up host name for %s\n", sender_host_address); expand_level++; @@ -1606,7 +1606,7 @@ reserved IP address. */ if (f.running_in_test_harness && Ustrcmp(sender_host_address, "99.99.99.99") == 0) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("Test harness: host name lookup returns DEFER\n"); host_lookup_deferred = TRUE; yield = DEFER; @@ -1639,7 +1639,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) int old_pool = store_pool; sender_host_dnssec = dns_is_secure(dnsa); - DEBUG(D_dns) + DEBUG(dns) debug_printf_indent("Reverse DNS security status: %s\n", sender_host_dnssec ? "DNSSEC verified (AD)" : "unverified"); @@ -1678,13 +1678,13 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) store_release_above(s + (slen = Ustrlen(s)) + 1); if (!*s) { - HDEBUG(D_host_lookup) debug_printf_indent("IP address lookup yielded " + HDEBUG(host_lookup) debug_printf_indent("IP address lookup yielded " "an empty name: treated as non-existent host name\n"); continue; } if (Ustrspn(s, letter_digit_hyphen_dot) != slen) { - HDEBUG(D_host_lookup) debug_printf_indent("IP address lookup yielded " + HDEBUG(host_lookup) debug_printf_indent("IP address lookup yielded " "an illegal name (bad char): treated as non-existent host name\n"); continue; } @@ -1705,7 +1705,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) if (rc == DNS_AGAIN) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("IP address PTR lookup gave temporary error\n"); host_lookup_deferred = TRUE; yield = DEFER; @@ -1717,7 +1717,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) else if (strcmpic(ordername, US"byaddr") == 0) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("IP address lookup using gethostbyaddr()\n"); rc = host_name_lookup_byaddr(); if (rc == DEFER) @@ -1744,7 +1744,7 @@ if (!sender_host_name) goto out; } -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) { uschar ** aliases = sender_host_aliases; debug_printf_indent("IP address lookup yielded %q\n", sender_host_name); @@ -1780,39 +1780,39 @@ for (uschar * hname = sender_host_name; hname; hname = *aliases++) || rc == HOST_FOUND_LOCAL ) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("checking addresses for %s\n", hname); /* If the forward lookup was not secure we cancel the is-secure variable */ - DEBUG(D_dns) debug_printf_indent("Forward DNS security status: %s\n", + DEBUG(dns) debug_printf_indent("Forward DNS security status: %s\n", h.dnssec_used == DS_YES ? "DNSSEC verified (AD)" : "unverified"); if (h.dnssec_used != DS_YES) sender_host_dnssec = FALSE; for (host_item * hh = &h; hh; hh = hh->next) if (host_is_in_net(hh->address, sender_host_address, 0)) { - HDEBUG(D_host_lookup) debug_printf_indent(" %s OK\n", hh->address); + HDEBUG(host_lookup) debug_printf_indent(" %s OK\n", hh->address); ok = TRUE; break; } else - HDEBUG(D_host_lookup) debug_printf_indent(" %s\n", hh->address); + HDEBUG(host_lookup) debug_printf_indent(" %s\n", hh->address); - if (!ok) HDEBUG(D_host_lookup) + if (!ok) HDEBUG(host_lookup) debug_printf_indent("no IP address for %s matched %s\n", hname, sender_host_address); } else if (rc == HOST_FIND_AGAIN) { - HDEBUG(D_host_lookup) debug_printf_indent("temporary error for host name lookup\n"); + HDEBUG(host_lookup) debug_printf_indent("temporary error for host name lookup\n"); host_lookup_deferred = TRUE; sender_host_name = NULL; yield = DEFER; goto out; } else - HDEBUG(D_host_lookup) debug_printf_indent("no IP addresses found for %s\n", hname); + HDEBUG(host_lookup) debug_printf_indent("no IP addresses found for %s\n", hname); /* If this name is no good, and it's the sender name, set it null pro tem; if it's an alias, just remove it from the list. */ @@ -1840,7 +1840,7 @@ if (sender_host_name) { yield = OK; goto out; } /* We have failed to find an address that matches. */ -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) debug_printf_indent("%s does not match any IP address for %s\n", sender_host_address, save_hostname); @@ -2017,7 +2017,7 @@ for (int i = 1; i <= times; default: error = US"?"; break; } - DEBUG(D_host_lookup) debug_printf_indent("%s(af=%s) returned %d (%s)\n", + DEBUG(host_lookup) debug_printf_indent("%s(af=%s) returned %d (%s)\n", f.running_in_test_harness ? "host_fake_gethostbyname" : #if HAVE_IPV6 # if HAVE_GETIPNODEBYNAME @@ -2057,7 +2057,7 @@ for (int i = 1; i <= times; && verify_check_this_host(&ignore_target_hosts, NULL, host->name, text_address, NULL) == OK) { - DEBUG(D_host_lookup) + DEBUG(host_lookup) debug_printf_indent("ignored host %s [%s]\n", host->name, text_address); continue; } @@ -2120,7 +2120,7 @@ if (!host->address) #endif string_sprintf("no IP address found for host %s", host->name); - HDEBUG(D_host_lookup) debug_printf_indent("%s\n", msg); + HDEBUG(host_lookup) debug_printf_indent("%s\n", msg); if (temp_error) goto RETURN_AGAIN; if (host_checking || !f.log_testing_mode) log_write(L_host_lookup_failed, LOG_MAIN, "%s", msg); @@ -2134,7 +2134,7 @@ host_remove_duplicates(host, &last); yield = local_host_check? host_scan_for_local_hosts(host, &last, NULL) : HOST_FOUND; -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) { if (fully_qualified_name) debug_printf_indent("fully qualified name = %s\n", *fully_qualified_name); @@ -2172,7 +2172,7 @@ RETURN_AGAIN: deliver_domain = save; if (rc == OK) { - DEBUG(D_host_lookup) debug_printf_indent("%s is in dns_again_means_nonexist: " + DEBUG(host_lookup) debug_printf_indent("%s is in dns_again_means_nonexist: " "returning HOST_FIND_FAILED\n", host->name); return HOST_FIND_FAILED; } @@ -2297,7 +2297,7 @@ for (; i >= 0; i--) lookup_dnssec_authenticated = !dnssec_request ? NULL : dns_is_secure(dnsa) ? US"yes" : US"no"; - DEBUG(D_dns) + DEBUG(dns) if ( (dnssec_request || dnssec_require) && !dns_is_secure(dnsa) && dns_is_aa(dnsa) @@ -2333,7 +2333,7 @@ for (; i >= 0; i--) { if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf_indent("%s A DNSSEC\n", host->name); + DEBUG(host_lookup) debug_printf_indent("%s A DNSSEC\n", host->name); if (host->dnssec_used == DS_UNK) /* set in host_find_bydns() */ host->dnssec_used = DS_YES; } @@ -2342,13 +2342,13 @@ for (; i >= 0; i--) if (dnssec_require) { dnssec_fail = TRUE; - DEBUG(D_host_lookup) debug_printf_indent("dnssec fail on %s for %.256s", + DEBUG(host_lookup) debug_printf_indent("dnssec fail on %s for %.256s", i>0 ? "AAAA" : "A", host->name); continue; } if (host->dnssec_used == DS_YES) /* set in host_find_bydns() */ { - DEBUG(D_host_lookup) debug_printf_indent("%s A cancel DNSSEC\n", host->name); + DEBUG(host_lookup) debug_printf_indent("%s A cancel DNSSEC\n", host->name); host->dnssec_used = DS_NO; lookup_dnssec_authenticated = US"no"; } @@ -2368,7 +2368,7 @@ for (; i >= 0; i--) { dns_address * da = dns_address_from_rr(dnsa, rr); - DEBUG(D_host_lookup) + DEBUG(host_lookup) if (!da) debug_printf_indent("no addresses extracted from A6 RR for %s\n", host->name); @@ -2382,7 +2382,7 @@ for (; i >= 0; i--) verify_check_this_host(&ignore_target_hosts, NULL, host->name, da->address, NULL) == OK) { - DEBUG(D_host_lookup) + DEBUG(host_lookup) debug_printf_indent("ignored host %s [%s]\n", host->name, da->address); continue; } @@ -2538,7 +2538,7 @@ dns_scan dnss = {0}; BOOL dnssec_require, dnssec_request; dnssec_status_t dnssec; -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) { debug_printf_indent("check dnssec require list\n"); expand_level++; @@ -2547,7 +2547,7 @@ dnssec_require = dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->require, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK; -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) { expand_level--; debug_printf_indent("check dnssec request list\n"); @@ -2557,7 +2557,7 @@ dnssec_request = dnssec_require || ( dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->request, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK); -HDEBUG(D_host_lookup) +HDEBUG(host_lookup) expand_level--; /* Set the default fully qualified name to the incoming name, initialize the @@ -2597,7 +2597,7 @@ if (whichrrs & HOST_FIND_BY_SRV) rc = dns_lookup_timerwrap(dnsa, temp_fully_qualified_name, ind_type, CUSS &temp_fully_qualified_name); - DEBUG(D_dns) + DEBUG(dns) if ((dnssec_request || dnssec_require) && !dns_is_secure(dnsa) && dns_is_aa(dnsa)) @@ -2630,7 +2630,7 @@ if (whichrrs & HOST_FIND_BY_SRV) &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } - DEBUG(D_host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " + DEBUG(host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " "(domain in srv_fail_domains)\n", rc == DNS_FAIL ? "FAIL":"AGAIN"); } else if (rc == DNS_SUCCEED) @@ -2658,7 +2658,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) lookup_dnssec_authenticated = NULL; rc = dns_lookup_timerwrap(dnsa, host->name, ind_type, fully_qualified_name); - DEBUG(D_dns) + DEBUG(dns) if ( (dnssec_request || dnssec_require) && !dns_is_secure(dnsa) && dns_is_aa(dnsa)) @@ -2667,7 +2667,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) if (dnssec_request) if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) + DEBUG(host_lookup) debug_printf_indent("%s (MX resp) DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } @@ -2685,7 +2685,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) case DNS_SUCCEED: if (!dnssec_require || dns_is_secure(dnsa)) break; - DEBUG(D_host_lookup) + DEBUG(host_lookup) debug_printf_indent("dnssec fail on MX for %.256s\n", host->name); #ifndef STAND_ALONE if (match_isinlist(host->name, CUSS &mx_fail_domains, 0, @@ -2702,7 +2702,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } - DEBUG(D_host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " + DEBUG(host_lookup) debug_printf_indent("DNS_%s treated as DNS_NODATA " "(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); break; } @@ -2716,7 +2716,7 @@ if (rc != DNS_SUCCEED) { if (!(whichrrs & (HOST_FIND_BY_A | HOST_FIND_BY_AAAA))) { - DEBUG(D_host_lookup) debug_printf_indent("Address records are not being sought\n"); + DEBUG(host_lookup) debug_printf_indent("Address records are not being sought\n"); yield = HOST_FIND_FAILED; goto out; } @@ -2743,7 +2743,7 @@ if (rc != DNS_SUCCEED) else if (rc == HOST_IGNORED) rc = HOST_FIND_FAILED; /* No special action */ - DEBUG(D_host_lookup) + DEBUG(host_lookup) if (host->address) { if (fully_qualified_name) @@ -2834,7 +2834,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); for (h = host; h != last->next; prev = h, h = h->next) if (strcmpic(h->name, data) == 0) { - DEBUG(D_host_lookup) + DEBUG(host_lookup) debug_printf_indent("discarded duplicate host %s (MX=%d)\n", data, precedence > h->mx ? precedence : h->mx); if (precedence >= h->mx) goto NEXT_MX_RR; /* Skip greater precedence */ @@ -2935,12 +2935,12 @@ if (ind_type == T_SRV) if (host == last && host->name[0] == 0) { - DEBUG(D_host_lookup) debug_printf_indent("the single SRV record is \".\"\n"); + DEBUG(host_lookup) debug_printf_indent("the single SRV record is \".\"\n"); yield = HOST_FIND_FAILED; goto out; } - DEBUG(D_host_lookup) + DEBUG(host_lookup) { debug_printf_indent("original ordering of hosts from SRV records:\n"); for (h = host; h != last->next; h = h->next) @@ -3152,7 +3152,7 @@ host_remove_duplicates(host, &last); rc = host_scan_for_local_hosts(host, &last, removed); if (rc != HOST_FIND_FAILED) yield = rc; -DEBUG(D_host_lookup) +DEBUG(host_lookup) { if (fully_qualified_name) debug_printf_indent("fully qualified name = %s\n", *fully_qualified_name); @@ -3219,7 +3219,7 @@ BOOL sec; rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname); sec = dns_is_secure(dnsa); -DEBUG(D_transport) +DEBUG(transport) debug_printf_indent("TLSA lookup ret %s %sDNSSEC\n", dns_rc_names[rc], sec ? "" : "not "); switch (rc) @@ -3230,7 +3230,7 @@ switch (rc) case DNS_SUCCEED: if (sec) { - DEBUG(D_transport) + DEBUG(transport) { dns_scan dnss = {0}; for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; @@ -3290,14 +3290,14 @@ disable_ipv6 = FALSE; primary_hostname = US""; store_init(); store_pool = POOL_MAIN; -debug_selector = D_host_lookup|D_interface; +debug_modify_channel(US"+host_lookup +interface"); debug_file = stdout; debug_fd = fileno(debug_file); printf("Exim stand-alone host functions test\n"); host_find_interfaces(); -debug_selector = D_host_lookup | D_dns; +debug_modify_channel(US"-interface +dns"); if (argc > 1) primary_hostname = argv[1]; diff --git a/src/src/ip.c b/src/src/ip.c index 80038e3ec..d8772287f 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -249,7 +249,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) /* seen for with-data, experimental TFO option, with-cookie case */ /* seen for with-data, proper TFO opt, with-cookie case */ { - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf(" TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); /*XXX also seen on successful TFO, sigh */ @@ -263,7 +263,7 @@ if (fastopen_blob && f.tcp_fastopen_ok) /* seen for with-data, proper TFO opt, cookie-req */ /* with netwk delay, post-conn tcp_info sees unacked 1 for R, 2 for C; code in smtp_out.c */ /* ? older Experimental TFO option behaviour ? */ - DEBUG(D_transport|D_v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n", + DEBUG(transport|v) debug_printf(" TFO mode sendto, %s data: EINPROGRESS\n", fastopen_blob->len > 0 ? "with" : "no"); if (!fastopen_blob->data) { @@ -275,12 +275,12 @@ if (fastopen_blob && f.tcp_fastopen_ok) break; case EOPNOTSUPP: - DEBUG(D_transport) + DEBUG(transport) debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); goto legacy_connect; case EPIPE: - DEBUG(D_transport) + DEBUG(transport) debug_printf("Tried TCP Fast Open but kernel too old to support it\n"); goto legacy_connect; } @@ -290,14 +290,14 @@ if (fastopen_blob && f.tcp_fastopen_ok) if (setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)) < 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n"); goto legacy_connect; } if ((rc = sendto(sock, fastopen_blob->data, fastopen_blob->len, 0, s_ptr, s_len)) >= 0) { - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf(" TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; @@ -315,18 +315,18 @@ if (fastopen_blob && f.tcp_fastopen_ok) if ((rc = connectx(sock, &ends, SAE_ASSOCID_ANY, CONNECT_DATA_IDEMPOTENT, &iov, 1, &len, NULL)) == 0) { - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf(" TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); tcp_out_fastopen = fastopen_blob->len > 0 ? TFO_ATTEMPTED_DATA : TFO_ATTEMPTED_NODATA; if (len != fastopen_blob->len) - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf(" only queued %lu data!\n", (unsigned long)len); } else if (errno == EINPROGRESS) { - DEBUG(D_transport|D_v) debug_printf(" TFO mode connectx, %s data: EINPROGRESS\n", + DEBUG(transport|v) debug_printf(" TFO mode connectx, %s data: EINPROGRESS\n", fastopen_blob->len > 0 ? "with" : "no"); if (!fastopen_blob->data) { @@ -345,7 +345,7 @@ else legacy_connect: #endif - DEBUG(D_transport|D_v) if (fastopen_blob) + DEBUG(transport|v) if (fastopen_blob) debug_printf(" non-TFO mode connection attempt to %s, %lu data\n", address, (unsigned long)fastopen_blob->len); if ((rc = connect(sock, s_ptr, s_len)) >= 0) @@ -604,7 +604,7 @@ if (time_left <= 0) do { - /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/ + /*DEBUG(transport) debug_printf("waiting for data on fd\n");*/ rc = poll_one_fd(fd, POLLIN, time_left * 1000); /* If some interrupt arrived, just retry. We presume this to be rare, @@ -619,7 +619,7 @@ do if (rc < 0 && errno == EINTR) { - DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n"); + DEBUG(transport) debug_printf("EINTR while waiting for socket data\n"); /* Watch out, 'continue' jumps to the condition, not to the loops top */ if ((time_left = timelimit - time(NULL)) > 0) continue; diff --git a/src/src/local_scan.h b/src/src/local_scan.h index ad2601c38..f3a2e8257 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -44,8 +44,8 @@ ABI is changed in a non backward compatible way. The minor number is increased each time a new feature is added (in a way that doesn't break backward compatibility). */ -#define LOCAL_SCAN_ABI_VERSION_MAJOR 7 -#define LOCAL_SCAN_ABI_VERSION_MINOR 1 +#define LOCAL_SCAN_ABI_VERSION_MAJOR 8 +#define LOCAL_SCAN_ABI_VERSION_MINOR 0 #define LOCAL_SCAN_ABI_VERSION \ LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR @@ -95,10 +95,10 @@ codes that dynamically-loaded ${dlfunc functions must return. */ #define LOG_REJECT 16 /* Write to the reject log, with headers */ -/* Accessible debugging bits */ +/* Accessible debugging channels */ -#define D_v 0x00000001 -#define D_local_scan 0x00000002 +#define D_v US"v" +#define D_local_scan US"local_scan" /* Option types that can be used for local_scan_options. The boolean ones @@ -166,8 +166,6 @@ typedef struct recipient_item { /* Global variables that are documented as visible in the function. */ -extern bitmask_word_t debug_selector; /* Debugging bits */ - extern int body_linecount; /* Line count in body */ extern int body_zerocount; /* Binary zero count in body */ extern uschar *expand_string_message; /* Error info for failing expansion */ @@ -193,7 +191,9 @@ extern BOOL smtp_input; /* TRUE if input is via SMTP */ /* Functions that are documented as visible in local_scan(). */ extern int child_close(pid_t, int); +extern void debug_modify_channel(const uschar *); extern void debug_printf(const char *, ...) PRINTF_FUNCTION(1,2); +extern BOOL is_debug(const uschar *); extern const uschar * expand_string_2(const uschar *, BOOL *); static inline uschar * expand_nc_string(uschar * s) diff --git a/src/src/log.c b/src/src/log.c index 0793b3269..49caac524 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -286,7 +286,7 @@ if (fd < 0 && errno == ENOENT) const uschar * lastslash = Ustrrchr(name, '/'); uschar * dirname = string_copyn(name, lastslash - name); created = directory_make(NULL, dirname, LOG_DIRECTORY_MODE, FALSE); - DEBUG(D_any) + DEBUG(any) if (created) debug_printf("created log directory %s\n", dirname); else @@ -847,6 +847,7 @@ log_vwrite(bitmask_word_t selector, int flags, const char * format, va_list ap) { int paniclogfd; ssize_t written_len; +BOOL will_log = FALSE; gstring gs = { .size = LOG_BUFFER_SIZE-2 }, * g = &gs; /* If panic_recurseflag is set, we have failed to open the panic log. This is @@ -956,19 +957,16 @@ if (flags & LOG_PANIC && dtrigger_selector & BIT(DTi_panictrigger)) /* If debugging, show all log entries, but don't show headers. Do it all in one go so that it doesn't get split when multi-processing. */ -DEBUG(D_any|D_v) +DEBUG(any|v) { va_list aq; string_fmt_append_noextend(g, "LOG:"); /* Show the selector that was passed into the call. */ - for (int i = 0; i < log_options_count; i++) - { - unsigned int bitnum = log_options[i].bit; - if (bitnum < BITWORDSIZE && selector == BIT(bitnum)) - string_fmt_append_noextend(g, " %s", log_options[i].name); - } + for (unsigned bitnum = 0; bitnum < logwrite_options_count; bitnum++) + if (bitnum < BITWORDSIZE && selector & BIT(bitnum)) + string_fmt_append_noextend(g, " %s", logwrite_options[bitnum].name); string_fmt_append_noextend(g, "%s%s%s%s\n ", flags & LOG_MAIN ? " MAIN" : "", @@ -1006,7 +1004,7 @@ if (!(flags & (LOG_MAIN|LOG_PANIC|LOG_REJECT))) if (f.disable_logging) { - DEBUG(D_any) debug_printf("log writing disabled\n"); + DEBUG(any) debug_printf("log writing disabled\n"); if ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE) exim_exit(EXIT_FAILURE); return; } @@ -1072,18 +1070,34 @@ gs.size = LOG_BUFFER_SIZE; string_fmt_append_noextend(g, "\n"); string_from_gstring(g); +/* See if the selector means we will log, given the enabled channels */ + +if (!selector) + will_log = TRUE; +else while (selector) + { + bitmask_word_t w = selector & ~(selector - 1); /* lowest set bit */ + unsigned bitnum = 0; + /* This relies on the ordering of logwrite_options[] */ + while (BIT(bitnum) != w) bitnum++; + if (bit_test(log_selector, logwrite_options[bitnum].logchan_bit)) + { + will_log = TRUE; + break; + } + selector &= ~w; /* clear that bit */ + } + /* Handle loggable errors when running a utility, or when address testing. Write to log_stderr unless debugging (when it will already have been written), or unless there is no log_stderr (expn called from daemon, for example). */ if (!f.really_exim || f.log_testing_mode) { - if ( !debug_selector - && log_stderr - && (selector == 0 || (selector & log_selector[0]) != 0) - ) + if (!ANY_DEBUG && log_stderr && will_log) if (host_checking) - fprintf(log_stderr, "LOG: %s", CS(log_buffer + 20)); /* no timestamp */ +/*XXX +20 wrong if logging millisec or with-TZ */ + fprintf(log_stderr, "LOG: %s", CS log_buffer + 20); /* no timestamp */ else fprintf(log_stderr, "%s", CS log_buffer); @@ -1097,8 +1111,7 @@ been opened, but we don't want to keep on writing to it for too long after it has been renamed. Therefore, do a stat() and see if the inode has changed, and if so, re-open. */ -if ( flags & LOG_MAIN - && (!selector || selector & log_selector[0])) +if (flags & LOG_MAIN && will_log) { if ( logging_mode & LOG_MODE_SYSLOG && (syslog_duplication || !(flags & (LOG_REJECT|LOG_PANIC)))) @@ -1278,7 +1291,7 @@ if (flags & LOG_PANIC) if (panic_save_buffer) if (write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer)) < 0) - DEBUG(D_any) debug_printf("sucks"); + DEBUG(any) debug_printf("sucks"); if ( (written_len = write_gstring_to_fd_buf(paniclogfd, g)) != gstring_length(g)) @@ -1348,37 +1361,43 @@ syslog_open = FALSE; /************************************************* -* Multi-bit set or clear * +* Decode bit settings for log/debug * *************************************************/ -/* These functions take a list of bit indexes (terminated by -1) and -clear or set the corresponding bits in the selector. +/* Locate a word in a channel list. -Arguments: - selector address of the bit string - selsize number of words in the bit string - bits list of bits to set +Arguments: word The name to search for + len Number of chars in name + names List of channel names + count Number of list entries, incl. leading specials +Return index, or zero for not-found */ -void -bits_clear(bitmask_word_t * selector, size_t selsize, int * bits) +unsigned +chan_name_to_idx(const uschar * word, unsigned len, + const uschar * const * names, unsigned count) { -for(; *bits != -1; ++bits) - BIT_CLEAR(selector, selsize, *bits); -} - -void -bits_set(bitmask_word_t * selector, size_t selsize, int * bits) -{ -for(; *bits != -1; ++bits) - BIT_SET(selector, selsize, *bits); -} +const uschar * const * start = names + BIT_TABLE_IDX_USABLE; +const uschar * const * end = names + count; +while (start < end) + { + const uschar * const * middle = start + (end - start)/2; + int c = Ustrncmp(word, *middle, len); + if (c == 0) + if ((*middle)[len]) + c = -1; + else + return middle - names; /* Found */ + if (c < 0) + end = middle; + else + start = middle + 1; + } /* Loop to match selector name */ -/************************************************* -* Decode bit settings for log/debug * -*************************************************/ +return 0; /* Fail */ +} /* This function decodes a string containing bit settings in the form of +name and/or -name sequences, and sets/unsets bits in a bit string accordingly. It @@ -1386,9 +1405,11 @@ also recognizes a numeric setting of the form =, but this is not intended for user use. It's an easy way for Exim to pass the debug settings when it is re-exec'ed. -The option table is a list of names and bit indexes. The index -1 -means "set all bits, except for those listed in notall". The notall -list is terminated by -1. +The option table is a list of names, with offsets corresponding to bit numbers +in the bit string. The name "all" means "set all bits, except for those listed +in notall". The notall list is terminated by -1. + +For the debug bitstring we also set various summary bits. The action taken for bad values varies depending upon why we're here. For log messages, or if the debugging is triggered from config, then we write @@ -1398,20 +1419,19 @@ we treat it as an unknown option: error message to stderr and die. Arguments: selector address of the bit string selsize number of words in the bit string - notall list of bit-numbers to exclude from "all" + notall list of words to exclude from "all" string the configured string - options the table of option names + options table of option names count size of table - which "log" or "debug" - flags DEBUG_FROM_CONFIG + flags DCB_LOG, DCB_DEBUG, DCB_FROM_CONFIG Returns: nothing on success - bomb out on failure */ void -decode_bits(bitmask_word_t * selector, size_t selsize, int * notall, - const uschar * string, bit_table * options, int count, uschar * which, - int flags) +decode_bits(bitmask_word_t * selector, size_t selsize, + const uschar * const * notall, const uschar * string, + const uschar * const * options, int count, int flags) { uschar * errmsg; @@ -1420,14 +1440,27 @@ if (!string) return; if (*string == '=') { int n; + const uschar * s = string + 1; + memset(selector, 0, sizeof(*selector)*selsize); - if ( sscanf(CCS string+1, SC_EXIM_BITMASK "%n", selector, &n) == 1 - && !string[1+n]) - return; - errmsg = string_sprintf("malformed numeric %s_selector setting: %q (n %d, fmt %q)", which, - string, n, SC_EXIM_BITMASK); - goto ERROR_RETURN; + for (unsigned idx = 0; + idx < selsize + && sscanf(CCS s, SC_EXIM_BITMASK "%n", selector+idx, &n) == 1; + idx++) + { + s += n; + switch (*s) + { + case '\0': return; /* no more words; finished */ + case ',': s++; break; /* next word */ + default: + errmsg = string_sprintf( + "malformed numeric %s_selector setting: %q (n %d, fmt %q)", + flags & DCB_LOG ? "log" : "debug", string, n, SC_EXIM_BITMASK); + goto ERROR_RETURN; + } + } } /* Handle symbolic setting */ @@ -1437,69 +1470,74 @@ else for(;;) BOOL adding; const uschar * s; int len; - bit_table * start, * end; Uskip_whitespace(&string); - if (!*string) return; - - if (*string != '+' && *string != '-') + switch (*string++) { - errmsg = string_sprintf("malformed %s_selector setting: " - "+ or - expected but found %q", which, string); - goto ERROR_RETURN; + case '\0': return; /* No more string to handle */ + case '+': adding = TRUE; break; + case '-': adding = FALSE; break; + default: errmsg = string_sprintf("malformed %s_selector setting: " + "+ or - expected but found %q", flags & DCB_LOG ? "log" : "debug", string); + goto ERROR_RETURN; } - adding = *string++ == '+'; - s = string; - while (isalnum(*string) || *string == '_') string++; + for (s = string; isalnum(*string) || *string == '_'; ) string++; len = string - s; - start = options; - end = options + count; + if (Ustrncmp(s, "all", len) == 0) + if (adding) + { + memset(selector, -1, sizeof(*selector)*selsize); + for (const uschar * const * p = notall; *p; p++) + bit_clear(selector, chan_name_to_idx(*p, Ustrlen(*p), options, count)); + } + else + memset(selector, 0, sizeof(*selector)*selsize); - while (start < end) + else { - bit_table *middle = start + (end - start)/2; - int c = Ustrncmp(s, middle->name, len); - if (c == 0) - if (middle->name[len] != 0) c = -1; else - { - unsigned int bit = middle->bit; + unsigned idx = chan_name_to_idx(s, len, options, count); + if (!idx) + { + errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", flags & DCB_LOG ? "log" : "debug", + adding ? '+' : '-', len, s); + goto ERROR_RETURN; + } - if (bit == -1) - { - if (adding) - { - memset(selector, -1, sizeof(*selector)*selsize); - bits_clear(selector, selsize, notall); - } - else - memset(selector, 0, sizeof(*selector)*selsize); - } - else if (adding) - BIT_SET(selector, selsize, bit); - else - BIT_CLEAR(selector, selsize, bit); + if (adding) + { + bit_set(selector, idx); - break; /* Out of loop to match selector name */ - } - if (c < 0) end = middle; else start = middle + 1; - } /* Loop to match selector name */ + if (flags & DCB_DEBUG) + { + bit_set(selector, BIT_TABLE_IDX_NONZERO); - if (start >= end) - { - errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which, - adding ? '+' : '-', len, s); - goto ERROR_RETURN; + if (Ustrncmp(s, "v", len) != 0) + { + bit_set(selector, BIT_TABLE_IDX_NONVERB); + + /*XXX this might be a table in globals.c */ + if ( Ustrncmp(s, "pid", len) != 0 && Ustrncmp(s, "noutf8", len) != 0 + && Ustrncmp(s, "timestamp", len) != 0) + bit_set(selector, BIT_TABLE_IDX_IS_ANY); + } + } + } + else + bit_clear(selector, idx); } } /* Loop for selector names */ +/*NOTREACHED*/ +return; /* stupid compiler */ + /* Handle disasters */ ERROR_RETURN: -if (Ustrcmp(which, "debug") == 0) +if (flags & DCB_DEBUG) { - if (flags & DEBUG_FROM_CONFIG) + if (flags & DCB_FROM_CONFIG) { log_write(0, LOG_CONFIG|LOG_PANIC, "%s", errmsg); return; @@ -1507,10 +1545,38 @@ if (Ustrcmp(which, "debug") == 0) fprintf(stderr, "exim: %s\n", errmsg); exim_exit(EXIT_FAILURE); } -else log_write_die(0, LOG_CONFIG, "%s", errmsg); +else + log_write_die(0, LOG_CONFIG, "%s", errmsg); +} + + +/* Channel configuration */ + +void +logging_modify_channels(const uschar * string) +{ +decode_bits(log_selector, log_selector_size, log_notall_names, string, + log_chan_names, log_options_count, DCB_LOG); } +/* Called during init. +We could instead just feed one long string to logging_enable_channels(). +We might save some startup time by doing this in buildconfig. +*/ + +void +logging_set_defaults(void) +{ +memset(log_selector, 0, sizeof(bitmask_word_t) * log_selector_size); +bit_set(log_selector, BIT_TABLE_IDX_NONZERO); + +for (const uschar * const * p = log_default_names; + p < log_default_names + log_default_count; p++) + bit_set(log_selector, + chan_name_to_idx(*p, Ustrlen(*p), log_chan_names, log_options_count)); +} + /************************************************* * Activate a debug logfile (late) * @@ -1552,10 +1618,9 @@ if (tag_name && (Ustrchr(tag_name, '/') != NULL)) return; } -debug_selector = D_default; +debug_set_default_bits(&debug_selector); if (opts) - decode_bits(&debug_selector, 1, debug_notall, opts, - debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG); + debug_decode_bits(&debug_selector, opts, DCB_FROM_CONFIG); /* When activating from a transport process we may never have logged at all resulting in certain setup not having been done. Hack this for now so we @@ -1581,10 +1646,10 @@ if (debug_fd < 0) Ustrncpy(debuglog_name, filename, sizeof(debuglog_name)-1); if ((debug_fd = log_open_as_exim(filename)) >= 0) debug_file = fdopen(debug_fd, "w"); - DEBUG(D_deliver) debug_print_ids(US"debug enabled by spoolfile\n"); + DEBUG(deliver) debug_print_ids(US"debug enabled by spoolfile\n"); } /* -else DEBUG(D_deliver) +else DEBUG(deliver) debug_printf("debug already active; ignoring spoolfile '%s'\n", filename); */ } @@ -1597,7 +1662,7 @@ debug_printf("debug terminated by %s\n", kill ? "kill" : "stop"); debug_pretrigger_discard(); if (!debug_file || !debuglog_name[0]) return; -debug_selector = 0; +debug_decode_bits(&debug_selector, US"=0", 0); fclose(debug_file); debug_file = NULL; debug_fd = -1; @@ -1606,5 +1671,5 @@ if (kill) unlink_log(lt_debug); /* End of log.c */ -/* vi: sw ai sw=2 +/* vi: aw ai sw=2 */ diff --git a/src/src/lookups/cdb.c b/src/src/lookups/cdb.c index 98ff462a3..0a91f640a 100644 --- a/src/src/lookups/cdb.c +++ b/src/src/lookups/cdb.c @@ -206,7 +206,7 @@ if ((mapbuf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fileno, 0)) /* If we got here the map failed. Basically we can ignore this since we fall back to slower methods.... However lets debug log it... */ -DEBUG(D_lookup) debug_printf_indent("cdb mmap failed - %d\n", errno); +DEBUG(lookup) debug_printf_indent("cdb mmap failed - %d\n", errno); #endif /* HAVE_MMAP */ /* In this case we have either not got MMAP allowed, or it failed */ @@ -293,7 +293,7 @@ if ((hash_offset + (hash_offlen * CDB_HASH_ENTRY)) > cdbp->filelen) { *errmsg = string_sprintf("cdb: corrupt cdb file %s (too short)", filename); - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c index 58a839e84..4108d024b 100644 --- a/src/src/lookups/dbmdb.c +++ b/src/src/lookups/dbmdb.c @@ -182,7 +182,7 @@ if (key_p == key_buffer) empty element to put one in. Boundary: key length 1, is a NULL */ key_item_len = key_p - key_buffer - 1; -DEBUG(D_lookup) debug_printf_indent("NUL-joined key length: %d\n", key_item_len); +DEBUG(lookup) debug_printf_indent("NUL-joined key length: %d\n", key_item_len); /* beware that dbmdb_find() adds 1 to length to get back terminating NUL, so because we've calculated the real length, we need to subtract one more here */ diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index a17264501..ef541bdf0 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -323,7 +323,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) do { - DEBUG(D_lookup) debug_printf_indent("dnsdb key: %s\n", domain); + DEBUG(lookup) debug_printf_indent("dnsdb key: %s\n", domain); /* Do the lookup and sort out the result. There are four special types that are handled specially: T_CSA, T_ZNS, T_ADDRESSES and T_MXH. diff --git a/src/src/lookups/json.c b/src/src/lookups/json.c index 92da9b9cb..e257120e6 100644 --- a/src/src/lookups/json.c +++ b/src/src/lookups/json.c @@ -105,7 +105,7 @@ for (int k = 1; (key = string_nextinlist(&keystring, &sep, NULL, 0)); k++) : json_object_get(j, CCS key) ) ) { - DEBUG(D_lookup) debug_printf_indent("%s, for key %d: '%s'\n", + DEBUG(lookup) debug_printf_indent("%s, for key %d: '%s'\n", numeric ? US"bad index, or not json array" : US"no such key, or not json object", diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index 06b82aa4c..29f9f5a1d 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -181,7 +181,7 @@ int rescount = 0; BOOL attribute_found = FALSE; BOOL ldapi = FALSE; -DEBUG(D_lookup) debug_printf_indent("perform_ldap_search:" +DEBUG(lookup) debug_printf_indent("perform_ldap_search:" " ldap%s URL = %q server=%s port=%d " "sizelimit=%d timelimit=%d tcplimit=%d\n", search_type == SEARCH_LDAP_MULTIPLE ? "m" : @@ -225,7 +225,7 @@ else port = ludp->lud_port; } -DEBUG(D_lookup) debug_printf_indent("after ldap_url_parse: host=%s port=%d\n", +DEBUG(lookup) debug_printf_indent("after ldap_url_parse: host=%s port=%d\n", host, port); if (port == 0) port = LDAP_PORT; /* Default if none given */ @@ -347,7 +347,7 @@ if (!lcp) { const uschar * s = string_from_gstring(g); - DEBUG(D_lookup) debug_printf_indent("ldap_initialize with URL %s\n", s); + DEBUG(lookup) debug_printf_indent("ldap_initialize with URL %s\n", s); if ((rc = ldap_initialize(&ld, CS s)) != LDAP_SUCCESS) { *errmsg = string_sprintf("ldap_initialize: (error %d) URL %q\n", @@ -423,7 +423,7 @@ if (!lcp) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&eldap_version); #endif - DEBUG(D_lookup) debug_printf_indent("initialized for LDAP (v%d) server %s%s\n", + DEBUG(lookup) debug_printf_indent("initialized for LDAP (v%d) server %s%s\n", eldap_version, host, porttext); /* If not using ldapi and TLS is available, set appropriate TLS options: hard @@ -443,7 +443,7 @@ if (!lcp) : Ustrcmp(eldap_require_cert, "try") == 0 ? LDAP_OPT_X_TLS_TRY : LDAP_OPT_X_TLS_NEVER; - DEBUG(D_lookup) debug_printf_indent( + DEBUG(lookup) debug_printf_indent( "Require certificate overrides LDAP_OPT_X_TLS option (%d)\n", tls_option); } @@ -452,13 +452,13 @@ if (!lcp) if (strncmp(ludp->lud_scheme, "ldaps", 5) == 0) { tls_option = LDAP_OPT_X_TLS_HARD; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("LDAP_OPT_X_TLS_HARD set due to ldaps:// URI\n"); } else { tls_option = LDAP_OPT_X_TLS_TRY; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("LDAP_OPT_X_TLS_TRY set due to ldap:// URI\n"); } ldap_set_option(ld, LDAP_OPT_X_TLS, (void *)&tls_option); @@ -501,14 +501,14 @@ if (!lcp) * default that loaded at instantiation). */ rc = ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_REQUIRE_CERT, &cert_option); if (rc) - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("Unable to set TLS require cert_option(%d) globally: %s\n", cert_option, ldap_err2string(rc)); } #endif #ifdef LDAP_OPT_X_TLS_NEWCTX if ((rc = ldap_set_option(ldsetctx, LDAP_OPT_X_TLS_NEWCTX, &am_server))) - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("Unable to reload TLS context %d: %s\n", rc, ldap_err2string(rc)); #endif @@ -530,7 +530,7 @@ if (!lcp) /* Found cached connection */ else - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("re-using cached connection to LDAP server %s%s\n", host, porttext); @@ -546,7 +546,7 @@ if ( !lcp->bound || lcp->password && password && Ustrcmp(lcp->password, password) != 0 ) { - DEBUG(D_lookup) debug_printf_indent("%sbinding with user=%s password=%s\n", + DEBUG(lookup) debug_printf_indent("%sbinding with user=%s password=%s\n", lcp->bound ? "re-" : "", user, password); if (eldap_start_tls && !lcp->is_start_tls_called && !ldapi) @@ -565,7 +565,7 @@ if ( !lcp->bound } lcp->is_start_tls_called = TRUE; #else - DEBUG(D_lookup) debug_printf_indent("TLS initiation not supported with this Exim" + DEBUG(lookup) debug_printf_indent("TLS initiation not supported with this Exim" " and your LDAP library.\n"); #endif } @@ -593,7 +593,7 @@ if ( !lcp->bound if (search_type == SEARCH_LDAP_AUTH && rc == LDAP_INVALID_CREDENTIALS) { - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("Invalid credentials: ldapauth returns FAIL\n"); error_yield = FAIL; goto RETURN_ERROR_NOMSG; @@ -623,7 +623,7 @@ if ( !lcp->bound if (search_type == SEARCH_LDAP_AUTH) { - DEBUG(D_lookup) debug_printf_indent("Bind succeeded: ldapauth returns OK\n"); + DEBUG(lookup) debug_printf_indent("Bind succeeded: ldapauth returns OK\n"); *res = US""; goto RETURN_OK; } @@ -656,7 +656,7 @@ ldap_set_option(lcp->ld, LDAP_OPT_REFERRALS, referrals); /* Start the search on the server. */ -DEBUG(D_lookup) debug_printf_indent("Start search\n"); +DEBUG(lookup) debug_printf_indent("Start search\n"); msgid = ldap_search(lcp->ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0); @@ -688,7 +688,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == then we get two entries, one for A and one for B. Here we just count the values per entry */ - DEBUG(D_lookup) debug_printf_indent("LDAP result loop\n"); + DEBUG(lookup) debug_printf_indent("LDAP result loop\n"); for(e = ldap_first_entry(lcp->ld, result), valuecount = 0; e; @@ -697,7 +697,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == uschar *new_dn; BOOL insert_space = FALSE; - DEBUG(D_lookup) debug_printf_indent("LDAP entry loop\n"); + DEBUG(lookup) debug_printf_indent("LDAP entry loop\n"); rescount++; /* Count results */ @@ -746,7 +746,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == else for (uschar * attr = US ldap_first_attribute(lcp->ld, e, &ber); attr; attr = US ldap_next_attribute(lcp->ld, e, ber)) { - DEBUG(D_lookup) debug_printf_indent("LDAP attr loop\n"); + DEBUG(lookup) debug_printf_indent("LDAP attr loop\n"); /* In case of attrs_requested == 1 we just count the values, in all other cases (0, >1) we count the values per attribute */ @@ -774,7 +774,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == int len = Ustrlen(value); ++valuecount; - DEBUG(D_lookup) debug_printf_indent("LDAP value loop %s:%s\n", attr, value); + DEBUG(lookup) debug_printf_indent("LDAP value loop %s:%s\n", attr, value); /* In case we requested one attribute only but got several times into that attr loop, we need to append the additional values. @@ -867,7 +867,7 @@ if (dn) #endif } -DEBUG(D_lookup) debug_printf_indent("search ended by ldap_result yielding %d\n",rc); +DEBUG(lookup) debug_printf_indent("search ended by ldap_result yielding %d\n",rc); if (rc == 0) { @@ -889,7 +889,7 @@ methods of handling error codes and generating error messages. */ if (rc == -1 || !result) { int err; - DEBUG(D_lookup) debug_printf_indent("ldap_result failed\n"); + DEBUG(lookup) debug_printf_indent("ldap_result failed\n"); #if defined LDAP_LIB_SOLARIS || defined LDAP_LIB_OPENLDAP2 ldap_get_option(lcp->ld, LDAP_OPT_ERROR_NUMBER, &err); @@ -932,7 +932,7 @@ We need to parse the message to find out exactly what's happened. */ ldap_rc = rc; ldap_parse_rc = ldap_parse_result(lcp->ld, result, &rc, CSS &matched, CSS &error2, NULL, NULL, 0); - DEBUG(D_lookup) debug_printf_indent("ldap_parse_result: %d\n", ldap_parse_rc); + DEBUG(lookup) debug_printf_indent("ldap_parse_result: %d\n", ldap_parse_rc); if (ldap_parse_rc < 0 && (ldap_parse_rc != LDAP_NO_RESULTS_RETURNED #ifdef LDAP_RES_SEARCH_REFERENCE @@ -974,7 +974,7 @@ We need to parse the message to find out exactly what's happened. */ the lookup, so return DEFER (which is the default in error_yield). */ -DEBUG(D_lookup) debug_printf_indent("ldap_parse_result yielded %d: %s\n", +DEBUG(lookup) debug_printf_indent("ldap_parse_result yielded %d: %s\n", rc, ldap_err2string(rc)); if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED @@ -1000,7 +1000,7 @@ if (rc != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED #endif { - DEBUG(D_lookup) debug_printf_indent("lookup failure forced\n"); + DEBUG(lookup) debug_printf_indent("lookup failure forced\n"); error_yield = FAIL; } goto RETURN_ERROR; @@ -1036,7 +1036,7 @@ if (!attribute_found) /* Otherwise, it's all worked */ -DEBUG(D_lookup) debug_printf_indent("LDAP search: returning: %s\n", data->s); +DEBUG(lookup) debug_printf_indent("LDAP search: returning: %s\n", data->s); *res = data->s; RETURN_OK: @@ -1050,7 +1050,7 @@ RETURN_ERROR_BREAK: *defer_break = TRUE; RETURN_ERROR: -DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); +DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); RETURN_ERROR_NOMSG: if (result) ldap_msgfree(result); @@ -1152,7 +1152,7 @@ while (strncmpic(url, US"ldap", 4) != 0) { *errmsg = string_sprintf("LDAP_OP_DEREF not defined in this LDAP " "library - cannot use \"dereference\""); - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } #endif @@ -1165,7 +1165,7 @@ while (strncmpic(url, US"ldap", 4) != 0) else { *errmsg = US"LDAP option REFERRALS is not \"follow\" or \"nofollow\""; - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } } @@ -1174,7 +1174,7 @@ while (strncmpic(url, US"ldap", 4) != 0) { *errmsg = string_sprintf("LDAP_OP_REFERRALS not defined in this LDAP " "library - cannot use \"referrals\""); - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } #endif @@ -1184,7 +1184,7 @@ while (strncmpic(url, US"ldap", 4) != 0) *errmsg = string_sprintf("unknown parameter \"%.*s\" precedes LDAP URL", namelen, name); - DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); return DEFER; } Uskip_whitespace(&url); @@ -1192,7 +1192,7 @@ while (strncmpic(url, US"ldap", 4) != 0) } } *errmsg = US"malformed parameter setting precedes LDAP URL"; - DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); return DEFER; } @@ -1222,7 +1222,7 @@ if (user) *t = 0; } -DEBUG(D_lookup) +DEBUG(lookup) debug_printf_indent("LDAP parameters: user=%s pass=%s size=%d time=%d connect=%d " "dereference=%d referrals=%s\n", user, password, sizelimit, timelimit, tcplimit, dereference, referrals == LDAP_OPT_ON ? "on" : "off"); @@ -1240,7 +1240,7 @@ if (search_type == SEARCH_LDAP_AUTH) } if (!*password) { - DEBUG(D_lookup) debug_printf_indent("Empty password: ldapauth returns FAIL\n"); + DEBUG(lookup) debug_printf_indent("Empty password: ldapauth returns FAIL\n"); return FAIL; } } @@ -1253,7 +1253,7 @@ if (Ustrncmp(p, "://", 3) != 0) { *errmsg = string_sprintf("LDAP URL does not start with \"ldap://\", " "\"ldaps://\", or \"ldapi://\" (it starts with \"%.16s...\")", url); - DEBUG(D_lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("LDAP query error: %s\n", *errmsg); return DEFER; } @@ -1358,7 +1358,7 @@ eldap_dn = NULL; for (LDAP_CONNECTION *lcp; lcp = ldap_connections; ldap_connections = lcp->next) { - DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", + DEBUG(lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", lcp->host, lcp->port); if(lcp->bound) ldap_unbind(lcp->ld); } diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c index 2dedb2011..04a728ac5 100644 --- a/src/src/lookups/lf_sqlperform.c +++ b/src/src/lookups/lf_sqlperform.c @@ -55,7 +55,7 @@ int rc; uschar * server; BOOL defer_break = FALSE; -DEBUG(D_lookup) debug_printf_indent("%s query: %q opts '%s'\n", name, query, opts); +DEBUG(lookup) debug_printf_indent("%s query: %q opts '%s'\n", name, query, opts); /* Handle queries that do have server information at the start (old style). */ diff --git a/src/src/lookups/lmdb.c b/src/src/lookups/lmdb.c index dc8bec3ba..21aef3b47 100644 --- a/src/src/lookups/lmdb.c +++ b/src/src/lookups/lmdb.c @@ -87,24 +87,24 @@ Lmdbstrct * lmdb_p = handle; dbkey.mv_data = CS keystring; dbkey.mv_size = length; -DEBUG(D_lookup) debug_printf_indent("LMDB: lookup key: %s\n", CS keystring); +DEBUG(lookup) debug_printf_indent("LMDB: lookup key: %s\n", CS keystring); if ((ret = mdb_get(lmdb_p->txn, lmdb_p->db_dbi, &dbkey, &data)) == 0) { *result = string_copyn(US data.mv_data, data.mv_size); - DEBUG(D_lookup) debug_printf_indent("LMDB: lookup result: %s\n", *result); + DEBUG(lookup) debug_printf_indent("LMDB: lookup result: %s\n", *result); return OK; } else if (ret == MDB_NOTFOUND) { *errmsg = US"LMDB: lookup, no data found"; - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return FAIL; } else { *errmsg = string_sprintf("LMDB: lookup error: %s", mdb_strerror(ret)); - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } } diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c index dca125188..0e3335d86 100644 --- a/src/src/lookups/mysql.c +++ b/src/src/lookups/mysql.c @@ -105,7 +105,7 @@ mysql_connection *cn; while ((cn = mysql_connections)) { mysql_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close MYSQL connection: %s\n", cn->server); + DEBUG(lookup) debug_printf_indent("close MYSQL connection: %s\n", cn->server); mysql_close(cn->handle); } } @@ -235,7 +235,7 @@ if (!cn) if (sdata[1][0] == 0) sdata[1] = NULL; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("MYSQL new connection: host=%s port=%d socket=%s " "database=%s user=%s\n", sdata[0], port, socket, sdata[1], sdata[2]); @@ -266,7 +266,7 @@ if (!cn) /* Else use a previously cached connection */ -else DEBUG(D_lookup) +else DEBUG(lookup) debug_printf_indent("MYSQL using cached connection for %s\n", server_copy); /* Run the query */ @@ -291,7 +291,7 @@ if (!(mysql_result = mysql_use_result(mysql_handle))) { if (mysql_field_count(mysql_handle) == 0) { - DEBUG(D_lookup) debug_printf_indent("MYSQL: query was not one that returns data\n"); + DEBUG(lookup) debug_printf_indent("MYSQL: query was not one that returns data\n"); result = string_cat(result, string_sprintf("%lld", mysql_affected_rows(mysql_handle))); *do_cache = 0; @@ -344,7 +344,7 @@ while((i = mysql_next_result(mysql_handle)) >= 0) goto MYSQL_EXIT; } else /* just ignore more results */ - DEBUG(D_lookup) debug_printf_indent("MYSQL: got unexpected more results\n"); + DEBUG(lookup) debug_printf_indent("MYSQL: got unexpected more results\n"); /* If result is NULL then no data has been found and so we return FAIL. Otherwise, we must terminate the string which has been built; string_cat() @@ -376,7 +376,7 @@ if (result) } else { - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return yield; /* FAIL or DEFER */ } } diff --git a/src/src/lookups/nmh.c b/src/src/lookups/nmh.c index 0e93186c1..c4c7ee7fd 100644 --- a/src/src/lookups/nmh.c +++ b/src/src/lookups/nmh.c @@ -268,7 +268,7 @@ if (!cn) cn->next = nmh_connections; nmh_connections = cn; } -else DEBUG(D_lookup) +else DEBUG(lookup) debug_printf_indent("cached socket\n"); /* Build and send the query string */ @@ -277,7 +277,7 @@ g = string_fmt_append(NULL, "%s%c%n%c%s", table, '\0', &i, mode, keystring); s = string_from_gstring(g); -DEBUG(D_lookup) +DEBUG(lookup) debug_printf("%s %d: send '%s\\0%s'\n", __FUNCTION__, __LINE__, s, s + i); i = write(sock, s, gstring_length(g)); @@ -301,7 +301,7 @@ if (read(sock, resp, 1) != 1) return DEFER; } -DEBUG(D_lookup) +DEBUG(lookup) debug_printf("%s %d: recv '%.1s'\n", __FUNCTION__, __LINE__, resp); switch (resp[0]) @@ -328,7 +328,7 @@ nmh_connection *cn; while ((cn = nmh_connections)) { nmh_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close NMH connection: %s\n", cn->server); + DEBUG(lookup) debug_printf_indent("close NMH connection: %s\n", cn->server); close(cn->socket); } } diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c index 9472fc2ff..995f83ab1 100644 --- a/src/src/lookups/oracle.c +++ b/src/src/lookups/oracle.c @@ -223,7 +223,7 @@ oracle_connection *cn; while ((cn = oracle_connections)) { oracle_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close ORACLE connection: %s\n", cn->server); + DEBUG(lookup) debug_printf_indent("close ORACLE connection: %s\n", cn->server); ologof(cn->handle); } } @@ -307,7 +307,7 @@ for (cn = oracle_connections; cn; cn = cn->next) if (!cn) { - DEBUG(D_lookup) debug_printf_indent("ORACLE new connection: host=%s database=%s " + DEBUG(lookup) debug_printf_indent("ORACLE new connection: host=%s database=%s " "user=%s\n", sdata[0], sdata[1], sdata[2]); /* Get store for a new connection, initialize it, and connect to the server */ @@ -347,7 +347,7 @@ if (!cn) /* Else use a previously cached connection - we can write to the server string to obliterate the password because it is in a nextinlist temporary buffer. */ -else DEBUG(D_lookup) +else DEBUG(lookup) debug_printf_indent("ORACLE using cached connection for %s\n", server_copy); /* We have a connection. Open a cursor and run the query */ @@ -490,7 +490,7 @@ if (result) } else { - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return yield; /* FAIL or DEFER */ } } @@ -516,7 +516,7 @@ uschar *list = oracle_servers; do_cache = do_cache; /* Placate picky compilers */ -DEBUG(D_lookup) debug_printf_indent("ORACLE query: %s\n", query); +DEBUG(lookup) debug_printf_indent("ORACLE query: %s\n", query); while ((server = string_nextinlist(&list, &sep, NULL, 0))) { diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c index bef6c59e2..009f95ad9 100644 --- a/src/src/lookups/pgsql.c +++ b/src/src/lookups/pgsql.c @@ -58,7 +58,7 @@ pgsql_connection *cn; while ((cn = pgsql_connections)) { pgsql_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close PGSQL connection: %s\n", cn->server); + DEBUG(lookup) debug_printf_indent("close PGSQL connection: %s\n", cn->server); PQfinish(cn->handle); } } @@ -82,7 +82,7 @@ static void notice_processor(void *arg, const char *message) { arg = arg; /* Keep compiler happy */ -DEBUG(D_lookup) debug_printf_indent("PGSQL: %s\n", message); +DEBUG(lookup) debug_printf_indent("PGSQL: %s\n", message); } @@ -188,7 +188,7 @@ if (!cn) last_slash = Ustrrchr(server, '/'); last_dot = Ustrrchr(server, '.'); - DEBUG(D_lookup) debug_printf_indent("PGSQL new connection: socket=%s " + DEBUG(lookup) debug_printf_indent("PGSQL new connection: socket=%s " "database=%s user=%s\n", server, sdata[0], sdata[1]); /* A valid socket name looks like this: /var/run/postgresql/.s.PGSQL.5432 @@ -237,7 +237,7 @@ if (!cn) return DEFER; } - DEBUG(D_lookup) debug_printf_indent("PGSQL new connection: host=%s port=%s " + DEBUG(lookup) debug_printf_indent("PGSQL new connection: host=%s port=%s " "database=%s user=%s\n", server, port, sdata[0], sdata[1]); } @@ -284,7 +284,7 @@ if (!cn) /* Else use a previously cached connection */ -else DEBUG(D_lookup) +else DEBUG(lookup) debug_printf_indent("PGSQL using cached connection for %s\n", server_copy); /* Run the query */ @@ -301,7 +301,7 @@ switch(PQresultStatus(pg_result)) result = string_cat(result, US PQcmdTuples(pg_result)); *do_cache = 0; - DEBUG(D_lookup) debug_printf_indent("PGSQL: command does not return any data " + DEBUG(lookup) debug_printf_indent("PGSQL: command does not return any data " "but was successful. Rows affected: %Y\n", result); break; @@ -376,7 +376,7 @@ if (result) } else { - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return yield; /* FAIL or DEFER */ } } diff --git a/src/src/lookups/psl.c b/src/src/lookups/psl.c index 3b2af489e..cf01a21bb 100644 --- a/src/src/lookups/psl.c +++ b/src/src/lookups/psl.c @@ -54,11 +54,11 @@ BOOL key_utf8; if ((key_utf8 = string_is_utf8(keystring))) { - DEBUG(D_lookup) debug_printf_indent("converting utf8 key %q\n", keystring); + DEBUG(lookup) debug_printf_indent("converting utf8 key %q\n", keystring); if (!(keystring = string_domain_utf8_to_alabel(keystring, errmsg))) return FAIL; length = Ustrlen(keystring); - DEBUG(D_lookup) debug_printf_indent(" result %q\n", keystring); + DEBUG(lookup) debug_printf_indent(" result %q\n", keystring); } else for (k = keystring; *k; k++) @@ -83,7 +83,7 @@ while ((s = US fgets(CS rulebuf, sizeof(rulebuf), handle))) goto fail; if (t != r) { - DEBUG(D_lookup) debug_printf_indent("converting utf8 psl entry %q\n" + DEBUG(lookup) debug_printf_indent("converting utf8 psl entry %q\n" " result %q\n", r, t); r = t; } @@ -160,7 +160,7 @@ if (key_utf8 && res) { if (!(*result = string_domain_alabel_to_utf8(res, errmsg))) goto fail; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("utf8 converting result %q\n to %q\n", res, *result); } else diff --git a/src/src/lookups/readsock.c b/src/src/lookups/readsock.c index 6b9061b8b..b78ea7405 100644 --- a/src/src/lookups/readsock.c +++ b/src/src/lookups/readsock.c @@ -23,7 +23,7 @@ if (Ustrncmp(sspec, "inet:", 5) == 0) int port; uschar * port_name; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent(" new inet socket needed for readsocket\n"); server_name = sspec + 5; @@ -81,7 +81,7 @@ else struct sockaddr_un sockun; /* don't call this "sun" ! */ int rc; - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent(" new unix socket needed for readsocket\n"); if ((cctx->sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) @@ -120,7 +120,7 @@ if (do_tls) goto bad; #endif -DEBUG(D_expand|D_lookup) debug_printf_indent(" connected to socket %s\n", sspec); +DEBUG(expand|lookup) debug_printf_indent(" connected to socket %s\n", sspec); return OK; bad: @@ -145,7 +145,7 @@ readsock_open(const uschar * filename, uschar ** errmsg) client_conn_ctx * cctx = store_get(sizeof(*cctx), GET_UNTAINTED); cctx->sock = -1; cctx->tls_ctx = NULL; -DEBUG(D_lookup) debug_printf_indent("readsock: allocated context\n"); +DEBUG(lookup) debug_printf_indent("readsock: allocated context\n"); return cctx; } @@ -176,7 +176,7 @@ int timeout = 5; gstring * yield; int ret = DEFER; -DEBUG(D_lookup) +DEBUG(lookup) debug_printf_indent("readsock: file=%q key=%q len=%d opts=%q\n", filename, keystring, length, opts); diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c index e88ded154..03c290ee2 100644 --- a/src/src/lookups/redis.c +++ b/src/src/lookups/redis.c @@ -47,7 +47,7 @@ redis_connection *cn; while ((cn = redis_connections)) { redis_connections = cn->next; - DEBUG(D_lookup) debug_printf_indent("close REDIS connection: %s\n", cn->server); + DEBUG(lookup) debug_printf_indent("close REDIS connection: %s\n", cn->server); redisFree(cn->handle); } } @@ -153,7 +153,7 @@ if (!cn) return DEFER; } - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("REDIS new connection: host=%s port=%d socket=%s database=%s\n", sdata[0], port, socket, sdata[1]); @@ -175,7 +175,7 @@ if (!cn) cn->next = redis_connections; redis_connections = cn; } -else DEBUG(D_lookup) +else DEBUG(lookup) debug_printf_indent("REDIS using cached connection for %s\n", server_copy); /* Authenticate if there is a password */ @@ -196,7 +196,7 @@ if(sdata[1]) *defer_break = FALSE; goto REDIS_EXIT; } - DEBUG(D_lookup) debug_printf_indent("REDIS: Selecting database=%s\n", sdata[1]); + DEBUG(lookup) debug_printf_indent("REDIS: Selecting database=%s\n", sdata[1]); } /* split string on whitespace into argv */ @@ -217,7 +217,7 @@ if(sdata[1]) g = string_catn(g, s, 1); argv[i] = string_from_gstring(g); - DEBUG(D_lookup) debug_printf_indent("REDIS: argv[%d] '%s'\n", i, argv[i]); + DEBUG(lookup) debug_printf_indent("REDIS: argv[%d] '%s'\n", i, argv[i]); Uskip_whitespace(&s); } @@ -240,7 +240,7 @@ switch (redis_reply->type) /* trap MOVED cluster responses and follow them */ if (Ustrncmp(redis_reply->str, "MOVED", 5) == 0) { - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("REDIS: cluster redirect %s\n", redis_reply->str); /* follow redirect This is cheating, we simply set defer_break = FALSE to move on to @@ -255,7 +255,7 @@ switch (redis_reply->type) /* NOTREACHED */ case REDIS_REPLY_NIL: - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("REDIS: query was not one that returned any data\n"); result = string_catn(result, US"", 1); *do_cache = 0; @@ -308,19 +308,19 @@ switch (redis_reply->type) result = string_catn(result, US tentry->str, tentry->len); break; case REDIS_REPLY_ARRAY: - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("REDIS: result has nesting of arrays which" " is not supported. Ignoring!\n"); break; default: - DEBUG(D_lookup) debug_printf_indent( + DEBUG(lookup) debug_printf_indent( "REDIS: result has unsupported type. Ignoring!\n"); break; } } break; default: - DEBUG(D_lookup) debug_printf_indent("REDIS: query returned unsupported type\n"); + DEBUG(lookup) debug_printf_indent("REDIS: query returned unsupported type\n"); break; } } @@ -352,7 +352,7 @@ if (result) } else { - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); /* NOTE: Required to close connection since it needs to be reopened */ return yield; /* FAIL or DEFER */ } diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c index e41e1dcb0..131486622 100644 --- a/src/src/lookups/spf.c +++ b/src/src/lookups/spf.c @@ -35,7 +35,7 @@ static void * spf_open(const uschar * filename, uschar ** errmsg) { misc_module_info * mi; -DEBUG(D_lookup) debug_printf_indent("spf lookup spf_open\n"); +DEBUG(lookup) debug_printf_indent("spf lookup spf_open\n"); if ((mi = misc_mod_find(US"spf", errmsg))) { typedef void * (*fn_t)(const uschar *, uschar **); diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c index c91440e1e..9deacf905 100644 --- a/src/src/lookups/sqlite.c +++ b/src/src/lookups/sqlite.c @@ -30,7 +30,7 @@ int ret; if (!filename || !*filename) { - DEBUG(D_lookup) debug_printf_indent("Using sqlite_dbfile: %s\n", sqlite_dbfile); + DEBUG(lookup) debug_printf_indent("Using sqlite_dbfile: %s\n", sqlite_dbfile); filename = sqlite_dbfile; } if (!filename || *filename != '/') @@ -40,7 +40,7 @@ else if ((ret = sqlite3_open(CCS filename, &db)) != 0) *errmsg = string_copy(US sqlite3_errmsg(db)); sqlite3_close(db); db = NULL; - DEBUG(D_lookup) debug_printf_indent("Error opening database: %s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("Error opening database: %s\n", *errmsg); } if (db) diff --git a/src/src/lookups/testdb.c b/src/src/lookups/testdb.c index 7745bd193..b0046af55 100644 --- a/src/src/lookups/testdb.c +++ b/src/src/lookups/testdb.c @@ -44,13 +44,13 @@ testdb_find(void * handle, const uschar * filename, const uschar * query, if (Ustrcmp(query, "fail") == 0) { *errmsg = US"testdb lookup forced FAIL"; - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return FAIL; } if (Ustrcmp(query, "defer") == 0) { *errmsg = US"testdb lookup forced DEFER"; - DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg); + DEBUG(lookup) debug_printf_indent("%s\n", *errmsg); return DEFER; } diff --git a/src/src/macros.h b/src/src/macros.h index 07d5e0003..628bac32f 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ +/* Copyright (c) The Exim Maintainers 2020 - 2026 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -98,19 +98,6 @@ don't make the file descriptors two-way. */ #define mac_islookup(li,b) ((li)->type & (b)) -/* Debugging control */ - -#define LOG_NAME_SIZE 256 -#define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) -#define DEBUG(x) if (IS_DEBUG(x)) -#define HDEBUG(x) if (host_checking || IS_DEBUG(x)) - -#define EARLY_DEBUG(x, fmt, ...) \ - if (debug_fd >= 0) \ - { DEBUG(x) debug_printf_indent(fmt, __VA_ARGS__); } \ - else if (debug_startup) \ - fprintf(stderr, "%s", string_sprintf(fmt, __VA_ARGS__)); - /* The default From: text for DSNs */ #define DEFAULT_DSN_FROM "Mail Delivery System " @@ -145,6 +132,8 @@ enough to hold all the headers from a normal kind of message. */ #define LOG_BUFFER_SIZE 8192 +#define LOG_NAME_SIZE 256 + /* The size of the circular buffer that remembers recent SMTP commands */ #define SMTP_HBUFF_SIZE 20 @@ -327,6 +316,10 @@ for having to swallow the rest of an SMTP message is whether the value is /* Bit masks for debug and log selectors */ +#ifndef bitmask_word_t +# define bitmask_word_t uint64_t +#endif + /* Assume words are at least 32 bits wide. Tiny waste of space on 64 bit platforms, but this ensures bit vectors always work the same way. */ #ifdef EXIM_BITMAP_WORD_BITS @@ -336,21 +329,33 @@ platforms, but this ensures bit vectors always work the same way. */ #endif /* This macro is for single-word bit vectors: the debug selector, -and the first word of the log selector. */ +and the first word of the log selector. For multi-word vectors we +use inlinable functions. */ + #define BIT(n) ((bitmask_word_t)1 << (n)) -/* And these are for multi-word vectors. */ #define BITWORD(n) ( (n) / BITWORDSIZE) #define BITMASK(n) (BIT((n) % BITWORDSIZE)) -#define BIT_CLEAR(s,z,n) ((s)[BITWORD(n)] &= ~BITMASK(n)) -#define BIT_SET(s,z,n) ((s)[BITWORD(n)] |= BITMASK(n)) -#define BIT_TEST(s,z,n) ((s)[BITWORD(n)] & BITMASK(n)) +/* Debugging control */ + +#define DEBUG_SELECTOR_SIZE (BITWORD(debug_options_count) + 1) -/* Used in globals.c for initializing bit_table structures. T will be either -D or L corresponding to the debug and log selector bits declared below. */ +static inline bitmask_word_t bit_test(bitmask_word_t *, unsigned); +extern bitmask_word_t * debug_selector; /* Debugging bits */ +#define DEBUG_BIT(n) (debug_selector && bit_test(debug_selector, n)) +#define ANY_DEBUG DEBUG_BIT(BIT_TABLE_IDX_NONZERO) -#define BIT_TABLE(T,name) { US #name, T##i_##name } +extern BOOL is_debug(const uschar *); +#define IS_DEBUG(list) (ANY_DEBUG && is_debug(US # list)) +#define DEBUG(list) if (IS_DEBUG(list)) +#define HDEBUG(list) if (host_checking || IS_DEBUG(list)) + +#define EARLY_DEBUG(x, fmt, ...) \ + if (debug_fd >= 0) \ + { DEBUG(x) debug_printf_indent(fmt, __VA_ARGS__); } \ + else if (debug_startup) \ + fprintf(stderr, "%s", string_sprintf(fmt, __VA_ARGS__)); /* IOTA allows us to keep an implicit sequential count, like a simple enum, but we can have sequentially numbered identifiers which are not declared @@ -360,6 +365,7 @@ masks, alternating between sequential bit index and corresponding mask. */ #define IOTA(iota) (__LINE__ - iota) #define IOTA_INIT(zero) (__LINE__ - zero + 1) +/*XXX*/ /* Options bits for debugging. DEBUG_BIT() declares both a bit index and the corresponding mask. Di_all is a special value recognized by decode_bits(). These must match the debug_options table in globals.c . @@ -367,90 +373,73 @@ These must match the debug_options table in globals.c . Exim's code assumes in a number of places that the debug_selector is one word, and this is exposed in the local_scan ABI. The D_v and D_local_scan bit masks are part of the local_scan API so are #defined in local_scan.h . +XXX => v & local_scan must live in word zero Thanks to the "one word", debug bits beyond 31 are not available on 32b-int systems, and coding must account for that. */ -#ifndef bitmask_word_t -# define bitmask_word_t uint64_t -#endif +/* Special bits used for debug and logging control. These are summarizing sets +of enabled channels, and are in the first word of the selector array for quick +access. */ + +#define BIT_TABLE_IDX_ALL 0 /* code for nearly-all-bits-set */ +#define BIT_TABLE_IDX_NONZERO 1 /* at least one bit is set */ +#define BIT_TABLE_IDX_NONVERB 2 /* a bit apart from "v" is set */ +#define BIT_TABLE_IDX_IS_ANY 3 /* a bit apart from "v'-like ones is set */ +#define BIT_TABLE_IDX_USABLE 4 /* first named bit */ #define BITMASK_IDX_TO_BIT(idx) ((bitmask_word_t)1 << (idx)) #define BIT_TABLE_BIT(class, name) \ class##i_##name = IOTA(class##i_iota), \ class##_##name = BITMASK_IDX_TO_BIT(class##i_##name) -#define DEBUG_BIT(name) BIT_TABLE_BIT(D, name) -#define DEBUG_Z_BIT(name) Di_##name = 0, D_##name = 0 - -enum { - Di_all = -1, - Di_v = 0, - Di_local_scan = 1, - - Di_iota = IOTA_INIT(2), - DEBUG_BIT(acl), /* 2 */ - DEBUG_BIT(auth), - DEBUG_BIT(deliver), - DEBUG_BIT(dns), - DEBUG_BIT(dnsbl), - DEBUG_BIT(exec), /* 7 */ - DEBUG_BIT(expand), - DEBUG_BIT(filter), - DEBUG_BIT(hints_lookup), - DEBUG_BIT(host_lookup), - DEBUG_BIT(ident), - DEBUG_BIT(interface), - DEBUG_BIT(lists), - DEBUG_BIT(load), /* 15 */ - DEBUG_BIT(lookup), - DEBUG_BIT(memory), - DEBUG_BIT(noutf8), - DEBUG_BIT(pid), - DEBUG_BIT(process_info), - DEBUG_BIT(queue_run), - DEBUG_BIT(receive), - DEBUG_BIT(resolver), /* 23 */ - DEBUG_BIT(retry), - DEBUG_BIT(rewrite), - DEBUG_BIT(route), - DEBUG_BIT(timestamp), - DEBUG_BIT(tls), - DEBUG_BIT(transport), - DEBUG_BIT(uid), - DEBUG_BIT(verify), /* 31 */ -#if BITWORDSIZE > 32 - DEBUG_BIT(macro), /* 33 */ - DEBUG_BIT(regex), -#else -# warn BITWORDSIZE <= 32 - DEBUG_Z_BIT(macro), - DEBUG_Z_BIT(regex), -#endif -}; - - -/* Multi-bit debug masks */ - -#define D_all 0xffffffff - -#define D_any (D_all & \ - ~(D_v | \ - D_noutf8 | \ - D_pid | \ - D_timestamp) ) +/*XXX This fails with the Sun Studio compiler: the bitfield +defns for 31, 32, 33 spit warnings, and we get unexpected debug +output for (at least) macro and regex channels. I suspect it has +elected to use a signed 32b int as its enum type, which is not unfair. + +( + C23 lets you spec the underlying type for an enum: + enum pet : unsigned char { CAT, DOG, ROCK }; +) + +We really only need the enum to give us an auto-inc for assgning bitnums. +But we also have IOTA. Could we use that for #defines for the bitmasks? +We'd have to list everthing twice... hmm. Losing the hard link between +the bit-idx & bitmask would not be good. + +Could we live totally without the bitnum? BIT_SET etc use? +MMM, prob not. + +Could we do bit-in-word mask rather than plain bitmask? +But how does that work for combining bits? +(currently we can just bitwise-or) +Though, for L-bits we just say we do not. +Make the same restriction on D-bits? It could work, +but currently DEBUG is keyed on the plain bitmask; +it would have to change to being the idx. +OK, so redefine DEBUG in the way LOGGING is done. +And perhaps a multi-bit version (macro-vararg) for combined-bit use. +Nope, this isn't working out. + +We also probably want a dedicated bit (? in word zero of the +array-of-words?) to say that at least one debug bit is set - +so that a fast test can be inlined. + +Next up, one more level of indirection: +use buildconfig.c to write the C and/or CPP code needed. +Expand the defn of BIT_TABLE() and struct bit_table +to be { name, BITWORD(idx), BITMASK(idx) } +Enhance decode_bits() to cope with that. +[ preferably, logging should use this also ] +buildconfig.c writes both debug_options[] (for decoding text spec in +cmdline and in config file) +AND an enum with all the named index bits (cf. Di_acl in macros.h) +NOTE that D_v and D_local_scan masks are defined in local_scan.h +and changing those will be a pain. +NOTE the existence of debug_notall[]. +*/ -#define D_default (0xffffffff & \ - ~(D_expand | \ - D_filter | \ - D_interface | \ - D_load | \ - D_local_scan | \ - D_memory | \ - D_noutf8 | \ - D_pid | \ - D_timestamp | \ - D_resolver)) /* Bits for debug triggers */ @@ -467,9 +456,9 @@ Add also to log_options[] when creating new ones. */ #define LOG_BIT(name) BIT_TABLE_BIT(L, name) -enum logbit { - Li_all = -1, +/* Bit numbers used by calls to log_write() */ +enum logwrite_bit { Li_iota = IOTA_INIT(0), LOG_BIT(address_rewrite), LOG_BIT(all_parents), @@ -487,59 +476,82 @@ enum logbit { LOG_BIT(smtp_incomplete_transaction), LOG_BIT(smtp_protocol_error), LOG_BIT(smtp_syntax_error), /* 15 */ +}; - Li_8bitmime = BITWORDSIZE, - Li_acl_warn_skipped, - Li_arguments, - Li_connection_id, - Li_deliver_time, - Li_delivery_size, - Li_dkim, - Li_dkim_verbose, - Li_dmarc, - Li_dmarc_verbose, - Li_dnssec, - Li_dsn, - Li_ident_timeout, - Li_incoming_interface, - Li_incoming_port, - Li_millisec, - Li_msg_id, - Li_msg_id_created, - Li_outgoing_interface, - Li_outgoing_port, - Li_pid, - Li_pipelining, - Li_protocol_detail, - Li_proxy, - Li_queue_time, - Li_queue_time_exclusive, - Li_queue_time_overall, - Li_receive_time, - Li_received_sender, - Li_received_recipients, - Li_rejected_header, - Li_return_path_on_delivery, - Li_sender_on_delivery, - Li_sender_verify_fail, - Li_smtp_confirmation, - Li_smtp_mailauth, - Li_smtp_no_mail, - Li_spf, - Li_spf_verbose, - Li_subject, - Li_tls_certificate_verified, - Li_tls_cipher, - Li_tls_on_connect, - Li_tls_peerdn, - Li_tls_resumption, - Li_tls_sni, - Li_unknown_in_list, - - log_selector_size = BITWORD(Li_unknown_in_list) + 1 +/* Bit numbers used by the LOGGING() macro */ + +enum logging_test_bit { /* Must be in alpha order, matching log_chan_names[] */ + Lt_all = BIT_TABLE_IDX_ALL, /* 0 */ + + Lt_8bitmime = BIT_TABLE_IDX_USABLE, /* 4 */ + Lt_acl_warn_skipped, + Lt_address_rewrite, + Lt_DUMMY_all, /* 7 */ + Lt_all_parents, + Lt_arguments, + Lt_connection_id, + Lt_connection_reject, + Lt_delay_delivery, + Lt_deliver_time, + Lt_delivery_size, + Lt_dkim, /* 15 */ + Lt_dkim_verbose, + Lt_dmarc, + Lt_dmarc_verbose, + Lt_dnslist_defer, + Lt_dnssec, + Lt_dsn, + Lt_etrn, + Lt_host_lookup_failed, + Lt_ident_timeout, + Lt_incoming_interface, + Lt_incoming_port, + Lt_lost_incoming_connection, + Lt_millisec, + Lt_msg_id, + Lt_msg_id_created, + Lt_outgoing_interface, /* 31 */ + Lt_outgoing_port, + Lt_pid, + Lt_pipelining, + Lt_protocol_detail, + Lt_proxy, + Lt_queue_run, + Lt_queue_time, + Lt_queue_time_exclusive, + Lt_queue_time_overall, + Lt_receive_time, + Lt_received_recipients, + Lt_received_sender, + Lt_rejected_header, + Lt_retry_defer, + Lt_return_path_on_delivery, + Lt_sender_on_delivery, /* 47 */ + Lt_sender_verify_fail, + Lt_size_reject, + Lt_skip_delivery, + Lt_smtp_confirmation, + Lt_smtp_connection, + Lt_smtp_incomplete_transaction, + Lt_smtp_mailauth, + Lt_smtp_no_mail, + Lt_smtp_protocol_error, + Lt_smtp_syntax_error, + Lt_spf, + Lt_spf_verbose, + Lt_subject, + Lt_tls_certificate_verified, + Lt_tls_cipher, + Lt_tls_on_connect, /* 63 */ + Lt_tls_peerdn, + Lt_tls_resumption, + Lt_tls_sni, + Lt_unknown_in_list, + + log_selector_size = BITWORD(Lt_unknown_in_list) + 1 }; -#define LOGGING(opt) BIT_TEST(log_selector, log_selector_size, Li_##opt) +#define LOGGING(opt) bit_test(log_selector, Lt_##opt) /* Private error numbers for delivery failures, set negative so as not to conflict with system errno values. Take care to maintain the string @@ -851,8 +863,11 @@ local_scan.h */ #define LOG_CONFIG_FOR (256+128) /* Add " for" instead of ":\n" */ #define LOG_CONFIG_IN (512+128) /* Add " in line x[ of file y]" */ -/* and for debug_bits() logging action control: */ -#define DEBUG_FROM_CONFIG 0x0001 +/* flags for decode_bits */ + +#define DCB_LOG 0x0001 +#define DCB_DEBUG 0x0002 +#define DCB_FROM_CONFIG 0x0003 /* SMTP command identifiers for the smtp_connection_had field that records the most recent SMTP commands. SCH_NONE is "empty". The smtp_names array must have @@ -1126,10 +1141,10 @@ alarm is active. Clear it down on cancelling the alarm so we can tell there should not be one active. */ # define ALARM(seconds) \ - debug_selector & D_any \ + ANY_DEBUG \ ? (sigalarm_setter = CUS __FUNCTION__, alarm(seconds)) : alarm(seconds); # define ALARM_CLR(seconds) \ - debug_selector & D_any \ + ANY_DEBUG \ ? (sigalarm_setter = NULL, alarm(seconds)) : alarm(seconds); #endif @@ -1249,7 +1264,7 @@ When doing en extended loop of matching, release store periodically. */ /* Debug an option access. Use for non-list ones about to be expanded (lists have their own debugging, under D_list). */ #define GET_OPTION(name) \ - DEBUG(D_expand) debug_printf_indent("try option '" name "'\n"); + DEBUG(expand) debug_printf_indent("try option '" name "'\n"); #ifdef EXPERIMENTAL_SRV_SMTPS diff --git a/src/src/malware.c b/src/src/malware.c index 3effeab41..6ee646147 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -258,7 +258,7 @@ static inline int m_panic_defer_3(struct scan * scanent, const uschar * hostport, const uschar * str, int fd_to_close) { -DEBUG(D_acl) debug_print_socket(fd_to_close); +DEBUG(acl) debug_print_socket(fd_to_close); (void) close(fd_to_close); return m_panic_defer(scanent, hostport, str); } @@ -334,7 +334,7 @@ if (!(list_ele = string_nextinlist(list, sep, NULL, 0))) *errstr = US listerr; else { - DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ", + DEBUG(acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ", string_printing(list_ele)); cre = m_pcre_compile(CUS list_ele, cacheable, errstr); } @@ -373,7 +373,7 @@ while ((rcv = read(fd, p, 1)) > 0) } if (!ok) { - DEBUG(D_acl) + DEBUG(acl) { debug_printf_indent("Malware scan: read %s (%s)\n", rcv==0 ? "EOF" : "error", strerror(errno)); @@ -383,7 +383,7 @@ if (!ok) } *p = '\0'; -DEBUG(D_acl) debug_printf_indent("Malware scan: read '%s'\n", buffer); +DEBUG(acl) debug_printf_indent("Malware scan: read '%s'\n", buffer); return p - buffer; } @@ -631,7 +631,7 @@ if (*av_scanner == '$') string_sprintf("av_scanner starts with $, but expansion failed: %s", expand_string_message)); - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("Expanded av_scanner global: %s\n", av_scanner_work); /* disable result caching in this case */ malware_name = NULL; @@ -656,7 +656,7 @@ if (!malware_ok) scanner_name)); if (strcmpic(scanner_name, US scanent->name) != 0) continue; - DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo=%s\n", + DEBUG(acl) debug_printf_indent("Malware scan: %s tmo=%s\n", scanner_name, readconf_printtime(timeout)); if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0))) @@ -664,7 +664,7 @@ if (!malware_ok) if (scanent->conn == MC_NONE) break; - DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options); + DEBUG(acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options); switch(scanent->conn) { case MC_TCP: @@ -703,7 +703,7 @@ if (!malware_ok) par_count++; } scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest); - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s: %s\n", scanner_name, scanrequest); /* send scan request */ @@ -751,7 +751,7 @@ if (!malware_ok) return malware_panic_defer(errstr); scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename); - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s: %s\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s: %s\n", scanner_name, scanrequest); if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0) @@ -832,7 +832,7 @@ badseek: err = errno; if (lseek(drweb_fd, 0, SEEK_SET) < 0) goto badseek; - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n", scanner_name, scanner_options); /* send scan request */ @@ -882,7 +882,7 @@ badseek: err = errno; { drweb_slen = htonl(Ustrlen(eml_filename)); - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n", scanner_name, scanner_options); /* send scan request */ @@ -1004,7 +1004,7 @@ badseek: err = errno; eml_filename); /* and send it */ - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s %s\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s %s\n", scanner_name, buf); if (m_sock_send(malware_daemon_ctx.sock, buf, Ustrlen(buf), &errstr) < 0) return m_panic_defer(scanent, CUS callout_address, errstr); @@ -1066,7 +1066,7 @@ badseek: err = errno; malware_name = NULL; - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", scanner_name, scanner_options); /* pass options */ memset(av_buffer, 0, sizeof(av_buffer)); @@ -1164,7 +1164,7 @@ badseek: err = errno; if (p) *p = '\0'; - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", scanner_name, scanner_options); /* send scan request */ @@ -1297,7 +1297,7 @@ badseek: err = errno; /* redirect STDERR too */ commandline = string_sprintf("%s 2>&1", commandline); - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", scanner_name, commandline); /* store exims signal handlers */ @@ -1398,7 +1398,7 @@ badseek: err = errno; if ((p = Ustrrchr(file_name, '/'))) *p = '\0'; - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", scanner_name, scanner_options); if ( write(malware_daemon_ctx.sock, file_name, Ustrlen(file_name)) < 0 @@ -1575,7 +1575,7 @@ badseek: err = errno; int i = random_number(num_servers); clamd_address * cd = cv[i]; - DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n", + DEBUG(acl) debug_printf_indent("trying server name %s, port %u\n", cd->hostspec, cd->tcp_port); /* Lookup the host. This is to ensure that we connect to the same IP @@ -1637,7 +1637,7 @@ badseek: err = errno; chunks, a 4-byte number (network order), terminated by a zero-length chunk. We only send one chunk. */ - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n", scanner_name); @@ -1747,7 +1747,7 @@ badseek: err = errno; just use the email file itself. */ /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */ - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "Malware scan: issuing %s local-path scan [%s]\n", scanner_name, scanner_options); @@ -1811,7 +1811,7 @@ badseek: err = errno; p = av_buffer + Ustrlen(av_buffer) - 1; if (*p == '\n') *p = '\0'; - DEBUG(D_acl) debug_printf_indent("Malware response: %s\n", av_buffer); + DEBUG(acl) debug_printf_indent("Malware response: %s\n", av_buffer); while (isspace(*--p) && (p > av_buffer)) *p = '\0'; @@ -1848,7 +1848,7 @@ badseek: err = errno; *p = '\0'; } malware_name = string_copy(vname); - DEBUG(D_acl) debug_printf_indent("Malware found, name %q\n", malware_name); + DEBUG(acl) debug_printf_indent("Malware found, name %q\n", malware_name); } else if (Ustrcmp(result_tag, "ERROR") == 0) @@ -1859,7 +1859,7 @@ badseek: err = errno; { /* Everything should be OK */ malware_name = NULL; - DEBUG(D_acl) debug_printf_indent("Malware not found\n"); + DEBUG(acl) debug_printf_indent("Malware not found\n"); } else @@ -1899,7 +1899,7 @@ badseek: err = errno; } else sockline_scanner = sockline_scanner_default; - DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ", + DEBUG(acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ", string_printing(sockline_scanner)); /* find scanner output trigger */ @@ -1916,7 +1916,7 @@ badseek: err = errno; /* prepare scanner call - security depends on expansions check above */ commandline = string_sprintf( CS sockline_scanner, eml_filename); - DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ", + DEBUG(acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ", string_printing(commandline)); /* Pass the command string to the socket */ @@ -1936,7 +1936,7 @@ badseek: err = errno; US"buffer too small", malware_daemon_ctx.sock); av_buffer[bread] = '\0'; linebuffer = string_copy(av_buffer); - DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ", + DEBUG(acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ", string_printing(linebuffer)); /* try trigger match */ @@ -1944,7 +1944,7 @@ badseek: err = errno; { if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer))) malware_name = US "unknown"; - DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ", + DEBUG(acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ", string_printing(malware_name)); } else /* no virus found */ @@ -1977,7 +1977,7 @@ badseek: err = errno; malware_name = NULL; - DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name); + DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name); if ((retval = mksd_scan_packed(scanent, malware_daemon_ctx.sock, eml_filename, tmo)) != OK) { @@ -2087,19 +2087,19 @@ badseek: err = errno; { if (Ustrcmp(scanrequest, "pass_unscanned") == 0) { - DEBUG(D_acl) debug_printf_indent("pass unscanned files as clean\n"); + DEBUG(acl) debug_printf_indent("pass unscanned files as clean\n"); strict = FALSE; goto sendreq; } scanrequest = string_sprintf("%s\n", scanrequest); avast_stage = AVA_OPT; /* just sent option */ - DEBUG(D_acl) debug_printf_indent("send to avast OPTION: %s", scanrequest); + DEBUG(acl) debug_printf_indent("send to avast OPTION: %s", scanrequest); } else { scanrequest = string_sprintf("SCAN %s\n", eml_dir); avast_stage = AVA_RSP; /* just sent command */ - DEBUG(D_acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir); + DEBUG(acl) debug_printf_indent("send to avast REQUEST: SCAN %s\n", eml_dir); } /* send config-cmd or scan-request to socket */ @@ -2128,7 +2128,7 @@ badseek: err = errno; if ((malware_name = m_pcre_exec(ava_re_virus, buf))) { unescape(malware_name); - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("unescaped malware name: '%s'\n", malware_name); break; } @@ -2138,7 +2138,7 @@ badseek: err = errno; if ((malware_name = m_pcre_exec(ava_re_error, buf))) { unescape(malware_name); - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("unescaped error message: '%s'\n", malware_name); break; } @@ -2150,7 +2150,7 @@ badseek: err = errno; } /* here also for any unexpected response from the scanner */ - DEBUG(D_acl) debug_printf("avast response not handled: '%s'\n", buf); + DEBUG(acl) debug_printf("avast response not handled: '%s'\n", buf); goto endloop; @@ -2167,7 +2167,7 @@ badseek: err = errno; else if (nread == 0) error_message = US"got nothing from scanner"; else if (buf[0] != '2') error_message = buf; - DEBUG(D_acl) debug_printf_indent("sent to avast QUIT\n"); + DEBUG(acl) debug_printf_indent("sent to avast QUIT\n"); if (send(malware_daemon_ctx.sock, "QUIT\n", 5, 0) == -1) return m_panic_defer_3(scanent, CUS callout_address, string_sprintf("unable to send quit request to socket (%s): %s", @@ -2189,7 +2189,7 @@ badseek: err = errno; /* match virus name against pattern (caseless ------->----------v) */ if (malware_name && regex_match_and_setup(re, malware_name, 0, -1)) { - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "Matched regex to malware [%s] [%s]\n", malware_re, malware_name); return OK; } diff --git a/src/src/match.c b/src/src/match.c index c843b2420..4ef9d3560 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -402,7 +402,7 @@ if (Uskip_whitespace(&list) == '<') uschar c = *s == '\\' ? string_interpret_escape(&s) : *s; if (ispunct(c) || iscntrl(c)) { - DEBUG(D_lists) + DEBUG(lists) { uschar s[2] = {0}; *s = c; debug_printf_indent("list separator: '%W'\n", s); @@ -477,7 +477,7 @@ BOOL textonly_re; /* Save time by not scanning for the option name when we don't need it. */ -HDEBUG(D_any) +HDEBUG(any) { const uschar * listname = readconf_find_option(listptr); if (*listname) ot = string_sprintf("%s in %s?", name, listname); @@ -487,7 +487,7 @@ HDEBUG(D_any) if (!*listptr) { - HDEBUG(D_lists) + HDEBUG(lists) if (ot) debug_printf_indent("%s no (option unset)\n", ot); else debug_printf_indent("%s not in empty list (option unset? cannot trace name)\n", name); return FAIL; @@ -526,7 +526,7 @@ else { if (f.expand_string_forcedfail) { - HDEBUG(D_lists) debug_printf_indent("expansion of %q forced failure: " + HDEBUG(lists) debug_printf_indent("expansion of %q forced failure: " "assume not in this list\n", *listptr); return FAIL; } @@ -551,7 +551,7 @@ if (textonly_re) switch (type) /* For an unnamed list, use the expanded version in comments */ #define LIST_LIMIT_PR 2048 -HDEBUG(D_any) if (!ot) +HDEBUG(any) if (!ot) { /* We failed to identify an option name, so give the list text */ int n, m; gstring * g = string_fmt_append(NULL, "%s in \"%n%.*s%n\"", @@ -561,7 +561,7 @@ HDEBUG(D_any) if (!ot) gstring_release_unused(g); ot = string_from_gstring(g); } -HDEBUG(D_lists) +HDEBUG(lists) { debug_printf_indent("%s\n", ot); expand_level++; @@ -574,7 +574,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { uschar * ss = sss; - HDEBUG(D_lists) debug_printf_indent("list element: %W\n", ss); + HDEBUG(lists) debug_printf_indent("list element: %W\n", ss); /* Address lists may contain +caseful, to restore caseful matching of the local part. We have to know the layout of the control block, unfortunately. @@ -727,7 +727,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { case OK: (void)fclose(f); - HDEBUG(D_lists) debug_printf_indent("%s %s (matched %q in %s)\n", + HDEBUG(lists) debug_printf_indent("%s %s (matched %q in %s)\n", ot, yield == OK ? "yes" : "no", sss, filename); /* The "pattern" being matched came from the file; we use a stack-local. @@ -742,7 +742,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) error = string_sprintf("DNS lookup of %s deferred", ss); if (ignore_defer) { - HDEBUG(D_lists) + HDEBUG(lists) debug_printf_indent("%s: item ignored by +ignore_defer\n", error); break; } @@ -760,12 +760,12 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) case ERROR: if (ignore_unknown) { - HDEBUG(D_lists) debug_printf_indent( + HDEBUG(lists) debug_printf_indent( "%s: item ignored by +ignore_unknown\n", error); } else { - HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot, + HDEBUG(lists) debug_printf_indent("%s %s (%s)\n", ot, include_unknown ? "yes":"no", error); (void)fclose(f); if (!include_unknown) @@ -801,7 +801,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) namedlist_block * nb; tree_node * t; - HDEBUG(D_lists) + HDEBUG(lists) { debug_printf_indent(" start sublist %s\n", ss+1); expand_level += 2; } if (is_tainted_metadata(ss)) goto BAD_TAINT; @@ -839,7 +839,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) { int res = match_check_list(&(nb->string), 0, anchorptr, &use_cache_bits, func, arg, type, name, valueptr); - HDEBUG(D_lists) + HDEBUG(lists) { expand_level -= 2; debug_printf_indent(" end sublist %s\n", ss+1); } switch (res) @@ -879,7 +879,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) p->next = nb->cache_data; nb->cache_data = p; if (*valueptr) - HDEBUG(D_lists) debug_printf_indent("data from lookup saved for " + HDEBUG(lists) debug_printf_indent("data from lookup saved for " "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr); } } @@ -891,7 +891,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) else { - HDEBUG(D_lists) + HDEBUG(lists) { expand_level -= 2; debug_printf_indent("cached %s match for %s\n", @@ -909,7 +909,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) *valueptr = p->data; break; } - HDEBUG(D_lists) debug_printf_indent("cached lookup data = %s\n", *valueptr); + HDEBUG(lists) debug_printf_indent("cached lookup data = %s\n", *valueptr); } } @@ -918,7 +918,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if ((bits & (-bits)) == bits) /* Only one of the two bits is set */ { - HDEBUG(D_lists) debug_printf_indent("%s %s (matched %q%s)\n", ot, + HDEBUG(lists) debug_printf_indent("%s %s (matched %q%s)\n", ot, yield == OK ? "yes" : "no", sss, cached); goto YIELD_RETURN; } @@ -932,7 +932,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) switch ((func)(arg, ss, valueptr, &error)) { case OK: - HDEBUG(D_lists) debug_printf_indent("%s %s (matched %q)\n", ot, + HDEBUG(lists) debug_printf_indent("%s %s (matched %q)\n", ot, yield == OK ? "yes" : "no", sss); goto YIELD_RETURN; @@ -941,7 +941,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) error = string_sprintf("DNS lookup of %q deferred", ss); if (ignore_defer) { - HDEBUG(D_lists) + HDEBUG(lists) debug_printf_indent("%s: item ignored by +ignore_defer\n", error); break; } @@ -961,12 +961,12 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) case ERROR: if (ignore_unknown) { - HDEBUG(D_lists) debug_printf_indent( + HDEBUG(lists) debug_printf_indent( "%s: item ignored by +ignore_unknown\n", error); } else { - HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot, + HDEBUG(lists) debug_printf_indent("%s %s (%s)\n", ot, include_unknown? "yes":"no", error); if (!include_unknown) { @@ -984,9 +984,9 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) /* End of list reached: if the last item was negated yield OK, else FAIL. */ -HDEBUG(D_any) +HDEBUG(any) { - HDEBUG(D_lists) expand_level--; + HDEBUG(lists) expand_level--; debug_printf_indent("%s %s (end of list)\n", ot, yield == OK ? "no":"yes"); } return yield == OK ? FAIL : OK; @@ -995,9 +995,9 @@ return yield == OK ? FAIL : OK; BAD_TAINT: DEFER_RETURN: - HDEBUG(D_any) + HDEBUG(any) { - HDEBUG(D_lists) expand_level--; + HDEBUG(lists) expand_level--; debug_printf_indent("%s list match deferred for %s\n", ot, sss); } return DEFER; @@ -1010,7 +1010,7 @@ OK_RETURN: yield = OK; YIELD_RETURN: - HDEBUG(D_lists) expand_level--; + HDEBUG(lists) expand_level--; return yield; } @@ -1121,7 +1121,7 @@ const uschar * s; uschar * pdomain, * sdomain; uschar * value = NULL; -DEBUG(D_lists) debug_printf_indent("address match test: subject=%s pattern=%s\n", +DEBUG(lists) debug_printf_indent("address match test: subject=%s pattern=%s\n", subject, pattern); /* Find the subject's domain */ diff --git a/src/src/mime.c b/src/src/mime.c index 0197894da..604e920fa 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -526,7 +526,7 @@ while(1) if (!fgets(CS header, MIME_MAX_HEADER_SIZE, f)) { /* Hit EOF or read error. Ugh. */ - DEBUG(D_acl) debug_printf_indent("MIME: Hit EOF ...\n"); + DEBUG(acl) debug_printf_indent("MIME: Hit EOF ...\n"); return rc; } @@ -538,12 +538,12 @@ while(1) if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0) { /* END boundary found */ - DEBUG(D_acl) debug_printf_indent("MIME: End boundary found %s\n", + DEBUG(acl) debug_printf_indent("MIME: End boundary found %s\n", context->boundary); return rc; } - DEBUG(D_acl) debug_printf_indent("MIME: Next part with boundary %s\n", + DEBUG(acl) debug_printf_indent("MIME: Next part with boundary %s\n", context->boundary); break; } @@ -564,7 +564,7 @@ while(1) for (p1 = p; *p1 != ';' && *p1; p1++) ; *mh->value = string_copynlc(p, p1-p); - DEBUG(D_acl) debug_printf_indent("MIME: found %s header, value is '%s'\n", + DEBUG(acl) debug_printf_indent("MIME: found %s header, value is '%s'\n", mh->name, *mh->value); if (*(p = p1)) p++; /* jump past the ; */ @@ -579,7 +579,7 @@ while(1) while (*p) { - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("MIME: considering paramlist '%s'\n", p); /* look for interesting parameters */ @@ -629,19 +629,19 @@ while(1) } } - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("MIME: charset %s fname '%s'\n", mime_filename_charset ? mime_filename_charset : US"", fname); fname = rfc2231_to_2047(fname, mime_filename_charset, &slen); - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("MIME: 2047-name %s\n", fname); fname = rfc2047_decode(fname, FALSE, NULL, ' ', NULL, &err_msg); - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "MIME: plain-name %s\n", fname); if (!fname || Ustrlen(fname) == slen) @@ -674,7 +674,7 @@ while(1) ? rfc2047_decode(p3, check_rfc2047_length, NULL, 32, NULL, &dummy_errstr) : NULL; - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "MIME: found %s parameter in %s header, value '%s'\n", mp->name, mh->name, *mp->value); @@ -696,7 +696,7 @@ while(1) if (decoding_failed) mime_filename = string_from_gstring(mime_fname_rfc2231); - DEBUG(D_acl) debug_printf_indent( + DEBUG(acl) debug_printf_indent( "MIME: found %s parameter in %s header, value is '%s'\n", "filename", mh->name, mime_filename); } @@ -737,7 +737,7 @@ while(1) if ( mime_content_type && nested_context.boundary && Ustrncmp(mime_content_type,"multipart",9) == 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf_indent("MIME: Entering multipart recursion, boundary '%s'\n", nested_context.boundary); diff --git a/src/src/miscmods/arc.c b/src/src/miscmods/arc.c index cdd746547..2176fc5a9 100644 --- a/src/src/miscmods/arc.c +++ b/src/src/miscmods/arc.c @@ -199,14 +199,14 @@ for (pas = &ctx->arcset_chain, prev = NULL, next = ctx->arcset_chain; if (as->instance > i) break; if (as->instance == i) { - DEBUG(D_acl) debug_printf("ARC: existing instance %u\n", i); + DEBUG(acl) debug_printf("ARC: existing instance %u\n", i); return as; } next = as->next; prev = as; } -DEBUG(D_acl) debug_printf("ARC: new instance %u\n", i); +DEBUG(acl) debug_printf("ARC: new instance %u\n", i); *pas = as = store_get(sizeof(arc_set), GET_UNTAINTED); memset(as, 0, sizeof(arc_set)); as->next = next; @@ -482,7 +482,7 @@ memset(al, 0, sizeof(arc_line)); if ((e = arc_parse_line(al, h, off, l_ext))) { - DEBUG(D_acl) debug_printf("ARC: %s\n", e); + DEBUG(acl) debug_printf("ARC: %s\n", e); return string_sprintf("line parse: %s", e); } if (!(i = arc_instance_from_hdr(al))) return US"instance find"; @@ -507,7 +507,7 @@ const uschar * e; /*debug_printf("consider hdr '%s'\n", h->text);*/ if (strncmpic(ARC_HDR_AAR, h->text, ARC_HDRLEN_AAR) == 0) { - DEBUG(D_acl) + DEBUG(acl) { int len = h->slen; uschar * s; @@ -518,7 +518,7 @@ if (strncmpic(ARC_HDR_AAR, h->text, ARC_HDRLEN_AAR) == 0) if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AAR, offsetof(arc_set, hdr_aar), is_signing ? le_instance_only : le_instance_plus_ip, NULL))) { - DEBUG(D_acl) debug_printf("inserting AAR: %s\n", e); + DEBUG(acl) debug_printf("inserting AAR: %s\n", e); return string_sprintf("inserting AAR: %s", e); } } @@ -526,7 +526,7 @@ else if (strncmpic(ARC_HDR_AMS, h->text, ARC_HDRLEN_AMS) == 0) { arc_line * ams; - DEBUG(D_acl) + DEBUG(acl) { int len = h->slen; uschar * s; @@ -537,7 +537,7 @@ else if (strncmpic(ARC_HDR_AMS, h->text, ARC_HDRLEN_AMS) == 0) if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AMS, offsetof(arc_set, hdr_ams), is_signing ? le_instance_only : le_all, &ams))) { - DEBUG(D_acl) debug_printf("inserting AMS: %s\n", e); + DEBUG(acl) debug_printf("inserting AMS: %s\n", e); return string_sprintf("inserting AMS: %s", e); } @@ -550,7 +550,7 @@ else if (strncmpic(ARC_HDR_AMS, h->text, ARC_HDRLEN_AMS) == 0) } else if (strncmpic(ARC_HDR_AS, h->text, ARC_HDRLEN_AS) == 0) { - DEBUG(D_acl) + DEBUG(acl) { int len = h->slen; uschar * s; @@ -561,7 +561,7 @@ else if (strncmpic(ARC_HDR_AS, h->text, ARC_HDRLEN_AS) == 0) if ((e = arc_insert_hdr(ctx, h, ARC_HDRLEN_AS, offsetof(arc_set, hdr_as), is_signing ? le_instance_only : le_all, NULL))) { - DEBUG(D_acl) debug_printf("inserting AS: %s\n", e); + DEBUG(acl) debug_printf("inserting AS: %s\n", e); return string_sprintf("inserting AS: %s", e); } } @@ -585,7 +585,7 @@ header_line * h; hdr_rlist * r = NULL, * rprev = NULL; const uschar * e; -DEBUG(D_acl) debug_printf("ARC: collecting arc sets\n"); +DEBUG(acl) debug_printf("ARC: collecting arc sets\n"); for (h = header_list; h; h = h->next) { r = store_get(sizeof(hdr_rlist), GET_UNTAINTED); @@ -667,7 +667,7 @@ int len; if (hm < 0 || !exim_sha_init(&hhash_ctx, hm)) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("ARC: hash setup error, possibly nonhandled hashtype\n"); return; } @@ -677,7 +677,7 @@ walk the message headers in reverse order, adding to the hash any found for the first time. For that last point, maintain used-marks on the list of message headers. */ -DEBUG(D_acl) debug_printf("ARC: AMS header data for verification:\n"); +DEBUG(acl) debug_printf("ARC: AMS header data for verification:\n"); for (r = headers_rlist; r; r = r->prev) r->used = FALSE; @@ -689,7 +689,7 @@ while ((hn = string_nextinlist(&headernames, &sep, NULL, 0))) { if (relaxed) s = arc_relax_header_n(s, r->h->slen, TRUE); - DEBUG(D_acl) debug_printf("%Z\n", s); + DEBUG(acl) debug_printf("%Z\n", s); exim_sha_update_string(&hhash_ctx, s); r->used = TRUE; break; @@ -700,11 +700,11 @@ while ((hn = string_nextinlist(&headernames, &sep, NULL, 0))) s = ams->rawsig_no_b_val.data, len = ams->rawsig_no_b_val.len; if (relaxed) len = Ustrlen(s = arc_relax_header_n(s, len, FALSE)); -DEBUG(D_acl) debug_printf("%.*Z\n", len, s); +DEBUG(acl) debug_printf("%.*Z\n", len, s); exim_sha_update(&hhash_ctx, s, len); exim_sha_finish(&hhash_ctx, hhash); -DEBUG(D_acl) +DEBUG(acl) { debug_printf("ARC: header hash: %.*H\n", hhash->len, hhash->data); } return; } @@ -742,7 +742,7 @@ if (hashes) if (Ustrncmp(ele, al->a_hash.data, al->a_hash.len) == 0) break; if (!ele) { - DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%b\n", hashes, &al->a); + DEBUG(acl) debug_printf("pubkey h=%s vs sig a=%b\n", hashes, &al->a); *errstr = US"no usable sig for this pubkey hash list"; return NULL; } @@ -835,11 +835,11 @@ switch (rc) case OK: break; case FAIL: - DEBUG(D_acl) + DEBUG(acl) debug_printf("ARC i=%d %s verify %s\n", as->instance, why, errstr); break; case ERROR: - DEBUG(D_acl) debug_printf("ARC verify %s init: %s\n", why, errstr); + DEBUG(acl) debug_printf("ARC verify %s init: %s\n", why, errstr); break; } return rc; @@ -890,13 +890,11 @@ if (!(b = arc_ams_setup_vfy_bodyhash(ams))) return US"fail"; } -DEBUG(D_acl) - { +DEBUG(acl) debug_printf("ARC i=%d AMS Body bytes hashed: %lu\n" " Body %b computed: %.*H\n", as->instance, b->signed_body_bytes, &ams->a_hash, b->bh.len, b->bh.data); - } /* We know the bh-tag blob is of a nul-term string, so safe as a string */ @@ -905,7 +903,7 @@ if ( !ams->bh.data || memcmp(sighash.data, b->bh.data, b->bh.len) != 0 ) { - DEBUG(D_acl) + DEBUG(acl) { debug_printf("ARC i=%d AMS Body hash from headers: ", as->instance); debug_printf("%.*H\n", sighash.len, sighash.data); @@ -914,7 +912,7 @@ if ( !ams->bh.data return as->ams_verify_done = arc_state_reason = US"AMS body hash miscompare"; } -DEBUG(D_acl) debug_printf("ARC i=%d AMS Body hash compared OK\n", as->instance); +DEBUG(acl) debug_printf("ARC i=%d AMS Body hash compared OK\n", as->instance); /* We know the b-tag blob is of a nul-term string, so safe as a string */ arc_decode_base64(ams->b.data, &sighash); @@ -923,7 +921,7 @@ arc_get_verify_hhash(ctx, ams, &hhash_computed); if ((hm = arc_dkim_hashname_blob_to_method(&ams->a_hash)) < 0) { - DEBUG(D_acl) debug_printf("ARC i=%d AMS verify bad a_hash\n", as->instance); + DEBUG(acl) debug_printf("ARC i=%d AMS verify bad a_hash\n", as->instance); return as->ams_verify_done = arc_state_reason = US"AMS sig nonverify"; } @@ -932,7 +930,7 @@ if (rc != OK) return as->ams_verify_done = arc_state_reason = rc == FAIL ? US"AMS sig nonverify" : errstr; -DEBUG(D_acl) debug_printf("ARC i=%d AMS verify pass\n", as->instance); +DEBUG(acl) debug_printf("ARC i=%d AMS verify pass\n", as->instance); as->ams_verify_passed = TRUE; return NULL; } @@ -966,7 +964,7 @@ for(inst = as->instance; as; as = as->prev, inst--) else goto good; - DEBUG(D_acl) debug_printf("ARC chain fail at %s\n", arc_state_reason); + DEBUG(acl) debug_printf("ARC chain fail at %s\n", arc_state_reason); return US"fail"; good: @@ -984,7 +982,7 @@ for(inst = as->instance; as; as = as->prev, inst--) if (inst != 0) { arc_state_reason = string_sprintf("(sequence; expected i=%d)", inst); - DEBUG(D_acl) debug_printf("ARC chain fail %s\n", arc_state_reason); + DEBUG(acl) debug_printf("ARC chain fail %s\n", arc_state_reason); return US"fail"; } @@ -1021,7 +1019,7 @@ blob sighash; const uschar * errstr; int rc; -DEBUG(D_acl) debug_printf("ARC: AS vfy i=%d\n", as->instance); +DEBUG(acl) debug_printf("ARC: AS vfy i=%d\n", as->instance); /* 1. If the value of the "cv" tag on that seal is "fail", the chain state is "fail" and the algorithm stops here. (This @@ -1051,7 +1049,7 @@ hm = arc_dkim_hashname_blob_to_method(&hdr_as->a_hash); if (hm < 0 || !exim_sha_init(&hhash_ctx, hm)) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("ARC: hash setup error, possibly nonhandled hashtype\n"); arc_state_reason = US"seal hash setup error"; return US"fail"; @@ -1067,7 +1065,7 @@ if (hm < 0 || !exim_sha_init(&hhash_ctx, hm)) Headers are CRLF-separated, but the last one is not crlf-terminated. */ -DEBUG(D_acl) debug_printf("ARC: AS header data for verification:\n"); +DEBUG(acl) debug_printf("ARC: AS header data for verification:\n"); for (as2 = ctx->arcset_chain; as2 && as2->instance <= as->instance; as2 = as2->next) @@ -1081,7 +1079,7 @@ for (as2 = ctx->arcset_chain; al->relaxed = s = arc_relax_header_n(al->complete->text, al->complete->slen, TRUE); len = Ustrlen(s); - DEBUG(D_acl) debug_printf("%Z\n", s); + DEBUG(acl) debug_printf("%Z\n", s); exim_sha_update(&hhash_ctx, s, len); al = as2->hdr_ams; @@ -1089,7 +1087,7 @@ for (as2 = ctx->arcset_chain; al->relaxed = s = arc_relax_header_n(al->complete->text, al->complete->slen, TRUE); len = Ustrlen(s); - DEBUG(D_acl) debug_printf("%Z\n", s); + DEBUG(acl) debug_printf("%Z\n", s); exim_sha_update(&hhash_ctx, s, len); al = as2->hdr_as; @@ -1100,7 +1098,7 @@ for (as2 = ctx->arcset_chain; al->relaxed = s = arc_relax_header_n(al->complete->text, al->complete->slen, TRUE); len = Ustrlen(s); - DEBUG(D_acl) debug_printf("%Z\n", s); + DEBUG(acl) debug_printf("%Z\n", s); exim_sha_update(&hhash_ctx, s, len); } @@ -1109,7 +1107,7 @@ for (as2 = ctx->arcset_chain; */ exim_sha_finish(&hhash_ctx, &hhash_computed); -DEBUG(D_acl) +DEBUG(acl) { debug_printf("ARC i=%d AS Header %b computed: ", as->instance, &hdr_as->a_hash); @@ -1142,7 +1140,7 @@ if (rc != OK) return US"fail"; } -DEBUG(D_acl) debug_printf("ARC: AS vfy i=%d pass\n", as->instance); +DEBUG(acl) debug_printf("ARC: AS vfy i=%d pass\n", as->instance); return NULL; } @@ -1157,7 +1155,7 @@ if (!as) for ( ; as; as = as->prev) if (arc_seal_verify(ctx, as)) return US"fail"; -DEBUG(D_acl) debug_printf("ARC: AS vfy overall pass\n"); +DEBUG(acl) debug_printf("ARC: AS vfy overall pass\n"); return NULL; } /******************************************************************************/ @@ -1258,7 +1256,7 @@ out: if (!(arc_state = res)) return DEFER; - DEBUG(D_acl) debug_printf_indent("ARC verify result %s %s%s%s\n", arc_state, + DEBUG(acl) debug_printf_indent("ARC verify result %s %s%s%s\n", arc_state, arc_state_reason ? "(":"", arc_state_reason, arc_state_reason ? ")":""); if (!condlist) condlist = US"none:pass"; @@ -1390,7 +1388,7 @@ else ctx->arcset_chain_last->next = as; ctx->arcset_chain_last = as; -DEBUG(D_transport) debug_printf("ARC: AAR '%.*s'\n", h->slen - 2, h->text); +DEBUG(transport) debug_printf("ARC: AAR '%.*s'\n", h->slen - 2, h->text); return g; } @@ -1409,7 +1407,7 @@ const uschar * errstr; typedef const uschar * (*fn_t) (const blob *, hashmethod, const uschar *, blob *); -DEBUG(D_transport) +DEBUG(transport) { hctx hhash_ctx; debug_printf("ARC: %s header data for signing:\n", why); @@ -1439,7 +1437,7 @@ errstr = (((fn_t *) arc_dkim_mod_info->functions)[DKIM_SIGN_DATA]) if (errstr) { log_write(0, LOG_MAIN, "ARC: %s signing: %s\n", why, errstr); - DEBUG(D_transport) + DEBUG(transport) debug_printf("private key, or private-key file content, was: '%s'\n", privkey); return FALSE; @@ -1565,7 +1563,7 @@ h->text = g->s + ams_off; al->complete = h; ctx->arcset_chain_last->hdr_ams = al; -DEBUG(D_transport) debug_printf("ARC: AMS '%.*s'\n", h->slen - 2, h->text); +DEBUG(transport) debug_printf("ARC: AMS '%.*s'\n", h->slen - 2, h->text); return g; } @@ -1624,7 +1622,7 @@ blob sig; - all ARC set headers, set-number order, aar then ams then as, including self (but with an empty b= in self) */ -DEBUG(D_transport) debug_printf("ARC: building AS for status '%s'\n", status); +DEBUG(transport) debug_printf("ARC: building AS for status '%s'\n", status); /* Construct the AS except for the signature */ @@ -1678,14 +1676,14 @@ if (!arc_sig_from_pseudoheader(hdata, hashtype, privkey, &sig, US"AS")) /* Lose the trailing semicolon */ gstring_trim(arcset, 1); arcset = arc_sign_append_sig(arcset, &sig); -DEBUG(D_transport) debug_printf("ARC: AS '%.*s'\n", arcset->ptr - 2, arcset->s); +DEBUG(transport) debug_printf("ARC: AS '%.*s'\n", arcset->ptr - 2, arcset->s); /* Finally, append the AMS and AAR to the new AS */ return string_catn(arcset, arcset_interim->s, arcset_interim->ptr); badline: - DEBUG(D_transport) + DEBUG(transport) debug_printf("ARC: while building AS, missing %s in chain\n", badline_str); return NULL; } @@ -1699,7 +1697,7 @@ arc_ams_setup_sign_bodyhash(void) blob canon = {.data = US"relaxed", .len = 7}; /*XXX hardwired */ blob hash = {.data = US"sha256", .len = 6}; /*XXX hardwired */ -DEBUG(D_transport) debug_printf("ARC: requesting bodyhash\n"); +DEBUG(transport) debug_printf("ARC: requesting bodyhash\n"); return arc_set_bodyhash(TRUE, &canon, &hash, -1); } @@ -1837,7 +1835,7 @@ if ((opts = string_nextinlist(&signspec, &sep, NULL, 0))) } } -DEBUG(D_transport) debug_printf("ARC: sign for %s\n", identity); +DEBUG(transport) debug_printf("ARC: sign for %s\n", identity); /* Make an rlist of any new DKIM headers, then add the "normals" rlist to it. Then scan the list for an A-R header. */ @@ -1871,7 +1869,7 @@ if (!(arc_sign_find_ar(headers, identity, &ar))) feed from the DKIM module. Use that to give the instance number for the ARC set we are about to build. */ -DEBUG(D_transport) +DEBUG(transport) if (arc_sign_ctx.arcset_chain_last) debug_printf("ARC: existing chain highest instance: %d\n", arc_sign_ctx.arcset_chain_last->instance); @@ -1962,7 +1960,7 @@ uschar * errstr; if (strncmpic(ARC_HDR_AMS, g->s, ARC_HDRLEN_AMS) != 0) return US"not AMS"; -DEBUG(D_receive) debug_printf("ARC: spotted AMS header\n"); +DEBUG(receive) debug_printf("ARC: spotted AMS header\n"); /* Parse the AMS header */ memset(&al, 0, sizeof(arc_line)); @@ -1970,13 +1968,13 @@ h.next = NULL; h.slen = len_string_from_gstring(g, &h.text); if ((errstr = arc_parse_line(&al, &h, ARC_HDRLEN_AMS, le_all))) { - DEBUG(D_acl) debug_printf("ARC: %s\n", errstr); + DEBUG(acl) debug_printf("ARC: %s\n", errstr); goto badline; } if (!al.a_hash.data) { - DEBUG(D_acl) debug_printf("ARC: no a_hash from '%.*s'\n", h.slen, h.text); + DEBUG(acl) debug_printf("ARC: no a_hash from '%.*s'\n", h.slen, h.text); goto badline; } @@ -2063,7 +2061,7 @@ authres_arc(gstring * g) if (arc_state) { int start = 0; /* Compiler quietening */ - DEBUG(D_acl) start = gstring_length(g); + DEBUG(acl) start = gstring_length(g); g = string_append(g, 2, US";\n\tarc=", arc_state); if (arc_received_instance > 0) @@ -2081,11 +2079,11 @@ if (arc_state) } else if (arc_state_reason) g = string_append(g, 3, US" (", arc_state_reason, US")"); - DEBUG(D_acl) debug_printf_indent("ARC:\tauthres '%.*s'\n", + DEBUG(acl) debug_printf_indent("ARC:\tauthres '%.*s'\n", gstring_length(g) - start - 3, g->s + start + 3); } else - DEBUG(D_acl) debug_printf_indent("ARC:\tno authres\n"); + DEBUG(acl) debug_printf_indent("ARC:\tno authres\n"); return g; } diff --git a/src/src/miscmods/dkim.c b/src/src/miscmods/dkim.c index d6858a00c..b36bbebf9 100644 --- a/src/src/miscmods/dkim.c +++ b/src/src/miscmods/dkim.c @@ -146,12 +146,12 @@ pdkim_pubkey * p; if (!dnstxt) { - DEBUG(D_acl) debug_printf_indent("pubkey dns lookup fail\n"); + DEBUG(acl) debug_printf_indent("pubkey dns lookup fail\n"); return NULL; } if (!(p = pdkim_parse_pubkey_record(dnstxt))) { - DEBUG(D_acl) debug_printf_indent("pubkey dns record format error\n"); + DEBUG(acl) debug_printf_indent("pubkey dns record format error\n"); return NULL; } *pubkey_p = &p->key; @@ -504,7 +504,7 @@ dkim_acl_call(uschar * id, gstring ** res_ptr, uschar ** user_msgptr, uschar ** log_msgptr) { int rc; -DEBUG(D_receive) +DEBUG(receive) debug_printf("calling acl_smtp_dkim for identity '%s' domain '%s' sel '%s'\n", id, dkim_signing_domain, dkim_signing_selector); @@ -645,7 +645,7 @@ if (dkim_verify_signers && *dkim_verify_signers) if (seen_this_item) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("acl_smtp_dkim: skipping signer %s, " "already seen\n", item); continue; @@ -657,7 +657,7 @@ if (dkim_verify_signers && *dkim_verify_signers) if ((rc = dkim_exim_acl_run(item, &results, user_msgptr, log_msgptr)) != OK) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("acl_smtp_dkim: acl_check returned %d on %s, " "skipping remaining items\n", rc, item); break; @@ -1078,7 +1078,7 @@ produce, if some other package (eg. ARC) is signing. */ if (!dkim_sign_ctx.sig && !dkim->force_bodyhash) { - DEBUG(D_transport) debug_printf("DKIM: no viable signatures to use\n"); + DEBUG(transport) debug_printf("DKIM: no viable signatures to use\n"); sigbuf = string_get(1); /* return a zero-len string */ } else @@ -1108,7 +1108,7 @@ else if (!sig) { - DEBUG(D_transport) debug_printf("DKIM: no signatures to use\n"); + DEBUG(transport) debug_printf("DKIM: no signatures to use\n"); sigbuf = string_get(1); /* return a zero-len string */ } else for (sigbuf = NULL; sig; sig = sig->next) @@ -1216,7 +1216,7 @@ es_ctx sctx; const uschar * errstr; if ((errstr = exim_dkim_signing_init(privkey, &sctx))) - { DEBUG(D_transport) debug_printf("signing key setup: %s\n", errstr); } + { DEBUG(transport) debug_printf("signing key setup: %s\n", errstr); } else errstr = exim_dkim_sign(&sctx, hm, data, signature); return errstr; @@ -1232,7 +1232,7 @@ authres_dkim(gstring * g) { int start = 0; /* compiler quietening */ -DEBUG(D_acl) start = gstring_length(g); +DEBUG(acl) start = gstring_length(g); for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next) { @@ -1293,7 +1293,7 @@ for (pdkim_signature * sig = dkim_signatures; sig; sig = sig->next) g = string_append(g, 2, US" header.a=", dkim_sig_to_a_tag(sig)); } -DEBUG(D_acl) +DEBUG(acl) if (gstring_length(g) == start) debug_printf_indent("DKIM:\tno authres\n"); else diff --git a/src/src/miscmods/dkim_transport.c b/src/src/miscmods/dkim_transport.c index 1e9a1153c..05a5e65a1 100644 --- a/src/src/miscmods/dkim_transport.c +++ b/src/src/miscmods/dkim_transport.c @@ -48,9 +48,9 @@ dkt_send_file(int out_fd, int in_fd, off_t off ) { #ifdef OS_SENDFILE -DEBUG(D_transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off)); +DEBUG(transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off)); #else -DEBUG(D_transport) debug_printf("send file fd=%d\n", out_fd); +DEBUG(transport) debug_printf("send file fd=%d\n", out_fd); #endif /*XXX should implement timeout, like transport_write_block_fd() ? */ @@ -163,7 +163,7 @@ int hsize; const uschar * errstr; BOOL rc; -DEBUG(D_transport) debug_printf("dkim signing direct-mode\n"); +DEBUG(transport) debug_printf("dkim signing direct-mode\n"); /* Get headers in string for signing and transmission. Do CRLF and dotstuffing (but no body nor dot-termination) */ @@ -266,7 +266,7 @@ const uschar * errstr; dkim_spool_name = spool_fname(US"input", message_subdir, message_id, string_sprintf("-" PID_T_FMT "-K", getpid())); -DEBUG(D_transport) debug_printf("dkim signing via file %s\n", dkim_spool_name); +DEBUG(transport) debug_printf("dkim signing via file %s\n", dkim_spool_name); if ((dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE)) < 0) { diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index 5a5ea7398..8bbf84841 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -163,7 +163,7 @@ there was a previous error. */ if (!header_from) { - DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); + DEBUG(receive) debug_printf_indent("DMARC: no From: header\n"); dmarc_abort = TRUE; } else if (!dmarc_abort) @@ -217,7 +217,7 @@ if (!dmarc_abort && !sender_host_authenticated) if (sr == SPF_RESULT_INVALID) { - DEBUG(D_receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); + DEBUG(receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; @@ -241,7 +241,7 @@ if (!dmarc_abort && !sender_host_authenticated) sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR : ARES_RESULT_UNKNOWN; origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; - DEBUG(D_receive) debug_printf_indent("DMARC using SPF sender domain = %s\n", + DEBUG(receive) debug_printf_indent("DMARC using SPF sender domain = %s\n", spf_sender_domain); } if (!*spf_sender_domain) @@ -278,7 +278,7 @@ The EDITME provides a DMARC_API variable */ sig->selector, #endif dkim_result, US""); - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC adding DKIM sender domain = %s\n", sig->domain); if (libdm_status != DMARC_PARSE_OKAY) log_write(0, LOG_MAIN|LOG_PANIC, @@ -317,22 +317,22 @@ The EDITME provides a DMARC_API variable */ { case DMARC_DNS_ERROR_NXDOMAIN: case DMARC_DNS_ERROR_NO_RECORD: - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC no record found for %s\n", dmarc_header_from_sender); has_dmarc_record = FALSE; break; case DMARC_PARSE_OKAY: - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC record found for %s\n", dmarc_header_from_sender); break; case DMARC_PARSE_ERROR_BAD_VALUE: - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC record parse error for %s\n", dmarc_header_from_sender); has_dmarc_record = FALSE; break; default: /* everything else, skip dmarc */ - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC skipping (%s), unsure what to do with %s", opendmarc_policy_status_to_str(libdm_status), header_from); @@ -421,7 +421,7 @@ The EDITME provides a DMARC_API variable */ dmarc_alignment_dkim = dmarc_dkim_alignment == DMARC_POLICY_DKIM_ALIGNMENT_PASS; - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index ab0027f17..0449f9f0e 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -111,12 +111,12 @@ if ( !dmarc_tld_file || !(dmarc_tld_file = expand_string(dmarc_tld_file)) || !*dmarc_tld_file) { - DEBUG(D_receive) debug_printf_indent("DMARC: no dmarc_tld_file\n"); + DEBUG(receive) debug_printf_indent("DMARC: no dmarc_tld_file\n"); dmarc_abort = TRUE; } else if (!sender_host_address) { - DEBUG(D_receive) debug_printf_indent("DMARC: no sender_host_address\n"); + DEBUG(receive) debug_printf_indent("DMARC: no sender_host_address\n"); dmarc_abort = TRUE; } else @@ -194,7 +194,7 @@ for (int c = 0; ruf[c]; c++) continue; /* Move to first character past the colon */ recipient += 7; - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC forensic report to %s%s\n", recipient, host_checking || f.running_in_test_harness ? " (not really)" : ""); if (host_checking || f.running_in_test_harness) @@ -246,18 +246,18 @@ if (dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL) else /* RFC 7489 6.6.3 step 5: multiple records are treated as no record */ { - DEBUG(D_receive) debug_printf_indent("DMARC: multiple rr\n"); + DEBUG(receive) debug_printf_indent("DMARC: multiple rr\n"); res = NULL; break; } } } else - DEBUG(D_receive) debug_printf_indent("DMARC: no ret\n"); + DEBUG(receive) debug_printf_indent("DMARC: no ret\n"); expand_level--; store_free_dns_answer(dnsa); -DEBUG(D_receive) debug_printf_indent("DMARC: rr %q\n", res); +DEBUG(receive) debug_printf_indent("DMARC: rr %q\n", res); return res; } @@ -272,12 +272,12 @@ const lookup_info * li; void * handle; static const uschar * cached_key = NULL, * cached_res = NULL; -DEBUG(D_receive) debug_printf_indent("DMARC: lookup regdom for %q\n", dom); +DEBUG(receive) debug_printf_indent("DMARC: lookup regdom for %q\n", dom); if (cached_key && Ustrcmp(dom, cached_key) == 0) { res = cached_res; - DEBUG(D_receive) debug_printf_indent(" DMARC: cached value %q\n", res); + DEBUG(receive) debug_printf_indent(" DMARC: cached value %q\n", res); return res; } @@ -286,7 +286,7 @@ res = NULL; if (!(li = search_findtype_partial(US"regdom", &partial, &affix, &affixlen, &starflags, &opts))) { - DEBUG(D_receive) debug_printf_indent("DMARC: missing regdom lookup\n"); + DEBUG(receive) debug_printf_indent("DMARC: missing regdom lookup\n"); goto out; } @@ -309,7 +309,7 @@ dmarc_get_dns_policy_record(const uschar ** used_dom_p) { const uschar * s; -DEBUG(D_receive) debug_printf_indent("DMARC: lookup policy record for %s\n", +DEBUG(receive) debug_printf_indent("DMARC: lookup policy record for %s\n", dmarc_header_from_sender); /* RFC 7489 6.6.3 step 1: DNS domain matching the 5322.From */ @@ -341,7 +341,7 @@ gstring * g; GET_OPTION("dmarc_history_file"); if (!(s = dmarc_history_file) || !(s = expand_string(s)) || !*s) { - DEBUG(D_receive) debug_printf_indent("DMARC history file not set\n"); + DEBUG(receive) debug_printf_indent("DMARC history file not set\n"); return; } if (!host_checking) /* -bh mode: nothing written except debug */ @@ -429,7 +429,7 @@ g = string_fmt_append(g, "align_dkim %d\n" #endif /* Write the contents to the history file */ -DEBUG(D_receive) +DEBUG(receive) { debug_printf_indent("DMARC history data for debugging:\n"); expand_level++; @@ -464,15 +464,15 @@ authres_dmarc(gstring * g) if (f.dmarc_has_been_checked) { int start = 0; /* Compiler quietening */ - DEBUG(D_acl) start = gstring_length(g); + DEBUG(acl) start = gstring_length(g); g = string_append(g, 2, US";\n\tdmarc=", dmarc_pass_fail); if (dmarc_header_from_sender) g = string_append(g, 2, US" header.from=", dmarc_header_from_sender); - DEBUG(D_acl) debug_printf_indent("DMARC:\tauthres '%.*s'\n", + DEBUG(acl) debug_printf_indent("DMARC:\tauthres '%.*s'\n", gstring_length(g) - start - 3, g->s + start + 3); } else - DEBUG(D_acl) debug_printf_indent("DMARC:\tno authres\n"); + DEBUG(acl) debug_printf_indent("DMARC:\tno authres\n"); return g; } diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index 9fa4a1924..a14785802 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -201,7 +201,7 @@ const uschar * e = Ustrchr(tagrecord, '='), * s; /* RFC 6736 3.2 tagspec must have = */ if (!e) { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: missing '=' for tag in %q\n", tagrecord); return FALSE; } @@ -212,7 +212,7 @@ for (s = e; s > tagrecord && isspace(s[-1]); ) s--; /* RFC 6736 3.2 tag name at least 1 char */ if (s == tagrecord) { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: missing tag name in %q\n", tagrecord); return FALSE; } @@ -237,13 +237,13 @@ for (tag * ptp = policy_tags; ptp < policy_tags + nelem(policy_tags); ptp++) *vp = string_copy(s); return TRUE; } - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: bad value for tag %q: %q\n", ptp->name, s); return FALSE; } } -DEBUG(D_receive) +DEBUG(receive) debug_printf_indent("DMARC: no recognised tag in %q\n", tagrecord); return FALSE; } @@ -290,7 +290,7 @@ else res = a && b && Ustrcmp(a, b) == 0; } } -DEBUG(D_receive) +DEBUG(receive) if (res) debug_printf_indent("DMARC aligned(%s) %s %s\n", mode, a, b); return res; } @@ -315,7 +315,7 @@ dmarc_spf_alignment = DMARC_POLICY_SPF_ALIGNMENT_FAIL; if (f.dmarc_disable_verify || dmarc_abort) return OK; -DEBUG(D_receive) { debug_printf_indent("DMARC: process\n"); expand_level++; } +DEBUG(receive) { debug_printf_indent("DMARC: process\n"); expand_level++; } /* Store the header From: sender domain for this part of DMARC. If there is no from_header string, then it's likely this message @@ -325,7 +325,7 @@ there was a previous error. */ if (!header_from) { - DEBUG(D_receive) debug_printf_indent("DMARC: no From: header\n"); + DEBUG(receive) debug_printf_indent("DMARC: no From: header\n"); dmarc_abort = TRUE; } else @@ -380,7 +380,7 @@ if (!dmarc_abort && !sender_host_authenticated) typedef const pdkim_signature * (*sigs_fn_t)(void); /* RFC 7489 6.6.2 step 2: DMARC policy record from DNS */ - DEBUG(D_receive) + DEBUG(receive) { debug_printf_indent("DMARC: get policy record\n"); expand_level++; @@ -390,7 +390,7 @@ if (!dmarc_abort && !sender_host_authenticated) if (!(rr = dmarc_get_dns_policy_record(&dmarc_used_domain))) /*XXX want to handle nxdomain,temprror etc. here */ { - DEBUG(D_receive) debug_printf_indent("DMARC: no record found for %s\n", + DEBUG(receive) debug_printf_indent("DMARC: no record found for %s\n", dmarc_header_from_sender); dmarc_policy = DMARC_POLICY_ABSENT; dmarc_status = US"norecord"; @@ -403,7 +403,7 @@ if (!dmarc_abort && !sender_host_authenticated) else if (!dmarc_local_parse_policy(rr, &dmarc_parsed)) { - DEBUG(D_receive) debug_printf_indent("DMARC: invalid record found for %s\n", + DEBUG(receive) debug_printf_indent("DMARC: invalid record found for %s\n", dmarc_header_from_sender); dmarc_policy = DMARC_POLICY_ABSENT; dmarc_status = US"norecord"; @@ -425,20 +425,20 @@ if (!dmarc_abort && !sender_host_authenticated) /*XXX "at least one syntactically valid reporting URI" */ if (dmarc_parsed.rua && dmarc_tag_vfy_rua(dmarc_parsed.rua)) { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: invalid p or sp; continue for rua\n"); dmarc_parsed.p = US"none"; } else { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: invalid p or sp, and no rua. Abort.\n"); dmarc_abort = TRUE; goto out; } /* RFC 7489 6.6.2 step 3: Perform DKIM signature verification checks */ - DEBUG(D_receive) + DEBUG(receive) { expand_level--; debug_printf_indent("DMARC: process dkim results\n"); @@ -463,7 +463,7 @@ if (!dmarc_abort && !sender_host_authenticated) vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : DMARC_POLICY_DKIM_OUTCOME_NONE; - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: adding DKIM sender domain = %s\n", sig->domain); @@ -499,10 +499,10 @@ if (!dmarc_abort && !sender_host_authenticated) ) dmarc_dkim_alignment = DMARC_POLICY_DKIM_ALIGNMENT_PASS; } - DEBUG(D_receive) debug_printf_indent("DMARC: %u dkim sig%s\n", + DEBUG(receive) debug_printf_indent("DMARC: %u dkim sig%s\n", dkim_sig_count, dkim_sig_count == 1 ? "" : "s"); - DEBUG(D_receive) + DEBUG(receive) { expand_level--; debug_printf_indent("DMARC: process spf results\n"); @@ -524,7 +524,7 @@ if (!dmarc_abort && !sender_host_authenticated) if (sr == SPF_RESULT_INVALID) { - DEBUG(D_receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); + DEBUG(receive) debug_printf_indent("DMARC: spf result 'invalid'\n"); spf_result = DMARC_POLICY_SPF_OUTCOME_NONE; dmarc_spf_ares_result = ARES_RESULT_UNKNOWN; @@ -548,7 +548,7 @@ if (!dmarc_abort && !sender_host_authenticated) ARES_RESULT_UNKNOWN; /*XXX hmm, spf_origin never used? */ /* spf_origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM; */ - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC: using SPF sender domain = %s\n", spf_sender_domain); } @@ -568,7 +568,7 @@ if (!dmarc_abort && !sender_host_authenticated) } } - DEBUG(D_receive) + DEBUG(receive) { expand_level--; debug_printf_indent("DMARC: finished spf\n"); @@ -634,7 +634,7 @@ use the sp. Otherwise use the p. */ if (has_dmarc_record && !dmarc_abort) { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("DMARC results: spf_domain=%s dmarc_domain=%s " "spf_align=%s dkim_align=%s enforcement='%s'", spf_sender_domain, dmarc_used_domain, @@ -667,7 +667,7 @@ use the sp. Otherwise use the p. */ } out: - DEBUG(D_receive) + DEBUG(receive) { expand_level--; debug_printf_indent("DMARC: finished process, status %q\n", dmarc_status); diff --git a/src/src/miscmods/dscp.c b/src/src/miscmods/dscp.c index 8c25833d9..ee7c00128 100644 --- a/src/src/miscmods/dscp.c +++ b/src/src/miscmods/dscp.c @@ -119,13 +119,13 @@ else if (af == AF_INET6) #endif else { - DEBUG(D_transport) + DEBUG(transport) debug_printf("Unhandled address family %d in dscp_lookup()\n", af); return FALSE; } if (!dscp_name) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("[empty DSCP]\n"); return FALSE; } @@ -146,7 +146,7 @@ if (p != dscp_lookup && *p == '\0') RFC 2597 defines the values unshifted. */ if (rawlong < 0 || rawlong > 0x3F) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("DSCP value %ld out of range, ignored.\n", rawlong); return FALSE; } @@ -194,7 +194,7 @@ anyway. */ if (smtp_in_fd < 0) return US"no stdin"; if ((af = ip_get_address_family(smtp_in_fd)) < 0) { - HDEBUG(D_acl) debug_printf_indent( + HDEBUG(acl) debug_printf_indent( "smtp input is probably not a socket [%s], not setting DSCP\n", strerror(errno)); return NULL; @@ -204,7 +204,7 @@ if (!dscp_lookup(++opt, af, &socklevel, &optname, &value)) value = setsockopt(smtp_in_fd, socklevel, optname, &value, sizeof(value)); -HDEBUG(D_acl) +HDEBUG(acl) if (value < 0) debug_printf_indent("failed to set input DSCP[%s]: %s\n", opt, strerror(errno)); @@ -228,11 +228,11 @@ if ( dscp_str && dscp_lookup(dscp_str, host_af, &dscp_level, &dscp_option, &dscp_value) ) { - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent("DSCP %q=%x ", dscp_str, dscp_value); if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0) - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent("failed to set DSCP: %s ", strerror(errno)); /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the diff --git a/src/src/miscmods/exim_filter.c b/src/src/miscmods/exim_filter.c index 21ede4ad5..e86bf9b04 100644 --- a/src/src/miscmods/exim_filter.c +++ b/src/src/miscmods/exim_filter.c @@ -794,7 +794,7 @@ return nextsigchar(ptr, TRUE); static void indent(void) { -DEBUG(D_filter) for (int i = 0; i < output_indent; i++) debug_printf(" "); +DEBUG(filter) for (int i = 0; i < output_indent; i++) debug_printf(" "); } @@ -1673,8 +1673,7 @@ switch (c->type) if (filter_thisaddress) { - if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { indent(); debug_printf_indent("Extracted address %s\n", filter_thisaddress); @@ -1752,8 +1751,7 @@ switch (c->type) const pcre2_code * re; mcs_flags flags = textonly_re ? MCS_CACHEABLE : MCS_NOFLAGS; - if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { debug_printf_indent("Match expanded arguments:\n"); debug_printf_indent(" Subject = %s\n", exp[0]); @@ -1788,8 +1786,7 @@ switch (c->type) break; } -if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) +if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { indent(); debug_printf_indent("%sondition is %s: ", @@ -1953,7 +1950,7 @@ while (commands) else { - DEBUG(D_filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n", + DEBUG(filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n", commands->seen ? "" : "unseen ", expargs[0], commands->noerror ? " (noerror)" : "", @@ -1999,7 +1996,7 @@ while (commands) if (s[0] != '/' && filter_options & RDO_PREPEND_HOME && deliver_home && *deliver_home) s = string_sprintf("%s/%s", deliver_home, s); - DEBUG(D_filter) debug_printf_indent("Filter: %ssave message to: %s%s\n", + DEBUG(filter) debug_printf_indent("Filter: %ssave message to: %s%s\n", commands->seen ? "" : "unseen ", s, commands->noerror ? " (noerror)" : ""); @@ -2028,7 +2025,7 @@ while (commands) } else /* Ensure pipe command starts with | */ { - DEBUG(D_filter) debug_printf_indent("Filter: %spipe message to: %s%s\n", + DEBUG(filter) debug_printf_indent("Filter: %spipe message to: %s%s\n", commands->seen ? "" : "unseen ", s, commands->noerror ? " (noerror)" : ""); if (s[0] != '|') s = string_sprintf("|%s", s); @@ -2099,7 +2096,7 @@ while (commands) else if (filter_options & RDO_LOG) /* Locked out */ { - DEBUG(D_filter) + DEBUG(filter) debug_printf_indent("filter log command aborted: euid=%ld\n", (long int)geteuid()); *error_pointer = US"logwrite command forbidden"; @@ -2108,7 +2105,7 @@ while (commands) else if (filter_options & RDO_REALLOG) { int len; - DEBUG(D_filter) debug_printf_indent("writing filter log as euid %ld\n", + DEBUG(filter) debug_printf_indent("writing filter log as euid %ld\n", (long int)geteuid()); if (log_fd < 0) { @@ -2135,7 +2132,7 @@ while (commands) } } else - DEBUG(D_filter) + DEBUG(filter) debug_printf_indent("skipping logwrite (verifying or testing)\n"); break; @@ -2214,7 +2211,7 @@ while (commands) printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg); } else - DEBUG(D_filter) debug_printf_indent("Filter: %s %q\n", ff_name, fmsg); + DEBUG(filter) debug_printf_indent("Filter: %s %q\n", ff_name, fmsg); return ff_ret; case FINISH_COMMAND: @@ -2224,7 +2221,7 @@ while (commands) printf("%sinish\n", commands->seen ? "Seen f" : "F"); } else - DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n", + DEBUG(filter) debug_printf_indent("Filter: %sfinish\n", commands->seen ? " Seen " : ""); finish_obeyed = TRUE; return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED; @@ -2261,7 +2258,7 @@ while (commands) if (filter_test != FTEST_NONE) printf("%s command ignored because return_path is empty\n", command_list[commands->command]); - else DEBUG(D_filter) + else DEBUG(filter) debug_printf_indent("%s command ignored because return_path " "is empty\n", command_list[commands->command]); break; @@ -2360,7 +2357,7 @@ while (commands) if (arg) { int len = Ustrlen(mailargs[i]); - int indent = debug_selector != 0 ? output_indent : 0; + int indent = ANY_DEBUG ? output_indent : 0; while (len++ < 7 + indent) printf(" "); printf("%s: %s%s\n", mailargs[i], string_printing(arg), ( commands->args[mailarg_index_expand].u @@ -2389,7 +2386,7 @@ while (commands) break; } - DEBUG(D_filter) + DEBUG(filter) { debug_printf_indent("Filter: %smail to: %s%s%s\n", commands->seen ? "seen " : "", @@ -2500,7 +2497,7 @@ while (commands) break; case TESTPRINT_COMMAND: - if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) + if (filter_test != FTEST_NONE || IS_DEBUG(filter)) { const uschar * t = string_printing(expargs[0]); if (filter_test == FTEST_NONE) @@ -2549,7 +2546,7 @@ const uschar *save_headers_charset = headers_charset; filter_cmd *commands = NULL; filter_cmd **lastcmdptr = &commands; -DEBUG(D_route) debug_printf("Filter: start of processing\n"); +DEBUG(route) debug_printf("Filter: start of processing\n"); acl_level++; /* Initialize "not in an if command", set the global flag that is always TRUE @@ -2584,7 +2581,7 @@ ptr = nextsigchar(ptr, TRUE); if (read_command_list(&ptr, &lastcmdptr, FALSE)) yield = interpret_commands(commands, generated); -if (filter_test != FTEST_NONE || (debug_selector & D_filter) != 0) +if (filter_test != FTEST_NONE || IS_DEBUG(filter)) { uschar *s = US""; switch(yield) @@ -2630,7 +2627,7 @@ f.filter_running = FALSE; headers_charset = save_headers_charset; acl_level--; -DEBUG(D_route) debug_printf("Filter: end of processing\n"); +DEBUG(route) debug_printf("Filter: end of processing\n"); return yield; } diff --git a/src/src/miscmods/pam.c b/src/src/miscmods/pam.c index f39e09208..9a44b07b8 100644 --- a/src/src/miscmods/pam.c +++ b/src/src/miscmods/pam.c @@ -160,7 +160,7 @@ if (user == NULL || user[0] == 0) return FAIL; /* Start off PAM interaction */ -DEBUG(D_auth) debug_printf("Running PAM authentication for user %q\n", user); +DEBUG(auth) debug_printf("Running PAM authentication for user %q\n", user); pam_error = pam_start ("exim", CS user, &pamc, &pamh); @@ -184,12 +184,12 @@ pam_end(pamh, PAM_SUCCESS); if (pam_error == PAM_SUCCESS) { - DEBUG(D_auth) debug_printf("PAM success\n"); + DEBUG(auth) debug_printf("PAM success\n"); return OK; } *errptr = US pam_strerror(pamh, pam_error); -DEBUG(D_auth) debug_printf("PAM error: %s\n", *errptr); +DEBUG(auth) debug_printf("PAM error: %s\n", *errptr); if (pam_error == PAM_USER_UNKNOWN || pam_error == PAM_AUTH_ERR || diff --git a/src/src/miscmods/pdkim/pdkim.c b/src/src/miscmods/pdkim/pdkim.c index a7ec5f511..a3250ab6e 100644 --- a/src/src/miscmods/pdkim/pdkim.c +++ b/src/src/miscmods/pdkim/pdkim.c @@ -510,7 +510,7 @@ for (uschar * p = raw_hdr; ; p++) (void) string_from_gstring(cur_val); pdkim_strtrim(cur_val); - DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s); + DEBUG(acl) debug_printf(" %s=%s\n", cur_tag->s, cur_val->s); switch (*cur_tag->s) { @@ -580,7 +580,7 @@ for rsafp signatures. But later discussion is dropping those. */ } } else -bad_tag: DEBUG(D_acl) debug_printf(" Unknown tag encountered: %Y\n", cur_tag); +bad_tag: DEBUG(acl) debug_printf(" Unknown tag encountered: %Y\n", cur_tag); cur_tag = cur_val = NULL; in_b_val = FALSE; @@ -606,7 +606,7 @@ if (sig->keytype < 0 || sig->hashtype < 0) /* Cannot verify this signature */ while (--q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n')) *q = '\0'; -DEBUG(D_acl) +DEBUG(acl) { debug_printf( "DKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); @@ -644,7 +644,7 @@ for (const uschar * ele = raw_record, * tspec, * end, * val; *ele; ele = end) { int taglen = val++ - tspec; - DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, tspec, val); + DEBUG(acl) debug_printf(" %.*s=%s\n", taglen, tspec, val); while (taglen > 1 && isspace(tspec[taglen-1])) taglen--; /* Ignore whitespace before = */ Uskip_whitespace(&val); /* Ignore whitespace after = */ @@ -655,7 +655,7 @@ for (const uschar * ele = raw_record, * tspec, * end, * val; *ele; ele = end) gstring_trim(g, 1); if (!(val = string_from_gstring(g))) { - DEBUG(D_acl) + DEBUG(acl) debug_printf(" Missing value for tag '%.*s'\n", taglen, tspec); return NULL; } @@ -677,7 +677,7 @@ for (const uschar * ele = raw_record, * tspec, * end, * val; *ele; ele = end) } else bad_tag: - DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); + DEBUG(acl) debug_printf(" Unknown tag encountered\n"); } } @@ -686,7 +686,7 @@ if (!pub->version) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION); else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) { - DEBUG(D_acl) debug_printf(" Bad v= field\n"); + DEBUG(acl) debug_printf(" Bad v= field\n"); return NULL; } @@ -698,7 +698,7 @@ if (!pub->srvtype ) pub->srvtype = US"*"; if (pub->key.data) return pub; -DEBUG(D_acl) debug_printf(" Missing p= field\n"); +DEBUG(acl) debug_printf(" Missing p= field\n"); return NULL; } @@ -768,7 +768,7 @@ if (left > 0) { exim_sha_update(&b->body_hash_ctx, CUS canon_data->data, left); b->signed_body_bytes += left; - DEBUG(D_acl) debug_printf("%.*Z\n", left, canon_data->data); + DEBUG(acl) debug_printf("%.*Z\n", left, canon_data->data); } return relaxed_data; @@ -782,7 +782,7 @@ pdkim_finish_bodyhash(pdkim_ctx * ctx) { for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next) /* Finish hashes */ { - DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %s/%s/%ld len %ld\n", + DEBUG(acl) debug_printf("DKIM: finish bodyhash %s/%s/%ld len %ld\n", pdkim_hashes[b->hashtype].dkim_hashname, pdkim_canons[b->canon_method], b->bodylength, b->signed_body_bytes); exim_sha_finish(&b->body_hash_ctx, &b->bh); @@ -793,7 +793,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) { pdkim_bodyhash * b = sig->calc_body_hash; - DEBUG(D_acl) + DEBUG(acl) { debug_printf("DKIM [%s]%s Body bytes (%s) hashed: %lu\n" "DKIM [%s]%s Body %s computed: ", @@ -818,11 +818,11 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (sig->bodyhash.data && sig->bodyhash.len == b->bh.len && memcmp(b->bh.data, sig->bodyhash.data, b->bh.len) == 0) { - DEBUG(D_acl) debug_printf("DKIM [%s] Body hash compared OK\n", sig->domain); + DEBUG(acl) debug_printf("DKIM [%s] Body hash compared OK\n", sig->domain); } else { - DEBUG(D_acl) + DEBUG(acl) { debug_printf("DKIM [%s] Body hash signature from headers: ", sig->domain); debug_printf("%.*H\n", sig->bodyhash.len, sig->bodyhash.data); @@ -975,7 +975,7 @@ if (ctx->flags & PDKIM_MODE_SIGN) else { #ifdef notdef - DEBUG(D_acl) debug_printf("DKIM >> raw hdr: %.*Z\n", + DEBUG(acl) debug_printf("DKIM >> raw hdr: %.*Z\n", ctx->cur_head->ptr, CUS g->s); #endif if (strncasecmp(CCS g->s, @@ -987,7 +987,7 @@ else required tags here, but prefer to create the internal sig and expicitly fail verification of it later. */ - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); sig = pdkim_parse_sig_header(ctx, g->s); @@ -1074,7 +1074,7 @@ else for (unsigned p = 0; p < len; p++) return rc; ctx->flags = (ctx->flags & ~(PDKIM_SEEN_LF|PDKIM_SEEN_CR)) | PDKIM_PAST_HDRS; - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); continue; } @@ -1323,7 +1323,7 @@ check_bare_ed25519_pubkey(pdkim_pubkey * p) int excess = p->key.len - 32; if (excess > 0) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DKIM: unexpected pubkey len %lu\n", (unsigned long) p->key.len); p->key.data += excess; p->key.len = 32; } @@ -1350,7 +1350,7 @@ if ( !(dns_txt_reply = ctx->dns_txt_callback(dns_txt_name)) return NULL; } -DEBUG(D_acl) +DEBUG(acl) { debug_printf( "DKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" @@ -1367,7 +1367,7 @@ if ( !(p = pdkim_parse_pubkey_record(CUS dns_txt_reply)) sig->verify_status = PDKIM_VERIFY_INVALID; sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD; - DEBUG(D_acl) + DEBUG(acl) { if (p) debug_printf(" Invalid public key service type '%s'\n", p->srvtype); @@ -1379,7 +1379,7 @@ if ( !(p = pdkim_parse_pubkey_record(CUS dns_txt_reply)) return NULL; } -DEBUG(D_acl) debug_printf( +DEBUG(acl) debug_printf( "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); /* Import public key */ @@ -1392,7 +1392,7 @@ instead. Assume writing on the sig is ok in that case. */ if (sig->keytype < 0) if ((sig->keytype = pdkim_keyname_to_keytype(p->keytype)) < 0) { - DEBUG(D_acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype); + DEBUG(acl) debug_printf("verify_init: unhandled keytype %s\n", p->keytype); sig->verify_status = PDKIM_VERIFY_INVALID; sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT; return NULL; @@ -1405,7 +1405,7 @@ if ((*errstr = exim_dkim_verify_init(&p->key, sig->keytype == KEYTYPE_ED25519 ? KEYFMT_ED25519_BARE : KEYFMT_DER, vctx, &sig->keybits))) { - DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr); + DEBUG(acl) debug_printf("verify_init: %s\n", *errstr); sig->verify_status = PDKIM_VERIFY_INVALID; sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT; return NULL; @@ -1430,7 +1430,7 @@ int sep; if (!siglist) return NULL; /* first select in order of hashtypes */ -DEBUG(D_acl) debug_printf("DKIM: dkim_verify_hashes '%s'\n", dkim_verify_hashes); +DEBUG(acl) debug_printf("DKIM: dkim_verify_hashes '%s'\n", dkim_verify_hashes); for (prefs = dkim_verify_hashes, sep = 0, yield = NULL, ss = &yield; ele = string_nextinlist(&prefs, &sep, NULL, 0); ) { @@ -1448,7 +1448,7 @@ for (prefs = dkim_verify_hashes, sep = 0, yield = NULL, ss = &yield; /* then in order of keytypes */ siglist = yield; -DEBUG(D_acl) debug_printf("DKIM: dkim_verify_keytypes '%s'\n", dkim_verify_keytypes); +DEBUG(acl) debug_printf("DKIM: dkim_verify_keytypes '%s'\n", dkim_verify_keytypes); for (prefs = dkim_verify_keytypes, sep = 0, yield = NULL, ss = &yield; ele = string_nextinlist(&prefs, &sep, NULL, 0); ) { @@ -1464,7 +1464,7 @@ for (prefs = dkim_verify_keytypes, sep = 0, yield = NULL, ss = &yield; } } -DEBUG(D_acl) for (pdkim_signature * s = yield; s; s = s->next) +DEBUG(acl) for (pdkim_signature * s = yield; s; s = s->next) debug_printf(" retain d=%s s=%s a=%s\n", s->domain, s->selector, dkim_sig_to_a_tag(s)); return yield; @@ -1495,7 +1495,7 @@ if (ctx->cur_header && ctx->cur_header->ptr > 0) if (rnl) store_free(rnl); } else - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); /* Build (and/or evaluate) body hash. Do this even if no DKIM sigs, in case we @@ -1510,7 +1510,7 @@ if (!(ctx->flags & PDKIM_MODE_SIGN)) if (!ctx->sig) { - DEBUG(D_acl) debug_printf("DKIM: no signatures\n"); + DEBUG(acl) debug_printf("DKIM: no signatures\n"); *return_signatures = NULL; return PDKIM_OK; } @@ -1526,7 +1526,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if ( !(ctx->flags & PDKIM_MODE_SIGN) && sig->verify_status == PDKIM_VERIFY_FAIL) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DKIM: [%s] abandoning this signature\n", sig->domain); continue; } @@ -1560,12 +1560,12 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) } if (ctx->flags & PDKIM_MODE_SIGN) - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM >> Headers to be signed: >>>>>>>>>>>>\n" " %s\n", sig->sign_headers); - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM >> Header data for hash, canonicalized (%-7s), in sequence >>\n", pdkim_canons[sig->canon_headers]); @@ -1613,7 +1613,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) /*XXX we could avoid doing this for all but the GnuTLS/RSA case */ hdata = exim_dkim_data_append(hdata, rh); - DEBUG(D_acl) debug_printf("%Z\n", rh); + DEBUG(acl) debug_printf("%Z\n", rh); } } @@ -1670,7 +1670,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) /* Feed header to the hash algorithm */ exim_sha_update_string(&hhash_ctx, CUS rh); - DEBUG(D_acl) debug_printf("%Z\n", rh); + DEBUG(acl) debug_printf("%Z\n", rh); hdrs->tag = 1; break; } @@ -1683,10 +1683,10 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) } } - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); - DEBUG(D_acl) + DEBUG(acl) { debug_printf( "DKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n"); @@ -1699,7 +1699,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (sig->canon_headers == PDKIM_CANON_RELAXED) sig_hdr = pdkim_relax_header(sig_hdr, FALSE); - DEBUG(D_acl) + DEBUG(acl) { debug_printf("DKIM >> Signed DKIM-Signature header, canonicalized (%-7s) >>>>>>>\n", pdkim_canons[sig->canon_headers]); @@ -1712,7 +1712,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) exim_sha_update_string(&hhash_ctx, CUS sig_hdr); exim_sha_finish(&hhash_ctx, &hhash); - DEBUG(D_acl) + DEBUG(acl) { debug_printf("DKIM [%s] Header %s computed: ", sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname); @@ -1752,7 +1752,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) return PDKIM_ERR_RSA_SIGNING; } - DEBUG(D_acl) + DEBUG(acl) { debug_printf( "DKIM [%s] b computed: ", sig->domain); debug_printf("%.*H\n", sig->sighash.len, sig->sighash.data); @@ -1781,7 +1781,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) sig->verify_status = PDKIM_VERIFY_INVALID; sig->verify_ext_status = PDKIM_VERIFY_INVALID_SIGNATURE_ERROR; - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( " Error in DKIM-Signature header: tags missing or invalid (%s)\n" "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", !(sig->domain && *sig->domain) ? "d=" @@ -1801,13 +1801,13 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) sig->verify_status = PDKIM_VERIFY_INVALID; sig->verify_ext_status = PDKIM_VERIFY_INVALID_DKIM_VERSION; - DEBUG(D_acl) debug_printf( + DEBUG(acl) debug_printf( " Error in DKIM-Signature header: unsupported DKIM version\n" "DKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); goto NEXT_VERIFY; } - DEBUG(D_acl) + DEBUG(acl) { debug_printf( "DKIM [%s] b from mail: ", sig->domain); debug_printf("%.*H\n", sig->sighash.len, sig->sighash.data); @@ -1832,7 +1832,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break; if (!ele) { - DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n", + DEBUG(acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n", sig->pubkey->hashes, pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname); @@ -1854,7 +1854,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if ((*err = exim_dkim_verify(&vctx, hm, &hhash, &sig->sighash))) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("headers verify: %s\n", **err ? *err : US"fail"); sig->verify_status = PDKIM_VERIFY_FAIL; sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE; @@ -1867,7 +1867,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) dkim_verify_min_keysizes); if (ss && (minbits = atoi(CCS ss)) > sig->keybits) { - DEBUG(D_acl) debug_printf("Key too short: Actual: %s %u Minima '%s'\n", + DEBUG(acl) debug_printf("Key too short: Actual: %s %u Minima '%s'\n", pdkim_keytypes[sig->keytype], sig->keybits, dkim_verify_min_keysizes); sig->verify_status = PDKIM_VERIFY_FAIL; sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_KEYSIZE; @@ -1891,7 +1891,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) } NEXT_VERIFY: - DEBUG(D_acl) + DEBUG(acl) { debug_printf("DKIM [%s] %s signature status: %s", sig->domain, dkim_sig_to_a_tag(sig), @@ -1973,7 +1973,7 @@ if (hashtype >= nelem(pdkim_hashes)) return NULL; } -DEBUG(D_acl) +DEBUG(acl) { pdkim_signature s = *sig; ev_ctx vctx; @@ -2031,7 +2031,7 @@ if (hashtype == -1 || canon_method == -1) return NULL; if (!ctx) { - DEBUG(D_receive) debug_printf("pdkim_set_bodyhash: null context\n"); + DEBUG(receive) debug_printf("pdkim_set_bodyhash: null context\n"); return NULL; } @@ -2040,12 +2040,12 @@ for (b = ctx->bodyhash; b; b = b->next) && canon_method == b->canon_method && bodylength == b->bodylength) { - DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %s/%s/%ld\n", + DEBUG(receive) debug_printf("DKIM: using existing bodyhash %s/%s/%ld\n", pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength); return b; } -DEBUG(D_receive) debug_printf("DKIM: new bodyhash %s/%s/%ld\n", +DEBUG(receive) debug_printf("DKIM: new bodyhash %s/%s/%ld\n", pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength); b = store_get(sizeof(pdkim_bodyhash), GET_UNTAINTED); b->next = ctx->bodyhash; @@ -2055,7 +2055,7 @@ b->bodylength = bodylength; if (!exim_sha_init(&b->body_hash_ctx, /*XXX hash method: extend for sha512 */ pdkim_hashes[hashtype].exim_hashmethod)) { - DEBUG(D_acl) + DEBUG(acl) debug_printf("DKIM: hash init error, possibly nonhandled hashtype\n"); return NULL; } @@ -2095,7 +2095,7 @@ memset(ctx, 0, sizeof(pdkim_ctx)); ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN; /* The line buffer is for message data, hence tainted */ ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED); -DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback; +DEBUG(acl) ctx->dns_txt_callback = dns_txt_callback; } diff --git a/src/src/miscmods/pdkim/signing.c b/src/src/miscmods/pdkim/signing.c index 464e117d6..5bd432881 100644 --- a/src/src/miscmods/pdkim/signing.c +++ b/src/src/miscmods/pdkim/signing.c @@ -58,10 +58,10 @@ exim_gnutls_logger_cb(int level, const char *message) size_t len = strlen(message); if (len < 1) { - DEBUG(D_tls) debug_printf("GnuTLS<%d> empty debug message\n", level); + DEBUG(tls) debug_printf("GnuTLS<%d> empty debug message\n", level); return; } -DEBUG(D_tls) debug_printf("GnuTLS<%d>: %s%s", level, message, +DEBUG(tls) debug_printf("GnuTLS<%d>: %s%s", level, message, message[len-1] == '\n' ? "" : "\n"); } #endif @@ -72,7 +72,7 @@ void exim_dkim_signers_init(void) { #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 -DEBUG(D_tls) +DEBUG(tls) { gnutls_global_set_log_function(exim_gnutls_logger_cb); /* arbitrarily chosen level; bump upto 9 for more */ @@ -457,7 +457,7 @@ if ( (s1 = as_mpi(&der, &sign_ctx->n)) return s1; #ifdef extreme_debug -DEBUG(D_acl) debug_printf_indent("rsa_signing_init:\n"); +DEBUG(acl) debug_printf_indent("rsa_signing_init:\n"); { uschar * s; gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->n); @@ -544,7 +544,7 @@ if ( !(s_sig = gcry_sexp_find_token(s_sig, "s", 0)) m_sig = gcry_sexp_nth_mpi(s_sig, 1, GCRYMPI_FMT_USG); #ifdef extreme_debug -DEBUG(D_acl) +DEBUG(acl) { uschar * s; gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, m_sig); @@ -605,7 +605,7 @@ if ((rc = as_tag(pubkey, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL)) != ASN1_SUCCESS) goto asn_err; /* sequence; skip the entire thing */ -DEBUG(D_acl) stage = US"S2"; +DEBUG(acl) stage = US"S2"; if ((rc = as_tag(pubkey, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, &alen)) != ASN1_SUCCESS) goto asn_err; pubkey->data += alen; pubkey->len -= alen; @@ -613,26 +613,26 @@ pubkey->data += alen; pubkey->len -= alen; /* bitstring: limit range to size of bitstring; move over header + content wrapper */ -DEBUG(D_acl) stage = US"BS"; +DEBUG(acl) stage = US"BS"; if ((rc = as_tag(pubkey, 0, ASN1_TAG_BIT_STRING, &alen)) != ASN1_SUCCESS) goto asn_err; pubkey->len = alen; pubkey->data++; pubkey->len--; /* sequence; just move past the header */ -DEBUG(D_acl) stage = US"S3"; +DEBUG(acl) stage = US"S3"; if ((rc = as_tag(pubkey, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL)) != ASN1_SUCCESS) goto asn_err; /* read two integers */ -DEBUG(D_acl) stage = US"MPI"; +DEBUG(acl) stage = US"MPI"; nbits = pubkey->len; if ((errstr = as_mpi(pubkey, &verify_ctx->n))) return errstr; nbits = (nbits - pubkey->len) * 8; if ((errstr = as_mpi(pubkey, &verify_ctx->e))) return errstr; #ifdef extreme_debug -DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n"); +DEBUG(acl) debug_printf_indent("rsa_verify_init:\n"); { uschar * s; gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, verify_ctx->n); @@ -646,7 +646,7 @@ if (bits) *bits = nbits; return NULL; asn_err: -DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc)); +DEBUG(acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc)); return US asn1_strerror(rc); } @@ -691,7 +691,7 @@ if ( (stage = US"pkey sexp build", gerr = gcry_pk_verify(s_sig, s_hash, s_pkey)) ) { - DEBUG(D_acl) debug_printf_indent("verify: error in stage '%s'\n", stage); + DEBUG(acl) debug_printf_indent("verify: error in stage '%s'\n", stage); return gerr == GCRY_ERR_BAD_SIGNATURE ? US"" : US gcry_strerror(gerr); } @@ -896,7 +896,7 @@ else { EVP_PKEY_CTX_free(ctx); return NULL; } EVP_PKEY_CTX_free(ctx); - DEBUG(D_tls) + DEBUG(tls) if (Ustrcmp(ERR_reason_error_string(ERR_peek_error()), "wrong signature length") == 0) debug_printf("sig len (from msg hdr): %d, expected (from dns pubkey) %d\n", (int) sig->len, EVP_PKEY_size(verify_ctx->key)); diff --git a/src/src/miscmods/proxy.c b/src/src/miscmods/proxy.c index 320b57ea8..569cc93e3 100644 --- a/src/src/miscmods/proxy.c +++ b/src/src/miscmods/proxy.c @@ -40,7 +40,7 @@ if ( sender_host_address && verify_check_this_host(CUSS &hosts_proxy, NULL, NULL, sender_host_address, NULL) == OK) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Detected proxy protocol configured host\n"); /* having this set when we could still fail is ugly */ proxy_session = TRUE; @@ -228,7 +228,7 @@ do if (ret == -1) goto proxyfail; -DEBUG(D_receive) proxy_debug(US &hdr, 0, ret); +DEBUG(receive) proxy_debug(US &hdr, 0, ret); /* For v2, handle reading the length, and then the rest. */ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) @@ -236,7 +236,7 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) int retmore; uint8_t ver; - DEBUG(D_receive) debug_printf("v2\n"); + DEBUG(receive) debug_printf("v2\n"); /* First get the length fields. */ do @@ -245,7 +245,7 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) } while (retmore == -1 && errno == EINTR && !had_command_timeout); if (retmore == -1) goto proxyfail; - DEBUG(D_receive) proxy_debug(US &hdr, ret, ret + retmore); + DEBUG(receive) proxy_debug(US &hdr, ret, ret + retmore); ret += retmore; @@ -258,13 +258,13 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) if (ver != 0x02) { - DEBUG(D_receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver); + DEBUG(receive) debug_printf("Invalid Proxy Protocol version: %d\n", ver); goto proxyfail; } /* The v2 header will always be 16 bytes per the spec. */ size = 16 + ntohs(hdr.v2.len); - DEBUG(D_receive) debug_printf("Detected PROXYv2 header, size %d (limit %d)\n", + DEBUG(receive) debug_printf("Detected PROXYv2 header, size %d (limit %d)\n", size, (int)sizeof(hdr)); /* We should now have 16 octets (PROXY_V2_HEADER_SIZE), and we know the total @@ -272,7 +272,7 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) get the rest. */ if (size > sizeof(hdr)) { - DEBUG(D_receive) debug_printf("PROXYv2 header size unreasonably large; security attack?\n"); + DEBUG(receive) debug_printf("PROXYv2 header size unreasonably large; security attack?\n"); goto proxyfail; } @@ -284,9 +284,9 @@ if ((ret == PROXY_INITIAL_READ) && (memcmp(&hdr.v2, v2sig, sizeof(v2sig)) == 0)) } while (retmore == -1 && errno == EINTR && !had_command_timeout); if (retmore == -1) goto proxyfail; - DEBUG(D_receive) proxy_debug(US &hdr, ret, ret + retmore); + DEBUG(receive) proxy_debug(US &hdr, ret, ret + retmore); ret += retmore; - DEBUG(D_receive) debug_printf("PROXYv2: have %d/%d required octets\n", ret, size); + DEBUG(receive) debug_printf("PROXYv2: have %d/%d required octets\n", ret, size); } while (ret < size); } /* end scope for getting rest of data for v2 */ @@ -310,7 +310,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip)); if (!string_is_ip_address(US tmpip, NULL)) { - DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); + DEBUG(receive) debug_printf("Invalid %s source IP\n", iptype); goto proxyfail; } proxy_local_address = sender_host_address; @@ -323,7 +323,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) inet_ntop(AF_INET, &tmpaddr.sin_addr, CS &tmpip, sizeof(tmpip)); if (!string_is_ip_address(US tmpip, NULL)) { - DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype); + DEBUG(receive) debug_printf("Invalid %s dest port\n", iptype); goto proxyfail; } proxy_external_address = string_copy(US tmpip); @@ -336,7 +336,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6)); if (!string_is_ip_address(US tmpip6, NULL)) { - DEBUG(D_receive) debug_printf("Invalid %s source IP\n", iptype); + DEBUG(receive) debug_printf("Invalid %s source IP\n", iptype); goto proxyfail; } proxy_local_address = sender_host_address; @@ -349,7 +349,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) inet_ntop(AF_INET6, &tmpaddr6.sin6_addr, CS &tmpip6, sizeof(tmpip6)); if (!string_is_ip_address(US tmpip6, NULL)) { - DEBUG(D_receive) debug_printf("Invalid %s dest port\n", iptype); + DEBUG(receive) debug_printf("Invalid %s dest port\n", iptype); goto proxyfail; } proxy_external_address = string_copy(US tmpip6); @@ -357,7 +357,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) proxy_external_port = tmpport; goto done; default: - DEBUG(D_receive) + DEBUG(receive) debug_printf("Unsupported PROXYv2 connection type: 0x%02x\n", hdr.v2.fam); goto proxyfail; @@ -369,7 +369,7 @@ if (ret >= 16 && memcmp(&hdr.v2, v2sig, 12) == 0) iptype = US"local"; break; default: - DEBUG(D_receive) + DEBUG(receive) debug_printf("Unsupported PROXYv2 command: 0x%x\n", cmd); goto proxyfail; } @@ -394,19 +394,19 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) if (!end || (end == US &hdr + ret) || end[1] != '\n') { - DEBUG(D_receive) debug_printf("Partial or invalid PROXY header\n"); + DEBUG(receive) debug_printf("Partial or invalid PROXY header\n"); goto proxyfail; } *end = '\0'; /* Terminate the string */ size = end + 2 - p; /* Skip header + CRLF */ - DEBUG(D_receive) debug_printf("Detected PROXYv1 header\n"); - DEBUG(D_receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size); + DEBUG(receive) debug_printf("Detected PROXYv1 header\n"); + DEBUG(receive) debug_printf("Bytes read not within PROXY header: %d\n", ret - size); /* Step through the string looking for the required fields. Ensure strict adherence to required formatting, exit for any error. */ p += 5; if (!isspace(*p++)) { - DEBUG(D_receive) debug_printf("Missing space after PROXY command\n"); + DEBUG(receive) debug_printf("Missing space after PROXY command\n"); goto proxyfail; } if (!Ustrncmp(p, CCS"TCP4", 4)) @@ -420,27 +420,27 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) } else { - DEBUG(D_receive) debug_printf("Invalid TCP type\n"); + DEBUG(receive) debug_printf("Invalid TCP type\n"); goto proxyfail; } p += Ustrlen(iptype); if (!isspace(*p++)) { - DEBUG(D_receive) debug_printf("Missing space after TCP4/6 command\n"); + DEBUG(receive) debug_printf("Missing space after TCP4/6 command\n"); goto proxyfail; } /* Find the end of the arg */ if ((sp = Ustrchr(p, ' ')) == NULL) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Did not find proxied src %s\n", iptype); goto proxyfail; } *sp = '\0'; if(!string_is_ip_address(p, NULL)) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Proxied src arg is not an %s address\n", iptype); goto proxyfail; } @@ -449,14 +449,14 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) p = sp + 1; if ((sp = Ustrchr(p, ' ')) == NULL) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Did not find proxy dest %s\n", iptype); goto proxyfail; } *sp = '\0'; if(!string_is_ip_address(p, NULL)) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Proxy dest arg is not an %s address\n", iptype); goto proxyfail; } @@ -464,14 +464,14 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) p = sp + 1; if ((sp = Ustrchr(p, ' ')) == NULL) { - DEBUG(D_receive) debug_printf("Did not find proxied src port\n"); + DEBUG(receive) debug_printf("Did not find proxied src port\n"); goto proxyfail; } *sp = '\0'; tmp_port = strtol(CCS p, &endc, 10); if (*endc || tmp_port == 0) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Proxied src port '%s' not an integer\n", p); goto proxyfail; } @@ -480,13 +480,13 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) p = sp + 1; if ((sp = Ustrchr(p, '\0')) == NULL) { - DEBUG(D_receive) debug_printf("Did not find proxy dest port\n"); + DEBUG(receive) debug_printf("Did not find proxy dest port\n"); goto proxyfail; } tmp_port = strtol(CCS p, &endc, 10); if (*endc || tmp_port == 0) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("Proxy dest port '%s' not an integer\n", p); goto proxyfail; } @@ -496,13 +496,13 @@ else if (ret >= 8 && memcmp(hdr.v1.line, "PROXY", 5) == 0) else { /* Wrong protocol */ - DEBUG(D_receive) debug_printf("Invalid proxy protocol version negotiation\n"); + DEBUG(receive) debug_printf("Invalid proxy protocol version negotiation\n"); (void) swallow_until_crlf(smtp_in_fd, US &hdr, ret, sizeof(hdr)-ret); goto proxyfail; } done: - DEBUG(D_receive) + DEBUG(receive) debug_printf("Valid %s sender from Proxy Protocol header\n", iptype); yield = proxy_session; @@ -512,7 +512,7 @@ should cause a synchronization failure */ proxyfail: ALARM(0); - DEBUG(D_receive) if (had_command_timeout) + DEBUG(receive) if (had_command_timeout) debug_printf("Timeout while reading proxy header\n"); if (yield) @@ -522,7 +522,7 @@ proxyfail: host_build_sender_fullhost(); } else - DEBUG(D_receive) + DEBUG(receive) debug_printf("Failure to extract proxied host, only QUIT allowed\n"); return yield; diff --git a/src/src/miscmods/radius.c b/src/src/miscmods/radius.c index fd75b3ae4..3c512def5 100644 --- a/src/src/miscmods/radius.c +++ b/src/src/miscmods/radius.c @@ -89,7 +89,7 @@ int sep = ':', result; if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) user = US""; pwd = string_nextinlist(&radius_args, &sep, NULL, 0); -DEBUG(D_auth) debug_printf("Running RADIUS authentication for user %q " +DEBUG(auth) debug_printf("Running RADIUS authentication for user %q " "and %q\n", user, pwd); *errptr = NULL; @@ -139,7 +139,7 @@ else if (!rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0)) if (*errptr) { - DEBUG(D_auth) debug_printf("%s\n", *errptr); + DEBUG(auth) debug_printf("%s\n", *errptr); return ERROR; } @@ -149,7 +149,7 @@ result = rc_auth(0, send, &received, msg); result = rc_auth(h, 0, send, &received, msg); #endif -DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result); +DEBUG(auth) debug_printf("RADIUS code returned %d\n", result); switch (result) { @@ -211,7 +211,7 @@ else break; } -if (*errptr) DEBUG(D_auth) debug_printf("%s\n", *errptr); +if (*errptr) DEBUG(auth) debug_printf("%s\n", *errptr); rad_close(h); return result; diff --git a/src/src/miscmods/sieve_filter.c b/src/src/miscmods/sieve_filter.c index 3d1e56f84..4271b8958 100644 --- a/src/src/miscmods/sieve_filter.c +++ b/src/src/miscmods/sieve_filter.c @@ -772,8 +772,7 @@ compare(struct Sieve * filter, const gstring * needle, const gstring * haystack, { int r = 0; -if ( (filter_test != FTEST_NONE && debug_selector != 0) - || (debug_selector & D_filter) != 0) +if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { debug_printf_indent("String comparison (match "); switch (mt) @@ -859,8 +858,7 @@ switch (mt) } break; } -if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) +if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent(" Result %s\n", r?"true":"false"); return r; } @@ -976,15 +974,14 @@ for (new_addr = *generated; new_addr; new_addr = new_addr->next) ) ) { - if ( filter_test != FTEST_NONE && debug_selector != 0 - || (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Repeated %s `%s' ignored.\n", file ? "fileinto" : "redirect", addr); return; } -if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) +if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("%s `%s'\n", file ? "fileinto" : "redirect", addr); new_addr = deliver_make_addr(addr, TRUE); @@ -2680,8 +2677,7 @@ while (*filter->pc) filter->errmsg = CUS "missing test"; return -1; } - if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { if (exec) debug_printf_indent("if %s\n", cond?"true":"false"); } @@ -2710,8 +2706,7 @@ while (*filter->pc) filter->errmsg = CUS "missing test"; return -1; } - if ((filter_test != FTEST_NONE && debug_selector != 0) || - (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { if (exec) debug_printf_indent("elsif %s\n", cond?"true":"false"); } @@ -3060,16 +3055,16 @@ while (*filter->pc) (void)child_close(pid, 0); } } - if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Notification to `%s': '%s'.\n", method.s, message.ptr != -1 ? message.s : CUS ""); #endif } else - if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Repeated notification to `%s' ignored.\n", method.s); } else - if ((filter_test != FTEST_NONE && debug_selector != 0) || debug_selector & D_filter) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Ignoring notification, triggering message contains Auto-submitted: field.\n"); } } @@ -3262,7 +3257,7 @@ while (*filter->pc) for (int i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]); - if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Sieve: mail was personal, vacation file basename: %s\n", hexdigest); if (filter_test == FTEST_NONE) @@ -3341,7 +3336,7 @@ while (*filter->pc) } } } - else if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0) + else if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) debug_printf_indent("Sieve: mail was not personal, vacation would ignore it\n"); } } @@ -3534,7 +3529,7 @@ struct Sieve sieve; int r; uschar * msg; -DEBUG(D_route) debug_printf_indent("Sieve: start of processing\n"); +DEBUG(route) debug_printf_indent("Sieve: start of processing\n"); expand_level++; sieve.filter = filter; @@ -3609,7 +3604,7 @@ if (filter_test != FTEST_NONE) printf("%s\n", (const char*) msg); #endif expand_level--; -DEBUG(D_route) debug_printf_indent("Sieve: end of processing\n"); +DEBUG(route) debug_printf_indent("Sieve: end of processing\n"); return r; } @@ -3643,3 +3638,5 @@ misc_module_info sieve_filter_module_info = }; /* End of sieve_filter.c */ +/* vi: aw ai sw=2 +*/ diff --git a/src/src/miscmods/socks.c b/src/src/miscmods/socks.c index 6694044da..5860af2ad 100644 --- a/src/src/miscmods/socks.c +++ b/src/src/miscmods/socks.c @@ -107,14 +107,14 @@ switch(method) case AUTH_NONE: return OK; case AUTH_NAME: - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" socks auth NAME '%s' '%s'\n", + HDEBUG(transport|acl|v) debug_printf_indent(" socks auth NAME '%s' '%s'\n", sob->auth_name, sob->auth_pwd); i = Ustrlen(sob->auth_name); j = Ustrlen(sob->auth_pwd); s = string_sprintf("%c%c%.255s%c%.255s%n", AUTH_NAME_VER, i, sob->auth_name, j, sob->auth_pwd, &len); - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent(" SOCKS>>%3.*H\n", len, s); if (send(fd, s, len, 0) < 0) return FAIL; @@ -123,10 +123,10 @@ switch(method) #endif if (!fd_ready(fd, tmo) || read(fd, s, 2) != 2) return FAIL; - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SOCKS<<%3.2H\n", s); + HDEBUG(transport|acl_v) debug_printf_indent(" SOCKS<<%3.2H\n", s); if (s[0] == AUTH_NAME_VER && s[1] == 0) { - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" socks auth OK\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" socks auth OK\n"); return OK; } @@ -259,7 +259,7 @@ for(;;) if ((idx = socks_get_proxy(proxies, nproxies)) < 0) { - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" no proxies left\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" no proxies left\n"); errno = EBUSY; return -1; } @@ -289,7 +289,7 @@ for(;;) /* Do the socks protocol stuff */ -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) debug_printf_indent(" SOCKS>> 05 01 %02x\n", sob->auth_type); /* expect method response */ @@ -302,7 +302,7 @@ if ( !fd_ready(fd, tmo) || read(fd, buf, 2) != 2 ) goto rcv_err; -HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SOCKS<<%3.2H\n", buf); +HDEBUG(transport|acl|v) debug_printf_indent(" SOCKS<<%3.2H\n", buf); if ( buf[0] != 5 || socks_auth(fd, buf[1], sob, tmo) != OK ) @@ -336,7 +336,7 @@ if ( buf[0] != 5 } state = US"connect"; -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) debug_printf_indent(" SOCKS>>%3.*H\n", (int)size, buf); if (send(fd, buf, size, 0) < 0) goto snd_err; @@ -348,7 +348,7 @@ if ( !fd_ready(fd, tmo) || (size = read(fd, buf, size)) < 2 ) goto rcv_err; -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) debug_printf_indent(" SOCKS<<%3.*H\n", (int)size, buf); if ( buf[0] != 5 @@ -361,14 +361,14 @@ proxy_external_address = string_copy( proxy_external_port = ntohs(*((uint16_t *)(buf + (buf[3] == 4 ? 20 : 8)))); proxy_session = TRUE; -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) debug_printf_indent(" proxy farside: [%s]:%d\n", proxy_external_address, proxy_external_port); if (early_data && early_data->data && early_data->len) if (send(fd, early_data->data, early_data->len, 0) < 0) { int save_errno = errno; - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) { debug_printf_indent("failed: %s", CUstrerror(save_errno)); if (save_errno == ETIMEDOUT) @@ -383,20 +383,22 @@ if (early_data && early_data->data && early_data->len) return fd; snd_err: - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" proxy snd_err %s: %s\n", state, strerror(errno)); + HDEBUG(transport|acl|v) + debug_printf_indent(" proxy snd_err %s: %s\n", state, strerror(errno)); return -1; proxy_err: { struct socks_err * se = buf[1] > nelem(socks_errs) ? NULL : socks_errs + buf[1]; - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent(" proxy %s: %s\n", state, se ? se->reason : US"unknown error code received"); errno = se ? se->errcode : EPROTO; } rcv_err: - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" proxy rcv_err %s: %s\n", state, strerror(errno)); + HDEBUG(transport|acl|v) + debug_printf_indent(" proxy rcv_err %s: %s\n", state, strerror(errno)); if (!errno) errno = EPROTO; else if (errno == ENOENT) errno = ECONNABORTED; return -1; diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index bc4131071..f01ab7a98 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -85,7 +85,7 @@ SPF_dns_rr_t srr = { .source = spf_dns_server }; -DEBUG(D_receive) +DEBUG(receive) { debug_printf_indent("SPF_dns_exim_lookup '%s'\n", domain); expand_level++; } /* Shortcircuit SPF RR lookups by returning NO_DATA. They were obsoleted by @@ -93,7 +93,7 @@ RFC 6686/7208 years ago. see bug #1294 */ if (rr_type == T_SPF) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("faking NO_DATA for SPF RR(99) lookup\n"); srr.herrno = NO_DATA; goto out; @@ -156,7 +156,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; if (rr->size < 1+6) continue; /* min for version str */ if (strncmpic(rr->data+1, US SPF_VER_STR, 6) != 0) { - HDEBUG(D_host_lookup) debug_printf_indent("not an spf record: %.*s\n", + HDEBUG(host_lookup) debug_printf_indent("not an spf record: %.*s\n", (int) s[0], s+1); continue; } @@ -175,7 +175,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; s = string_copy_malloc(string_from_gstring(g)); gstring_reset(g); gstring_release_unused(g); - DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_lookup '%s'\n", s); + DEBUG(receive) debug_printf_indent("SPF_dns_exim_lookup '%s'\n", s); break; } @@ -202,7 +202,7 @@ out: /* spfrr->rr must have been malloc()d for this */ SPF_dns_rr_dup(&spfrr, &srr); - DEBUG(D_receive) expand_level--; + DEBUG(receive) expand_level--; store_free_dns_answer(dnsa); return spfrr; } @@ -214,7 +214,7 @@ SPF_dns_exim_new(int debug) { SPF_dns_server_t * spf_dns_server = store_malloc(sizeof(SPF_dns_server_t)); -/* DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_new\n"); */ +/* DEBUG(receive) debug_printf_indent("SPF_dns_exim_new\n"); */ memset(spf_dns_server, 0, sizeof(SPF_dns_server_t)); spf_dns_server->destroy = NULL; @@ -253,7 +253,7 @@ SPF_dns_server_t * dc; int debug = 0; const uschar *s; -DEBUG(D_receive) debug = 1; +DEBUG(receive) debug = 1; /* We insert our own DNS access layer rather than letting the spf library do it, so that our dns access path is used for debug tracing and for the @@ -261,17 +261,17 @@ testsuite. */ if (!(dc = SPF_dns_exim_new(debug))) { - DEBUG(D_receive) debug_printf_indent("SPF_dns_exim_new() failed\n"); + DEBUG(receive) debug_printf_indent("SPF_dns_exim_new() failed\n"); return FALSE; } if (!(dc = SPF_dns_cache_new(dc, NULL, debug, 8))) { - DEBUG(D_receive) debug_printf_indent("SPF_dns_cache_new() failed\n"); + DEBUG(receive) debug_printf_indent("SPF_dns_cache_new() failed\n"); return FALSE; } if (!(spf_server = SPF_server_new_dns(dc, debug))) { - DEBUG(D_receive) debug_printf_indent("SPF_server_new() failed.\n"); + DEBUG(receive) debug_printf_indent("SPF_server_new() failed.\n"); return FALSE; } @@ -303,7 +303,7 @@ static int spf_conn_init(const uschar * spf_helo_domain, const uschar * spf_remote_addr, const uschar ** errstr) { -DEBUG(D_receive) debug_printf_indent("spf_conn_init: %s %s\n", +DEBUG(receive) debug_printf_indent("spf_conn_init: %s %s\n", spf_helo_domain, spf_remote_addr); if (!spf_server && !spf_init(NULL)) @@ -314,7 +314,7 @@ if (!spf_server && !spf_init(NULL)) if (SPF_server_set_rec_dom(spf_server, CS primary_hostname)) { - DEBUG(D_receive) debug_printf_indent("SPF_server_set_rec_dom(%q) failed.\n", + DEBUG(receive) debug_printf_indent("SPF_server_set_rec_dom(%q) failed.\n", primary_hostname); spf_server = NULL; *errstr = US"spf: setting host name"; @@ -327,7 +327,7 @@ if ( SPF_request_set_ipv4_str(spf_request, CCS spf_remote_addr) && SPF_request_set_ipv6_str(spf_request, CCS spf_remote_addr) ) { - DEBUG(D_receive) + DEBUG(receive) debug_printf_indent("SPF_request_set_ipv4_str() and " "SPF_request_set_ipv6_str() failed [%s]\n", spf_remote_addr); spf_server = NULL; @@ -338,7 +338,7 @@ if ( SPF_request_set_ipv4_str(spf_request, CCS spf_remote_addr) if (SPF_request_set_helo_dom(spf_request, CCS spf_helo_domain)) { - DEBUG(D_receive) debug_printf_indent("SPF_set_helo_dom(%q) failed.\n", + DEBUG(receive) debug_printf_indent("SPF_set_helo_dom(%q) failed.\n", spf_helo_domain); spf_server = NULL; spf_request = NULL; @@ -385,7 +385,7 @@ spf_process(const uschar ** listptr, const uschar * spf_envelope_sender, { int rc = SPF_RESULT_PERMERROR, ret; -DEBUG(D_receive) { debug_printf_indent("SPF: process\n"); expand_level++; } +DEBUG(receive) { debug_printf_indent("SPF: process\n"); expand_level++; } if (!(spf_server && spf_request)) /* no global context, assume temp error and skip to evaluation */ @@ -417,11 +417,11 @@ else rc = SPF_response_result(spf_response); - DEBUG(D_acl) spf_response_debug(spf_response); + DEBUG(acl) spf_response_debug(spf_response); } /* We got a result. Now see if we should return OK or FAIL for it */ -DEBUG(D_acl) +DEBUG(acl) debug_printf_indent("SPF: result is %s (%d)\n", SPF_strresult(rc), rc); if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none"))) @@ -434,7 +434,7 @@ else 0, NULL, NULL, MCL_STRING, TRUE, NULL); } -DEBUG(D_receive) expand_level--; +DEBUG(receive) expand_level--; return ret; } @@ -447,7 +447,7 @@ uschar * s; if (spf_result) { int start = 0; /* Compiler quietening */ - DEBUG(D_acl) start = gstring_length(g); + DEBUG(acl) start = gstring_length(g); g = string_append(g, 2, US";\n\tspf=", spf_result); if (spf_result_guessed) @@ -463,11 +463,11 @@ if (spf_result) ? string_append(g, 2, US" smtp.helo=", s) : string_cat(g, US" smtp.mailfrom=<>"); } - DEBUG(D_acl) debug_printf_indent("SPF:\tauthres '%.*s'\n", + DEBUG(acl) debug_printf_indent("SPF:\tauthres '%.*s'\n", gstring_length(g) - start - 3, g->s + start + 3); } else - DEBUG(D_acl) debug_printf_indent("SPF:\tno authres\n"); + DEBUG(acl) debug_printf_indent("SPF:\tno authres\n"); return g; } @@ -484,7 +484,7 @@ if (spf_response) s = US spf_response->header_comment; } *human_readable_p = s ? string_copy(s) : US""; -DEBUG(D_acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); +DEBUG(acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); return res; } @@ -498,7 +498,7 @@ SPF_dns_server_t * dc; SPF_server_t * spf_server = NULL; int debug = 0; -DEBUG(D_lookup) debug = 1; +DEBUG(lookup) debug = 1; if ((dc = SPF_dns_exim_new(debug))) if ((dc = SPF_dns_cache_new(dc, NULL, debug, 8))) @@ -568,7 +568,7 @@ if (SPF_request_set_env_from(spf_request, CS keystring)) SPF_request_query_mailfrom(spf_request, &spf_response); *result = string_copy(US SPF_strresult(SPF_response_result(spf_response))); -DEBUG(D_lookup) spf_response_debug(spf_response); +DEBUG(lookup) spf_response_debug(spf_response); SPF_response_free(spf_response); SPF_request_free(spf_request); diff --git a/src/src/miscmods/spf_perl.c b/src/src/miscmods/spf_perl.c index c30e0efe4..081963eb6 100644 --- a/src/src/miscmods/spf_perl.c +++ b/src/src/miscmods/spf_perl.c @@ -106,11 +106,11 @@ uschar * errstr; gstring * g; typedef gstring * (*fn_t)(gstring *, uschar **, uschar *, const uschar **); -DEBUG(D_acl) debug_printf_indent("calling Mail::SPF\n"); +DEBUG(acl) debug_printf_indent("calling Mail::SPF\n"); expand_level++; if (!(g = (((fn_t *) spf_perl_mi->functions)[PERL_CAT]) (NULL, &errstr, US"my_spf_req", argv))) - DEBUG(D_acl) debug_printf_indent("SPF err %q\n", errstr); + DEBUG(acl) debug_printf_indent("SPF err %q\n", errstr); expand_level--; return g; } @@ -160,7 +160,7 @@ uschar * errstr; const uschar * arglist = *listptr; expand_level++; -DEBUG(D_acl) +DEBUG(acl) debug_printf_indent("%s: mfrom:<%s>\n", __FUNCTION__, spf_envelope_sender); if (!setup_spf_perl_mi(&errstr)) @@ -186,7 +186,7 @@ else sep = '\n'; spf_result = string_nextinlist(CUSS &res_list, &sep, NULL, 0); - DEBUG(D_acl) debug_printf_indent("MAIL::SPF result is %q\n", spf_received); + DEBUG(acl) debug_printf_indent("MAIL::SPF result is %q\n", spf_received); spf_received = res_list; /* remainder of the returned string */ @@ -221,7 +221,7 @@ uschar * s; if (spf_result) { int start = 0; /* Compiler quietening */ - DEBUG(D_acl) start = gstring_length(g); + DEBUG(acl) start = gstring_length(g); g = string_append(g, 2, US";\n\tspf=", spf_result); if (spf_result_guessed) @@ -237,11 +237,11 @@ if (spf_result) ? string_append(g, 2, US" smtp.helo=", s) : string_cat(g, US" smtp.mailfrom=<>"); } - DEBUG(D_acl) debug_printf_indent("SPF:\tauthres '%.*s'\n", + DEBUG(acl) debug_printf_indent("SPF:\tauthres '%.*s'\n", gstring_length(g) - start - 3, g->s + start + 3); } else - DEBUG(D_acl) debug_printf_indent("SPF:\tno authres\n"); + DEBUG(acl) debug_printf_indent("SPF:\tno authres\n"); return g; } @@ -266,7 +266,7 @@ if (spf_result) } *human_readable_p = s ? string_copy(s) : US""; -DEBUG(D_acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); +DEBUG(acl) debug_printf_indent(" SPF: %d '%s'\n", res, s); return res; } @@ -298,7 +298,7 @@ spf_lookup_find(void * handle, const uschar * filename, uschar * errstr; int res = FAIL; -DEBUG(D_acl) debug_printf_indent("%s: mfrom:<%s> ip %q\n", __FUNCTION__, +DEBUG(acl) debug_printf_indent("%s: mfrom:<%s> ip %q\n", __FUNCTION__, keystring, filename); expand_level++; @@ -315,7 +315,7 @@ if (setup_spf_perl_mi(&errstr)) uschar * res_list = US string_from_gstring(g); int sep = '\n'; *result = string_nextinlist(CUSS &res_list, &sep, NULL, 0); - DEBUG(D_acl) debug_printf_indent("MAIL::SPF result is %q\n", *result); + DEBUG(acl) debug_printf_indent("MAIL::SPF result is %q\n", *result); res = OK; } } diff --git a/src/src/miscmods/xclient.c b/src/src/miscmods/xclient.c index 77bf743a4..8657c6982 100644 --- a/src/src/miscmods/xclient.c +++ b/src/src/miscmods/xclient.c @@ -148,7 +148,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) goto fatal_501; } - DEBUG(D_transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); + DEBUG(transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); cmd = XCLIENT_CMD_UNKNOWN; for (struct xclient_cmd * x = xclient_cmds + 1; x < xclient_cmds + nelem(xclient_cmds); x++) @@ -177,7 +177,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) Uskip_nonwhite(&s); len = s - word; - DEBUG(D_transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); + DEBUG(transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); if (len == 0) { errmsg = US"XCLIENT: zero-length value for param"; goto fatal_501; } diff --git a/src/src/moan.c b/src/src/moan.c index 318d7c6aa..a5d3c0977 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -194,11 +194,11 @@ pid = child_open_exim(&fd, US"moan_send_message"); if (pid < 0) { - DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n", + DEBUG(any) debug_printf("Failed to create child to send message: %s\n", strerror(errno)); return FALSE; } -else DEBUG(D_any) +else DEBUG(any) debug_printf("Child process " PID_T_FMT " for sending message\n", pid); /* Creation of child succeeded */ @@ -606,7 +606,7 @@ pid_t pid = child_open_exim(&fd, US"moan_tell_someone"); if (pid < 0) { - DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n", + DEBUG(any) debug_printf("Failed to create child to send message: %s\n", strerror(errno)); return; } @@ -670,7 +670,7 @@ moan_smtp_batch(const uschar * cmd_buffer, const char * format, ...) va_list ap; int yield = receive_messagecount > 0 ? EXIT_FAILURE : 2; -DEBUG(D_any) debug_printf("Handling error in batched SMTP input\n"); +DEBUG(any) debug_printf("Handling error in batched SMTP input\n"); /* On stdout, write stuff that a program could parse fairly easily. */ @@ -779,7 +779,7 @@ while ((item = string_nextinlist(&listptr, &sep, NULL, 0))) } } -DEBUG(D_any) debug_printf("errors_copy check returned %s\n", +DEBUG(any) debug_printf("errors_copy check returned %s\n", (yield == NULL)? US"NULL" : yield); expand_nmax = -1; @@ -841,7 +841,7 @@ pid = child_open_exim(&fd, US"moan_skipped_syntax_errors"); if (pid < 0) { - DEBUG(D_any) debug_printf("Failed to create child to send message: %s\n", + DEBUG(any) debug_printf("Failed to create child to send message: %s\n", strerror(errno)); return TRUE; } diff --git a/src/src/os.c b/src/src/os.c index 44a53a575..dbf2e899b 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -12,8 +12,8 @@ # include # include #else -# define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) -# define DEBUG(x) if (IS_DEBUG(x)) /* for cppcheck */ +// # define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) +// # define DEBUG(x) if (IS_DEBUG(D_##x)) /* for cppcheck */ #endif #ifndef CS @@ -528,7 +528,7 @@ for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s (%s)\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, ifa->ifa_name); } @@ -634,7 +634,7 @@ what we want to know. */ if ((vs = socket(FAMILY, SOCK_DGRAM, 0)) < 0) { #if HAVE_IPV6 - DEBUG(D_interface) + DEBUG(interface) debug_printf("Unable to create IPv6 socket to find interface addresses:\n " "error %d %s\nTrying for an IPv4 socket\n", errno, strerror(errno)); vs = socket(AF_INET, SOCK_DGRAM, 0); @@ -667,7 +667,7 @@ number of interfaces, even though they don't all fit in the buffer. */ if (ifc.V_ifc_len > sizeof(buf)) { ifc.V_ifc_len = sizeof(buf); - DEBUG(D_interface) + DEBUG(interface) debug_printf("more than %d interfaces found: remainder not used\n" "(set MAX_INTERFACES in Local/Makefile and rebuild if you want more)\n", MAX_INTERFACES); @@ -761,7 +761,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len) last = next; } - DEBUG(D_interface) debug_printf_indent("Actual local interface address is %s (%s)\n", + DEBUG(interface) debug_printf_indent("Actual local interface address is %s (%s)\n", last->address, ifreq.V_ifr_name); } @@ -794,7 +794,7 @@ yield->next->port = 0; yield->next->next = NULL; #endif -DEBUG(D_interface) debug_printf("Unable to find local interface addresses " +DEBUG(interface) debug_printf("Unable to find local interface addresses " "on this OS: returning loopback address(es)\n"); return yield; } diff --git a/src/src/parse.c b/src/src/parse.c index 1fe4f70f8..0eb9b70b1 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -1249,7 +1249,7 @@ parse_forward_list(const uschar *s, int options, address_item **anchor, { int count = 0; -DEBUG(D_route) debug_printf("parse_forward_list: %s\n", s); +DEBUG(route) debug_printf("parse_forward_list: %s\n", s); for (;;) { @@ -1329,7 +1329,7 @@ for (;;) len = ss - s; - DEBUG(D_route) debug_printf("extract item: %.*s\n", len, s); + DEBUG(route) debug_printf("extract item: %.*s\n", len, s); /* Handle special addresses if permitted. If the address is :unknown: ignore it - this is for backward compatibility with old alias files. You diff --git a/src/src/queue.c b/src/src/queue.c index b63482a43..ec71a5021 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -182,7 +182,7 @@ for (; i <= *subcount; i++) buffer[subptr+1] = subdirchar; } - DEBUG(D_queue_run) debug_printf("looking in %s\n", buffer); + DEBUG(queue_run) debug_printf("looking in %s\n", buffer); if (!(dd = exim_opendir(buffer))) continue; @@ -470,7 +470,7 @@ for (int i = queue_run_in_order ? -1 : 0; { rmark reset_point1 = store_mark(); - DEBUG(D_queue_run) + DEBUG(queue_run) { if (i == 0) debug_printf("queue running main directory\n"); @@ -504,7 +504,7 @@ for (int i = queue_run_in_order ? -1 : 0; break; } else - DEBUG(D_load) debug_printf("load average = %.2f max = %.2f\n", + DEBUG(load) debug_printf("load average = %.2f max = %.2f\n", (double)load_average/1000.0, (double)deliver_queue_load_max/1000.0); @@ -524,10 +524,10 @@ for (int i = queue_run_in_order ? -1 : 0; that happens to complete. */ set_process_info("running queue (ph 1): parallel limit %u", nelem(qpid)); - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("q2stage waiting for child %d\n", (int)qpid[0]); waitpid(qpid[0], NULL, 0); - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("q2stage reaped child %d\n", (int)qpid[0]); #ifndef MEASURE_TIMING if (f.running_in_test_harness) j = 0; else @@ -590,7 +590,7 @@ for (int i = queue_run_in_order ? -1 : 0; else if (q->queue_run_first_delivery && !f.deliver_firsttime) { - DEBUG(D_queue_run) debug_printf("%s: not first delivery\n", fq->text); + DEBUG(queue_run) debug_printf("%s: not first delivery\n", fq->text); wanted = FALSE; } @@ -607,7 +607,7 @@ for (int i = queue_run_in_order ? -1 : 0; != NULL) ) ) { - DEBUG(D_queue_run) debug_printf("%s: sender address did not match %s\n", + DEBUG(queue_run) debug_printf("%s: sender address did not match %s\n", fq->text, deliver_selectstring_sender); wanted = FALSE; } @@ -631,12 +631,12 @@ for (int i = queue_run_in_order ? -1 : 0; if (i >= recipients_count) { - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("%s: no recipient address matched %s\n", fq->text, deliver_selectstring); wanted = FALSE; } - else DEBUG(D_acl) if (atrn_domains) + else DEBUG(acl) if (atrn_domains) debug_printf_indent("%s matches ATRN\n", fq->text); } @@ -713,7 +713,7 @@ single_item_retry: for (int ret; (ret = wait (&status)) != pid; ) if (ret == -1) { - DEBUG(D_any) debug_printf("%s %d: wait: %s\n", __FUNCTION__, __LINE__, + DEBUG(any) debug_printf("%s %d: wait: %s\n", __FUNCTION__, __LINE__, strerror(errno)); status = 0; break; @@ -737,9 +737,9 @@ single_item_retry: if (status & 0xff00 && single_id) { single_id = FALSE; - DEBUG(D_queue_run) debug_printf("qrun single-item pause before retry\n"); + DEBUG(queue_run) debug_printf("qrun single-item pause before retry\n"); millisleep(500); - DEBUG(D_queue_run) debug_printf("qrun single-item retry after pause\n"); + DEBUG(queue_run) debug_printf("qrun single-item retry after pause\n"); goto single_item_retry; } @@ -815,7 +815,7 @@ if (q->queue_2stage) set_process_info("running queue (ph 1): wait-all, child %u/%u", i+1, active); waitpid(qpid[i], NULL, 0); - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("q2stage reaped child " PID_T_FMT "\n", qpid[i]); } else break; /* should be no holes in table, so we're done */ @@ -824,7 +824,7 @@ if (q->queue_2stage) report_time_since(×tamp_startup, US"queue_run phase 1 done"); #endif q->queue_2stage = f.queue_2stage = FALSE; - DEBUG(D_queue_run) debug_printf("queue_run phase 2 start\n"); + DEBUG(queue_run) debug_printf("queue_run phase 2 start\n"); queue_run(q, start_id, stop_id, TRUE); } @@ -844,7 +844,7 @@ if (!recurse) if (atrn_domains && !msg_handled) { - DEBUG(D_any) debug_printf("ATRN: no messages; sending QUIT\n"); + DEBUG(any) debug_printf("ATRN: no messages; sending QUIT\n"); (void) send(0, "QUIT\r\n", 6, 0); } } @@ -855,7 +855,7 @@ if (!recurse) void single_queue_run(qrunner * q, const uschar * start_id, const uschar * stop_id) { -DEBUG(D_queue_run) debug_printf("Single queue run%s%s%s%s\n", +DEBUG(queue_run) debug_printf("Single queue run%s%s%s%s\n", start_id ? US" starting at " : US"", start_id ? start_id: US"", stop_id ? US" stopping at " : US"", @@ -915,7 +915,7 @@ for (queue_filename * fq = queue_get_spool_list(-1, /* entire queue */ && match_isinlist(s+1, &domains, 0, &domainlist_anchor, NULL, MCL_DOMAIN + MCL_NOEXPAND, TRUE, NULL) == OK) { - DEBUG(D_all) + DEBUG(all) debug_printf_indent("found a matching message: '%s'\n", r->address); yield = OK; } @@ -1419,7 +1419,7 @@ switch(action) { uschar * fname = spool_fname(US"msglog", message_subdir, id, US""); - DEBUG(D_any) debug_printf(" removing %s", fname); + DEBUG(any) debug_printf(" removing %s", fname); if (Uunlink(fname) < 0) { if (errno != ENOENT) @@ -1427,12 +1427,12 @@ switch(action) yield = FALSE; printf("Error while removing %s: %s\n", fname, strerror(errno)); } - else DEBUG(D_any) debug_printf(" (no file)\n"); + else DEBUG(any) debug_printf(" (no file)\n"); } else { removed = TRUE; - DEBUG(D_any) debug_printf(" (ok)\n"); + DEBUG(any) debug_printf(" (ok)\n"); } for (int i = 0; i < 3; i++) @@ -1440,7 +1440,7 @@ switch(action) suffix[1] = (US"DHJ")[i]; fname = spool_fname(US"input", message_subdir, id, suffix); - DEBUG(D_any) debug_printf(" removing %s", fname); + DEBUG(any) debug_printf(" removing %s", fname); if (Uunlink(fname) < 0) { if (errno != ENOENT) @@ -1448,12 +1448,12 @@ switch(action) yield = FALSE; printf("Error while removing %s: %s\n", fname, strerror(errno)); } - else DEBUG(D_any) debug_printf(" (no file)\n"); + else DEBUG(any) debug_printf(" (no file)\n"); } else { removed = TRUE; - DEBUG(D_any) debug_printf(" (done)\n"); + DEBUG(any) debug_printf(" (done)\n"); } } } @@ -1670,14 +1670,14 @@ if (s) if (Ustat(ss, &statbuf) == 0) { f.queue_smtp = TRUE; - DEBUG(D_receive) debug_printf("queue_smtp set because %s exists\n", ss); + DEBUG(receive) debug_printf("queue_smtp set because %s exists\n", ss); } } else if (Ustat(ss, &statbuf) == 0) { queue_only = TRUE; - DEBUG(D_receive) debug_printf("queue_only set because %s exists\n", ss); + DEBUG(receive) debug_printf("queue_only set because %s exists\n", ss); } } @@ -1694,12 +1694,12 @@ int bsize = 1 + MESSAGE_ID_LENGTH + 1 + Ustrlen(queue_name) + 1; uschar * buf = store_get(bsize, GET_UNTAINTED); int fd; -DEBUG(D_queue_run) debug_printf("%s: %s\n", __FUNCTION__, msgid); +DEBUG(queue_run) debug_printf("%s: %s\n", __FUNCTION__, msgid); if ( deliver_queue_load_max >= 0 && os_getloadavg() > deliver_queue_load_max) { - DEBUG(D_queue_run) debug_printf(" - avoided due to load-avg\n"); + DEBUG(queue_run) debug_printf(" - avoided due to load-avg\n"); return; } @@ -1713,11 +1713,11 @@ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) ssize_t len = daemon_notifier_sockname(&sa_un); if (sendto(fd, buf, bsize, 0, (struct sockaddr *)&sa_un, (socklen_t)len) < 0) - DEBUG(D_queue_run) + DEBUG(queue_run) debug_printf("%s: sendto %s\n", __FUNCTION__, strerror(errno)); close(fd); } -else DEBUG(D_queue_run) debug_printf(" socket: %s\n", strerror(errno)); +else DEBUG(queue_run) debug_printf(" socket: %s\n", strerror(errno)); } #endif diff --git a/src/src/rda.c b/src/src/rda.c index bea4ad54c..36992e16c 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -122,7 +122,7 @@ if (saved_errno == ENOENT) saved_errno = errno; ALARM_CLR(0); - DEBUG(D_route) debug_printf_indent("stat(%s)=%d\n", s, rc); + DEBUG(route) debug_printf_indent("stat(%s)=%d\n", s, rc); } if (sigalrm_seen || rc != 0) @@ -133,7 +133,7 @@ if (sigalrm_seen || rc != 0) } *error = string_sprintf("%s does not exist", filename); -DEBUG(D_route) debug_printf_indent("%s\n", *error); +DEBUG(route) debug_printf_indent("%s\n", *error); return FILE_NOT_EXIST; } @@ -200,7 +200,7 @@ directory test. */ if (!(fwd = Ufopen(filename, "rb"))) switch(errno) { case ENOENT: /* File does not exist */ - DEBUG(D_route) debug_printf_indent("%s does not exist\n%schecking parent directory\n", + DEBUG(route) debug_printf_indent("%s does not exist\n%schecking parent directory\n", filename, options & RDO_ENOTDIR ? "ignore_enotdir set => skip " : ""); *yield = options & RDO_ENOTDIR || rda_exists(filename, error) == FILE_NOT_EXIST @@ -209,14 +209,14 @@ if (!(fwd = Ufopen(filename, "rb"))) switch(errno) case ENOTDIR: /* Something on the path isn't a directory */ if (!(options & RDO_ENOTDIR)) goto DEFAULT_ERROR; - DEBUG(D_route) debug_printf_indent("non-directory on path %s: file assumed not to " + DEBUG(route) debug_printf_indent("non-directory on path %s: file assumed not to " "exist\n", filename); *yield = FF_NONEXIST; return NULL; case EACCES: /* Permission denied */ if (!(options & RDO_EACCES)) goto DEFAULT_ERROR; - DEBUG(D_route) debug_printf_indent("permission denied for %s: file assumed not to " + DEBUG(route) debug_printf_indent("permission denied for %s: file assumed not to " "exist\n", filename); *yield = FF_NONEXIST; return NULL; @@ -295,7 +295,7 @@ if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size) } filebuf[statbuf.st_size] = 0; -DEBUG(D_route) debug_printf_indent(OFF_T_FMT " %sbytes read from %s\n", +DEBUG(route) debug_printf_indent(OFF_T_FMT " %sbytes read from %s\n", statbuf.st_size, is_tainted(filename) ? "(tainted) " : "", filename); (void)fclose(fwd); @@ -365,7 +365,7 @@ if (*filtertype != FILTER_FORWARD) { int old_expand_forbid = expand_forbid; - DEBUG(D_route) debug_printf_indent("data is %s filter program\n", + DEBUG(route) debug_printf_indent("data is %s filter program\n", *filtertype == FILTER_EXIM ? "an Exim" : "a Sieve"); /* RDO_FILTER is an "allow" bit */ @@ -425,7 +425,7 @@ if (*filtertype != FILTER_FORWARD) /* Not a filter script */ -DEBUG(D_route) debug_printf_indent("file is not a filter file\n"); +DEBUG(route) debug_printf_indent("file is not a filter file\n"); yield = parse_forward_list(data, options, /* specials that are allowed */ @@ -573,7 +573,7 @@ uschar *data; uschar *readerror = US""; void (*oldsignal)(int); -DEBUG(D_route) debug_printf_indent("rda_interpret (%s): '%s'\n", +DEBUG(route) debug_printf_indent("rda_interpret (%s): '%s'\n", rdata->isfile ? "file" : "string", string_printing(rdata->string)); /* Do the expansions of the file name or data first, while still privileged. */ @@ -587,7 +587,7 @@ if (!(data = expand_string(rdata->string))) } rdata->string = data; -DEBUG(D_route) +DEBUG(route) debug_printf_indent("expanded: '%s'%s\n", data, is_tainted(data) ? " (tainted)":""); if (rdata->isfile && data[0] != '/') @@ -652,9 +652,9 @@ if ((pid = exim_fork(US"router-interpret")) == 0) if (ugid->uid != root_uid && ugid->uid != exim_uid) { - DEBUG(D_rewrite) debug_printf_indent("turned off address rewrite logging (not " + DEBUG(rewrite) debug_printf_indent("turned off address rewrite logging (not " "root or exim in this process)\n"); - BIT_CLEAR(log_selector, log_selector_size, Li_address_rewrite); + logging_modify_channels(US"-address_rewrite"); } /* Now do the business */ @@ -793,7 +793,7 @@ out: exim_underbar_exit(EXIT_SUCCESS); bad: - DEBUG(D_rewrite) debug_printf_indent("rda_interpret: failed write to pipe\n"); + DEBUG(rewrite) debug_printf_indent("rda_interpret: failed write to pipe\n"); goto out; } @@ -972,7 +972,7 @@ while ((rc = wait(&status)) != pid) goto FINAL_EXIT; } -DEBUG(D_route) +DEBUG(route) debug_printf_indent("rda_interpret: subprocess yield=%d error=%s\n", yield, *error); if (had_disaster) diff --git a/src/src/readconf.c b/src/src/readconf.c index 3397e7368..ba91ad0fc 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -508,9 +508,10 @@ options_logging(void) { uschar buf[EXIM_DRIVERNAME_MAX]; -for (bit_table * bp = log_options; bp < log_options + log_options_count; bp++) +for (const uschar * const * p = log_chan_names + BIT_TABLE_IDX_USABLE; + p < log_chan_names + log_options_count; p++) if (*p) { - spf(buf, sizeof(buf), US"_LOG_%T", bp->name); + spf(buf, sizeof(buf), US"_LOG_%T", *p); builtin_macro_create(buf); } } @@ -787,7 +788,7 @@ macro_create(const uschar * name, const uschar * val, BOOL command_line) { macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED); -EARLY_DEBUG(D_macro, "%s: '%s' '%s'\n", __FUNCTION__, name, val); +EARLY_DEBUG(macro, "%s: '%s' '%s'\n", __FUNCTION__, name, val); m->next = NULL; m->command_line = command_line; m->namelen = Ustrlen(name); @@ -980,11 +981,11 @@ if (*s) for (macro_item * m = *s == '_' ? macros : macros_user; m; m = m->next) { int moveby; - DEBUG(D_macro) + DEBUG(macro) if (f.expansion_test) printf("macro '%s' -> '%s'\n", m->name, m->replacement); else - EARLY_DEBUG(D_macro, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, + EARLY_DEBUG(macro, "%s: matched '%s' in '%.*s'\n", __FUNCTION__, m->name, (int) Ustrlen(ss)-1, ss); /* Expand the buffer if necessary */ @@ -3583,7 +3584,7 @@ if (!*spool_directory) /* Expand the spool directory name; it may, for example, contain the primary host name. Same comment about failure. */ -DEBUG(D_any) if (Ustrchr(spool_directory, '$')) +DEBUG(any) if (Ustrchr(spool_directory, '$')) debug_printf("Expanding spool_directory option\n"); if (!(s = expand_string(spool_directory))) @@ -3834,7 +3835,7 @@ else d->driver_name, class); const char * errormsg; - DEBUG(D_any) debug_printf("Loading %q %s driver from %s\n", + DEBUG(any) debug_printf("Loading %q %s driver from %s\n", d->driver_name, class, LOOKUP_MODULE_DIR); for(struct dirent * ent; ent = readdir(dd); ) if (Ustrcmp(ent->d_name, fname) == 0) @@ -3870,7 +3871,7 @@ else store_pool = POOL_PERM; add_driver_info(info_anchor, di, size_of_info); store_pool = old_pool; - DEBUG(D_any) + DEBUG(any) debug_printf("Loaded module %q (%s)\n", d->driver_name, class); goto found; } @@ -4097,13 +4098,13 @@ for (optionlist * ol = di->options; ol < di->options + count; ol++) { if (ss <= value || (ss[-1] != '$' && ss[-1] != '{') || isalnum(ss[Ustrlen(s)])) continue; - DEBUG(D_transport) debug_printf("driver %s: %q option depends on %s\n", + DEBUG(transport) debug_printf("driver %s: %q option depends on %s\n", d->name, ol->name, s); return TRUE; } } -DEBUG(D_transport) debug_printf("driver %s does not depend on %s\n", d->name, s); +DEBUG(transport) debug_printf("driver %s does not depend on %s\n", d->name, s); return FALSE; } @@ -4605,7 +4606,7 @@ while(*next_section) int mid = last/2; int n = Ustrlen(next_section); - EARLY_DEBUG(D_any, "%s: %s\n", __FUNCTION__, next_section); + EARLY_DEBUG(any, "%s: %s\n", __FUNCTION__, next_section); expand_level++; if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, US"s"); diff --git a/src/src/receive.c b/src/src/receive.c index f40b7313f..90760f621 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -296,7 +296,7 @@ if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) { int_eximarith_t space = receive_statvfs(TRUE, &inodes); - DEBUG(D_receive) + DEBUG(receive) debug_printf("spool directory space = " PR_EXIM_ARITH "K inodes = %d " "check_space = " PR_EXIM_ARITH "K inodes = %d msg_size = %d\n", space, inodes, check_spool_space, check_spool_inodes, msg_size); @@ -314,7 +314,7 @@ if (check_log_space > 0 || check_log_inodes > 0) { int_eximarith_t space = receive_statvfs(FALSE, &inodes); - DEBUG(D_receive) + DEBUG(receive) debug_printf("log directory space = " PR_EXIM_ARITH "K inodes = %d " "check_space = " PR_EXIM_ARITH "K inodes = %d\n", space, inodes, check_log_space, check_log_inodes); @@ -586,7 +586,7 @@ Returns: TRUE if it did remove something; FALSE otherwise BOOL receive_remove_recipient(const uschar * recipient) { -DEBUG(D_receive) debug_printf("receive_remove_recipient(%q) called\n", +DEBUG(receive) debug_printf("receive_remove_recipient(%q) called\n", recipient); for (int count = 0; count < recipients_count; count++) if (Ustrcmp(recipients_list[count].address, recipient) == 0) @@ -1008,11 +1008,11 @@ for(;;) if (linelength == -1) /* \r already seen (see below) */ { - DEBUG(D_receive) debug_printf("Add missing LF\n"); + DEBUG(receive) debug_printf("Add missing LF\n"); bdat_ungetc('\n'); continue; } - DEBUG(D_receive) debug_printf("Add missing CRLF\n"); + DEBUG(receive) debug_printf("Add missing CRLF\n"); bdat_ungetc('\r'); /* not even \r was seen */ fix_nl = TRUE; @@ -1087,7 +1087,7 @@ int ch; /* Remember that this message uses wireformat. */ -DEBUG(D_receive) debug_printf("CHUNKING: %s\n", +DEBUG(receive) debug_printf("CHUNKING: %s\n", fout ? "writing spoolfile in wire format" : "flushing input"); f.spool_file_wireformat = TRUE; @@ -1197,7 +1197,7 @@ static void give_local_error(int errcode, uschar *text1, uschar *text2, int error_rc, FILE *f, header_line *hptr) { -DEBUG(D_all) debug_printf("%s%s\n", text2, text1); +DEBUG(all) debug_printf("%s%s\n", text2, text1); if (error_handling == ERRORS_SENDER) { @@ -1259,7 +1259,7 @@ switch(where) if (acl_removed_headers) { - DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers removed by %s ACL:\n", acl_name); + DEBUG(receive|acl) debug_printf_indent(">>Headers removed by %s ACL:\n", acl_name); for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old) { @@ -1278,15 +1278,15 @@ if (acl_removed_headers) ) { h->type = htype_old; - DEBUG(D_receive|D_acl) debug_printf_indent(" %s", h->text); + DEBUG(receive|acl) debug_printf_indent(" %s", h->text); } } acl_removed_headers = NULL; - DEBUG(D_receive|D_acl) debug_printf_indent(">>\n"); + DEBUG(receive|acl) debug_printf_indent(">>\n"); } if (!acl_added_headers) return; -DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers added by %s ACL:\n", acl_name); +DEBUG(receive|acl) debug_printf_indent(">>Headers added by %s ACL:\n", acl_name); for (header_line * h = acl_added_headers, * next; h; h = next) { @@ -1297,7 +1297,7 @@ for (header_line * h = acl_added_headers, * next; h; h = next) case htype_add_top: h->next = header_list; header_list = h; - DEBUG(D_receive|D_acl) debug_printf_indent(" (at top)"); + DEBUG(receive|acl) debug_printf_indent(" (at top)"); break; case htype_add_rec: @@ -1312,7 +1312,7 @@ for (header_line * h = acl_added_headers, * next; h; h = next) } h->next = last_received->next; last_received->next = h; - DEBUG(D_receive|D_acl) debug_printf_indent(" (after Received:)"); + DEBUG(receive|acl) debug_printf_indent(" (after Received:)"); break; case htype_add_rfc: @@ -1327,13 +1327,13 @@ for (header_line * h = acl_added_headers, * next; h; h = next) of all headers. Our current header must follow it. */ h->next = last_received->next; last_received->next = h; - DEBUG(D_receive|D_acl) debug_printf_indent(" (before any non-Received: or Resent-*: header)"); + DEBUG(receive|acl) debug_printf_indent(" (before any non-Received: or Resent-*: header)"); break; default: h->next = NULL; header_last->next = h; - DEBUG(D_receive|D_acl) debug_printf_indent(" "); + DEBUG(receive|acl) debug_printf_indent(" "); break; } @@ -1348,11 +1348,11 @@ for (header_line * h = acl_added_headers, * next; h; h = next) h->type = header_checkname(h, FALSE); if (h->type >= 'a') h->type = htype_other; - DEBUG(D_receive|D_acl) debug_printf("%s", h->text); + DEBUG(receive|acl) debug_printf("%s", h->text); } acl_added_headers = NULL; -DEBUG(D_receive|D_acl) debug_printf_indent(">>\n"); +DEBUG(receive|acl) debug_printf_indent(">>\n"); } @@ -1482,11 +1482,11 @@ for (header_line * my_headerlist = header_list; my_headerlist; && strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0 ) { - DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n"); + DEBUG(receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n"); goto DO_MIME_ACL; } -DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n"); +DEBUG(receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n"); return TRUE; DO_MIME_ACL: @@ -1539,7 +1539,7 @@ if (rc == OK) if (strncmpic(US entry->d_name, US"__rfc822_", 9) == 0) { rfc822_file_path = string_sprintf("%s/%s", scandir, entry->d_name); - DEBUG(D_receive) + DEBUG(receive) debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path); break; @@ -1633,7 +1633,7 @@ else received_header->slen = Ustrlen(received_header->text); -DEBUG(D_receive) debug_printf(">>Generated Received: header line\n%c %s", +DEBUG(receive) debug_printf(">>Generated Received: header line\n%c %s", received_header->type, received_header->text); } @@ -2265,7 +2265,7 @@ OVERSIZE: if (isspace(*p)) { - DEBUG(D_receive) debug_printf("WARNING: bad header line " + DEBUG(receive) debug_printf("WARNING: bad header line " " (starts with whitespace). Assuming first line of body\n"); #ifndef DISABLE_DKIM f.dkim_disable_verify = TRUE; /* This could be a DKIM-bypass attack */ @@ -2275,7 +2275,7 @@ OVERSIZE: while (mac_isgraph(*p) && *p != ':') p++; if (Uskip_whitespace(&p) != ':') { - DEBUG(D_receive) debug_printf("WARNING: bad header line" + DEBUG(receive) debug_printf("WARNING: bad header line" " (no colon). Assuming first line of body\n"); #ifndef DISABLE_DKIM f.dkim_disable_verify = TRUE; @@ -2395,7 +2395,7 @@ we are going to generate a bit later on. If next != NULL, it contains the first data line - which terminated the headers before reaching a blank line (not the normal case). */ -DEBUG(D_receive) +DEBUG(receive) { debug_printf(">>Headers received:\n"); acl_level++; @@ -2494,7 +2494,7 @@ for (header_line * h = header_list->next; h; h = h->next) originator_login, qualify_domain_sender); from_header = header_last; h->type = htype_old; - DEBUG(D_receive|D_rewrite) + DEBUG(receive|rewrite) debug_printf("rewrote \"%s:\" header using gecos\n", name); } } @@ -2927,13 +2927,13 @@ if (LOGGING(received_recipients)) recipients will get here only if the conditions were right (allow_unqualified_ recipient is TRUE). */ -DEBUG(D_rewrite) +DEBUG(rewrite) { debug_printf_indent("qualify & rewrite recipients list\n"); acl_level++; } for (int i = 0; i < recipients_count; i++) recipients_list[i].address = /* deconst ok as src was not cont */ US rewrite_address(recipients_list[i].address, TRUE, TRUE, global_rewrite_rules, rewrite_existflags); -DEBUG(D_rewrite) acl_level--; +DEBUG(rewrite) acl_level--; /* If there is no From: header, generate one for local (without suppress_local_fixups) or submission_mode messages. If there is no sender @@ -3105,17 +3105,17 @@ if ( from_header /* If there are any rewriting rules, apply them to the sender address, unless it has already been rewritten as part of verification for SMTP input. */ -DEBUG(D_rewrite) +DEBUG(rewrite) { debug_printf("rewrite rules on sender address\n"); acl_level++; } if (global_rewrite_rules && !sender_address_unrewritten && *sender_address) { /* deconst ok as src was not const */ sender_address = US rewrite_address(sender_address, FALSE, TRUE, global_rewrite_rules, rewrite_existflags); - DEBUG(D_receive|D_rewrite) + DEBUG(receive|rewrite) debug_printf("rewritten sender = %s\n", sender_address); } -DEBUG(D_rewrite) acl_level--; +DEBUG(rewrite) acl_level--; /* The headers must be run through rewrite_header(), because it ensures that @@ -3132,13 +3132,13 @@ We start at the second header, skipping our own Received:. This rewriting is documented as happening *after* recipient addresses are taken from the headers by the -t command line option. An added Sender: gets rewritten here. */ -DEBUG(D_rewrite) +DEBUG(rewrite) { debug_printf("qualify and rewrite headers\n"); acl_level++; } for (header_line * h = header_list->next, * newh; h; h = h->next) if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules, rewrite_existflags, TRUE))) h = newh; -DEBUG(D_rewrite) acl_level--; +DEBUG(rewrite) acl_level--; /* An RFC 822 (sic) message is not legal unless it has at least one of "to", @@ -3169,7 +3169,7 @@ search_tidyup(); /* Free any cached resources */ /* Show the complete set of headers if debugging. Note that the first one (the new Received:) has not yet been set. */ -DEBUG(D_receive) +DEBUG(receive) { debug_printf(">>Headers after rewriting and local additions:\n"); acl_level++; @@ -3227,7 +3227,7 @@ to access it both via a file descriptor and a stdio stream. Try to make the directory if it isn't there. */ spool_name = spool_fname(US"input", message_subdir, message_id, US"-D"); -DEBUG(D_receive) debug_printf("Data file name: %s\n", spool_name); +DEBUG(receive) debug_printf("Data file name: %s\n", spool_name); if ((data_fd = Uopen(spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE)) < 0) { @@ -3414,7 +3414,7 @@ if (fflush(spool_data_file) == EOF || ferror(spool_data_file) || /* No I/O errors were encountered while writing the data file. */ -DEBUG(D_receive) debug_printf("Data file written for message %s\n", message_id); +DEBUG(receive) debug_printf("Data file written for message %s\n", message_id); gettimeofday(&received_time_complete, NULL); @@ -3431,7 +3431,7 @@ syntactically good recipient address.) */ if (extract_recip && (bad_addresses || recipients_count == 0)) { - DEBUG(D_receive) + DEBUG(receive) { if (recipients_count == 0) debug_printf("*** No recipients\n"); if (bad_addresses) @@ -3619,7 +3619,7 @@ else const uschar * addr = recipients_list[c].address; uschar * msg= US"PRDR R=<%s> %s"; uschar * code; - DEBUG(D_receive) + DEBUG(receive) debug_printf("PRDR processing recipient %s (%d of %d)\n", addr, c+1, recipients_count); rc = acl_check(ACL_WHERE_PRDR, addr, @@ -3805,7 +3805,7 @@ if (sigsetjmp(local_scan_env, 1) == 0) os_non_restarting_signal(SIGILL, local_scan_crash_handler); os_non_restarting_signal(SIGBUS, local_scan_crash_handler); - DEBUG(D_receive) debug_printf("calling local_scan(); timeout=%d\n", + DEBUG(receive) debug_printf("calling local_scan(); timeout=%d\n", local_scan_timeout); local_scan_data = NULL; @@ -3819,7 +3819,7 @@ if (sigsetjmp(local_scan_env, 1) == 0) f.enable_dollar_recipients = FALSE; store_pool = POOL_MAIN; /* In case changed */ - DEBUG(D_receive) debug_printf("local_scan() returned %d %s\n", rc, + DEBUG(receive) debug_printf("local_scan() returned %d %s\n", rc, local_scan_data); os_non_restarting_signal(SIGSEGV, SIG_DFL); @@ -3899,8 +3899,7 @@ multiline SMTP responses. */ else { - uschar *istemp = US""; - uschar *smtp_code; + uschar * istemp = US"", * smtp_code; gstring * g; errmsg = local_scan_data; @@ -3909,12 +3908,12 @@ else switch(rc) { default: - log_write(0, LOG_MAIN, "invalid return %d from local_scan(). Temporary " - "rejection given", rc); + log_write(0, LOG_MAIN, + "invalid return %d from local_scan(). Temporary rejection given", rc); goto TEMPREJECT; case LOCAL_SCAN_REJECT_NOLOGHDR: - BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header); + logging_modify_channels(US"-rejected_header"); /* Fall through */ case LOCAL_SCAN_REJECT: @@ -3923,7 +3922,7 @@ else break; case LOCAL_SCAN_TEMPREJECT_NOLOGHDR: - BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header); + logging_modify_channels(US"-rejected_header"); /* Fall through */ case LOCAL_SCAN_TEMPREJECT: @@ -3974,7 +3973,7 @@ if (fake_response != OK) for (recipient_item * r = recipients_list; r < recipients_list + recipients_count; r++) { - DEBUG(D_receive) if (r->dsn_flags & (rf_notify_success | rf_notify_delay)) + DEBUG(receive) if (r->dsn_flags & (rf_notify_success | rf_notify_delay)) debug_printf("DSN: clearing flags due to fake-response for message\n"); r->dsn_flags = r->dsn_flags & ~(rf_notify_success | rf_notify_delay) | rf_notify_never; @@ -4431,7 +4430,7 @@ NOT_ACCEPTED: message_id[0] = 0; /* Indicate no message accepted */ TIDYUP: -DEBUG(D_receive) debug_printf("%s: tidyup\n", __FUNCTION__); +DEBUG(receive) debug_printf("%s: tidyup\n", __FUNCTION__); process_info[process_info_len] = 0; /* Remove message id */ if (spool_data_file && cutthrough_done == NOT_TRIED) @@ -4600,5 +4599,5 @@ return yield; /* TRUE if more messages (SMTP only) */ } /* End of receive.c */ -/* vi: se aw ai sw=2 +/* vi: aw ai sw=2 */ diff --git a/src/src/regex_cache.c b/src/src/regex_cache.c index ab26b8a96..f0981a313 100644 --- a/src/src/regex_cache.c +++ b/src/src/regex_cache.c @@ -52,7 +52,7 @@ int rlen = sizeof(re_req) + klen; re_req * req; int fd, old_pool = store_pool; -DEBUG(D_regex) +DEBUG(regex) debug_printf_indent("sending RE '%s' to daemon\n", key); store_pool = POOL_MAIN; @@ -68,11 +68,11 @@ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0) ssize_t len = daemon_notifier_sockname(&sa_un); if (sendto(fd, req, rlen, 0, (struct sockaddr *)&sa_un, (socklen_t)len) < 0) - DEBUG(D_regex) + DEBUG(regex) debug_printf("%s: sendto %s\n", __FUNCTION__, strerror(errno)); close(fd); } -else DEBUG(D_regex) debug_printf(" socket: %s\n", strerror(errno)); +else DEBUG(regex) debug_printf(" socket: %s\n", strerror(errno)); } @@ -81,7 +81,7 @@ regex_from_cache(const uschar * key, BOOL caseless) { tree_node * node = tree_search(caseless ? regex_caseless_cache : regex_cache, key); -DEBUG(D_regex) +DEBUG(regex) debug_printf_indent("compiled %sRE '%s' %sfound in local cache\n", caseless ? "caseless " : "", key, node ? "" : "not "); @@ -99,8 +99,8 @@ Ustrcpy(node->name, key); node->data.ptr = (void *)cre; if (!tree_insertnode(caseless ? ®ex_caseless_cache : ®ex_cache, node)) - { DEBUG(D_regex) debug_printf_indent("duplicate key!\n"); } -else DEBUG(D_regex) + { DEBUG(regex) debug_printf_indent("duplicate key!\n"); } +else DEBUG(regex) debug_printf_indent("compiled RE '%s' saved in local cache\n", key); /* Additionally, if not re-execed and not the daemon, tell the daemon of the RE @@ -204,7 +204,7 @@ if ( flags & MCS_CACHEABLE && (yield = regex_from_cache(key, caseless))) return yield; -DEBUG(D_regex) debug_printf_indent("compiling %sRE '%s'\n", +DEBUG(regex) debug_printf_indent("compiling %sRE '%s'\n", caseless ? "caseless " : "", pattern); store_pool = POOL_PERM; @@ -246,6 +246,6 @@ else if ((cre = regex_compile(req->re, &errstr, pcre_gen_cmp_ctx))) regex_cachesize++; -DEBUG(D_any) if (!cre) debug_printf("%s\n", errstr); +DEBUG(any) if (!cre) debug_printf("%s\n", errstr); return; } diff --git a/src/src/retry.c b/src/src/retry.c index 515c94288..720f849ae 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -37,7 +37,7 @@ retry_ultimate_address_timeout(const uschar * retry_key, const uschar *domain, BOOL address_timeout; retry_config * retry; -DEBUG(D_retry) +DEBUG(retry) { debug_printf("retry time not reached: checking ultimate address timeout\n"); debug_printf(" now=" TIME_T_FMT " first_failed=" TIME_T_FMT @@ -53,19 +53,19 @@ if (retry && retry->rules) { retry_rule *last_rule; for (last_rule = retry->rules; last_rule->next; last_rule = last_rule->next) ; - DEBUG(D_retry) + DEBUG(retry) debug_printf(" received_time=" TIME_T_FMT " diff=%d timeout=%d\n", received_time.tv_sec, (int)(now - received_time.tv_sec), last_rule->timeout); address_timeout = (now - received_time.tv_sec > last_rule->timeout); } else { - DEBUG(D_retry) + DEBUG(retry) debug_printf("no retry rule found: assume timed out\n"); address_timeout = TRUE; } -DEBUG(D_retry) +DEBUG(retry) if (address_timeout) debug_printf("on queue longer than maximum retry for address - " "allowing delivery\n"); @@ -164,7 +164,7 @@ dbdata_retry * host_retry_record, * message_retry_record; if (host->status != hstatus_unknown) return FALSE; host->status = hstatus_usable; -DEBUG(D_transport|D_retry) +DEBUG(transport|retry) { debug_printf_indent("checking retry status of %s\n", host->name); acl_level++; @@ -186,7 +186,7 @@ the retry database when it is updated). */ if ((node = tree_search(tree_unusable, host_key))) { - DEBUG(D_transport|D_retry) + DEBUG(transport|retry) debug_printf_indent("found in tree of unusables\n"); host->status = node->data.val > 255 ? hstatus_unusable_expired : hstatus_unusable; @@ -201,16 +201,16 @@ if (!continue_retry_db) dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE); else if (continue_retry_db != (open_db *)-1) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent(" using cached retry hintsdb handle\n"); dbm_file = continue_retry_db; } -else DEBUG(D_hints_lookup) +else DEBUG(hints_lookup) debug_printf_indent(" using cached retry hintsdb nonpresence\n"); if (!dbm_file) { - DEBUG(D_deliver|D_retry|D_hints_lookup) + DEBUG(deliver|retry|hints_lookup) debug_printf_indent("no retry data available\n"); goto out; } @@ -219,28 +219,28 @@ message_retry_record = dbfn_read(dbm_file, message_key); if (!continue_retry_db) dbfn_close(dbm_file); else - DEBUG(D_hints_lookup) debug_printf_indent("retaining retry hintsdb handle\n"); + DEBUG(hints_lookup) debug_printf_indent("retaining retry hintsdb handle\n"); /* Ignore the data if it is too old - too long since it was written */ if (!host_retry_record) { - DEBUG(D_transport|D_retry) debug_printf_indent("no host retry record\n"); + DEBUG(transport|retry) debug_printf_indent("no host retry record\n"); } else if (now - host_retry_record->gen.time_stamp > retry_data_expire) { host_retry_record = NULL; - DEBUG(D_transport|D_retry) debug_printf_indent("host retry record too old\n"); + DEBUG(transport|retry) debug_printf_indent("host retry record too old\n"); } if (!message_retry_record) { - DEBUG(D_transport|D_retry) debug_printf_indent("no message retry record\n"); + DEBUG(transport|retry) debug_printf_indent("no message retry record\n"); } else if (now - message_retry_record->gen.time_stamp > retry_data_expire) { message_retry_record = NULL; - DEBUG(D_transport|D_retry) + DEBUG(transport|retry) debug_printf_indent("message retry record too old\n"); } @@ -299,7 +299,7 @@ if (message_retry_record) } out: -DEBUG(D_transport|D_retry) acl_level--; +DEBUG(transport|retry) acl_level--; return yield; } @@ -348,7 +348,7 @@ rti->message = host : addr->message; rti->flags = flags; -DEBUG(D_transport|D_retry) +DEBUG(transport|retry) { int letter = rti->more_errno & 255; debug_printf("added retry %sitem for %s: errno=%d more_errno=", @@ -426,12 +426,12 @@ if (alternate) alternate = string_sprintf("*@%s", alternate); /* Scan the configured retry items. */ -DEBUG(D_retry) acl_level++; +DEBUG(retry) acl_level++; for (yield = retries; yield; yield = yield->next) { const uschar * plist = yield->pattern, * slist = yield->senders; - DEBUG(D_retry) + DEBUG(retry) { acl_level--; debug_printf_indent("Check retry rule (%s:%d) '%s'\n", @@ -543,7 +543,7 @@ for (yield = retries; yield; yield = yield->next) ) ) break; } -DEBUG(D_retry) acl_level--; +DEBUG(retry) acl_level--; return yield; } @@ -582,7 +582,7 @@ retry_update(address_item ** addr_defer, address_item ** addr_failed, open_db dbblock, * dbm_file = NULL; time_t now = time(NULL); -DEBUG(D_retry) { debug_printf_indent("Processing retry items\n"); acl_level++; } +DEBUG(retry) { debug_printf_indent("Processing retry items\n"); acl_level++; } /* Three-times loop to handle succeeded, failed, and deferred addresses. Deferred addresses must be handled after failed ones, because some may be moved @@ -595,7 +595,7 @@ for (int i = 0; i < 3; i++) address_item ** paddr = i==0 ? addr_succeed : i==1 ? addr_failed : addr_defer; address_item ** saved_paddr = NULL; - DEBUG(D_retry) + DEBUG(retry) { debug_printf_indent("%s addresses:\n", i == 0 ? "Succeeded" : i == 1 ? "Failed" : "Deferred"); @@ -620,7 +620,7 @@ for (int i = 0; i < 3; i++) { int update_count = 0, timedout_count = 0; - DEBUG(D_retry) + DEBUG(retry) { debug_printf_indent("%s%s\n", addr->address, addr->retries ? "" : ": no retry items"); @@ -646,7 +646,7 @@ for (int i = 0; i < 3; i++) if (!dbm_file) if (continue_retry_db && continue_retry_db != (open_db *)-1) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("using cached retry hintsdb handle\n"); dbm_file = continue_retry_db; } @@ -654,7 +654,7 @@ for (int i = 0; i < 3; i++) ? dbfn_open(US"retry", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE) : dbfn_open_multi(US"retry", O_RDWR|O_CREAT, &dbblock))) { - DEBUG(D_deliver|D_retry|D_hints_lookup) + DEBUG(deliver|retry|hints_lookup) debug_printf_indent("retry db not available for updating\n"); return; } @@ -676,7 +676,7 @@ for (int i = 0; i < 3; i++) if (rti->flags & rf_delete) { (void)dbfn_delete(dbm_file, rti->key); - DEBUG(D_retry) + DEBUG(retry) debug_printf_indent("deleted retry information for %s\n", rti->key); continue; } @@ -697,7 +697,7 @@ for (int i = 0; i < 3; i++) rti->flags & rf_host ? addr->domain : NULL, rti->basic_errno, rti->more_errno))) { - DEBUG(D_retry) debug_printf_indent("No configured retry item for %s%s%s\n", + DEBUG(retry) debug_printf_indent("No configured retry item for %s%s%s\n", rti->key, rti->flags & rf_host ? US" or " : US"", rti->flags & rf_host ? addr->domain : US""); @@ -705,7 +705,7 @@ for (int i = 0; i < 3; i++) continue; } - DEBUG(D_retry) + DEBUG(retry) if (rti->flags & rf_host) debug_printf_indent("retry for %s (%s) = %s %d %d\n", rti->key, addr->domain, retry->pattern, retry->basic_errno, @@ -726,7 +726,7 @@ for (int i = 0; i < 3; i++) message_length = Ustrlen(message); if (message_length > EXIM_DB_RLIMIT) { - DEBUG(D_retry) + DEBUG(retry) debug_printf_indent("truncating message from %u to %u bytes\n", message_length, EXIM_DB_RLIMIT); message_length = EXIM_DB_RLIMIT; @@ -763,7 +763,7 @@ for (int i = 0; i < 3; i++) /* Compute how long this destination has been failing */ failing_interval = now - retry_record->first_failed; - DEBUG(D_retry) debug_printf_indent("failing_interval=%d message_age=%d\n", + DEBUG(retry) debug_printf_indent("failing_interval=%d message_age=%d\n", failing_interval, message_age); /* For a non-host error, if the message has been on the queue longer @@ -845,7 +845,7 @@ for (int i = 0; i < 3; i++) ; if (now - received_time.tv_sec > last_rule->timeout) { - DEBUG(D_retry) debug_printf_indent("on queue longer than maximum retry\n"); + DEBUG(retry) debug_printf_indent("on queue longer than maximum retry\n"); timedout_count++; rule = NULL; } @@ -911,7 +911,7 @@ for (int i = 0; i < 3; i++) Ustrncpy(retry_record->text, message, message_length); retry_record->text[message_length] = 0; /* nul-term string in db */ - DEBUG(D_retry) + DEBUG(retry) { int letter = retry_record->more_errno & 255; debug_printf_indent("Writing retry data for %s\n", rti->key); @@ -929,12 +929,12 @@ for (int i = 0; i < 3; i++) if (dbfn_write(dbm_file, rti->key, retry_record, sizeof(dbdata_retry) + message_length) != 0) - DEBUG(D_retry) debug_printf_indent("retry record write failed\n"); + DEBUG(retry) debug_printf_indent("retry record write failed\n"); if (!exim_lockfile_needed()) dbfn_transaction_commit(dbm_file); } /* Loop for each retry item */ - DEBUG(D_retry) acl_level--; + DEBUG(retry) acl_level--; /* If all the non-delete retry items are timed out, the address is timed out, provided that we didn't skip any hosts because their retry @@ -943,11 +943,11 @@ for (int i = 0; i < 3; i++) if (update_count > 0 && update_count == timedout_count) if (!testflag(endaddr, af_retry_skipped)) { - DEBUG(D_retry) debug_printf_indent("timed out: all retries expired\n"); + DEBUG(retry) debug_printf_indent("timed out: all retries expired\n"); timed_out = TRUE; } else - DEBUG(D_retry) + DEBUG(retry) debug_printf_indent("timed out but some hosts were skipped\n"); } /* Loop for an address and its parents */ @@ -1009,7 +1009,7 @@ for (int i = 0; i < 3; i++) paddr = &(endaddr->next); /* Advance to next address */ } /* Loop for all addresses */ - DEBUG(D_retry) acl_level--; + DEBUG(retry) acl_level--; } /* Loop for succeed, fail, defer */ /* Close and unlock the database */ @@ -1020,10 +1020,10 @@ if (dbm_file) dbfn_close(dbm_file); else dbfn_close_multi(dbm_file); - else DEBUG(D_hints_lookup) + else DEBUG(hints_lookup) debug_printf_indent("retaining retry hintsdb handle\n"); -DEBUG(D_retry) +DEBUG(retry) { acl_level--; debug_printf_indent("end of retry processing\n"); } } diff --git a/src/src/rewrite.c b/src/src/rewrite.c index cf65fc242..0affaaae8 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -241,7 +241,7 @@ for (rewrite_rule * rule = rewrite_rules; /* We have a validly rewritten address */ - if (LOGGING(address_rewrite) || IS_DEBUG(D_rewrite)) + if (LOGGING(address_rewrite) || IS_DEBUG(rewrite)) { const uschar * where = CUS"?"; @@ -448,7 +448,7 @@ uschar * s = Ustrchr(h->text, ':') + 1; Uskip_whitespace(&s); -DEBUG(D_rewrite) /* The header text includes the trailing newline */ +DEBUG(rewrite) /* The header text includes the trailing newline */ debug_printf_indent("rewrite_one_header: type=%c:\n %s", h->type, h->text); f.parse_allow_group = TRUE; /* Allow group syntax */ @@ -523,7 +523,7 @@ while (*s) if (domain <= 0 || strcmpic(recipient+domain, routed_old) != 0) continue; recipient[domain-1] = 0; new = string_sprintf("%s@%s", recipient, routed_new); - DEBUG(D_rewrite) + DEBUG(rewrite) { recipient[domain-1] = '@'; debug_printf("%s rewritten by router as %s\n", recipient, new); @@ -653,7 +653,7 @@ while (*s) Ustrcat(newt, s); - DEBUG(D_rewrite) debug_printf("newlen=%d newtype=%c newtext:\n%s", + DEBUG(rewrite) debug_printf("newlen=%d newtype=%c newtext:\n%s", slen, type, newtstart); /* Compute the length of the rest of the header line before we possibly @@ -676,7 +676,7 @@ while (*s) /* Set up for scanning the rest of the header */ s = newh->text + remlen; - DEBUG(D_rewrite) debug_printf("remainder: %s", *s ? s : US"\n"); + DEBUG(rewrite) debug_printf("remainder: %s", *s ? s : US"\n"); } } diff --git a/src/src/rfc2047.c b/src/src/rfc2047.c index 7d3e42cb7..e3515f5b7 100644 --- a/src/src/rfc2047.c +++ b/src/src/rfc2047.c @@ -273,7 +273,7 @@ while (mimeword) } else { - DEBUG(D_any) debug_printf("iconv error translating \"%.*s\" to %s: " + DEBUG(any) debug_printf("iconv error translating \"%.*s\" to %s: " "%s\n", (int)(endword + 2 - mimeword), mimeword, target, strerror(errno)); } } diff --git a/src/src/route.c b/src/src/route.c index 778e524c1..07be01c65 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -357,7 +357,7 @@ for (router_instance * r = routers; r; r = r->drinst.next) set_router(r, r->pass_router_name, &(r->pass_router), TRUE); #ifdef notdef - DEBUG(D_route) debug_printf_indent("DSN: %s %s\n", r->name, + DEBUG(route) debug_printf_indent("DSN: %s %s\n", r->name, r->dsn_lasthop ? "lasthop set" : "propagating DSN"); #endif } @@ -522,7 +522,7 @@ route_check_dls(const uschar * rname, const uschar * type, const uschar * list, { if (!list) return OK; /* Empty list always succeeds */ -DEBUG(D_route) debug_printf_indent("checking %s\n", type); +DEBUG(route) debug_printf_indent("checking %s\n", type); /* The domain and local part use the same matching function, whereas sender has its own code. */ @@ -539,13 +539,13 @@ switch(domloc case FAIL: *perror = string_sprintf("%s router skipped: %s mismatch", rname, type); - DEBUG(D_route) debug_printf_indent("%s\n", *perror); + DEBUG(route) debug_printf_indent("%s\n", *perror); return SKIP; default: /* Paranoia, and keeps compilers happy */ case DEFER: *perror = string_sprintf("%s check lookup or other defer", type); - DEBUG(D_route) debug_printf_indent("%s\n", *perror); + DEBUG(route) debug_printf_indent("%s\n", *perror); return DEFER; } } @@ -588,7 +588,7 @@ route_check_access(const uschar * path, uid_t uid, gid_t gid, int bits) struct stat statbuf; uschar * rp = US realpath(CCS path, CS big_buffer); -DEBUG(D_route) debug_printf_indent("route_check_access(%s,%d,%d,%o)\n", path, +DEBUG(route) debug_printf_indent("route_check_access(%s,%d,%d,%o)\n", path, (int)uid, (int)gid, bits); if (!rp) return FALSE; @@ -596,7 +596,7 @@ if (!rp) return FALSE; for (uschar * sp = rp + 1, * slash; slash = Ustrchr(sp, '/'); sp = slash + 1) { *slash = '\0'; - DEBUG(D_route) debug_printf_indent("stat %s\n", rp); + DEBUG(route) debug_printf_indent("stat %s\n", rp); if (Ustat(rp, &statbuf) < 0) return FALSE; if ((statbuf.st_mode & (statbuf.st_uid == uid ? 0100 : statbuf.st_gid == gid ? 0010 : 001) @@ -610,7 +610,7 @@ for (uschar * sp = rp + 1, * slash; slash = Ustrchr(sp, '/'); sp = slash + 1) /* Down to the final component */ -DEBUG(D_route) debug_printf_indent("stat %s\n", rp); +DEBUG(route) debug_printf_indent("stat %s\n", rp); if (Ustat(rp, &statbuf) < 0) return FALSE; @@ -623,7 +623,7 @@ if ((statbuf.st_mode & bits) != bits) return FALSE; } -DEBUG(D_route) debug_printf_indent("route_check_access() succeeded\n"); +DEBUG(route) debug_printf_indent("route_check_access() succeeded\n"); return TRUE; } @@ -667,7 +667,7 @@ uschar *check; if (!s) return OK; -DEBUG(D_route|D_expand) debug_printf_indent("checking require_files\n"); +DEBUG(route|expand) debug_printf_indent("checking require_files\n"); listptr = s; while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) @@ -733,7 +733,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) /* Note that we have values set, and proceed to next item */ - DEBUG(D_route) + DEBUG(route) debug_printf_indent("check subsequent files for access by %s\n", ss); ugid_set = TRUE; continue; @@ -764,7 +764,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) rc = Ustat(ss, &statbuf); - DEBUG(D_route) + DEBUG(route) { debug_printf_indent("file check: %s\n", check); if (ss != check) debug_printf_indent("expanded file: %s\n", ss); @@ -783,7 +783,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) pid_t pid; void (*oldsignal)(int); - DEBUG(D_route) debug_printf_indent("root is denied access: forking to check " + DEBUG(route) debug_printf_indent("root is denied access: forking to check " "in subprocess\n"); /* Before forking, ensure that SIGCHLD is set to SIG_DFL before forking, so @@ -799,7 +799,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) if (pid < 0) { - DEBUG(D_route) + DEBUG(route) debug_printf_indent("require_files: fork failed: %s\n", strerror(errno)); errno = EACCES; goto HANDLE_ERROR; @@ -815,7 +815,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) string_sprintf("require_files check, file=%s", ss)); if (route_check_access(ss, uid, gid, 4)) exim_underbar_exit(EXIT_SUCCESS); - DEBUG(D_route) debug_printf_indent("route_check_access() failed\n"); + DEBUG(route) debug_printf_indent("route_check_access() failed\n"); exim_underbar_exit(EXIT_FAILURE); } @@ -840,7 +840,7 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) if (rc == 0 && ugid_set && !route_check_access(ss, uid, gid, 4)) { - DEBUG(D_route) debug_printf_indent("route_check_access() failed\n"); + DEBUG(route) debug_printf_indent("route_check_access() failed\n"); rc = -1; } @@ -852,12 +852,12 @@ while ((check = string_nextinlist(&listptr, &sep, NULL, 0))) HANDLE_ERROR: if (rc < 0) { - DEBUG(D_route) debug_printf_indent("errno = %d\n", errno); + DEBUG(route) debug_printf_indent("errno = %d\n", errno); if (errno == EACCES) { if (eacces_code == 1) { - DEBUG(D_route) debug_printf_indent("EACCES => ENOENT\n"); + DEBUG(route) debug_printf_indent("EACCES => ENOENT\n"); errno = ENOENT; /* Treat as non-existent */ } } @@ -879,7 +879,7 @@ return OK; /* Come here on any of the errors that return DEFER. */ RETURN_DEFER: -DEBUG(D_route) debug_printf_indent("%s\n", *perror); +DEBUG(route) debug_printf_indent("%s\n", *perror); return DEFER; } @@ -932,7 +932,7 @@ f.search_find_defer = FALSE; if ((verify == v_none || verify == v_expn) && r->verify_only) { - DEBUG(D_route) debug_printf_indent("%s router skipped: verify_only set\n", rname); + DEBUG(route) debug_printf_indent("%s router skipped: verify_only set\n", rname); return SKIP; } @@ -940,7 +940,7 @@ if ((verify == v_none || verify == v_expn) && r->verify_only) if (f.address_test_mode && !r->address_test) { - DEBUG(D_route) debug_printf_indent("%s router skipped: address_test is unset\n", + DEBUG(route) debug_printf_indent("%s router skipped: address_test is unset\n", rname); return SKIP; } @@ -951,7 +951,7 @@ set. */ if ((verify == v_sender && !r->verify_sender) || (verify == v_recipient && !r->verify_recipient)) { - DEBUG(D_route) debug_printf_indent("%s router skipped: verify %d %d %d\n", + DEBUG(route) debug_printf_indent("%s router skipped: verify %d %d %d\n", rname, verify, r->verify_sender, r->verify_recipient); return SKIP; } @@ -960,7 +960,7 @@ if ((verify == v_sender && !r->verify_sender) || if (verify == v_expn && !r->expn) { - DEBUG(D_route) debug_printf_indent("%s router skipped: no_expn set\n", rname); + DEBUG(route) debug_printf_indent("%s router skipped: no_expn set\n", rname); return SKIP; } @@ -1004,10 +1004,10 @@ local_user_{uid,gid} and local_part_data. */ if (r->check_local_user) { - DEBUG(D_route) debug_printf_indent("checking for local user\n"); + DEBUG(route) debug_printf_indent("checking for local user\n"); if (!route_finduser(addr->local_part, pw, NULL)) { - DEBUG(D_route) debug_printf_indent("%s router skipped: %s is not a local user\n", + DEBUG(route) debug_printf_indent("%s router skipped: %s is not a local user\n", rname, addr->local_part); return SKIP; } @@ -1060,7 +1060,7 @@ debug_print_string(r->debug_string); if ((rc = check_files(r->require_files, perror)) != OK) { - DEBUG(D_route) debug_printf_indent("%s router %s: file check\n", rname, + DEBUG(route) debug_printf_indent("%s router %s: file check\n", rname, rc == SKIP ? "skipped" : "deferred"); return rc; } @@ -1069,17 +1069,17 @@ if ((rc = check_files(r->require_files, perror)) != OK) if (r->condition) { - DEBUG(D_route|D_expand) + DEBUG(route|expand) debug_printf_indent("checking \"condition\" \"%.80s\"...\n", r->condition); if (!expand_check_condition(r->condition, rname, US"router")) { if (f.search_find_defer) { *perror = US"condition check lookup defer"; - DEBUG(D_route) debug_printf_indent("%s\n", *perror); + DEBUG(route) debug_printf_indent("%s\n", *perror); return DEFER; } - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s router skipped: condition failure\n", rname); return SKIP; } @@ -1132,7 +1132,7 @@ route_finduser(const uschar *s, struct passwd **pw, uid_t *return_uid) { BOOL cache_set = (Ustrcmp(lastname, s) == 0); -DEBUG(D_uid) debug_printf_indent("seeking password data for user %q: %s\n", s, +DEBUG(uid) debug_printf_indent("seeking password data for user %q: %s\n", s, cache_set ? "using cached result" : "cache not available"); if (!cache_set) @@ -1151,7 +1151,7 @@ if (!cache_set) if (max_username_length > 0 && Ustrlen(lastname) > max_username_length) { - DEBUG(D_uid) debug_printf_indent("forced failure of finduser(): string " + DEBUG(uid) debug_printf_indent("forced failure of finduser(): string " "length of %s is greater than %d\n", lastname, max_username_length); lastpw = NULL; } @@ -1180,17 +1180,17 @@ if (!cache_set) lastpw = &pwcache; } - else DEBUG(D_uid) if (errno != 0) + else DEBUG(uid) if (errno != 0) debug_printf_indent("getpwnam(%s) failed: %s\n", s, strerror(errno)); } if (!lastpw) { - DEBUG(D_uid) debug_printf_indent("getpwnam() returned NULL (user not found)\n"); + DEBUG(uid) debug_printf_indent("getpwnam() returned NULL (user not found)\n"); return FALSE; } -DEBUG(D_uid) debug_printf_indent("getpwnam() succeeded uid=%d gid=%d\n", +DEBUG(uid) debug_printf_indent("getpwnam() succeeded uid=%d gid=%d\n", lastpw->pw_uid, lastpw->pw_gid); if (return_uid) *return_uid = lastpw->pw_uid; @@ -1413,7 +1413,7 @@ new->start_router = addr->router->drinst.next; new->next = *addr_new; *addr_new = new; -DEBUG(D_route) debug_printf_indent("\"unseen\" set: replicated %s\n", addr->address); +DEBUG(route) debug_printf_indent("\"unseen\" set: replicated %s\n", addr->address); /* Make a new unique field, to distinguish from the normal one. */ @@ -1426,7 +1426,7 @@ are handled in the normal way. */ if (addr->transport && tree_search(tree_nonrecipients, addr->unique)) { - DEBUG(D_route) + DEBUG(route) debug_printf_indent("\"unseen\" delivery previously done - discarded\n"); parent->child_count--; if (*paddr_remote == addr) *paddr_remote = addr->next; @@ -1478,17 +1478,17 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) { int yield; BOOL more; - DEBUG(D_route) debug_printf_indent("forced failure in expansion of %q " + DEBUG(route) debug_printf_indent("forced failure in expansion of %q " "(router variable): decline action taken\n", ele); /* Expand "more" if necessary; DEFER => an expansion failed */ - if ((yield = exp_bool(addr, US"router", drname, D_route, + if ((yield = exp_bool(addr, US"router", drname, IS_DEBUG(route), US"more", r->more, r->expand_more, &more)) != OK) return yield; if (more) return PASS; - DEBUG(D_route) + DEBUG(route) debug_printf_indent("\"more\"=false: skipping remaining routers\n"); router_name = NULL; r = NULL; @@ -1500,7 +1500,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) "in %s router: %s", ele, drname, expand_string_message); /* Caller will replace that for logging, if a DB lookup, to avoid exposing passwords */ - DEBUG(D_route) debug_printf_indent("%s\n", addr->message); + DEBUG(route) debug_printf_indent("%s\n", addr->message); return f.search_find_defer ? DEFER : FAIL; } @@ -1511,7 +1511,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) (void)tree_insertnode(root, node); } node->data.ptr = US val; - DEBUG(D_route) debug_printf_indent("set r_%s%s = '%s'%s\n", + DEBUG(route) debug_printf_indent("set r_%s%s = '%s'%s\n", name, is_tainted(name)?" (tainted)":"", val, is_tainted(val)?" (tainted)":""); @@ -1559,7 +1559,7 @@ router_instance * r, * nextr; const uschar * old_domain = addr->domain; const uschar * rname_l; -HDEBUG(D_route) +HDEBUG(route) { debug_printf_indent(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf_indent("routing %s\n", addr->address); @@ -1578,7 +1578,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) int loopcount = 0, rc; rname_l = r->drinst.name; - DEBUG(D_route) + DEBUG(route) { expand_level--; debug_printf_indent("--------> %s router <--------\n", rname_l); @@ -1632,7 +1632,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (break_loop) { - DEBUG(D_route) debug_printf_indent("%s router skipped: previously routed %s\n", + DEBUG(route) debug_printf_indent("%s router skipped: previously routed %s\n", rname_l, parent->address); loop_detected = TRUE; break; @@ -1658,7 +1658,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) addr->local_part = r->caseful_local_part ? addr->cc_local_part : addr->lc_local_part; - DEBUG(D_route) debug_printf_indent("local_part=%s domain=%s\n", addr->local_part, + DEBUG(route) debug_printf_indent("local_part=%s domain=%s\n", addr->local_part, addr->domain); /* Handle any configured prefix by replacing the local_part address, @@ -1684,11 +1684,11 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) else addr->prefix = string_copyn_taint(addr->local_part, plen, GET_UNTAINTED); addr->local_part += plen; - DEBUG(D_route) debug_printf_indent("stripped prefix %s\n", addr->prefix); + DEBUG(route) debug_printf_indent("stripped prefix %s\n", addr->prefix); } else if (!r->prefix_optional) { - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s router skipped: prefix mismatch\n", rname_l); continue; } @@ -1708,11 +1708,11 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) : string_copy_taint(addr->local_part + lplen, GET_UNTAINTED); addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen; addr->local_part = string_copyn(addr->local_part, lplen); - DEBUG(D_route) debug_printf_indent("stripped suffix %s\n", addr->suffix); + DEBUG(route) debug_printf_indent("stripped suffix %s\n", addr->suffix); } else if (!r->suffix_optional) { - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s router skipped: suffix mismatch\n", rname_l); continue; } @@ -1764,23 +1764,23 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (r->address_data) { - DEBUG(D_route|D_expand) debug_printf_indent("processing address_data\n"); + DEBUG(route|expand) debug_printf_indent("processing address_data\n"); if (!(deliver_address_data = expand_string(r->address_data))) { if (f.expand_string_forcedfail) { - DEBUG(D_route) debug_printf_indent("forced failure in expansion of %q " + DEBUG(route) debug_printf_indent("forced failure in expansion of %q " "(address_data): decline action taken\n", r->address_data); /* Expand "more" if necessary; DEFER => an expansion failed */ - yield = exp_bool(addr, US"router", rname_l, D_route, + yield = exp_bool(addr, US"router", rname_l, IS_DEBUG(route), US"more", r->more, r->expand_more, &more); if (yield != OK) goto ROUTERS_LOOP_EXIT; if (!more) { - DEBUG(D_route) + DEBUG(route) debug_printf_indent("\"more\"=false: skipping remaining routers\n"); driver_srcfile = router_name = NULL; driver_srcline = 0; r = NULL; @@ -1824,12 +1824,12 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (r->dsn_lasthop && !(addr->dsn_flags & rf_dsnlasthop)) { addr->dsn_flags |= rf_dsnlasthop; - HDEBUG(D_route) debug_printf_indent("DSN: last hop for %s\n", addr->address); + HDEBUG(route) debug_printf_indent("DSN: last hop for %s\n", addr->address); } /* Run the router, and handle the consequences. */ - HDEBUG(D_route) debug_printf_indent("calling %s router\n", rname_l); + HDEBUG(route) debug_printf_indent("calling %s router\n", rname_l); { router_info * ri = r->drinst.info; @@ -1841,7 +1841,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (yield == FAIL) { - HDEBUG(D_route) debug_printf_indent("%s router forced address failure\n", rname_l); + HDEBUG(route) debug_printf_indent("%s router forced address failure\n", rname_l); goto ROUTERS_LOOP_EXIT; } @@ -1865,7 +1865,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (yield != PASS && yield != DECLINE) break; - HDEBUG(D_route) + HDEBUG(route) { debug_printf_indent("%s router %s for %s\n", rname_l, yield == PASS ? "passed" : "declined", addr->address); @@ -1885,13 +1885,13 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) { /* Expand "more" if necessary */ - yield = exp_bool(addr, US"router", rname_l, D_route, + yield = exp_bool(addr, US"router", rname_l, IS_DEBUG(route), US"more", r->more, r->expand_more, &more); if (yield != OK) goto ROUTERS_LOOP_EXIT; if (!more) { - HDEBUG(D_route) + HDEBUG(route) debug_printf_indent("\"more\" is false: skipping remaining routers\n"); r = NULL; break; @@ -1908,7 +1908,7 @@ running a router go direct to ROUTE_EXIT from code above. */ if (!r) { - HDEBUG(D_route) debug_printf_indent("no more routers\n"); + HDEBUG(route) debug_printf_indent("no more routers\n"); if (!addr->message) { uschar * message = US"Unrouteable address"; @@ -1937,7 +1937,7 @@ if (!r) if (yield == DEFER) { - HDEBUG(D_route) debug_printf_indent("%s router: defer for %s\n message: %s\n", + HDEBUG(route) debug_printf_indent("%s router: defer for %s\n message: %s\n", rname_l, addr->address, addr->message ? addr->message : US""); goto ROUTE_EXIT; } @@ -1955,7 +1955,7 @@ as a result of a domain change of some sort (widening, typically). */ if (yield == REROUTED) { - HDEBUG(D_route) debug_printf_indent("re-routed to %s\n", addr->address); + HDEBUG(route) debug_printf_indent("re-routed to %s\n", addr->address); yield = OK; goto ROUTE_EXIT; } @@ -1994,7 +1994,7 @@ if (r->translate_ip_address) goto ROUTE_EXIT; } - DEBUG(D_route) debug_printf_indent("%s [%s] translated to %s\n", + DEBUG(route) debug_printf_indent("%s [%s] translated to %s\n", h->name, h->address, newaddress); if (string_is_ip_address(newaddress, NULL) != 0) { @@ -2027,15 +2027,15 @@ if (r->translate_ip_address) /* See if this is an unseen routing; first expand the option if necessary. DEFER can be given if the expansion fails */ -if ((yield = exp_bool(addr, US"router", rname_l, D_route, +if ((yield = exp_bool(addr, US"router", rname_l, IS_DEBUG(route), US"unseen", r->unseen, r->expand_unseen, &unseen)) != OK) goto ROUTE_EXIT; /* Debugging output recording a successful routing */ -HDEBUG(D_route) debug_printf_indent("routed by %s router%s\n", rname_l, +HDEBUG(route) debug_printf_indent("routed by %s router%s\n", rname_l, unseen ? " (unseen)" : ""); -DEBUG(D_route) +DEBUG(route) { debug_printf_indent(" envelope to:\t%s\n", addr->address); debug_printf_indent(" transport:\t%s\n", addr->transport diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c index 9986c39aa..c5846d897 100644 --- a/src/src/routers/accept.c +++ b/src/src/routers/accept.c @@ -112,7 +112,7 @@ const uschar * errors_to; uschar * remove_headers; header_line * extra_headers; -DEBUG(D_route) debug_printf_indent("%s router called for %s\n domain = %s\n", +DEBUG(route) debug_printf_indent("%s router called for %s\n domain = %s\n", rblock->drinst.name, addr->address, addr->domain); /* Set up the errors address, if any. */ diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 5df6ea8f9..8e1adc0ed 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -152,7 +152,7 @@ const uschar * pre_widen = addr->domain, * post_widen = NULL; const uschar * fully_qualified_name, * listptr; uschar widen_buffer[256]; -DEBUG(D_route) +DEBUG(route) debug_printf_indent("%s router called for %s\n domain = %s\n", rblock->drinst.name, addr->address, addr->domain); @@ -229,14 +229,14 @@ for (;;) /* not expanded so should never be tainted */ widen = string_nextinlist(&listptr, &widen_sep, widen_buffer, sizeof(widen_buffer)); - DEBUG(D_route) debug_printf("%s router widened %s to %s\n", + DEBUG(route) debug_printf("%s router widened %s to %s\n", rblock->drinst.name, addr->domain, h.name); } else if (post_widen) { h.name = post_widen; post_widen = NULL; - DEBUG(D_route) debug_printf("%s router trying %s after widening failed\n", + DEBUG(route) debug_printf("%s router trying %s after widening failed\n", rblock->drinst.name, h.name); } else return DECLINE; @@ -279,7 +279,7 @@ for (;;) if (ob->search_parents) flags |= HOST_FIND_SEARCH_PARENTS; } - DEBUG(D_route) debug_printf_indent("main lookup for domain\n"); + DEBUG(route) debug_printf_indent("main lookup for domain\n"); { expand_level++; rc = host_find_bydns(&h, CUS rblock->ignore_target_hosts, flags, @@ -305,7 +305,7 @@ for (;;) return DEFER; case OK: - DEBUG(D_route) debug_printf("%s router rejected %s: no MX record(s)\n", + DEBUG(route) debug_printf("%s router rejected %s: no MX record(s)\n", rblock->drinst.name, fully_qualified_name); continue; } @@ -322,7 +322,7 @@ for (;;) { if (rblock->pass_on_timeout) { - DEBUG(D_route) debug_printf("%s router timed out, and pass_on_timeout is set\n", + DEBUG(route) debug_printf("%s router timed out, and pass_on_timeout is set\n", rblock->drinst.name); return PASS; } @@ -342,7 +342,7 @@ for (;;) return DEFER; case OK: - DEBUG(D_route) debug_printf("%s router: matched fail_defer_domains\n", + DEBUG(route) debug_printf("%s router: matched fail_defer_domains\n", rblock->drinst.name); addr->message = US"missing MX, or all MXs point to missing A records," " and defer requested"; @@ -435,7 +435,7 @@ if (rc == HOST_FOUND_LOCAL) else if (ob->check_secondary_mx && !testflag(addr, af_local_host_removed)) { - DEBUG(D_route) debug_printf("check_secondary_mx set and local host not secondary\n"); + DEBUG(route) debug_printf("check_secondary_mx set and local host not secondary\n"); return DECLINE; } diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c index 022592c9e..0adcc96f7 100644 --- a/src/src/routers/ipliteral.c +++ b/src/src/routers/ipliteral.c @@ -118,7 +118,7 @@ const uschar * ip; int len = Ustrlen(domain); int rc, ipv; -DEBUG(D_route) debug_printf_indent("%s router called for %s: domain = %s\n", +DEBUG(route) debug_printf_indent("%s router called for %s: domain = %s\n", rblock->drinst.name, addr->address, addr->domain); /* Check that the domain is an IP address enclosed in square brackets. Remember @@ -141,7 +141,7 @@ but if it is set, it should probably work. */ if (verify_check_this_host(CUSS&rblock->ignore_target_hosts, NULL, domain, ip, NULL) == OK) { - DEBUG(D_route) + DEBUG(route) debug_printf("%s is in ignore_target_hosts\n", ip); addr->message = US"IP literal host explicitly ignored"; return DECLINE; diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index 5d9c04d71..fd8880b4a 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -173,7 +173,7 @@ const pcre2_code *re = ob->re_response_pattern; int count, query_len, rc; int sep = 0; -DEBUG(D_route) debug_printf_indent("%s router called for %s: domain = %s\n", +DEBUG(route) debug_printf_indent("%s router called for %s: domain = %s\n", rblock->drinst.name, addr->address, addr->domain); reply = store_get(256, GET_TAINTED); @@ -194,7 +194,7 @@ else } query_len = Ustrlen(query); -DEBUG(D_route) debug_printf("%s router query is %q\n", rblock->drinst.name, +DEBUG(route) debug_printf("%s router query is %q\n", rblock->drinst.name, string_printing(query)); /* Now connect to the required port for each of the hosts in turn, until a @@ -208,7 +208,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, { host_item *h; - DEBUG(D_route) debug_printf("calling host %s\n", hostname); + DEBUG(route) debug_printf("calling host %s\n", hostname); host->name = hostname; host->address = NULL; @@ -260,7 +260,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, ob->protocol == ip_udp ? NULL : &tcp_fastopen_nodata) < 0) { close(query_cctx.sock); - DEBUG(D_route) + DEBUG(route) debug_printf("connection to %s failed: %s\n", h->address, strerror(errno)); continue; @@ -270,7 +270,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, if (send(query_cctx.sock, query, query_len, 0) < 0) { - DEBUG(D_route) debug_printf("send to %s failed\n", h->address); + DEBUG(route) debug_printf("send to %s failed\n", h->address); (void)close(query_cctx.sock); continue; } @@ -282,7 +282,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, (void)close(query_cctx.sock); if (count <= 0) { - DEBUG(D_route) debug_printf("%s from %s\n", (errno == ETIMEDOUT)? + DEBUG(route) debug_printf("%s from %s\n", (errno == ETIMEDOUT)? "timed out" : "recv failed", h->address); *reply = 0; continue; @@ -291,7 +291,7 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer, /* Success; break the loop */ reply[count] = 0; - DEBUG(D_route) debug_printf("%s router received %q from %s\n", + DEBUG(route) debug_printf("%s router received %q from %s\n", rblock->drinst.name, string_printing(reply), h->address); break; } @@ -310,7 +310,7 @@ defer otherwise. */ if (!hostname) { - DEBUG(D_route) debug_printf("%s router failed to get anything\n", rblock->drinst.name); + DEBUG(route) debug_printf("%s router failed to get anything\n", rblock->drinst.name); if (ob->optional) return PASS; addr->message = string_sprintf("%s router: failed to communicate with any " "host", rblock->drinst.name); @@ -326,7 +326,7 @@ if (re != NULL) { if (!regex_match_and_setup(re, reply, 0, -1)) { - DEBUG(D_route) debug_printf("%s router: %s failed to match response %s\n", + DEBUG(route) debug_printf("%s router: %s failed to match response %s\n", rblock->drinst.name, ob->response_pattern, reply); return DECLINE; } @@ -351,7 +351,7 @@ else while (isspace(reply[nn])) nn++; if (Ustrcmp(query + query_len/2 + 1, reply+nn) != 0) { - DEBUG(D_route) debug_printf("%s router: failed to match identification " + DEBUG(route) debug_printf("%s router: failed to match identification " "in response %s\n", rblock->drinst.name, reply); return DECLINE; } diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 3ddde3e56..4191b8384 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -248,7 +248,7 @@ manualroute_router_options_block * ob = transport_instance * transport = NULL; BOOL individual_transport_set = FALSE, randomize; -DEBUG(D_route) debug_printf_indent("%s router called for %s\n domain = %s\n", +DEBUG(route) debug_printf_indent("%s router called for %s\n domain = %s\n", rblock->drinst.name, addr->address, addr->domain); /* The initialization check ensures that either route_list or route_data is @@ -263,7 +263,7 @@ if (ob->route_list) { int rc; - DEBUG(D_route) debug_printf_indent("route_item = %s\n", route_item); + DEBUG(route) debug_printf_indent("route_item = %s\n", route_item); if (!parse_route_item(route_item, &domain, &hostlist, &options)) continue; /* Ignore blank items */ @@ -298,7 +298,7 @@ else single host or a list of hosts; options is pointing to the rest of the routelist item, which is either empty or contains various option words. */ -DEBUG(D_route) debug_printf_indent("original list of hosts = '%s' options = '%s'\n", +DEBUG(route) debug_printf_indent("original list of hosts = '%s' options = '%s'\n", hostlist, options); newhostlist = expand_string_copy(hostlist); @@ -317,12 +317,12 @@ if (!newhostlist) } else hostlist = newhostlist; -DEBUG(D_route) debug_printf_indent("expanded list of hosts = '%s' options = '%s'\n", +DEBUG(route) debug_printf_indent("expanded list of hosts = '%s' options = '%s'\n", hostlist, options); /* Get the hosts_randomize router option, expanding if needed */ -if (exp_bool(addr, US"router", rblock->drinst.name, D_route, +if (exp_bool(addr, US"router", rblock->drinst.name, IS_DEBUG(route), US"hosts_randomize", ob->hosts_randomize, ob->expand_hosts_randomize, &randomize) != OK) return DEFER; @@ -457,7 +457,7 @@ is controlled by host_all_ignored. */ if (!addr->host_list) { int i; - DEBUG(D_route) debug_printf("host_find_failed ignored every host\n"); + DEBUG(route) debug_printf("host_find_failed ignored every host\n"); if (ob->hai_code == hff_decline) return DECLINE; if (ob->hai_code == hff_pass) return PASS; diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 3e12ec0d7..6cfaf0ab5 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -145,7 +145,7 @@ while (generated != NULL) "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address); addr->child_count++; - DEBUG(D_route) + DEBUG(route) debug_printf("%s router generated %s\n", rblock->drinst.name, next->address); } } @@ -226,7 +226,7 @@ gid_t gid = ob->cmd_gid; uid_t *puid = &uid; gid_t *pgid = &gid; -DEBUG(D_route) debug_printf_indent("%s router called for %s: domain = %s\n", +DEBUG(route) debug_printf_indent("%s router called for %s: domain = %s\n", rblock->drinst.name, addr->address, addr->domain); ugid.uid_set = ugid.gid_set = FALSE; @@ -271,14 +271,14 @@ if (!ob->cmd_gid_set) return DEFER; } -DEBUG(D_route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n", +DEBUG(route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n", (long int)uid, (long int)gid, current_directory); /* If we are not running as root, we will not be able to change uid/gid. */ if (curr_uid != root_uid && (uid != curr_uid || gid != curr_gid)) { - DEBUG(D_route) + DEBUG(route) { debug_printf("not running as root: cannot change uid/gid\n"); debug_printf("subprocess will run with uid=%ld gid=%ld\n", @@ -360,7 +360,7 @@ the result. */ while (len > 0 && isspace(buffer[len-1])) len--; buffer[len] = 0; -DEBUG(D_route) debug_printf("command wrote: %s\n", buffer); +DEBUG(route) debug_printf("command wrote: %s\n", buffer); rword = buffer; Uskip_whitespace(&rword); diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index e90ad2147..f8068916a 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -317,7 +317,7 @@ while (generated) : strcmpic(next->address, parent->address) ) == 0) { - DEBUG(D_route) debug_printf("generated parent replaced by child\n"); + DEBUG(route) debug_printf("generated parent replaced by child\n"); next->address = string_copy(addr->address); break; } @@ -413,7 +413,7 @@ while (generated) || (sender_address && string_is_utf8(sender_address)); #endif - DEBUG(D_route) + DEBUG(route) { debug_printf("%s router generated %s\n %serrors_to=%s transport=%s\n", rblock->drinst.name, @@ -592,7 +592,7 @@ switch (frc) return DECLINE; case FF_BLACKHOLE: - DEBUG(D_route) debug_printf("address :blackhole:d\n"); + DEBUG(route) debug_printf("address :blackhole:d\n"); generated = NULL; discarded = US":blackhole:"; frc = FF_DELIVERED; @@ -622,7 +622,7 @@ switch (frc) if ( ob->forbid_smtp_code && regex_match(regex_smtp_code, addr->message, -1, &matched)) { - DEBUG(D_route) debug_printf("SMTP code at start of error message " + DEBUG(route) debug_printf("SMTP code at start of error message " "is ignored because forbid_smtp_code is set\n"); addr->message += Ustrlen(matched); } @@ -770,7 +770,7 @@ else next->prop = addr_prop; - DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s", + DEBUG(route) debug_printf("%s router autogenerated %s\n%s%s%s", rblock->drinst.name, next->address, (addr_prop.errors_address != NULL)? " errors to " : "", diff --git a/src/src/routers/rf_change_domain.c b/src/src/routers/rf_change_domain.c index 61c156b3e..342e8dc63 100644 --- a/src/src/routers/rf_change_domain.c +++ b/src/src/routers/rf_change_domain.c @@ -42,7 +42,7 @@ const uschar * at = Ustrrchr(addr->address, '@'); uschar * address = string_sprintf("%.*s@%s", (int)(at - addr->address), addr->address, domain); -DEBUG(D_route) debug_printf("domain changed to %s\n", domain); +DEBUG(route) debug_printf("domain changed to %s\n", domain); /* The current address item is made into the parent, and a new address is set up in the old space. */ @@ -68,12 +68,11 @@ addr->next = *addr_new; if (rewrite) { - DEBUG(D_route|D_rewrite) debug_printf("rewriting header lines\n"); - for (header_line * h = header_list; h != NULL; h = h->next) + DEBUG(route|rewrite) debug_printf("rewriting header lines\n"); + for (header_line * h = header_list; h; h = h->next) { - header_line *newh = - rewrite_header(h, parent->domain, domain, - global_rewrite_rules, rewrite_existflags, TRUE); + header_line * newh = rewrite_header(h, parent->domain, domain, + global_rewrite_rules, rewrite_existflags, TRUE); if (newh) { h = newh; diff --git a/src/src/routers/rf_expand_data.c b/src/src/routers/rf_expand_data.c index def615a71..2b757fb85 100644 --- a/src/src/routers/rf_expand_data.c +++ b/src/src/routers/rf_expand_data.c @@ -35,7 +35,7 @@ uschar *yield = expand_string(s); if (yield) return yield; if (f.expand_string_forcedfail) { - DEBUG(D_route) debug_printf("forced failure for expansion of %q\n", s); + DEBUG(route) debug_printf("forced failure for expansion of %q\n", s); *prc = DECLINE; } else diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c index 664c5c932..6f0017af6 100644 --- a/src/src/routers/rf_get_errors_address.c +++ b/src/src/routers/rf_get_errors_address.c @@ -48,7 +48,7 @@ if (!(s = expand_string(rblock->errors_to))) { if (f.expand_string_forcedfail) { - DEBUG(D_route) + DEBUG(route) debug_printf("forced expansion failure - ignoring errors_to\n"); return OK; } @@ -77,7 +77,7 @@ associated with an address. */ if (verify != v_none) { *errors_to = s; - DEBUG(D_route) + DEBUG(route) debug_printf("skipped verify errors_to address: already verifying\n"); } else @@ -107,13 +107,13 @@ else vopt_is_recipient, as otherwise sender_address may be altered because verify_address() thinks it is dealing with *the* sender of the message. */ - DEBUG(D_route|D_verify) + DEBUG(route|verify) debug_printf("------ Verifying errors address %s ------\n", s); if (verify_address(snew, -1, vopt_is_recipient /* vopt_fake_sender is the alternative */ | vopt_qualify, -1, -1, -1, NULL, NULL, NULL) == OK) *errors_to = snew->address; - DEBUG(D_route|D_verify) + DEBUG(route|verify) debug_printf("------ End verifying errors address %s ------\n", s); f.address_test_mode = save_address_test_mode; diff --git a/src/src/routers/rf_get_transport.c b/src/src/routers/rf_get_transport.c index 5d23d534e..c8519eaf8 100644 --- a/src/src/routers/rf_get_transport.c +++ b/src/src/routers/rf_get_transport.c @@ -85,7 +85,7 @@ else for (transport_instance * tp = transports; tp; tp = tp->drinst.next) if (Ustrcmp(tp->drinst.name, ss) == 0) { - DEBUG(D_route) debug_printf_indent("set transport '%s'\n", ss); + DEBUG(route) debug_printf_indent("set transport '%s'\n", ss); *tpptr = tp; return TRUE; } diff --git a/src/src/routers/rf_lookup_hostlist.c b/src/src/routers/rf_lookup_hostlist.c index 59e0761ea..38e5b2875 100644 --- a/src/src/routers/rf_lookup_hostlist.c +++ b/src/src/routers/rf_lookup_hostlist.c @@ -71,7 +71,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) next_h = h->next; if (h->address) { prev = h; continue; } - DEBUG(D_route|D_host_lookup) + DEBUG(route|host_lookup) debug_printf_indent("finding IP address for %s\n", h->name); expand_level++; @@ -99,7 +99,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) ? HOST_FIND_BY_MX | HOST_FIND_IPV4_FIRST : HOST_FIND_BY_MX; - DEBUG(D_route|D_host_lookup) + DEBUG(route|host_lookup) debug_printf("doing DNS MX lookup for %s\n", h->name); mx = MX_NONE; @@ -120,7 +120,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) else if (lookup_type & LK_BYNAME || string_is_ip_address(h->name, NULL) != 0) { - DEBUG(D_route|D_host_lookup) debug_printf_indent("calling host_find_byname\n"); + DEBUG(route|host_lookup) debug_printf_indent("calling host_find_byname\n"); rc = host_find_byname(h, ignore_target_hosts, HOST_FIND_QUALIFY_SINGLE, &canonical_name, TRUE); } @@ -138,7 +138,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) ? HOST_FIND_BY_A | HOST_FIND_BY_AAAA | HOST_FIND_IPV4_FIRST : HOST_FIND_BY_A | HOST_FIND_BY_AAAA; - DEBUG(D_route|D_host_lookup) debug_printf("doing DNS lookup\n"); + DEBUG(route|host_lookup) debug_printf("doing DNS lookup\n"); switch (rc = host_find_bydns(h, ignore_target_hosts, whichrrs, NULL, NULL, NULL, &rblock->dnssec, /* domains for request/require */ @@ -150,7 +150,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) case HOST_FIND_FAILED: if (lookup_type & LK_DEFAULT) { - DEBUG(D_route|D_host_lookup) + DEBUG(route|host_lookup) debug_printf("DNS lookup failed: trying %s\n", f.running_in_test_harness ? "host_fake_gethostbyname" : "getipnodebyname"); @@ -175,7 +175,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) expand_level--; if (rblock->pass_on_timeout) { - DEBUG(D_route) + DEBUG(route) debug_printf("%s router timed out and pass_on_timeout set\n", rblock->drinst.name); return PASS; @@ -235,7 +235,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h) { if (prev) { - DEBUG(D_route) + DEBUG(route) { debug_printf("Removed from host list:\n"); for (; h; h = h->next) debug_printf(" %s\n", h->name); diff --git a/src/src/routers/rf_queue_add.c b/src/src/routers/rf_queue_add.c index aa4645dcf..fb1c1b785 100644 --- a/src/src/routers/rf_queue_add.c +++ b/src/src/routers/rf_queue_add.c @@ -116,7 +116,7 @@ remote_delivery_count++; donelocal: -DEBUG(D_route) +DEBUG(route) { debug_printf_indent("queued for %s transport: local_part = %s\ndomain = %s\n" " errors_to=%s\n", diff --git a/src/src/routers/rf_self_action.c b/src/src/routers/rf_self_action.c index dba0774f8..b5f372d96 100644 --- a/src/src/routers/rf_self_action.c +++ b/src/src/routers/rf_self_action.c @@ -94,25 +94,25 @@ switch (code) return DEFER; case self_reroute: - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s: %s: domain changed to %s\n", msg, addr->domain, new); rf_change_domain(addr, new, rewrite, addr_new); return REROUTED; case self_send: - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s: %s: configured to try delivery anyway\n", msg, addr->domain); return OK; case self_pass: /* This is soft failure; pass to next router */ - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s: %s: passed to next router (self = pass)\n", msg, addr->domain); addr->message = msg; addr->self_hostname = string_copy(host->name); return PASS; case self_fail: - DEBUG(D_route) + DEBUG(route) debug_printf_indent("%s: %s: address failed (self = fail)\n", msg, addr->domain); addr->message = msg; setflag(addr, af_pass_message); diff --git a/src/src/search.c b/src/src/search.c index e81806379..def6b4c7a 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -85,15 +85,15 @@ if ((li = lookup_findonly(name))) return li; #ifdef LOOKUP_MODULE_DIR - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("searchtype %s not initially found\n", name); if (lookup_one_mod_load(name, NULL)) if ((li = lookup_findonly(name))) return li; else - { DEBUG(D_lookup) debug_printf_indent("find retry failed\n"); } - else DEBUG(D_lookup) + { DEBUG(lookup) debug_printf_indent("find retry failed\n"); } + else DEBUG(lookup) debug_printf_indent("scan modules dir for %s failed\n", name); #endif @@ -320,7 +320,7 @@ search_tidyup(void) { int old_pool = store_pool; -DEBUG(D_lookup) debug_printf_indent("search_tidyup called\n"); +DEBUG(lookup) debug_printf_indent("search_tidyup called\n"); expand_level++; /* Close individually each cached open file. */ @@ -416,7 +416,7 @@ if (filename && is_tainted(filename)) store_pool = POOL_SEARCH; if (!search_reset_point) search_reset_point = store_mark(); -DEBUG(D_lookup) debug_printf_indent("search_open: %s %q\n", li->name, +DEBUG(lookup) debug_printf_indent("search_open: %s %q\n", li->name, filename ? filename : US"NULL"); /* See if we already have this open for this type of search, and if so, @@ -431,12 +431,12 @@ if ((t = tree_search(search_tree, keybuffer))) { if ((c = (search_cache *)t->data.ptr)->handle) { - DEBUG(D_lookup) + DEBUG(lookup) if (c->handle != (void *)1) debug_printf_indent(" cached open\n"); store_pool = old_pool; return t; } - DEBUG(D_lookup) debug_printf_indent(" cached closed\n"); + DEBUG(lookup) debug_printf_indent(" cached closed\n"); } /* Otherwise, we need to open the file or database - each search type has its @@ -452,7 +452,7 @@ if (li->type == lookup_absfile && open_filecount >= lookup_open_max) else { search_cache * c = (search_cache *)(open_bot->data.ptr); - DEBUG(D_lookup) debug_printf_indent("Too many lookup files open\n closing %s\n", + DEBUG(lookup) debug_printf_indent("Too many lookup files open\n closing %s\n", open_bot->name); if ((open_bot = c->up)) ((search_cache *)(open_bot->data.ptr))->down = NULL; @@ -550,7 +550,7 @@ the callers don't have to test for NULL, set an empty string. */ search_error_message = US""; f.search_find_defer = FALSE; -DEBUG(D_lookup) debug_printf_indent("internal_search_find: file=%q\n " +DEBUG(lookup) debug_printf_indent("internal_search_find: file=%q\n " "type=%s key=%q opts=%s%s%s\n", filename, li->name, keystring, opts ? "\"" : "", opts, opts ? "\"" : ""); @@ -573,7 +573,7 @@ if ( (t = tree_search(c->item_cache, keystring)) ) { /* Data was in the cache already; set the pointer from the tree node */ data = e->data.ptr; - DEBUG(D_lookup) debug_printf_indent("cached data used for lookup of %s%s%s\n", + DEBUG(lookup) debug_printf_indent("cached data used for lookup of %s%s%s\n", keystring, filename ? US"\n in " : US"", filename ? filename : US""); } @@ -582,7 +582,7 @@ else uint do_cache = cache & CACHE_WR ? UINT_MAX : 0; int keylength = Ustrlen(keystring); - DEBUG(D_lookup) + DEBUG(lookup) { if (t) debug_printf_indent("cached data found but %s; ", @@ -639,7 +639,7 @@ else transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC, "tainted search query is not properly quoted%s: %s", loc, ks); - DEBUG(D_lookup) + DEBUG(lookup) { const uschar * quoter_name; int q = quoter_for_address(ks, "er_name); @@ -669,7 +669,7 @@ else else if (do_cache) { - DEBUG(D_lookup) debug_printf_indent("%s cache entry\n", + DEBUG(lookup) debug_printf_indent("%s cache entry\n", t ? "replacing old" : "creating new"); if (!t) /* No existing entry. Create new one. */ { @@ -694,15 +694,15 @@ cannot release the store at this stage. */ else if (cache & CACHE_WR) { - DEBUG(D_lookup) debug_printf_indent("lookup forced cache cleanup\n"); + DEBUG(lookup) debug_printf_indent("lookup forced cache cleanup\n"); c->item_cache = NULL; /* forget all lookups on this connection */ } - else DEBUG(D_lookup) + else DEBUG(lookup) debug_printf_indent("no_wr option: no cache invalidate\n"); } out: -DEBUG(D_lookup) +DEBUG(lookup) { if (data) debug_printf_indent("lookup yielded: %W\n", data); @@ -757,7 +757,7 @@ BOOL set_null_wild = FALSE, ret_key = FALSE; unsigned cache = CACHE_RD | CACHE_WR; uschar * yield; -DEBUG(D_lookup) +DEBUG(lookup) { if (partial < 0) affixlen = 99; /* So that "NULL" prints */ debug_printf_indent("search_find: file=%q\n key=%q " @@ -821,7 +821,7 @@ if (open_top != (tree_node *)handle) } } -DEBUG(D_lookup) +DEBUG(lookup) { debug_printf_indent("LRU list:\n"); for (tree_node * t = open_top; t; ) @@ -862,7 +862,7 @@ else if (partial >= 0) is_tainted(keystring) || is_tainted(affix) ? GET_TAINTED : GET_UNTAINTED); Ustrncpy(keystring2, affix, affixlen); Ustrcpy(keystring2 + affixlen, keystring); - DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2); + DEBUG(lookup) debug_printf_indent("trying partial match %s\n", keystring2); yield = internal_search_find(handle, filename, CUS keystring2, cache, opts); if (f.search_find_defer) return NULL; } @@ -900,7 +900,7 @@ else if (partial >= 0) if (affixlen > 0) Ustrncpy(keystring3, affix, affixlen); } - DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3); + DEBUG(lookup) debug_printf_indent("trying partial match %s\n", keystring3); yield = internal_search_find(handle, filename, CUS keystring3, cache, opts); if (f.search_find_defer) return NULL; @@ -945,7 +945,7 @@ if (!yield && starflags & SEARCH_STARAT) savechar = *--atat; *atat = '*'; - DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat); + DEBUG(lookup) debug_printf_indent("trying default match %s\n", atat); yield = internal_search_find(handle, filename, atat, cache, opts); *atat = savechar; if (f.search_find_defer) return NULL; @@ -968,7 +968,7 @@ and the second is empty. */ if (!yield && starflags & (SEARCH_STAR|SEARCH_STARAT)) { - DEBUG(D_lookup) debug_printf_indent("trying to match *\n"); + DEBUG(lookup) debug_printf_indent("trying to match *\n"); yield = internal_search_find(handle, filename, US"*", cache, opts); if (yield && expand_setup && *expand_setup >= 0) { @@ -1008,7 +1008,7 @@ it have been validated by the lookup. */ if (yield && ret_key) { yield = string_copy_taint(keystring, GET_UNTAINTED); - DEBUG(D_lookup) + DEBUG(lookup) debug_printf_indent("lookup yield replace by key: %s\n", yield); } diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index bdbe61d56..e2f23263c 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -807,7 +807,7 @@ for(;;) smtp_printf("250 %u byte chunk received\r\n", SP_NO_MORE, chunking_datasize); chunking_state = CHUNKING_OFFERED; - DEBUG(D_receive) + DEBUG(receive) debug_printf("chunking state '%s'\n", chunking_states[chunking_state]); /* Expect another BDAT cmd from input. RFC 3030 says nothing about @@ -860,7 +860,7 @@ next_cmd: chunking_state = strcmpic(smtp_cmd_data+n, US"LAST") == 0 ? CHUNKING_LAST : CHUNKING_ACTIVE; chunking_data_left = chunking_datasize; - DEBUG(D_receive) debug_printf("chunking state '%s', %d bytes\n", + DEBUG(receive) debug_printf("chunking state '%s', %d bytes\n", chunking_states[chunking_state], chunking_data_left); if (chunking_datasize == 0) @@ -916,7 +916,7 @@ while (chunking_data_left) bdat_pop_receive_functions(); chunking_state = CHUNKING_OFFERED; -DEBUG(D_receive) +DEBUG(receive) debug_printf("chunking state '%s'\n", chunking_states[chunking_state]); } @@ -935,9 +935,7 @@ if (!lwr_receive_getc) lwr_receive_ungetc = receive_ungetc; } else - { - DEBUG(D_receive) debug_printf("chunking double-push receive functions\n"); - } + DEBUG(receive) debug_printf("chunking double-push receive functions\n"); receive_getc = bdat_getc; receive_getbuf = bdat_getbuf; @@ -950,7 +948,7 @@ bdat_pop_receive_functions(void) { if (!lwr_receive_getc) { - DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n"); + DEBUG(receive) debug_printf("chunking double-pop receive functions\n"); return; } receive_getc = lwr_receive_getc; @@ -1028,7 +1026,7 @@ that we'll never expand it. */ yield = !! string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap); string_from_gstring(&gs); -DEBUG(D_receive) for (const uschar * t, * s = gs.s; +DEBUG(receive) for (const uschar * t, * s = gs.s; s && (t = Ustrchr(s, '\r')); s = t + 2) /* \r\n */ debug_printf("%s %.*s\n", @@ -1133,7 +1131,7 @@ smtp_fflush(BOOL uncork) { if (smtp_out_fd <= 0) return 0; -DEBUG(D_receive) debug_printf("SMTP>- %Vflush%V\n", "<", ">"); +DEBUG(receive) debug_printf("SMTP>- %Vflush%V\n", "<", ">"); #ifndef DISABLE_TLS if (tls_in.active.sock >= 0) @@ -1272,7 +1270,7 @@ while ((c = (receive_getc)(buffer_lim)) != '\n') { os_non_restarting_signal(SIGALRM, sigalrm_handler); /* c could be EOF, ERR, or a good (positive) value overflowing the buffer */ - DEBUG(D_receive) + DEBUG(receive) if (c < 0) debug_printf("SMTP(%s)<<\n", c == EOF ? "closed" : "error"); else @@ -1298,7 +1296,7 @@ string. */ while (ptr > 0 && isspace(smtp_cmd_buffer[ptr-1])) ptr--; smtp_cmd_buffer[ptr] = 0; -DEBUG(D_receive) debug_printf("SMTP<< %s\n", smtp_cmd_buffer); +DEBUG(receive) debug_printf("SMTP<< %s\n", smtp_cmd_buffer); /* NULLs are not allowed in SMTP commands */ @@ -1988,7 +1986,7 @@ while (done <= 0) { /* deconst ok as sender_address was not const */ sender_address = US rewrite_address_qualify(sender_address, FALSE); - DEBUG(D_receive) debug_printf("unqualified address %s accepted " + DEBUG(receive) debug_printf("unqualified address %s accepted " "and rewritten\n", raw_sender); } /* The function moan_smtp_batch() does not return. */ @@ -2045,7 +2043,7 @@ while (done <= 0) if (!recipient_domain) if (f.allow_unqualified_recipient) { - DEBUG(D_receive) debug_printf("unqualified address %s accepted\n", + DEBUG(receive) debug_printf("unqualified address %s accepted\n", recipient); /* deconst ok as recipient was not const */ recipient = US rewrite_address_qualify(recipient, TRUE); @@ -2158,12 +2156,12 @@ if (getsockopt(smtp_out_fd, IPPROTO_TCP, TCP_FASTOPEN, &is_fastopen, &len) == 0) { if (is_fastopen) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("TFO mode connection (TCP_FASTOPEN getsockopt)\n"); f.tcp_in_fastopen = TRUE; } } -else DEBUG(D_receive) +else DEBUG(receive) debug_printf("TCP_FASTOPEN getsockopt: %s\n", strerror(errno)); # elif defined(TCP_INFO) @@ -2175,14 +2173,14 @@ if (getsockopt(smtp_out_fd, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0) # ifdef TCPI_OPT_SYN_DATA /* FreeBSD 11,12 do not seem to have this yet */ if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("TFO mode connection (ACKd data-on-SYN)\n"); f.tcp_in_fastopen_data = f.tcp_in_fastopen = TRUE; } # ifdef TCPI_OPT_TFO_CHILD else if (tinfo.tcpi_options & TCPI_OPT_TFO_CHILD) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("TFO mode connection (SYN with TFO option)\n"); f.tcp_in_fastopen = TRUE; } @@ -2198,12 +2196,12 @@ if (getsockopt(smtp_out_fd, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0) if (tinfo.tcpi_state == TCP_SYN_RECV) /* Not seen on FreeBSD 12.1 */ { - DEBUG(D_receive) + DEBUG(receive) debug_printf("TFO mode connection (state TCP_SYN_RECV)\n"); f.tcp_in_fastopen = TRUE; } } -else DEBUG(D_receive) +else DEBUG(receive) debug_printf("TCP_INFO getsockopt: %s\n", strerror(errno)); # endif /* TCP_INFO */ } @@ -2271,7 +2269,7 @@ int optcount, sprint_len; struct in_addr addr; uschar * optstart = US OPTSTART; -DEBUG(D_receive) debug_printf("IP options exist\n"); +DEBUG(receive) debug_printf("IP options exist\n"); p = Ustpcpy(big_buffer, "IP options on incoming call:"); @@ -2550,7 +2548,7 @@ if (!f.sender_host_unknown) of writing. So for that error, carry on - we just can't do an IP options check. */ - DEBUG(D_receive) debug_printf("checking for IP options\n"); + DEBUG(receive) debug_printf("checking for IP options\n"); if ( smtp_out_fd < 0 || getsockopt(smtp_out_fd, IPPROTO_IP, IP_OPTIONS, US ipopt, @@ -2575,7 +2573,7 @@ if (!f.sender_host_unknown) /* Length of options = 0 => there are no options */ - else DEBUG(D_receive) debug_printf("no IP options found\n"); + else DEBUG(receive) debug_printf("no IP options found\n"); } #endif /* HAVE_IPV6 && !defined(NO_IP_OPTIONS) */ @@ -2960,7 +2958,7 @@ if (code > 0) { smtp_notquit_exit(US"bad-command-synprot", string_sprintf("%d", code), US"Too many syntax or protocol errors"); - DEBUG(D_any) debug_printf_indent("SMTP(close)>>\n"); + DEBUG(any) debug_printf_indent("SMTP(close)>>\n"); #ifndef DISABLE_TLS tls_close(NULL, TLS_SHUTDOWN_WAIT); #endif @@ -3324,7 +3322,7 @@ the Linux socket(7) manpage, SO_LINGER para, to the effect that exit() without close() results in the socket always lingering). */ (void) poll_one_fd(smtp_in_fd, POLLIN, 200); -DEBUG(D_any) debug_printf_indent("SMTP(close)>>\n"); +DEBUG(any) debug_printf_indent("SMTP(close)>>\n"); smtp_inout_close(); return 2; @@ -3438,19 +3436,19 @@ smtp_verify_helo(void) { BOOL yield = TRUE; -HDEBUG(D_receive) debug_printf("verifying EHLO/HELO argument %q\n", +HDEBUG(receive) debug_printf("verifying EHLO/HELO argument %q\n", sender_helo_name); if (sender_helo_name == NULL) { - HDEBUG(D_receive) debug_printf("no EHLO/HELO command was issued\n"); + HDEBUG(receive) debug_printf("no EHLO/HELO command was issued\n"); } /* Deal with the case of -bs without an IP address */ else if (sender_host_address == NULL) { - HDEBUG(D_receive) debug_printf("no client IP address: assume success\n"); + HDEBUG(receive) debug_printf("no client IP address: assume success\n"); f.helo_verified = TRUE; } @@ -3470,7 +3468,7 @@ else if (sender_helo_name[0] == '[') } #endif - HDEBUG(D_receive) + HDEBUG(receive) { if (f.helo_verified) debug_printf("matched host address\n"); } } @@ -3489,7 +3487,7 @@ else if ((f.helo_verified = strcmpic(sender_host_name, sender_helo_name) == 0)) { sender_helo_dnssec = sender_host_dnssec; - HDEBUG(D_receive) debug_printf("matched host name\n"); + HDEBUG(receive) debug_printf("matched host name\n"); } else { @@ -3501,7 +3499,7 @@ else break; } - HDEBUG(D_receive) if (f.helo_verified) + HDEBUG(receive) if (f.helo_verified) debug_printf("matched alias %s\n", *(--aliases)); } @@ -3515,7 +3513,7 @@ else dnssec_domains d = {.request = US"*", .require = US""}; - HDEBUG(D_receive) debug_printf("getting IP address for %s\n", + HDEBUG(receive) debug_printf("getting IP address for %s\n", sender_helo_name); rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A | HOST_FIND_BY_AAAA, NULL, NULL, NULL, &d, NULL, NULL); @@ -3525,7 +3523,7 @@ else { f.helo_verified = TRUE; if (h.dnssec_used == DS_YES) sender_helo_dnssec = TRUE; - HDEBUG(D_receive) + HDEBUG(receive) debug_printf("IP address for %s matches calling address\n" "Forward DNS security status: %sverified\n", sender_helo_name, sender_helo_dnssec ? "" : "un"); @@ -3697,7 +3695,7 @@ qualify_recipient(uschar ** recipient, uschar * smtp_cmd_data, uschar * tag) if (f.allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0) { int rd = Ustrlen(recipient) + 1; - DEBUG(D_receive) debug_printf("unqualified address %s accepted\n", + DEBUG(receive) debug_printf("unqualified address %s accepted\n", *recipient); /* deconst ok as *recipient was not const */ *recipient = US rewrite_address_qualify(*recipient, TRUE); @@ -3908,7 +3906,7 @@ else if (host_checking) { - HDEBUG(D_any) + HDEBUG(any) { debug_printf("ETRN command is: %s\n", etrn_command); debug_printf("ETRN command execution skipped\n"); @@ -3952,7 +3950,7 @@ if ((pid = exim_fork(US"etrn-command")) == 0) if ( !smtp_etrn_serialize || (pid = exim_fork(US"etrn-serialised-command")) == 0) { - DEBUG(D_exec) debug_print_argv(argv); + DEBUG(exec) debug_print_argv(argv); exim_nullstd(); /* Ensure std{in,out,err} exist */ /* argv[0] should be untainted, from child_exec_exim() */ execv(CS argv[0], (char *const *)argv); @@ -3972,10 +3970,10 @@ if ((pid = exim_fork(US"etrn-command")) == 0) else { int status; - DEBUG(D_any) + DEBUG(any) debug_printf("waiting for serialized ETRN process " PID_T_FMT "\n", pid); (void)wait(&status); - DEBUG(D_any) + DEBUG(any) debug_printf("serialized ETRN process " PID_T_FMT " ended\n", pid); } @@ -4040,7 +4038,7 @@ static misc_module_info * xclient_mi = NULL; #endif rmark reset_point = store_mark(); -DEBUG(D_receive) debug_printf("smtp_setup_msg entered\n"); +DEBUG(receive) debug_printf("smtp_setup_msg entered\n"); /* Reset for start of new message. We allow one RSET not to be counted as a nonmail command, for those MTAs that insist on sending it between every @@ -4064,7 +4062,7 @@ if (lwr_receive_getc && !atrn_mode) { /* This should have already happened, but if we've gotten confused, force a reset here. */ - DEBUG(D_receive) debug_printf("WARNING: smtp_setup_msg had to restore receive functions to lowers\n"); + DEBUG(receive) debug_printf("WARNING: smtp_setup_msg had to restore receive functions to lowers\n"); bdat_pop_receive_functions(); } @@ -4121,10 +4119,10 @@ while (done <= 0) smtp_cmd_data = NULL; if (smtp_in_auth(au, &s, &dummy_errmsg) == OK) - { DEBUG(D_auth) debug_printf("tls auth succeeded\n"); } + { DEBUG(auth) debug_printf("tls auth succeeded\n"); } else { - DEBUG(D_auth) debug_printf("tls auth not succeeded\n"); + DEBUG(auth) debug_printf("tls auth not succeeded\n"); #ifndef DISABLE_EVENT { uschar * save_name = sender_host_authenticated, * logmsg; @@ -4371,7 +4369,7 @@ while (done <= 0) f.helo_verified = old_helo_verified; break; /* End of HELO/EHLO processing */ } - HDEBUG(D_all) debug_printf("%s verification failed but host is in " + HDEBUG(all) debug_printf("%s verification failed but host is in " "helo_try_verify_hosts\n", hello); } } @@ -4384,7 +4382,7 @@ while (done <= 0) if (misc_mod_conn_init(sender_helo_name, sender_host_address, &errstr) != OK) { - DEBUG(D_receive) + DEBUG(receive) debug_printf("A module conn-init routine failed: %s\n", errstr); done = 1; break; @@ -4601,7 +4599,7 @@ while (done <= 0) au->advertised = FALSE; if (au->server) { - DEBUG(D_auth+D_expand) debug_printf_indent( + DEBUG(auth|expand) debug_printf_indent( "Evaluating advertise_condition for %s %s authenticator\n", au->drinst.name, au->public_name); if ( !au->advertise_condition @@ -4881,7 +4879,7 @@ while (done <= 0) US"invalid data for BODY"); goto COMMAND_LOOP; } - DEBUG(D_receive) debug_printf("8BITMIME: %d\n", body_8bitmime); + DEBUG(receive) debug_printf("8BITMIME: %d\n", body_8bitmime); break; } arg_error = TRUE; @@ -4905,7 +4903,7 @@ while (done <= 0) : strcmpic(value, US"FULL") == 0 ? dsn_ret_full : 0; - DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret); + DEBUG(receive) debug_printf("DSN_RET: %d\n", dsn_ret); /* Check for invalid invalid value, and exit with error */ if (dsn_ret == 0) { @@ -4926,7 +4924,7 @@ while (done <= 0) goto COMMAND_LOOP; } dsn_envid = string_copy(value); - DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid); + DEBUG(receive) debug_printf("DSN_ENVID: %s\n", dsn_envid); } break; @@ -5016,7 +5014,7 @@ while (done <= 0) goto COMMAND_LOOP; } - DEBUG(D_receive) debug_printf("smtputf8 requested\n"); + DEBUG(receive) debug_printf("smtputf8 requested\n"); message_smtputf8 = allow_utf8_domains = TRUE; if (Ustrncmp(received_protocol, US"utf8", 4) != 0) { @@ -5051,7 +5049,7 @@ while (done <= 0) if (smtp_mailcmd_count > smtp_rlm_threshold && verify_check_host(&smtp_ratelimit_hosts) == OK) { - DEBUG(D_receive) debug_printf("rate limit MAIL: delay %.3g sec\n", + DEBUG(receive) debug_printf("rate limit MAIL: delay %.3g sec\n", smtp_delay_mail/1000.0); millisleep((int)smtp_delay_mail); smtp_delay_mail *= smtp_rlm_factor; @@ -5128,7 +5126,7 @@ while (done <= 0) sender_domain = Ustrlen(sender_address) + 1; /* deconst ok as sender_address was not const */ sender_address = US rewrite_address_qualify(sender_address, FALSE); - DEBUG(D_receive) debug_printf("unqualified address %s accepted\n", + DEBUG(receive) debug_printf("unqualified address %s accepted\n", raw_sender); } else @@ -5258,7 +5256,7 @@ while (done <= 0) goto COMMAND_LOOP; } rcpt_orcpt = string_copy(value); - DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", rcpt_orcpt); + DEBUG(receive) debug_printf("DSN orcpt: %s\n", rcpt_orcpt); } else if (fl.dsn_advertised && strcmpic(name, US"NOTIFY") == 0) @@ -5282,17 +5280,17 @@ while (done <= 0) if (*pp == ',') *pp++ = 0; if (strcmpic(p, US"SUCCESS") == 0) { - DEBUG(D_receive) debug_printf("DSN: Setting notify success\n"); + DEBUG(receive) debug_printf("DSN: Setting notify success\n"); rcpt_dsn_flags |= rf_notify_success; } else if (strcmpic(p, US"FAILURE") == 0) { - DEBUG(D_receive) debug_printf("DSN: Setting notify failure\n"); + DEBUG(receive) debug_printf("DSN: Setting notify failure\n"); rcpt_dsn_flags |= rf_notify_failure; } else if (strcmpic(p, US"DELAY") == 0) { - DEBUG(D_receive) debug_printf("DSN: Setting notify delay\n"); + DEBUG(receive) debug_printf("DSN: Setting notify delay\n"); rcpt_dsn_flags |= rf_notify_delay; } else @@ -5304,7 +5302,7 @@ while (done <= 0) } p = pp; } - DEBUG(D_receive) debug_printf("DSN Flags: %x\n", rcpt_dsn_flags); + DEBUG(receive) debug_printf("DSN Flags: %x\n", rcpt_dsn_flags); } } @@ -5313,7 +5311,7 @@ while (done <= 0) else { - DEBUG(D_receive) debug_printf("Invalid RCPT option: %s : %s\n", name, value); + DEBUG(receive) debug_printf("Invalid RCPT option: %s : %s\n", name, value); name[-1] = ' '; value[-1] = '='; break; @@ -5389,7 +5387,7 @@ while (done <= 0) if (rcpt_count > smtp_rlr_threshold && verify_check_host(&smtp_ratelimit_hosts) == OK) { - DEBUG(D_receive) debug_printf("rate limit RCPT: delay %.3g sec\n", + DEBUG(receive) debug_printf("rate limit RCPT: delay %.3g sec\n", smtp_delay_rcpt/1000.0); millisleep((int)smtp_delay_rcpt); smtp_delay_rcpt *= smtp_rlr_factor; @@ -5429,7 +5427,7 @@ while (done <= 0) recipients_list[recipients_count-1].orcpt = rcpt_orcpt; recipients_list[recipients_count-1].dsn_flags = rcpt_dsn_flags; - /* DEBUG(D_receive) debug_printf("DSN: orcpt: %s flags: %d\n", + /* DEBUG(receive) debug_printf("DSN: orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags); */ } @@ -5504,7 +5502,7 @@ while (done <= 0) chunking_state = strcmpic(smtp_cmd_data+n, US"LAST") == 0 ? CHUNKING_LAST : CHUNKING_ACTIVE; chunking_data_left = chunking_datasize; - DEBUG(D_receive) debug_printf("chunking state '%s', %d bytes\n", + DEBUG(receive) debug_printf("chunking state '%s', %d bytes\n", chunking_states[chunking_state], chunking_data_left); f.bdat_readers_wanted = TRUE; /* FIXME: redundant vs chunking_state? */ @@ -5733,7 +5731,7 @@ while (done <= 0) if (receive_hasc()) { - DEBUG(D_any) + DEBUG(any) debug_printf("Non-empty input buffer after STARTTLS; naive attack?\n"); if (tls_in.active.sock < 0) smtp_inend = smtp_inptr = smtp_inbuffer; @@ -5786,7 +5784,7 @@ while (done <= 0) sender_host_auth_pubname = sender_host_authenticated = NULL; authenticated_id = NULL; sync_cmd_limit = NON_SYNC_CMD_NON_PIPELINING; - DEBUG(D_tls) debug_printf("TLS active\n"); + DEBUG(tls) debug_printf("TLS active\n"); break; /* Successful STARTTLS */ } else @@ -5807,7 +5805,7 @@ while (done <= 0) failure - and there may some encrypted data still in the pipe to us, which we see as garbage commands. */ - DEBUG(D_tls) debug_printf("TLS failed to start\n"); + DEBUG(tls) debug_printf("TLS failed to start\n"); while (done <= 0) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED)) { case EOF_CMD: diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 2712ee0ce..146b97e3e 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -180,7 +180,7 @@ if (done_once) return; && tinfo.__tcpi_unacked > 0 ) { - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.__tcpi_unacked); tcp_out_fastopen = TFO_USED_NODATA; } @@ -227,7 +227,7 @@ if (done_once) return; && tinfo.tcpi_unacked > 1 ) { - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked); tcp_out_fastopen = TFO_USED_NODATA; } @@ -248,12 +248,12 @@ if (done_once) return; { if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA) { - DEBUG(D_transport|D_v) debug_printf("TFO: data was acked\n"); + DEBUG(transport|v) debug_printf("TFO: data was acked\n"); tcp_out_fastopen = TFO_USED_DATA; } else { - DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n"); + DEBUG(transport|v) debug_printf("TFO: had to retransmit\n"); tcp_out_fastopen = TFO_NOT_USED; } done_once = TRUE; @@ -284,7 +284,7 @@ if ((sock = ip_socket(SOCK_STREAM, sc->host_af)) < 0) /* Set TCP_NODELAY; Exim does its own buffering. */ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent("failed to set NODELAY: %s ", strerror(errno)); #ifdef SUPPORT_DSCP @@ -316,7 +316,7 @@ if (sc->interface) || getsockname(sock, (struct sockaddr *) &interface_sock, &size) < 0 ) { - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent("unable to bind outgoing SMTP call to %s: %s\n", sc->interface, strerror(errno)); close(sock); @@ -380,7 +380,7 @@ if (!save_errno) # ifdef TCP_FASTOPEN_CONNECT else { /* expecting client data */ - DEBUG(D_transport|D_acl|D_v) debug_printf(" set up lazy-connect\n"); + DEBUG(transport|acl|v) debug_printf(" set up lazy-connect\n"); setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, US &on, sizeof(on)); /* fastopen_blob = NULL; lazy TFO, triggered by data write */ tcp_out_fastopen = TFO_ATTEMPTED_DATA; @@ -395,7 +395,7 @@ if (!save_errno) else if (early_data && !fastopen_blob && early_data->data && early_data->len) { /* We had some early-data to send, but couldn't do TFO */ - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len); #ifdef TCP_QUICKACK_notdef @@ -420,7 +420,7 @@ if (!save_errno) /* Both bind() and connect() succeeded, and any early-data */ - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n"); + HDEBUG(transport|acl|v) debug_printf_indent("connected\n"); if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0) sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port); else @@ -440,7 +440,7 @@ if (!save_errno) /* Either bind() or connect() failed */ -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) { debug_printf_indent(" sock_connect failed: %s", CUstrerror(save_errno)); if (save_errno == ETIMEDOUT) @@ -462,7 +462,7 @@ smtp_port_for_connect(host_item * host, int tpt_port) if (host->port == PORT_NONE) host->port = tpt_port; /* Set the port actually used */ -else HDEBUG(D_transport|D_acl|D_v) if (tpt_port != host->port) +else HDEBUG(transport|acl|v) if (tpt_port != host->port) debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", tpt_port, host->port); } @@ -494,7 +494,7 @@ smtp_transport_options_block * ob = sc->ob; callout_address = string_sprintf("[%s]:%d", sc->host->address, sc->host->port); -HDEBUG(D_transport|D_acl|D_v) +HDEBUG(transport|acl|v) { gstring * g = sc->interface ? string_fmt_append(NULL, " from %s", sc->interface) @@ -554,7 +554,7 @@ BOOL more = mode == SCMD_MORE; client_conn_ctx * cctx; const uschar * where; -HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, +HDEBUG(transport|acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, more ? " (more expected)" : ""); if (!(cctx = outblock->cctx)) @@ -614,7 +614,7 @@ else if (rc <= 0) { - HDEBUG(D_transport|D_acl) debug_printf_indent("%s (fd %d) failed: %s\n", + HDEBUG(transport|acl) debug_printf_indent("%s (fd %d) failed: %s\n", where, cctx->sock, strerror(errno)); return FALSE; } @@ -783,7 +783,7 @@ for (;;) if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timelimit)) <= 0) { - DEBUG(D_deliver|D_transport|D_acl|D_v) + DEBUG(deliver|transport|acl|v) debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n", strerror(errno)); break; @@ -794,7 +794,7 @@ for (;;) ptrend = inblock->ptrend = inblock->buffer + rc; ptr = inblock->buffer; - DEBUG(D_transport|D_acl) debug_printf_indent("read response data: size=%d\n", rc); + DEBUG(transport|acl) debug_printf_indent("read response data: size=%d\n", rc); } /* Get here if there has been some kind of recv() error; errno is set, but we @@ -851,7 +851,7 @@ if (sx->pending_BANNER || sx->pending_EHLO) int rc; if ((rc = smtp_reap_early_pipe(sx, &count)) != OK) { - DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n"); + DEBUG(transport) debug_printf("failed reaping pipelined cmd responsess\n"); if (rc == DEFER) errno = ERRNO_TLSFAILURE; goto out; } @@ -866,7 +866,7 @@ for (;;) if ((count = read_response_line(&sx->inblock, ptr, size, timelimit)) < 0) return FALSE; - HDEBUG(D_transport|D_acl|D_v) + HDEBUG(transport|acl|v) debug_printf_indent(" %s %s\n", ptr == buffer ? "SMTP<<" : " ", ptr); /* Check the format of the response: it must start with three digits; if diff --git a/src/src/spam.c b/src/src/spam.c index b8e6bebfb..7f5f0ba42 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -222,7 +222,7 @@ else if (!(spamd_address_work = expand_string(spamd_address))) return DEFER; } -DEBUG(D_acl) debug_printf_indent("spamd: addrlist '%s'\n", spamd_address_work); +DEBUG(acl) debug_printf_indent("spamd: addrlist '%s'\n", spamd_address_work); /* check if previous spamd_address was expanded and has changed. dump cached results if so */ if ( spam_ok @@ -263,7 +263,7 @@ start = time(NULL); unsigned args; uschar * s; - DEBUG(D_acl) debug_printf_indent("spamd: addr entry '%s'\n", address); + DEBUG(acl) debug_printf_indent("spamd: addr entry '%s'\n", address); sd = store_get(sizeof(spamd_address_container), GET_UNTAINTED); for (sublist = address, args = 0, spamd_param_init(sd); @@ -271,7 +271,7 @@ start = time(NULL); args++ ) { - DEBUG(D_acl) debug_printf_indent("spamd: addr parm '%s'\n", s); + DEBUG(acl) debug_printf_indent("spamd: addr parm '%s'\n", s); switch (args) { case 0: sd->hostspec = s; @@ -310,7 +310,7 @@ start = time(NULL); { uschar * errstr; - DEBUG(D_acl) debug_printf_indent("spamd: trying server %s\n", sd->hostspec); + DEBUG(acl) debug_printf_indent("spamd: trying server %s\n", sd->hostspec); for (;;) { @@ -319,7 +319,7 @@ start = time(NULL); || sd->retry == 0 ) break; - DEBUG(D_acl) debug_printf_indent("spamd: server %s: retry conn\n", sd->hostspec); + DEBUG(acl) debug_printf_indent("spamd: server %s: retry conn\n", sd->hostspec); while (sd->retry > 0) sd->retry = sleep(sd->retry); } if (spamd_cctx.sock >= 0) diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 8937496c0..fca9e129b 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -56,7 +56,7 @@ for (int i = 0; i < 2; i++) set_subdir_str(message_subdir, id, i); fname = spool_fname(US"input", message_subdir, id, US"-D"); - DEBUG(D_deliver) debug_printf_indent("Trying spool file %s\n", fname); + DEBUG(deliver) debug_printf_indent("Trying spool file %s\n", fname); /* We protect against symlink attacks both in not propagating the file-descriptor to other processes as we exec, and also ensuring that we @@ -75,7 +75,7 @@ for (int i = 0; i < 2; i++) *queue_name ? US" Q=" : US"", *queue_name ? queue_name : US"", id); - else DEBUG(D_deliver) + else DEBUG(deliver) debug_printf("Spool%s%s file %s-D not found\n", *queue_name ? US" Q=" : US"", *queue_name ? queue_name : US"", @@ -400,7 +400,7 @@ for (int i = 0; i < 2; i++) errno = 0; #ifndef COMPILE_UTILITY -DEBUG(D_deliver) debug_printf_indent("reading spool file %s\n", fname); +DEBUG(deliver) debug_printf_indent("reading spool file %s\n", fname); #endif /* COMPILE_UTILITY */ /* The first line of a spool file contains the message id followed by -H (i.e. @@ -478,7 +478,7 @@ if (f.running_in_test_harness) #endif #ifndef COMPILE_UTILITY -DEBUG(D_deliver) debug_printf_indent("user=%s uid=%ld gid=%ld sender=%s\n", +DEBUG(deliver) debug_printf_indent("user=%s uid=%ld gid=%ld sender=%s\n", originator_login, (long int)originator_uid, (long int)originator_gid, sender_address); #endif @@ -521,7 +521,7 @@ for (;;) const lookup_info * li; if (!(li= search_findtype(var, s - var))) { - DEBUG(D_any) + DEBUG(any) debug_printf("Unrecognised quoter %.*s\n", (int)(s - var), var+1); where = NULL; goto SPOOL_FORMAT_ERROR; @@ -620,7 +620,13 @@ for (;;) dsn_envid = string_copy_taint(var + 10, proto_mem); #ifndef COMPILE_UTILITY else if (Ustrncmp(p, "ebug_selector ", 14) == 0) - sscanf(CS var + 15, SC_EXIM_BITMASK, &debug_selector); + { + const uschar * s = var + 15; + int n; + sscanf(CS s, SC_EXIM_BITMASK "%n", &debug_selector[0], &n); + for (int i = 1; i < DEBUG_SELECTOR_SIZE && *(s += n) == ','; i++) + sscanf(CS ++s, SC_EXIM_BITMASK "%n", &debug_selector[i], &n); + } else if (Ustrncmp(p, "ebuglog_name ", 13) == 0) debug_logging_from_spool(var + 14); #endif @@ -792,7 +798,7 @@ host_build_sender_fullhost(); #endif /* COMPILE_UTILITY */ #ifndef COMPILE_UTILITY -DEBUG(D_deliver) +DEBUG(deliver) debug_printf_indent("sender_local=%d ident=%s\n", f.sender_local, sender_ident ? sender_ident : US"unset"); #endif /* COMPILE_UTILITY */ @@ -806,7 +812,7 @@ if (Ustrncmp(big_buffer, "XX\n", 3) != 0 && goto SPOOL_FORMAT_ERROR; #ifndef COMPILE_UTILITY -DEBUG(D_deliver) debug_print_tree("Non-recipients", tree_nonrecipients); +DEBUG(deliver) debug_print_tree("Non-recipients", tree_nonrecipients); #endif /* COMPILE_UTILITY */ /* After reading the tree, the next line has not yet been read into the @@ -819,7 +825,7 @@ if (sscanf(CS big_buffer, "%d", &rcount) != 1 || rcount > 16384) goto SPOOL_FORMAT_ERROR; #ifndef COMPILE_UTILITY -DEBUG(D_deliver) debug_printf_indent("recipients_count=%d\n", rcount); +DEBUG(deliver) debug_printf_indent("recipients_count=%d\n", rcount); #endif /* COMPILE_UTILITY */ recipients_list_max = rcount; @@ -891,7 +897,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) { int dummy; #if !defined (COMPILE_UTILITY) - DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - Exim 3 spool file\n"); + DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - Exim 3 spool file\n"); #endif while (isdigit(*(--p)) || *p == ','); if (*p == ' ') @@ -906,7 +912,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) else if (*p == ' ') { #if !defined (COMPILE_UTILITY) - DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - early Exim 4 spool file\n"); + DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - early Exim 4 spool file\n"); #endif *p++ = 0; (void)sscanf(CS p, "%d", &pno); @@ -919,7 +925,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) int flags; #if !defined (COMPILE_UTILITY) - DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - Exim standard format spoolfile\n"); + DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - Exim standard format spoolfile\n"); #endif (void)sscanf(CS p+1, "%d", &flags); @@ -955,13 +961,13 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) } #if !defined(COMPILE_UTILITY) else - { DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - No additional fields\n"); } + { DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - No additional fields\n"); } if (orcpt || dsn_flags) - DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> orcpt: <%s> dsn_flags: 0x%x\n", + DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> orcpt: <%s> dsn_flags: 0x%x\n", big_buffer, orcpt, dsn_flags); if (errors_to) - DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> errorsto: <%s>\n", + DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> errorsto: <%s>\n", big_buffer, errors_to); #endif @@ -1034,7 +1040,7 @@ line count by adding the body linecount to the header linecount. Close the file and give a positive response. */ #ifndef COMPILE_UTILITY -DEBUG(D_deliver) debug_printf_indent("body_linecount=%d message_linecount=%d\n", +DEBUG(deliver) debug_printf_indent("body_linecount=%d message_linecount=%d\n", body_linecount, message_linecount); #endif /* COMPILE_UTILITY */ @@ -1054,7 +1060,7 @@ if (errno != 0) n = errno; #ifndef COMPILE_UTILITY - DEBUG(D_any) debug_printf("Error while reading spool file %s\n", fname); + DEBUG(any) debug_printf("Error while reading spool file %s\n", fname); #endif /* COMPILE_UTILITY */ fclose(fp); @@ -1065,7 +1071,7 @@ if (errno != 0) SPOOL_FORMAT_ERROR: #ifndef COMPILE_UTILITY -DEBUG(D_any) debug_printf("Format error in spool file %s%s%s\n", fname, +DEBUG(any) debug_printf("Format error in spool file %s%s%s\n", fname, where ? ": " : "", where ? where : US""); #else where = where; /* compiler quietening */ @@ -1094,7 +1100,7 @@ uschar * yield = NULL; if (!(fp = Ufopen(spool_fname(US"input", message_subdir, id, US"-H"), "rb"))) return NULL; -DEBUG(D_deliver) debug_printf_indent("reading spool file %s-H\n", id); +DEBUG(deliver) debug_printf_indent("reading spool file %s-H\n", id); /* Skip the line with the copy of the filename, then the line with login/uid/gid. Read the next line, which should be the envelope sender. diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 016f7cdd4..124c6fb1d 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -84,7 +84,7 @@ have the same pid. We therefore have one go at unlinking it before giving up. if (fd < 0 && errno == EEXIST) { - DEBUG(D_any) debug_printf("%s exists: unlinking\n", temp_name); + DEBUG(any) debug_printf("%s exists: unlinking\n", temp_name); Uunlink(temp_name); fd = Uopen(temp_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE); } @@ -96,7 +96,7 @@ automatically. */ if (fd >= 0) if (exim_fchown(fd, exim_uid, exim_gid, temp_name) || fchmod(fd, SPOOL_MODE)) { - DEBUG(D_any) debug_printf("failed setting perms on %s\n", temp_name); + DEBUG(any) debug_printf("failed setting perms on %s\n", temp_name); (void) close(fd); fd = -1; Uunlink(temp_name); } @@ -165,7 +165,7 @@ uschar * tname = spool_fname(US"input", message_subdir, US"hdr.", message_id); if ((fd = spool_open_temp(tname)) < 0) return spool_write_error(where, errmsg, US"open", NULL, NULL); fp = fdopen(fd, "wb"); -DEBUG(D_receive|D_deliver) debug_printf("Writing spool header file: %s\n", tname); +DEBUG(receive|deliver) debug_printf("Writing spool header file: %s\n", tname); /* We now have an open file to which the header data is to be written. Start with the file's leaf name, to make the file self-identifying. Continue with the @@ -232,8 +232,10 @@ tree_walk(acl_var_m, &acl_var_write, fp); if (*debuglog_name) { - fprintf(fp, "-debug_selector 0x" PR_EXIM_BITMASK "\n", debug_selector); - fprintf(fp, "-debuglog_name %s\n", debuglog_name); + fprintf(fp, "-debug_selector 0x" PR_EXIM_BITMASK, debug_selector[0]); + for (int i = 1; i < DEBUG_SELECTOR_SIZE; i++) + fprintf(fp, ",0x" PR_EXIM_BITMASK, debug_selector[i]); + fprintf(fp, "\n-debuglog_name %s\n", debuglog_name); } if (f.spool_file_wireformat) @@ -302,9 +304,9 @@ if (message_smtputf8) #endif /* Write the dsn flags to the spool header file */ -/* DEBUG(D_deliver) debug_printf("DSN: Write SPOOL: -dsn_envid %s\n", dsn_envid); */ +/* DEBUG(deliver) debug_printf("DSN: Write SPOOL: -dsn_envid %s\n", dsn_envid); */ if (dsn_envid) fprintf(fp, "-dsn_envid %s\n", dsn_envid); -/* DEBUG(D_deliver) debug_printf("DSN: Write SPOOL: -dsn_ret %d\n", dsn_ret); */ +/* DEBUG(deliver) debug_printf("DSN: Write SPOOL: -dsn_ret %d\n", dsn_ret); */ if (dsn_ret) fprintf(fp, "-dsn_ret %d\n", dsn_ret); /* To complete the envelope, write out the tree of non-recipients, followed by @@ -319,7 +321,7 @@ for (int i = 0; i < recipients_count; i++) recipient_item *r = recipients_list + i; const uschar *address = zap_newlines(r->address); - /* DEBUG(D_deliver) debug_printf("DSN: Flags: 0x%x\n", r->dsn_flags); */ + /* DEBUG(deliver) debug_printf("DSN: Flags: 0x%x\n", r->dsn_flags); */ if (r->pno < 0 && !r->errors_to && r->dsn_flags == 0) fprintf(fp, "%s\n", address); @@ -334,7 +336,7 @@ for (int i = 0; i < recipients_count; i++) r->dsn_flags, errors_to, Ustrlen(errors_to), r->pno); } - DEBUG(D_deliver) debug_printf("DSN: **** SPOOL_OUT - " + DEBUG(deliver) debug_printf("DSN: **** SPOOL_OUT - " "address: <%s> errorsto: <%s> orcpt: <%s> dsn_flags: 0x%x\n", r->address, r->errors_to, r->orcpt, r->dsn_flags); } @@ -389,7 +391,7 @@ if (fclose(fp) != 0) incarnation. */ fname = spool_fname(US"input", message_subdir, id, US"-H"); -DEBUG(D_receive|D_deliver) debug_printf("Renaming spool header file: %s\n", fname); +DEBUG(receive|deliver) debug_printf("Renaming spool header file: %s\n", fname); if (Urename(tname, fname) < 0) return spool_write_error(where, errmsg, US"rename", tname, NULL); @@ -426,7 +428,7 @@ if (close(fd) < 0) /* Return the number of characters in the headers, which is the file size, less the preliminary stuff, less the additional count fields on the headers. */ -DEBUG(D_receive) debug_printf("Size of headers = %d\n", +DEBUG(receive) debug_printf("Size of headers = %d\n", (int)(statbuf.st_size - size_correction)); return statbuf.st_size - size_correction; diff --git a/src/src/store.c b/src/src/store.c index 6478dc3e7..2268acbf9 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -388,7 +388,7 @@ store_writeprotect(int pool) #if !defined(COMPILE_UTILITY) && !defined(MISSING_POSIX_MEMALIGN) for (storeblock * b = paired_pools[pool].chainbase; b; b = b->next) if (mprotect(b, ALIGNED_SIZEOF_STOREBLOCK + b->length, PROT_READ) != 0) - DEBUG(D_any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno)); + DEBUG(any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno)); #endif } @@ -544,7 +544,7 @@ if (!quoter_name) giving warnings. */ #ifndef COMPILE_UTILITY - DEBUG(D_memory) + DEBUG(memory) debug_printf("---%d Get %6p %5d %-14s %4d\n", pool, pp->store_last_get, size, func, linenumber); #endif @@ -552,13 +552,13 @@ if (!quoter_name) #ifndef COMPILE_UTILITY else { - DEBUG(D_memory) + DEBUG(memory) debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber); if (!(pp = pool_for_quoter(quoter, NULL))) pp = quoted_pool_new(quoter, quoter_name); yield = pool_get(pp, size, FALSE, func, linenumber); - DEBUG(D_memory) + DEBUG(memory) debug_printf("---QQ Get %6p %5d %-14s %4d\n", pp->store_last_get, size, func, linenumber); } @@ -621,13 +621,13 @@ store_force_get_quoted(int size, unsigned quoter, const uschar * quoter_name, pooldesc * pp = pool_for_quoter(quoter, NULL); void * yield; -DEBUG(D_memory) +DEBUG(memory) debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber); if (!pp) pp = quoted_pool_new(quoter, quoter_name); yield = pool_get(pp, size, FALSE, func, linenumber); -DEBUG(D_memory) +DEBUG(memory) debug_printf("---QQ Get %6p %5d %-14s %4d\n", pp->store_last_get, size, func, linenumber); @@ -686,7 +686,7 @@ const void * p_qfn, * q_qfn; if (!p_name) { - DEBUG(D_any) debug_printf("No quoter name for addr\n"); + DEBUG(any) debug_printf("No quoter name for addr\n"); return FALSE; } @@ -782,7 +782,7 @@ if (CS ptr + rounded_oldsize != CS (pp->next_yield) || giving warnings. */ #ifndef COMPILE_UTILITY -DEBUG(D_memory) +DEBUG(memory) { quoted_pooldesc * qp; for (qp = quoted_pools; qp; qp = qp->next) @@ -940,7 +940,7 @@ while ((b = bb)) giving warnings. */ #ifndef COMPILE_UTILITY -DEBUG(D_memory) +DEBUG(memory) debug_printf("---%d Rst %6p %5d %-14s %4d\tpool %d\n", pool, ptr, count + oldmalloc - pool_malloc, func, linenumber, pool_malloc); @@ -1023,7 +1023,7 @@ if ((pp = pool_current_for_pointer(ptr))) giving warnings. */ #ifndef COMPILE_UTILITY - DEBUG(D_memory) + DEBUG(memory) { quoted_pooldesc * qp; for (qp = quoted_pools; qp; qp = qp->next) @@ -1040,7 +1040,7 @@ if ((pp = pool_current_for_pointer(ptr))) return; } #ifndef COMPILE_UTILITY -DEBUG(D_memory) +DEBUG(memory) debug_printf("non-last memory release try: %s %d\n", func, linenumber); #endif } @@ -1053,7 +1053,7 @@ store_mark_3(const char * func, int linenumber) void ** p; #ifndef COMPILE_UTILITY -DEBUG(D_memory) +DEBUG(memory) debug_printf("---%d Mrk %-14s %4d\tpool %d\n", store_pool, func, linenumber, pool_malloc); #endif /* COMPILE_UTILITY */ @@ -1111,7 +1111,7 @@ for (storeblock * b = pp->chainbase; b; b = b->next) from giving warnings. */ #ifndef COMPILE_UTILITY - DEBUG(D_memory) + DEBUG(memory) debug_printf("-Release %6p %-20s %4d %d\n", (void *)bb, func, linenumber, pool_malloc); @@ -1209,7 +1209,7 @@ if (!(yield = malloc(size))) "called from line %d in %s", size, line, func); #ifndef COMPILE_UTILITY -DEBUG(D_any) *(size_t *)yield = size; +DEBUG(any) *(size_t *)yield = size; #endif yield = US yield + sizeof(size_t); @@ -1225,7 +1225,7 @@ is not filled with zeros so as to catch problems. */ if (f.running_in_test_harness) memset(yield, 0xF0, size - sizeof(size_t)); -DEBUG(D_memory) debug_printf("--Malloc %6p %5lu bytes\t%-20s %4d\tpool %5d nonpool %5d\n", +DEBUG(memory) debug_printf("--Malloc %6p %5lu bytes\t%-20s %4d\tpool %5d nonpool %5d\n", yield, size, func, line, pool_malloc, nonpool_malloc); #endif /* COMPILE_UTILITY */ @@ -1260,8 +1260,8 @@ internal_store_free(void * block, const char * func, int linenumber) { uschar * p = US block - sizeof(size_t); #ifndef COMPILE_UTILITY -DEBUG(D_any) nonpool_malloc -= *(size_t *)p; -DEBUG(D_memory) debug_printf("----Free %6p %5ld bytes\t%-20s %4d\n", +DEBUG(any) nonpool_malloc -= *(size_t *)p; +DEBUG(memory) debug_printf("----Free %6p %5ld bytes\t%-20s %4d\n", block, *(size_t *)p, func, linenumber); #endif free(p); @@ -1303,7 +1303,7 @@ void store_exit(void) { #ifndef COMPILE_UTILITY -DEBUG(D_memory) +DEBUG(memory) { int i; debug_printf("----Exit nonpool max: %3d kB in %d blocks\n", diff --git a/src/src/string.c b/src/src/string.c index 90b9ec503..bb1bc6c02 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -954,7 +954,7 @@ if (sep <= 0) { if (!is_tainted(s)) sep = s[1]; - else DEBUG(D_any) + else DEBUG(any) debug_printf("attempt to use tainted change-of-seperator spec (%s %d)\n", config_filename, config_lineno); if (*++s) ++s; @@ -1683,7 +1683,7 @@ while (*fp) { gstring * zg = NULL; s = va_arg(ap, char *); - if (IS_DEBUG(D_noutf8)) + if (IS_DEBUG(noutf8)) for ( ; *s; s++) zg = string_catn(zg, CUS (*s == 'K' ? "|" : s), 1); else @@ -1709,7 +1709,7 @@ while (*fp) case 'W': /* Maybe mark up ctrls, spaces & newlines */ s = va_arg(ap, char *); - if (s && !IS_DEBUG(D_noutf8)) + if (s && !IS_DEBUG(noutf8)) { gstring * zg = NULL; int p = precision; diff --git a/src/src/structs.h b/src/src/structs.h index ba88f487b..833c16655 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -47,11 +47,11 @@ typedef struct macro_item { const uschar * replacement; } macro_item; -/* Structure for bit tables for debugging and logging */ +/* Structure for bit table for logging */ typedef struct bit_table { - uschar *name; - int bit; + uschar * name; + unsigned logchan_bit; } bit_table; /* Block for holding a uid and gid, possibly unset, and an initgroups flag. */ diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 04b439950..825ddb04f 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -461,7 +461,7 @@ return FALSE; static int tls_g_init(uschar ** errstr) { -DEBUG(D_tls) debug_printf("GnuTLS global init required\n"); +DEBUG(tls) debug_printf("GnuTLS global init required\n"); #if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL) /* By default, gnutls_global_init will init PKCS11 support in auto mode, @@ -487,7 +487,7 @@ if (!gnutls_allow_auto_pkcs11) #endif #if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0 -DEBUG(D_tls) +DEBUG(tls) { gnutls_global_set_log_function(exim_gnutls_logger_cb); /* arbitrarily chosen level; bump up to 9 for more */ @@ -569,11 +569,11 @@ uschar * errstr; if (errno == 0) if (rc == GNUTLS_E_INVALID_SESSION) { - DEBUG(D_tls) debug_printf("- INVALID_SESSION with zero errno\n"); + DEBUG(tls) debug_printf("- INVALID_SESSION with zero errno\n"); return; } else if (text) - DEBUG(D_tls) debug_printf("- zero errno; %s\n", text); + DEBUG(tls) debug_printf("- zero errno; %s\n", text); msg = rc == GNUTLS_E_FATAL_ALERT_RECEIVED ? string_sprintf("A TLS fatal alert has been received: %s", @@ -600,7 +600,7 @@ else if ( !tls_out.smtp_quit ) log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s", state->host->name, state->host->address, errstr); -else DEBUG(D_tls) +else DEBUG(tls) debug_printf("H=%s [%s] TLS error on connection %s\n", state->host->name, state->host->address, errstr); } @@ -613,7 +613,7 @@ tls_refill(unsigned lim) exim_gnutls_state_st * state = &state_server; ssize_t inbytes; -DEBUG(D_tls) debug_printf("Calling gnutls_record_recv" +DEBUG(tls) debug_printf("Calling gnutls_record_recv" "(session=%p, buffer=%p, buffersize=%u)\n", state->session, state->xfer_buffer, ssl_xfer_buffer_size); @@ -643,14 +643,14 @@ down. Revert to non-TLS handling. */ if (sigalrm_seen) { - DEBUG(D_tls) debug_printf("Got tls read timeout\n"); + DEBUG(tls) debug_printf("Got tls read timeout\n"); state->xfer_error = TRUE; return FALSE; } else if (inbytes == 0) { - DEBUG(D_tls) debug_printf("Got TLS_EOF\n"); + DEBUG(tls) debug_printf("Got TLS_EOF\n"); tls_close(NULL, TLS_NO_SHUTDOWN); return FALSE; } @@ -659,7 +659,7 @@ else if (inbytes == 0) else if (inbytes < 0) { - DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv\n", __FUNCTION__); + DEBUG(tls) debug_printf("%s: err from gnutls_record_recv\n", __FUNCTION__); record_io_error(state, (int) inbytes, US"recv", NULL); state->xfer_error = TRUE; return FALSE; @@ -682,7 +682,7 @@ return TRUE; { \ if (rc != GNUTLS_E_SUCCESS) \ { \ - DEBUG(D_tls) debug_printf("TLS: cert problem: %s: %s\n", \ + DEBUG(tls) debug_printf("TLS: cert problem: %s: %s\n", \ (Label), gnutls_strerror(rc)); \ return rc; \ } \ @@ -736,7 +736,7 @@ tls_support * tlsp = state->tlsp; tlsp->active.sock = state->fd_out; tlsp->active.tls_ctx = state; -DEBUG(D_tls) debug_printf("cipher: %s\n", state->ciphersuite); +DEBUG(tls) debug_printf("cipher: %s\n", state->ciphersuite); tlsp->certificate_verified = state->peer_cert_verified; #ifdef SUPPORT_DANE @@ -775,7 +775,7 @@ tlsp->channelbinding = NULL; rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &channel); if (rc) - { DEBUG(D_tls) debug_printf("extracting channel binding: %s\n", gnutls_strerror(rc)); } + { DEBUG(tls) debug_printf("extracting channel binding: %s\n", gnutls_strerror(rc)); } else { int old_pool = store_pool; @@ -786,7 +786,7 @@ tlsp->channelbinding = NULL; tlsp->channelbinding = b64encode_taint(CUS channel.data, (int)channel.size, !tlsp->channelbind_exporter && state->host ? GET_TAINTED : GET_UNTAINTED); store_pool = old_pool; - DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n"); + DEBUG(tls) debug_printf("Have channel bindings cached for possible auth usage\n"); } } #endif @@ -839,7 +839,7 @@ size_t sz; uschar * exp_tls_dhparam; BOOL use_file_in_spool = FALSE; -DEBUG(D_tls) debug_printf("Initialising GnuTLS server params\n"); +DEBUG(tls) debug_printf("Initialising GnuTLS server params\n"); if ((rc = gnutls_dh_params_init(&dh_server_params))) return tls_error_gnu(NULL, US"gnutls_dh_params_init", rc, errstr); @@ -852,7 +852,7 @@ if (!expand_check(tls_dhparam, US"tls_dhparam", &exp_tls_dhparam, errstr)) if (!exp_tls_dhparam) { - DEBUG(D_tls) debug_printf("Loading default hard-coded DH params\n"); + DEBUG(tls) debug_printf("Loading default hard-coded DH params\n"); m.data = US std_dh_prime_default(); m.size = Ustrlen(m.data); } @@ -860,7 +860,7 @@ else if (Ustrcmp(exp_tls_dhparam, "historic") == 0) use_file_in_spool = TRUE; else if (Ustrcmp(exp_tls_dhparam, "none") == 0) { - DEBUG(D_tls) debug_printf("Requested no DH parameters\n"); + DEBUG(tls) debug_printf("Requested no DH parameters\n"); return FAIL; } else if (exp_tls_dhparam[0] != '/') @@ -876,7 +876,7 @@ if (m.data) { if ((rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM))) return tls_error_gnu(NULL, US"gnutls_dh_params_import_pkcs3", rc, errstr); - DEBUG(D_tls) debug_printf("Loaded fixed standard D-H parameters\n"); + DEBUG(tls) debug_printf("Loaded fixed standard D-H parameters\n"); return OK; } @@ -886,12 +886,12 @@ different filename and ensure we have sufficient bits. */ if (!(dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL))) return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL, errstr); -DEBUG(D_tls) +DEBUG(tls) debug_printf("GnuTLS tells us that for D-H PK, NORMAL is %d bits\n", dh_bits); #else dh_bits = EXIM_SERVER_DH_BITS_PRE2_12; -DEBUG(D_tls) +DEBUG(tls) debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d bits\n", dh_bits); #endif @@ -899,7 +899,7 @@ DEBUG(D_tls) /* Some clients have hard-coded limits. */ if (dh_bits > tls_dh_max_bits) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("tls_dh_max_bits clamping override, using %d bits instead\n", tls_dh_max_bits); dh_bits = tls_dh_max_bits; @@ -960,7 +960,7 @@ if ((fd = Uopen(filename, O_RDONLY, 0)) >= 0) store_free(m.data); if (rc) return tls_error_gnu(NULL, US"gnutls_dh_params_import_pkcs3", rc, errstr); - DEBUG(D_tls) debug_printf("read D-H parameters from file %q\n", filename); + DEBUG(tls) debug_printf("read D-H parameters from file %q\n", filename); } /* If the file does not exist, fall through to compute new data and cache it. @@ -969,7 +969,7 @@ If there was any other opening error, it is serious. */ else if (errno == ENOENT) { rc = -1; - DEBUG(D_tls) + DEBUG(tls) debug_printf("D-H parameter cache file %q does not exist\n", filename); } else @@ -1007,12 +1007,12 @@ if (rc < 0) if (dh_bits >= EXIM_CLIENT_DH_MIN_BITS + 10) { dh_bits_gen = dh_bits - 10; - DEBUG(D_tls) + DEBUG(tls) debug_printf("being paranoid about DH generation, make it '%d' bits'\n", dh_bits_gen); } - DEBUG(D_tls) + DEBUG(tls) debug_printf("requesting generation of %d bit Diffie-Hellman prime ...\n", dh_bits_gen); if ((rc = gnutls_dh_params_generate2(dh_server_params, dh_bits_gen))) @@ -1060,10 +1060,10 @@ if (rc < 0) return tls_error_sys(string_sprintf("failed to rename %q as %q", temp_fn, filename), errno, NULL, errstr); - DEBUG(D_tls) debug_printf("wrote D-H parameters to file %q\n", filename); + DEBUG(tls) debug_printf("wrote D-H parameters to file %q\n", filename); } -DEBUG(D_tls) debug_printf("initialized server D-H parameters\n"); +DEBUG(tls) debug_printf("initialized server D-H parameters\n"); return OK; } @@ -1087,7 +1087,7 @@ rc = GNUTLS_E_NO_CERTIFICATE_FOUND; if (TRUE) goto err; #endif -DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n"); +DEBUG(tls) debug_printf("TLS: generating selfsigned server cert\n"); where = US"initialising pkey"; if ((rc = gnutls_x509_privkey_init(&pkey))) goto err; @@ -1180,11 +1180,11 @@ server_ocsp_stapling_cb(gnutls_session_t session, void * ptr, gnutls_datum_t * ocsp_response) { int ret; -DEBUG(D_tls) debug_printf("OCSP stapling callback: %s\n", US ptr); +DEBUG(tls) debug_printf("OCSP stapling callback: %s\n", US ptr); if ((ret = gnutls_load_file(ptr, ocsp_response)) < 0) { - DEBUG(D_tls) debug_printf("Failed to load ocsp stapling file %s\n", + DEBUG(tls) debug_printf("Failed to load ocsp stapling file %s\n", CS ptr); tls_in.ocsp = OCSP_NOT_RESP; return GNUTLS_E_NO_CERTIFICATE_STATUS; @@ -1207,7 +1207,7 @@ https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-valu switch (tls_id) { case 5: /* Status Request */ - DEBUG(D_tls) debug_printf("Seen status_request extension from client\n"); + DEBUG(tls) debug_printf("Seen status_request extension from client\n"); tls_in.ocsp = OCSP_NOT_RESP; break; #ifdef EXIM_HAVE_ALPN @@ -1221,18 +1221,18 @@ switch (tls_id) { gstring * g = NULL; - DEBUG(D_tls) debug_printf("Seen ALPN extension from client (s=%u):", size); + DEBUG(tls) debug_printf("Seen ALPN extension from client (s=%u):", size); for (const uschar * s = data+2; s-data < size-1; s += *s + 1) { server_seen_alpn++; g = string_append_listele_n(g, ':', s+1, *s); - DEBUG(D_tls) debug_printf(" '%.*s'", (int)*s, s+1); + DEBUG(tls) debug_printf(" '%.*s'", (int)*s, s+1); } - DEBUG(D_tls) debug_printf("\n"); + DEBUG(tls) debug_printf("\n"); if (server_seen_alpn > 1) { log_write(0, LOG_MAIN, "TLS ALPN (%Y) rejected", g); - DEBUG(D_tls) debug_printf("TLS: too many ALPNs presented in handshake\n"); + DEBUG(tls) debug_printf("TLS: too many ALPNs presented in handshake\n"); return GNUTLS_E_NO_APPLICATION_PROTOCOL; } break; @@ -1264,7 +1264,7 @@ tls_server_servercerts_ext(void * ctx, unsigned tls_id, /* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */ if (FALSE && tls_id == 5) /* status_request */ { - DEBUG(D_tls) debug_printf("Seen status_request extension\n"); + DEBUG(tls) debug_printf("Seen status_request extension\n"); tls_in.ocsp = exim_testharness_disable_ocsp_validity_check ? OCSP_VFY_NOT_TRIED : OCSP_VFIED; /* We know that GnuTLS verifies responses */ } @@ -1300,7 +1300,7 @@ static int tls_server_certstatus_cb(gnutls_session_t session, unsigned int htype, unsigned when, unsigned int incoming, const gnutls_datum_t * msg) { -DEBUG(D_tls) debug_printf("Sending certificate-status\n"); /*XXX we get this for tls1.2 but not for 1.3 */ +DEBUG(tls) debug_printf("Sending certificate-status\n"); /*XXX we get this for tls1.2 but not for 1.3 */ # ifdef SUPPORT_SRV_OCSP_STACK tls_in.ocsp = exim_testharness_disable_ocsp_validity_check ? OCSP_VFY_NOT_TRIED : OCSP_VFIED; /* We know that GnuTLS verifies responses */ @@ -1346,7 +1346,7 @@ extern char ** environ; if (environ) for (uschar ** p = USS environ; *p; p++) if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0) { - DEBUG(D_tls) debug_printf("Permitting known bad OCSP response\n"); + DEBUG(tls) debug_printf("Permitting known bad OCSP response\n"); exim_testharness_disable_ocsp_validity_check = TRUE; } } @@ -1374,7 +1374,7 @@ if (server && tls_ocsp_file) } # endif #endif -DEBUG(D_tls) +DEBUG(tls) debug_printf("TLS: basic cred init, %s\n", server ? "server" : "client"); } @@ -1408,7 +1408,7 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) else { int gnutls_cert_index = -rc; - DEBUG(D_tls) debug_printf("TLS: cert/key %d %s registered\n", + DEBUG(tls) debug_printf("TLS: cert/key %d %s registered\n", gnutls_cert_index, cfile); #ifndef DISABLE_OCSP @@ -1418,12 +1418,12 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) /* Set the OCSP stapling server info */ if (gnutls_buggy_ocsp) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("GnuTLS library is buggy for OCSP; avoiding\n"); } else if ((ofile = string_nextinlist(&olist, &osep, NULL, 0))) { - DEBUG(D_tls) debug_printf("OCSP response file %d = %s\n", + DEBUG(tls) debug_printf("OCSP response file %d = %s\n", gnutls_cert_index, ofile); # ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE if (Ustrncmp(ofile, US"PEM ", 4) == 0) @@ -1443,7 +1443,7 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) return tls_error_gnu(state, US"gnutls_certificate_set_ocsp_status_request_file2", rc, errstr); - DEBUG(D_tls) + DEBUG(tls) debug_printf(" %d response%s loaded\n", rc, rc>1 ? "s":""); /* Arrange callbacks for OCSP request observability */ @@ -1468,7 +1468,7 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) { if (ocsp_file_cnt++ > 0) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("oops; multiple OCSP files not supported\n"); break; } @@ -1478,7 +1478,7 @@ while (cfile = string_nextinlist(&clist, &csep, NULL, 0)) # endif /* SUPPORT_GNUTLS_EXT_RAW_PARSE */ } else - DEBUG(D_tls) debug_printf("ran out of OCSP response files in list\n"); + DEBUG(tls) debug_printf("ran out of OCSP response files in list\n"); } #endif /* DISABLE_OCSP */ } @@ -1491,7 +1491,7 @@ creds_load_client_certs(exim_gnutls_state_st * state, const host_item * host, { int rc = tls_add_certfile(state, host, cert, pkey, errstr); if (rc > 0) return rc; -DEBUG(D_tls) debug_printf("TLS: cert/key registered\n"); +DEBUG(tls) debug_printf("TLS: cert/key registered\n"); return OK; } @@ -1529,12 +1529,12 @@ else } #endif - DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n", + DEBUG(tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n", bundle, statbuf.st_size); if (statbuf.st_size == 0) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("cert file empty, no certs, no verification, ignoring any CRL\n"); return OK; } @@ -1565,7 +1565,7 @@ else if (cert_count < 0) return tls_error_gnu(state, US"setting certificate trust", cert_count, errstr); -DEBUG(D_tls) +DEBUG(tls) debug_printf("Added %d certificate authorities\n", cert_count); return OK; @@ -1576,13 +1576,13 @@ static int creds_load_crl(exim_gnutls_state_st * state, const uschar * crl, uschar ** errstr) { int cert_count; -DEBUG(D_tls) debug_printf("loading CRL file = %s\n", crl); +DEBUG(tls) debug_printf("loading CRL file = %s\n", crl); if ((cert_count = gnutls_certificate_set_x509_crl_file(state->lib_state.x509_cred, CS crl, GNUTLS_X509_FMT_PEM)) < 0) return tls_error_gnu(state, US"gnutls_certificate_set_x509_crl_file", cert_count, errstr); -DEBUG(D_tls) debug_printf("Processed %d CRLs\n", cert_count); +DEBUG(tls) debug_printf("Processed %d CRLs\n", cert_count); return OK; } @@ -1594,7 +1594,7 @@ creds_load_pristring(exim_gnutls_state_st * state, const uschar * p, if (!p) { p = exim_default_gnutls_priority; - DEBUG(D_tls) + DEBUG(tls) debug_printf("GnuTLS using default session cipher/priority %q\n", p); } return gnutls_priority_init( (gnutls_priority_t *) &state->lib_state.pri_cache, @@ -1637,7 +1637,7 @@ if ( opt_set_and_noexpand(tls_certificate) # endif && tls_set_watch(tls_privatekey, TRUE)) { - DEBUG(D_tls) debug_printf("TLS: preloading server certs\n"); + DEBUG(tls) debug_printf("TLS: preloading server certs\n"); if (creds_load_server_certs(&state_server, tls_certificate, tls_privatekey && *tls_privatekey ? tls_privatekey : tls_certificate, # ifdef DISABLE_OCSP @@ -1662,7 +1662,7 @@ else if ( !tls_certificate && !tls_privatekey } } else - DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n"); + DEBUG(tls) debug_printf("TLS: not preloading server certs\n"); /* If tls_verify_certificates is non-empty and has no $, load CAs. If none was configured and we can't handle "system", treat as empty. */ @@ -1675,7 +1675,7 @@ if ( opt_set_and_noexpand(tls_verify_certificates) { if (tls_set_watch(tls_verify_certificates, FALSE)) { - DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n"); + DEBUG(tls) debug_printf("TLS: preloading CA bundle for server\n"); if (creds_load_cabundle(&state_server, tls_verify_certificates, NULL, &dummy_errstr) != OK) return lifetime; @@ -1687,18 +1687,18 @@ if ( opt_set_and_noexpand(tls_verify_certificates) { if (tls_set_watch(tls_crl, FALSE)) { - DEBUG(D_tls) debug_printf("TLS: preloading CRL for server\n"); + DEBUG(tls) debug_printf("TLS: preloading CRL for server\n"); if (creds_load_crl(&state_server, tls_crl, &dummy_errstr) != OK) return lifetime; state_server.lib_state.crl = TRUE; } } else - DEBUG(D_tls) debug_printf("TLS: not preloading CRL for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading CRL for server\n"); } } else - DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading CA bundle for server\n"); #endif /* EXIM_HAVE_INOTIFY */ /* If tls_require_ciphers is non-empty and has no $, load the @@ -1708,14 +1708,14 @@ ciphers priority cache. If unset, load with the default. if (!tls_require_ciphers || opt_set_and_noexpand(tls_require_ciphers)) { const char * dummy_errpos; - DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server: %s\n", + DEBUG(tls) debug_printf("TLS: preloading cipher list for server: %s\n", tls_require_ciphers); if ( creds_load_pristring(&state_server, tls_require_ciphers, &dummy_errpos) == OK) state_server.lib_state.pri_string = TRUE; } else - DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading cipher list for server\n"); return lifetime; } @@ -1762,7 +1762,7 @@ if ( opt_set_and_noexpand(ob->tls_certificate) { const uschar * pkey = ob->tls_privatekey; - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: preloading client certs for transport '%s'\n", trname); /* The state->lib_state.x509_cred is used for the certs load, and is the sole @@ -1776,7 +1776,7 @@ if ( opt_set_and_noexpand(ob->tls_certificate) } } else - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: not preloading client certs, for transport '%s'\n", trname); /* If tls_verify_certificates is non-empty and has no $, load CAs. @@ -1790,7 +1790,7 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates) { if (!watch || tls_set_watch(ob->tls_verify_certificates, FALSE)) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: preloading CA bundle for transport '%s'\n", trname); if (creds_load_cabundle(&tpt_dummy_state, ob->tls_verify_certificates, dummy_host, &dummy_errstr) != OK) @@ -1801,18 +1801,18 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates) { if (!watch || tls_set_watch(ob->tls_crl, FALSE)) { - DEBUG(D_tls) debug_printf("TLS: preloading CRL for transport '%s'\n", trname); + DEBUG(tls) debug_printf("TLS: preloading CRL for transport '%s'\n", trname); if (creds_load_crl(&tpt_dummy_state, ob->tls_crl, &dummy_errstr) != OK) return; ob->tls_preload.crl = TRUE; } } else - DEBUG(D_tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", trname); + DEBUG(tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", trname); } } else - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", trname); /* We do not preload tls_require_ciphers to to the transport as it implicitly @@ -1889,7 +1889,7 @@ if (!host) /* server */ || Ustrstr(state->tls_certificate, US"tls_out_sni") ) ) { - DEBUG(D_tls) debug_printf("We will re-expand TLS session files if we receive SNI\n"); + DEBUG(tls) debug_printf("We will re-expand TLS session files if we receive SNI\n"); state->trigger_sni_changes = TRUE; } } @@ -1937,7 +1937,7 @@ if (!state->lib_state.conn_certs) if (!host) return tls_install_selfsign(state, errstr); else - DEBUG(D_tls) debug_printf("TLS: no client certificate specified; okay\n"); + DEBUG(tls) debug_printf("TLS: no client certificate specified; okay\n"); if ( state->tls_privatekey && !Expand_check_tlsvar(tls_privatekey, errstr) || f.expand_string_forcedfail @@ -1959,7 +1959,7 @@ if (!state->lib_state.conn_certs) if (state->exp_tls_certificate && *state->exp_tls_certificate) { BOOL load = TRUE; - DEBUG(D_tls) debug_printf("certificate file = %s\nkey file = %s\n", + DEBUG(tls) debug_printf("certificate file = %s\nkey file = %s\n", state->exp_tls_certificate, state->exp_tls_privatekey); if (state->received_sni) @@ -1967,12 +1967,12 @@ if (!state->lib_state.conn_certs) && Ustrcmp(state->exp_tls_privatekey, saved_tls_privatekey) == 0 ) { - DEBUG(D_tls) debug_printf("TLS SNI: cert and key unchanged\n"); + DEBUG(tls) debug_printf("TLS SNI: cert and key unchanged\n"); load = FALSE; /* avoid re-loading the same certs */ } else /* unload the pre-SNI certs before loading new ones */ { - DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair\n"); + DEBUG(tls) debug_printf("TLS SNI: have a changed cert/key pair\n"); gnutls_certificate_free_keys(state->lib_state.x509_cred); } @@ -1990,14 +1990,14 @@ if (!state->lib_state.conn_certs) errstr) ) ) { - DEBUG(D_tls) debug_printf("load-cert: '%s'\n", *errstr); + DEBUG(tls) debug_printf("load-cert: '%s'\n", *errstr); return rc; } } } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("%s certs were preloaded\n", host ? "client" : "server"); if (!state->tls_privatekey) state->tls_privatekey = state->tls_certificate; @@ -2036,7 +2036,7 @@ if (!state->lib_state.cabundle) if (!(state->exp_tls_verify_certificates && *state->exp_tls_verify_certificates)) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: tls_verify_certificates expanded empty, ignoring\n"); /* With no tls_verify_certificates, we ignore tls_crl too */ return OK; @@ -2044,7 +2044,7 @@ if (!state->lib_state.cabundle) } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: tls_verify_certificates not set or empty, ignoring\n"); return OK; } @@ -2053,7 +2053,7 @@ if (!state->lib_state.cabundle) } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("%s CA bundle was preloaded\n", host ? "client" : "server"); state->exp_tls_verify_certificates = US state->tls_verify_certificates; @@ -2074,7 +2074,7 @@ if (!state->lib_state.crl) } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("%s CRL was preloaded\n", host ? "client" : "server"); state->exp_tls_crl = US state->tls_crl; } @@ -2177,7 +2177,7 @@ if (host) memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init)); state->lib_state = ob->tls_preload; state->tlsp = tlsp; - DEBUG(D_tls) debug_printf("initialising GnuTLS client session\n"); + DEBUG(tls) debug_printf("initialising GnuTLS client session\n"); rc = gnutls_init(&state->session, GNUTLS_CLIENT); state->tls_certificate = ob->tls_certificate; @@ -2196,12 +2196,12 @@ else state = &state_server; state->tlsp = tlsp; - DEBUG(D_tls) debug_printf("initialising GnuTLS server session\n"); + DEBUG(tls) debug_printf("initialising GnuTLS server session\n"); #ifdef EXIM_TLS_EARLY_BANNER if (state->early_banner) { - DEBUG(D_tls) debug_printf("TLS: setting early-start flag\n"); + DEBUG(tls) debug_printf("TLS: setting early-start flag\n"); flags |= GNUTLS_ENABLE_EARLY_START; } #endif @@ -2222,7 +2222,7 @@ state->host = host; /* This handles the variables that might get re-expanded after TLS SNI; tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */ -DEBUG(D_tls) +DEBUG(tls) debug_printf("Expanding various TLS configuration options for session credentials\n"); if ((rc = tls_expand_session_files(state, errstr)) != OK) return rc; @@ -2238,7 +2238,7 @@ if (host) return DEFER; if (state->tlsp->sni && *state->tlsp->sni) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("Setting TLS client SNI to %q\n", state->tlsp->sni); sz = Ustrlen(state->tlsp->sni); if ((rc = gnutls_server_name_set(state->session, @@ -2247,7 +2247,7 @@ if (host) } } else if (state->tls_sni) - DEBUG(D_tls) debug_printf("*** PROBABLY A BUG *** " \ + DEBUG(tls) debug_printf("*** PROBABLY A BUG *** " \ "have an SNI set for a server [%s]\n", state->tls_sni); if (!state->lib_state.pri_string) @@ -2268,7 +2268,7 @@ if (!state->lib_state.pri_string) if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers) { p = state->exp_tls_require_ciphers; - DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority %q\n", p); + DEBUG(tls) debug_printf("GnuTLS session cipher/priority %q\n", p); } } @@ -2280,7 +2280,7 @@ if (!state->lib_state.pri_string) } else { - DEBUG(D_tls) debug_printf("cipher list preloaded\n"); + DEBUG(tls) debug_printf("cipher list preloaded\n"); state->exp_tls_require_ciphers = US state->tls_require_ciphers; } @@ -2298,10 +2298,10 @@ decides to make that trade-off. */ if (gnutls_compat_mode) { #if LIBGNUTLS_VERSION_NUMBER >= 0x020104 - DEBUG(D_tls) debug_printf("lowering GnuTLS security, compatibility mode\n"); + DEBUG(tls) debug_printf("lowering GnuTLS security, compatibility mode\n"); gnutls_session_enable_compatibility_mode(state->session); #else - DEBUG(D_tls) debug_printf("Unable to set gnutls_compat_mode - GnuTLS version too old\n"); + DEBUG(tls) debug_printf("Unable to set gnutls_compat_mode - GnuTLS version too old\n"); #endif } @@ -2407,7 +2407,7 @@ old_pool = store_pool; if (!s) { - DEBUG(D_tls) debug_printf("TLS: session init still incomplete\n"); + DEBUG(tls) debug_printf("TLS: session init still incomplete\n"); store_pool = old_pool; return DEFER; } @@ -2480,7 +2480,7 @@ cert_list = gnutls_certificate_get_peers(session, &cert_list_size); if (!cert_list || cert_list_size == 0) { - DEBUG(D_tls) debug_printf("TLS: no certificate from peer (%p & %d)\n", + DEBUG(tls) debug_printf("TLS: no certificate from peer (%p & %d)\n", cert_list, cert_list_size); if (state->verify_requirement >= VERIFY_REQUIRED) return tls_error(US"certificate verification failed", @@ -2491,7 +2491,7 @@ if (!cert_list || cert_list_size == 0) if ((ct = gnutls_certificate_type_get(session)) != GNUTLS_CRT_X509) { const uschar * ctn = US gnutls_certificate_type_get_name(ct); - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: peer cert not X.509 but instead %q\n", ctn); if (state->verify_requirement >= VERIFY_REQUIRED) return tls_error(US"certificate verification not possible, unhandled type", @@ -2503,7 +2503,7 @@ if ((ct = gnutls_certificate_type_get(session)) != GNUTLS_CRT_X509) do { \ if (rc != GNUTLS_E_SUCCESS) \ { \ - DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", \ + DEBUG(tls) debug_printf("TLS: peer cert problem: %s: %s\n", \ (Label), gnutls_strerror(rc)); \ if (state->verify_requirement >= VERIFY_REQUIRED) \ return tls_error_gnu(state, (Label), rc, errstr); \ @@ -2560,7 +2560,7 @@ verify_certificate(exim_gnutls_state_st * state, uschar ** errstr) int rc; uint verify; -DEBUG(D_tls) debug_printf("TLS: checking peer certificate\n"); +DEBUG(tls) debug_printf("TLS: checking peer certificate\n"); *errstr = NULL; rc = peer_status(state, errstr); @@ -2634,7 +2634,7 @@ else ? DANE_VFLAG_ONLY_CHECK_EE_USAGE : 0, &verify))) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLSA record problem: %s\n", dane_strerror(rc)); } else if (verify == 0) /* verification passed */ @@ -2711,7 +2711,7 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) if (!*errstr) { #ifdef GNUTLS_CERT_VFY_STATUS_PRINT - DEBUG(D_tls) + DEBUG(tls) { gnutls_datum_t txt; @@ -2728,13 +2728,13 @@ if (rc < 0 || verify & (GNUTLS_CERT_INVALID|GNUTLS_CERT_REVOKED)) ? US"certificate revoked" : US"certificate invalid"; } - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS certificate verification failed (%s): peerdn=%q\n", *errstr, state->peerdn ? state->peerdn : US""); if (state->verify_requirement >= VERIFY_REQUIRED) goto badcert; - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS verify failure overridden (host in tls_try_verify_hosts)\n"); } @@ -2750,7 +2750,7 @@ else CS state->exp_tls_verify_cert_hostnames) ) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS certificate verification failed: cert name mismatch (per GnuTLS)\n"); if (state->verify_requirement >= VERIFY_REQUIRED) goto badcert; @@ -2758,7 +2758,7 @@ else } state->peer_cert_verified = TRUE; - DEBUG(D_tls) debug_printf("TLS certificate verified: peerdn=%q\n", + DEBUG(tls) debug_printf("TLS certificate verified: peerdn=%q\n", state->peerdn ? state->peerdn : US""); } @@ -2794,10 +2794,10 @@ exim_gnutls_logger_cb(int level, const char *message) size_t len = strlen(message); if (len < 1) { - DEBUG(D_tls) debug_printf("GnuTLS<%d> empty debug message\n", level); + DEBUG(tls) debug_printf("GnuTLS<%d> empty debug message\n", level); return; } - DEBUG(D_tls) debug_printf("GnuTLS<%d>: %s%s", level, message, + DEBUG(tls) debug_printf("GnuTLS<%d>: %s%s", level, message, message[len-1] == '\n' ? "" : "\n"); } #endif @@ -2832,7 +2832,7 @@ uschar * dummy_errstr; rc = gnutls_server_name_get(session, sni_name, &data_len, &sni_type, 0); if (rc != GNUTLS_E_SUCCESS) { - DEBUG(D_tls) + DEBUG(tls) if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) debug_printf("TLS: no SNI presented in handshake\n"); else @@ -2843,7 +2843,7 @@ if (rc != GNUTLS_E_SUCCESS) if (sni_type != GNUTLS_NAME_DNS) { - DEBUG(D_tls) debug_printf("TLS: ignoring SNI of unhandled type %u\n", sni_type); + DEBUG(tls) debug_printf("TLS: ignoring SNI of unhandled type %u\n", sni_type); return 0; } @@ -2853,7 +2853,7 @@ state->received_sni = string_copy_perm(US sni_name, TRUE); /* We set this one now so that variable expansions below will work */ state->tlsp->sni = state->received_sni; -DEBUG(D_tls) debug_printf("Received TLS SNI %q%s\n", sni_name, +DEBUG(tls) debug_printf("Received TLS SNI %q%s\n", sni_name, state->trigger_sni_changes ? "" : " (unused for certificate selection)"); if (!state->trigger_sni_changes) @@ -2863,7 +2863,7 @@ if ((rc = tls_expand_session_files(state, &dummy_errstr)) != OK) { /* If the setup of certs/etc failed before handshake, TLS would not have been offered. The best we can do now is abort. */ - DEBUG(D_tls) debug_printf("expansion for SNI-dependent session files failed\n"); + DEBUG(tls) debug_printf("expansion for SNI-dependent session files failed\n"); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } @@ -2900,7 +2900,7 @@ if ((cert_list = gnutls_certificate_get_peers(session, &cert_list_size))) { if ((rc = import_cert(&cert_list[cert_list_size], &crt)) != GNUTLS_E_SUCCESS) { - DEBUG(D_tls) debug_printf("TLS: peer cert problem: depth %d: %s\n", + DEBUG(tls) debug_printf("TLS: peer cert problem: depth %d: %s\n", cert_list_size, gnutls_strerror(rc)); break; } @@ -2977,7 +2977,7 @@ static int tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, unsigned incoming, const gnutls_datum_t * msg) { -DEBUG(D_tls) debug_printf("newticket cb (on server)\n"); +DEBUG(tls) debug_printf("newticket cb (on server)\n"); tls_in.resumption |= RESUME_CLIENT_REQUESTED; return 0; } @@ -3000,7 +3000,7 @@ if (verify_check_host(&tls_resumption_hosts) == OK) &server_sessticket_key))) tls_in.resumption |= RESUME_SERVER_TICKET; else - DEBUG(D_tls) + DEBUG(tls) debug_printf("enabling session tickets: %s\n", US gnutls_strerror(rc)); /* Try to tell if we see a ticket request */ @@ -3022,12 +3022,12 @@ if (gnutls_session_resumption_requested(state->session)) in the Client Hello, for 1.2) which mucks up our logic. */ tls_in.resumption |= RESUME_CLIENT_SUGGESTED; - DEBUG(D_tls) debug_printf("client requested resumption\n"); + DEBUG(tls) debug_printf("client requested resumption\n"); } if (gnutls_session_is_resumed(state->session)) { tls_in.resumption |= RESUME_USED; - DEBUG(D_tls) debug_printf("Session resumed\n"); + DEBUG(tls) debug_printf("Session resumed\n"); } } #endif /* EXIM_HAVE_TLS_RESUME */ @@ -3049,7 +3049,7 @@ if (!expand_check(*tls_alpn, US"tls_alpn", &exp_alpn, errstr)) if (!exp_alpn) { - DEBUG(D_tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n"); + DEBUG(tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n"); *plist = NULL; } else @@ -3090,7 +3090,7 @@ if (tls_alpn_plist(&local_alpn, &plist, &plen, errstr) && plist) gnutls_handshake_set_hook_function(state->session, GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb); else - DEBUG(D_tls) + DEBUG(tls) debug_printf("setting alpn protocols: %s\n", US gnutls_strerror(rc)); } } @@ -3141,19 +3141,19 @@ if (tls_in.active.sock >= 0) if (verify_check_host(&tls_verify_hosts) == OK) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: a client certificate will be required\n"); state_server.verify_requirement = VERIFY_REQUIRED; } else if (verify_check_host(&tls_try_verify_hosts) == OK) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: a client certificate will be requested but not required\n"); state_server.verify_requirement = VERIFY_OPTIONAL; } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: a client certificate will not be requested\n"); state_server.verify_requirement = VERIFY_NONE; } @@ -3161,7 +3161,7 @@ else /* Initialize the library. If it fails, it will already have logged the error and sent an SMTP response. */ -DEBUG(D_tls) debug_printf("initialising GnuTLS as a server\n"); +DEBUG(tls) debug_printf("initialising GnuTLS as a server\n"); { #ifdef MEASURE_TIMING @@ -3242,7 +3242,7 @@ ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) { - DEBUG(D_tls) debug_printf(" error %d from gnutls_handshake: %s\n", + DEBUG(tls) debug_printf(" error %d from gnutls_handshake: %s\n", rc, gnutls_strerror(rc)); /* It seems that, except in the case of a timeout, we have to close the @@ -3283,11 +3283,11 @@ if ( gnutls_protocol_get_version(state->session) > GNUTLS_TLS1_2 && state->early_banner) { tls_write(NULL, banner->s, banner->ptr, SP_NO_MORE); - DEBUG(D_receive) + DEBUG(receive) { gstring_trim(banner, 2); debug_printf("SMTP>> %Y\n", banner); } gstring_reset(banner); - DEBUG(D_tls) debug_printf("TLS: wait for handshake complete\n"); + DEBUG(tls) debug_printf("TLS: wait for handshake complete\n"); tls_refill(GETC_BUFFER_UNLIMITED); } #endif @@ -3301,12 +3301,12 @@ if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET) tls_server_resume_posthandshake(state); #endif -DEBUG(D_tls) post_handshake_debug(state); +DEBUG(tls) post_handshake_debug(state); #ifdef EXIM_HAVE_ALPN if (server_seen_alpn > 0) { - DEBUG(D_tls) + DEBUG(tls) { /* The client offered ALPN. See what was negotiated. */ gnutls_datum_t p = {.size = 0}; int rc = gnutls_alpn_get_selected_protocol(state->session, &p); @@ -3325,9 +3325,9 @@ else if (server_seen_alpn == 0) return FAIL; } else - DEBUG(D_tls) debug_printf("TLS: no ALPN presented in handshake\n"); + DEBUG(tls) debug_printf("TLS: no ALPN presented in handshake\n"); else - DEBUG(D_tls) debug_printf("TLS: was not watching for ALPN\n"); + DEBUG(tls) debug_printf("TLS: was not watching for ALPN\n"); #endif /* Verify after the fact */ @@ -3339,7 +3339,7 @@ if (!verify_certificate(state, errstr)) (void) tls_error(US"certificate verification failed", *errstr, NULL, errstr); return FAIL; } - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: continuing on only because verification was optional, after: %s\n", *errstr); } @@ -3377,7 +3377,7 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) #else host->certname; #endif - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: server cert verification includes hostname: %q\n", state->exp_tls_verify_cert_hostnames); } @@ -3418,7 +3418,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; const uschar * p = rr->data; uint8_t usage = p[0], sel = p[1], type = p[2]; - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLSA: %d %d %d size %d\n", usage, sel, type, rr->size); if ( (usage != DANESSL_USAGE_DANE_TA && usage != DANESSL_USAGE_DANE_EE) @@ -3470,7 +3470,7 @@ tls_retrieve_session(tls_support * tlsp, gnutls_session_t session, tlsp->resumption = RESUME_SUPPORTED; if (!conn_args->have_lbserver) - { DEBUG(D_tls) debug_printf( + { DEBUG(tls) debug_printf( "resumption not supported: no LB detection done (continued-conn?)\n"); } else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host) == OK) { @@ -3491,15 +3491,15 @@ else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host if (!(rc = gnutls_session_set_data(session, CUS dt->session, (size_t)len - sizeof(dbdata_tls_session)))) { - DEBUG(D_tls) debug_printf("good session\n"); + DEBUG(tls) debug_printf("good session\n"); tlsp->resumption |= RESUME_CLIENT_SUGGESTED; } - else DEBUG(D_tls) debug_printf("setting session resumption data: %s\n", + else DEBUG(tls) debug_printf("setting session resumption data: %s\n", US gnutls_strerror(rc)); dbfn_close(dbm_file); } } -else DEBUG(D_tls) debug_printf("no resumption for this host\n"); +else DEBUG(tls) debug_printf("no resumption for this host\n"); } @@ -3516,7 +3516,7 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) gnutls_datum_t tkt; int rc; - DEBUG(D_tls) debug_printf("server offered session ticket\n"); + DEBUG(tls) debug_printf("server offered session ticket\n"); tlsp->ticket_received = TRUE; tlsp->resumption |= RESUME_SERVER_TICKET; @@ -3527,7 +3527,7 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) int dlen = sizeof(dbdata_tls_session) + tkt.size; dbdata_tls_session * dt = store_get(dlen, GET_TAINTED); - DEBUG(D_tls) debug_printf(" session data size %u\n", (unsigned)tkt.size); + DEBUG(tls) debug_printf(" session data size %u\n", (unsigned)tkt.size); memcpy(dt->session, tkt.data, tkt.size); gnutls_free(tkt.data); @@ -3537,15 +3537,15 @@ if (gnutls_session_get_flags(session) & GNUTLS_SFLAGS_SESSION_TICKET) dbfn_write(dbm_file, tlsp->resume_index, dt, dlen); dbfn_close(dbm_file); - DEBUG(D_tls) + DEBUG(tls) debug_printf(" wrote session db (len %u)\n", (unsigned)dlen); } } else - { DEBUG(D_tls) + { DEBUG(tls) debug_printf(" extract session data: %s\n", US gnutls_strerror(rc)); } - else DEBUG(D_tls) + else DEBUG(tls) debug_printf(" host not resumable; not saving ticket\n"); } } @@ -3563,7 +3563,7 @@ tls_client_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when, exim_gnutls_state_st * state = gnutls_session_get_ptr(sess); tls_support * tlsp = state->tlsp; -DEBUG(D_tls) debug_printf("newticket cb (on client)\n"); +DEBUG(tls) debug_printf("newticket cb (on client)\n"); if (!tlsp->ticket_received) tls_save_session(tlsp, sess, state->host); @@ -3589,7 +3589,7 @@ tls_client_resume_posthandshake(exim_gnutls_state_st * state, { if (gnutls_session_is_resumed(state->session)) { - DEBUG(D_tls) debug_printf("Session resumed\n"); + DEBUG(tls) debug_printf("Session resumed\n"); tlsp->resumption |= RESUME_USED; } @@ -3636,7 +3636,7 @@ BOOL request_ocsp = require_ocsp ? TRUE : verify_check_given_host(CUSS &ob->hosts_request_ocsp, host) == OK; #endif -DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", cctx->sock); +DEBUG(tls) debug_printf("initialising GnuTLS as a client on fd %d\n", cctx->sock); #ifdef SUPPORT_DANE /* If dane is flagged, have either request or require dane for this host, and @@ -3687,7 +3687,7 @@ if (ob->tls_alpn) return FALSE; } else - DEBUG(D_tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); + DEBUG(tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); } #else log_write(0, LOG_MAIN, @@ -3699,14 +3699,14 @@ if (ob->tls_alpn) int dh_min_bits = ob->tls_dh_min_bits; if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("WARNING: tls_dh_min_bits far too low," " clamping %d up to %d\n", dh_min_bits, EXIM_CLIENT_DH_MIN_MIN_BITS); dh_min_bits = EXIM_CLIENT_DH_MIN_MIN_BITS; } - DEBUG(D_tls) debug_printf("Setting D-H prime minimum" + DEBUG(tls) debug_printf("Setting D-H prime minimum" " acceptable bits to %d\n", dh_min_bits); gnutls_dh_set_prime_bits(state->session, dh_min_bits); @@ -3719,7 +3719,7 @@ the specified host patterns if one of them is defined */ #ifdef SUPPORT_DANE if (conn_args->dane && dane_tlsa_load(state, conn_args->tlsa_dnsa)) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: server certificate DANE required\n"); state->verify_requirement = VERIFY_DANE; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); @@ -3734,7 +3734,7 @@ else ) { tls_client_setup_hostname_checks(host, state, ob); - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: server certificate verification required\n"); state->verify_requirement = VERIFY_REQUIRED; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE); @@ -3742,14 +3742,14 @@ else else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK) { tls_client_setup_hostname_checks(host, state, ob); - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: server certificate verification optional\n"); state->verify_requirement = VERIFY_OPTIONAL; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST); } else { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: server certificate verification not required\n"); state->verify_requirement = VERIFY_NONE; gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE); @@ -3759,7 +3759,7 @@ else /* supported since GnuTLS 3.1.3 */ if (request_ocsp) { - DEBUG(D_tls) debug_printf("TLS: will request OCSP stapling\n"); + DEBUG(tls) debug_printf("TLS: will request OCSP stapling\n"); if ((rc = gnutls_ocsp_status_request_enable_client(state->session, NULL, 0, NULL)) != OK) { @@ -3787,7 +3787,7 @@ gnutls_transport_set_ptr(state->session, (gnutls_transport_ptr_t)(long) cctx->so state->fd_in = cctx->sock; state->fd_out = cctx->sock; -DEBUG(D_tls) debug_printf("about to gnutls_handshake\n"); +DEBUG(tls) debug_printf("about to gnutls_handshake\n"); /* There doesn't seem to be a built-in timeout on connection. */ sigalrm_seen = FALSE; @@ -3809,7 +3809,7 @@ if (rc != GNUTLS_E_SUCCESS) return FALSE; } -DEBUG(D_tls) post_handshake_debug(state); +DEBUG(tls) post_handshake_debug(state); /* Verify late */ @@ -3827,7 +3827,7 @@ if (gnutls_session_get_flags(state->session) & GNUTLS_SFLAGS_EXT_MASTER_SECRET) #ifndef DISABLE_OCSP if (request_ocsp) { - DEBUG(D_tls) + DEBUG(tls) { gnutls_datum_t stapling; gnutls_ocsp_resp_t resp; @@ -3864,7 +3864,7 @@ if (request_ocsp) } else { - DEBUG(D_tls) debug_printf("Passed OCSP checking\n"); + DEBUG(tls) debug_printf("Passed OCSP checking\n"); tlsp->ocsp = OCSP_VFIED; } } @@ -3880,7 +3880,7 @@ if (ob->tls_alpn) /* We requested. See what was negotiated. */ gnutls_datum_t p = {.size = 0}; if (gnutls_alpn_get_selected_protocol(state->session, &p) == 0) - { DEBUG(D_tls) debug_printf("ALPN negotiated: '%.*s'\n", (int)p.size, p.data); } + { DEBUG(tls) debug_printf("ALPN negotiated: '%.*s'\n", (int)p.size, p.data); } else if (verify_check_given_host(CUSS &ob->hosts_require_alpn, host) == OK) { gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_NO_APPLICATION_PROTOCOL); @@ -3888,7 +3888,7 @@ if (ob->tls_alpn) /* We requested. See what was negotiated. */ return FALSE; } else - DEBUG(D_tls) debug_printf("No ALPN negotiated"); + DEBUG(tls) debug_printf("No ALPN negotiated"); } #endif @@ -3918,7 +3918,7 @@ if (!tlsp || tlsp->active.sock < 0) return; /* TLS was not active */ tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ -HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent(" SMTP(TLS shutdown)>>\n"); +HDEBUG(transport|tls|acl|v) debug_printf_indent(" SMTP(TLS shutdown)>>\n"); gnutls_bye(state->session, GNUTLS_SHUT_WR); } @@ -3949,7 +3949,7 @@ if (!tlsp || tlsp->active.sock < 0) return; /* TLS was not active */ if (do_shutdown) { - DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", + DEBUG(tls) debug_printf("tls_close(): shutting down TLS%s\n", do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : ""); tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ @@ -4106,12 +4106,12 @@ if (len > INT_MAX) len = INT_MAX; if (state->xfer_buffer_lwm < state->xfer_buffer_hwm) - DEBUG(D_tls) + DEBUG(tls) debug_printf("*** PROBABLY A BUG *** " \ "tls_read() called with data in the tls_getc() buffer, %d ignored\n", state->xfer_buffer_hwm - state->xfer_buffer_lwm); -DEBUG(D_tls) +DEBUG(tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, len=" SIZE_T_FMT ")\n", state->session, buff, len); @@ -4123,11 +4123,11 @@ while (inbytes == GNUTLS_E_AGAIN); if (inbytes > 0) return inbytes; if (inbytes == 0) { - DEBUG(D_tls) debug_printf("Got TLS_EOF\n"); + DEBUG(tls) debug_printf("Got TLS_EOF\n"); } else { - DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv\n", __FUNCTION__); + DEBUG(tls) debug_printf("%s: err from gnutls_record_recv\n", __FUNCTION__); record_io_error(state, (int)inbytes, US"recv", NULL); } @@ -4165,18 +4165,18 @@ exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server; #ifdef SUPPORT_CORK if (more && !state->corked) { - DEBUG(D_tls) debug_printf("gnutls_record_cork(session=%p)\n", state->session); + DEBUG(tls) debug_printf("gnutls_record_cork(session=%p)\n", state->session); gnutls_record_cork(state->session); state->corked = TRUE; } #endif -DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__, +DEBUG(tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__, buff, left, more ? ", more" : ""); while (left > 0) { - DEBUG(D_tls) debug_printf("gnutls_record_send(session=%p, buffer=%p, left=" SIZE_T_FMT ")\n", + DEBUG(tls) debug_printf("gnutls_record_send(session=%p, buffer=%p, left=" SIZE_T_FMT ")\n", state->session, buff, left); errno = 0; @@ -4184,7 +4184,7 @@ while (left > 0) outbytes = gnutls_record_send(state->session, buff, left); while (outbytes == GNUTLS_E_AGAIN); - DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); + DEBUG(tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); if (outbytes < 0) { @@ -4197,13 +4197,13 @@ while (left > 0) log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before" " SMTP response and TLS close\n", sender_host_address); else - DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT," + DEBUG(tls) debug_printf("[%s] SSL_write: after QUIT," " client reset TCP before TLS close\n", sender_host_address); } else #endif { - DEBUG(D_tls) debug_printf("%s: gnutls_record_send err\n", __FUNCTION__); + DEBUG(tls) debug_printf("%s: gnutls_record_send err\n", __FUNCTION__); record_io_error(state, outbytes, US"send", NULL); } return -1; @@ -4220,7 +4220,7 @@ while (left > 0) if (len > INT_MAX) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("Whoops! Wrote more bytes (" SIZE_T_FMT ") than INT_MAX\n", len); len = INT_MAX; @@ -4229,7 +4229,7 @@ if (len > INT_MAX) #ifdef SUPPORT_CORK if (!more && state->corked) { - DEBUG(D_tls) debug_printf("gnutls_record_uncork(session=%p)\n", state->session); + DEBUG(tls) debug_printf("gnutls_record_uncork(session=%p)\n", state->session); do /* We can't use GNUTLS_RECORD_WAIT here, as it retries on GNUTLS_E_AGAIN || GNUTLS_E_INTR, which would break our timeout set by alarm(). @@ -4294,7 +4294,7 @@ if (i < needed_len) i = gnutls_rnd(GNUTLS_RND_NONCE, smallbuf, needed_len); if (i < 0) { - DEBUG(D_all) debug_printf("gnutls_rnd() failed, using fallback\n"); + DEBUG(all) debug_printf("gnutls_rnd() failed, using fallback\n"); return vaguely_random_number_fallback(max); } r = 0; @@ -4374,7 +4374,7 @@ if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, if (!(expciphers && *expciphers)) return_deinit(NULL); -DEBUG(D_tls) +DEBUG(tls) debug_printf("tls_require_ciphers expands to %q\n", expciphers); rc = gnutls_priority_init(&priority_cache, CS expciphers, &errpos); diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 72c5c7a46..0556a071c 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -506,7 +506,7 @@ if (!msg) } msg = string_sprintf("(%s): %s", prefix, msg); -DEBUG(D_tls) debug_printf("TLS error '%s'\n", msg); +DEBUG(tls) debug_printf("TLS error '%s'\n", msg); if (errstr) *errstr = msg; return host ? FAIL : DEFER; } @@ -613,7 +613,7 @@ else { if (Ustrcmp(dhexpanded, "none") == 0) { - DEBUG(D_tls) debug_printf("Requested no DH parameters.\n"); + DEBUG(tls) debug_printf("Requested no DH parameters.\n"); return TRUE; } @@ -679,12 +679,12 @@ if (dh_bitsize <= tls_dh_max_bits) #endif } else - DEBUG(D_tls) + DEBUG(tls) debug_printf(" Diffie-Hellman initialized from %s with %d-bit prime\n", dhexpanded ? dhexpanded : US"default", dh_bitsize); } else - DEBUG(D_tls) + DEBUG(tls) debug_printf(" dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n", dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits); @@ -717,21 +717,21 @@ static uschar * init_ecdh_auto(const SSL_CTX * sctx) { #if OPENSSL_VERSION_NUMBER < 0x10002000L -DEBUG(D_tls) debug_printf( +DEBUG(tls) debug_printf( " ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n"); return US"prime256v1"; #else # if defined SSL_CTRL_SET_ECDH_AUTO -DEBUG(D_tls) debug_printf( +DEBUG(tls) debug_printf( " ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n"); SSL_CTX_set_ecdh_auto(sctx, 1); return NULL; # else -DEBUG(D_tls) debug_printf( +DEBUG(tls) debug_printf( " ECDH OpenSSL 1.1.0+: temp key parameter settings: library default selection\n"); return NULL; @@ -792,7 +792,7 @@ for (ngroups = 0; ) if (Ustrcmp(curve, "auto") == 0) { - DEBUG(D_tls) if (ngroups > 0) + DEBUG(tls) if (ngroups > 0) debug_printf(" tls_eccurve 'auto' item takes precedence\n"); if ((exp_curve = init_ecdh_auto(sctx))) break; /* have a curve name to set */ return TRUE; /* all done */ @@ -812,7 +812,7 @@ for (ngroups = 0; curve = string_nextinlist(&curves_list, &sep, NULL, 0); ) { uschar * s = string_sprintf("Unknown curve name in tls_eccurve '%s'", curve); - DEBUG(D_tls) debug_printf("TLS error: %s\n", s); + DEBUG(tls) debug_printf("TLS error: %s\n", s); if (errstr) *errstr = s; return FALSE; } @@ -823,7 +823,7 @@ for (ngroups = 0; curve = string_nextinlist(&curves_list, &sep, NULL, 0); if ((rc = SSL_CTX_set1_groups(sctx, nids, ngroups)) == 0) tls_error(string_sprintf("Error enabling '%s' group(s)", exp_curve), NULL, NULL, errstr); else - DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' group(s)\n", exp_curve); + DEBUG(tls) debug_printf(" ECDH: enabled '%s' group(s)\n", exp_curve); # else /* Cannot handle a list; only 1 element nids array */ { @@ -840,7 +840,7 @@ else if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh)) == 0) tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr); else - DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve); + DEBUG(tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve); EC_KEY_free(ecdh); } # endif /*!EXIM_HAVE_OPENSSL_SET1_GROUPS*/ @@ -870,7 +870,7 @@ rsa_callback(SSL *s, int export, int keylength) RSA *rsa_key; BIGNUM *bn = BN_new(); -DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength); +DEBUG(tls) debug_printf("Generating %d bit RSA key...\n", keylength); if ( !BN_set_word(bn, (unsigned long)RSA_F4) || !(rsa_key = RSA_new()) @@ -902,7 +902,7 @@ EVP_PKEY * pkey; X509_NAME * name; uschar * where; -DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n"); +DEBUG(tls) debug_printf("TLS: generating selfsigned server cert\n"); where = US"allocating pkey"; if (!(pkey = EVP_PKEY_new())) goto err; @@ -987,7 +987,7 @@ Returns: nothing static void info_callback(const SSL * s, int where, int ret) { -DEBUG(D_tls) +DEBUG(tls) { gstring * g = NULL; @@ -1023,7 +1023,7 @@ keylog_callback(const SSL * ssl, const char * line) { char * filename; FILE * fp; -DEBUG(D_tls) debug_printf("%.200s\n", line); +DEBUG(tls) debug_printf("%.200s\n", line); if (!(filename = getenv("SSLKEYLOGFILE"))) return; if (!(fp = fopen(filename, "a"))) return; fprintf(fp, "%s\n", line); @@ -1047,7 +1047,7 @@ X509 * old_cert; ev = tlsp == &tls_out ? client_static_state->event_action : event_action; if (ev) { - DEBUG(D_tls) debug_printf("verify_event: %s %d\n", what, depth); + DEBUG(tls) debug_printf("verify_event: %s %d\n", what, depth); old_cert = tlsp->peercert; tlsp->peercert = X509_dup(cert); /* NB we do not bother setting peerdn */ @@ -1063,7 +1063,7 @@ if (ev) if (old_cert) tlsp->peercert = old_cert; /* restore 1st failing cert */ return 1; /* reject (leaving peercert set) */ } - DEBUG(D_tls) debug_printf("Event-action verify failure overridden " + DEBUG(tls) debug_printf("Event-action verify failure overridden " "(host in tls_try_verify_hosts)\n"); tlsp->verify_override = TRUE; } @@ -1118,7 +1118,7 @@ uschar dn[256]; if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn))) { - DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); + DEBUG(tls) debug_printf("X509_NAME_oneline() error\n"); log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", tlsp == &tls_out ? deliver_host_address : sender_host_address); return 0; @@ -1142,14 +1142,14 @@ if (preverify_ok == 0) tlsp->peercert = X509_dup(cert); /* record failing cert */ return 0; /* reject */ } - DEBUG(D_tls) debug_printf("SSL verify failure overridden (host in " + DEBUG(tls) debug_printf("SSL verify failure overridden (host in " "tls_try_verify_hosts)\n"); tlsp->verify_override = TRUE; } else if (depth != 0) { - DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, dn); + DEBUG(tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, dn); #ifndef DISABLE_EVENT if (verify_event(tlsp, cert, depth, dn, calledp, optionalp, US"SSL")) return 0; /* reject, with peercert set */ @@ -1177,7 +1177,7 @@ else int rc; while ((name = string_nextinlist(&list, &sep, NULL, 0))) { - DEBUG(D_tls|D_lookup) debug_printf_indent("%s suitable for cert, per OpenSSL?", name); + DEBUG(tls|lookup) debug_printf_indent("%s suitable for cert, per OpenSSL?", name); if ((rc = X509_check_host(cert, CCS name, 0, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS, @@ -1189,10 +1189,10 @@ else tlsp == &tls_out ? deliver_host_address : sender_host_address); name = NULL; } - DEBUG(D_tls|D_lookup) debug_printf_indent(" yes\n"); + DEBUG(tls|lookup) debug_printf_indent(" yes\n"); break; } - else DEBUG(D_tls|D_lookup) debug_printf_indent(" no\n"); + else DEBUG(tls|lookup) debug_printf_indent(" no\n"); } if (!name) #else @@ -1214,7 +1214,7 @@ else tlsp->peercert = X509_dup(cert); /* record failing cert */ return 0; /* reject */ } - DEBUG(D_tls) debug_printf("SSL verify name failure overridden (host in " + DEBUG(tls) debug_printf("SSL verify name failure overridden (host in " "tls_try_verify_hosts)\n"); tlsp->verify_override = TRUE; } @@ -1225,7 +1225,7 @@ else return 0; /* reject, with peercert set */ #endif - DEBUG(D_tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n", + DEBUG(tls) debug_printf("SSL%s verify ok: depth=0 SN=%s\n", *calledp ? "" : " authenticated", dn); *calledp = TRUE; } @@ -1265,14 +1265,14 @@ BOOL dummy_called, optional = FALSE; if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn))) { - DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); + DEBUG(tls) debug_printf("X509_NAME_oneline() error\n"); log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", deliver_host_address); return 0; } dn[sizeof(dn)-1] = '\0'; -DEBUG(D_tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n", +DEBUG(tls) debug_printf("verify_callback_client_dane: %s depth %d %s\n", preverify_ok ? "ok":"BAD", depth, dn); #ifndef DISABLE_EVENT @@ -1286,7 +1286,7 @@ if (preverify_ok == 1) else { int err = X509_STORE_CTX_get_error(x509ctx); - DEBUG(D_tls) + DEBUG(tls) debug_printf(" - err %d '%s'\n", err, X509_verify_cert_error_string(err)); if (err == X509_V_ERR_APPLICATION_VERIFICATION) preverify_ok = 1; @@ -1333,7 +1333,7 @@ ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd; STACK_OF(X509) * sk; int status, reason, i; -DEBUG(D_tls) +DEBUG(tls) debug_printf("tls_ocsp_file (%s) '%s'\n", is_pem ? "PEM" : "DER", filename); if (!filename || !*filename) return; @@ -1375,7 +1375,7 @@ if (!resp) if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - DEBUG(D_tls) debug_printf("OCSP response not valid: %s (%d)\n", + DEBUG(tls) debug_printf("OCSP response not valid: %s (%d)\n", OCSP_response_status_str(status), status); goto bad; } @@ -1390,7 +1390,7 @@ if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL) if (!(basic_response = OCSP_response_get1_basic(resp))) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("OCSP response parse error: unable to extract basic response.\n"); goto bad; } @@ -1429,7 +1429,7 @@ library does it for us anyway? */ if ((i = OCSP_basic_verify(basic_response, sk, NULL, OCSP_NOVERIFY)) < 0) { - DEBUG(D_tls) + DEBUG(tls) { ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); debug_printf("OCSP response has bad signature: %s\n", US ssl_errstring); @@ -1450,7 +1450,7 @@ XXX that will change when we add support for (TLS1.3) whole-chain stapling if (!(single_response = OCSP_resp_get0(basic_response, 0))) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("Unable to get first response from OCSP basic response.\n"); goto bad; } @@ -1458,7 +1458,7 @@ if (!(single_response = OCSP_resp_get0(basic_response, 0))) status = OCSP_single_get0_status(single_response, &reason, &rev, &thisupd, &nextupd); if (status != V_OCSP_CERTSTATUS_GOOD) { - DEBUG(D_tls) debug_printf("OCSP response bad cert status: %s (%d) %s (%d)\n", + DEBUG(tls) debug_printf("OCSP response bad cert status: %s (%d) %s (%d)\n", OCSP_cert_status_str(status), status, OCSP_crl_reason_str(reason), reason); goto bad; @@ -1466,7 +1466,7 @@ if (status != V_OCSP_CERTSTATUS_GOOD) if (!OCSP_check_validity(thisupd, nextupd, EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE)) { - DEBUG(D_tls) + DEBUG(tls) { BIO * bp = BIO_new(BIO_s_mem()); uschar * s = NULL; @@ -1498,7 +1498,7 @@ bad: if (environ) for (uschar ** p = USS environ; *p; p++) if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0) { - DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n"); + DEBUG(tls) debug_printf("Supplying known bad OCSP response\n"); goto supply_response; } } @@ -1524,7 +1524,7 @@ static int tls_add_certfile(SSL_CTX * sctx, const exim_openssl_state_st * cbinfo, const uschar * file, uschar ** errstr) { -DEBUG(D_tls) debug_printf("tls_certificate file '%s'\n", file); +DEBUG(tls) debug_printf("tls_certificate file '%s'\n", file); if (!SSL_CTX_use_certificate_chain_file(sctx, CS file)) return tls_error(string_sprintf( "SSL_CTX_use_certificate_chain_file file=%s", file), @@ -1536,7 +1536,7 @@ static int tls_add_pkeyfile(SSL_CTX * sctx, const exim_openssl_state_st * cbinfo, const uschar * file, uschar ** errstr) { -DEBUG(D_tls) debug_printf("tls_privatekey file '%s'\n", file); +DEBUG(tls) debug_printf("tls_privatekey file '%s'\n", file); if (!SSL_CTX_use_PrivateKey_file(sctx, CS file, SSL_FILETYPE_PEM)) return tls_error(string_sprintf( "SSL_CTX_use_PrivateKey_file file=%s", file), cbinfo->host, NULL, errstr); @@ -1616,7 +1616,7 @@ else if ( state->u_ocsp.server.file_expanded && olist && (Ustrcmp(olist, state->u_ocsp.server.file_expanded) == 0)) { - DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n"); + DEBUG(tls) debug_printf(" - value unchanged, using existing values\n"); olist = NULL; } else @@ -1648,7 +1648,7 @@ else ocsp_load_response(state, ofile, fmt_pem); } else - DEBUG(D_tls) debug_printf("ran out of ocsp file list\n"); + DEBUG(tls) debug_printf("ran out of ocsp file list\n"); #endif } } @@ -1712,7 +1712,7 @@ static int server_load_ciphers(SSL_CTX * ctx, exim_openssl_state_st * state, uschar * ciphers, uschar ** errstr) { -DEBUG(D_tls) debug_printf("required ciphers: %s\n", ciphers); +DEBUG(tls) debug_printf("required ciphers: %s\n", ciphers); if (!SSL_CTX_set_cipher_list(ctx, CS ciphers)) return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr); state->server_cipher_list = ciphers; @@ -1735,7 +1735,7 @@ if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())) /* Set up the information callback, which outputs if debugging is at a suitable level. */ -DEBUG(D_tls) +DEBUG(tls) { SSL_CTX_set_info_callback(ctx, info_callback); #if defined(EXIM_HAVE_OPENSSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE) @@ -1773,20 +1773,20 @@ state_server.lib_state.lib_ctx = ctx; if (opt_unset_or_noexpand(tls_dhparam)) { - DEBUG(D_tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam); + DEBUG(tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam); if (init_dh(ctx, tls_dhparam, &dummy_errstr)) state_server.lib_state.dh = TRUE; } else - DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading DH params for server\n"); if (opt_unset_or_noexpand(tls_eccurve)) { - DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve); + DEBUG(tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve); if (init_ecdh(ctx, &dummy_errstr)) state_server.lib_state.ecdh = TRUE; } else - DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading ECDH curve for server\n"); #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) /* If we can, preload the Authorities for checking client certs against. @@ -1804,7 +1804,7 @@ if ( opt_set_and_noexpand(tls_verify_certificates) && tls_set_watch(tls_crl, FALSE)) { uschar * v_certs = tls_verify_certificates; - DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n"); + DEBUG(tls) debug_printf("TLS: preloading CA bundle for server\n"); if (setup_certs(ctx, &v_certs, tls_crl, NULL, &dummy_errstr) == OK) state_server.lib_state.cabundle = TRUE; @@ -1832,7 +1832,7 @@ if ( opt_set_and_noexpand(tls_verify_certificates) state_server.u_ocsp.server.file = tls_ocsp_file; # endif - DEBUG(D_tls) debug_printf("TLS: preloading server certs\n"); + DEBUG(tls) debug_printf("TLS: preloading server certs\n"); if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK) state_server.lib_state.conn_certs = TRUE; } @@ -1850,11 +1850,11 @@ if ( opt_set_and_noexpand(tls_verify_certificates) } } else - DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n"); + DEBUG(tls) debug_printf("TLS: not preloading server certs\n"); } } else - DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading CA bundle for server\n"); #endif /* EXIM_HAVE_INOTIFY */ @@ -1864,14 +1864,14 @@ else if (opt_set_and_noexpand(tls_require_ciphers)) { - DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server\n"); + DEBUG(tls) debug_printf("TLS: preloading cipher list for server\n"); normalise_ciphers(&tls_require_ciphers, tls_require_ciphers); if (server_load_ciphers(ctx, &state_server, tls_require_ciphers, &dummy_errstr) == OK) state_server.lib_state.pri_string = TRUE; } else - DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n"); + DEBUG(tls) debug_printf("TLS: not preloading cipher list for server\n"); return lifetime; } @@ -1913,7 +1913,7 @@ if ( opt_set_and_noexpand(ob->tls_certificate) { uschar * pkey = ob->tls_privatekey; - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: preloading client certs for transport '%s'\n", trname); if ( tls_add_certfile(ctx, &tpt_dummy_state, ob->tls_certificate, @@ -1926,7 +1926,7 @@ if ( opt_set_and_noexpand(ob->tls_certificate) } } else - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: not preloading client certs, for transport '%s'\n", trname); @@ -1940,7 +1940,7 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates) ) { uschar * v_certs = ob->tls_verify_certificates; - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: preloading CA bundle for transport '%s'\n", trname); if (setup_certs(ctx, &v_certs, @@ -1949,7 +1949,7 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates) } } else - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", trname); #endif /*EXIM_HAVE_INOTIFY*/ @@ -2065,7 +2065,7 @@ if (exim_tk.name[0]) if (f.running_in_test_harness) ssl_session_timeout = TESTSUITE_TICKET_LIFE; -DEBUG(D_tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating"); +DEBUG(tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating"); if (RAND_bytes(exim_tk.aes_key, sizeof(exim_tk.aes_key)) <= 0) return; if (RAND_bytes(exim_tk.hmac_key, sizeof(exim_tk.hmac_key)) <= 0) return; if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return; @@ -2120,7 +2120,7 @@ tk_hmac_init( params[2] = OSSL_PARAM_construct_end(); if (EVP_MAC_CTX_set_params(hctx, params) == 0) { - DEBUG(D_tls) debug_printf("EVP_MAC_CTX_set_params: %s\n", + DEBUG(tls) debug_printf("EVP_MAC_CTX_set_params: %s\n", ERR_reason_error_string(ERR_get_error())); return 0; /* error in mac initialisation */ } @@ -2145,7 +2145,7 @@ exim_stek * key; if (enc) { - DEBUG(D_tls) debug_printf("ticket_key_callback: create new session\n"); + DEBUG(tls) debug_printf("ticket_key_callback: create new session\n"); tlsp->resumption |= RESUME_CLIENT_REQUESTED; if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0) @@ -2154,24 +2154,24 @@ if (enc) if (!(key = tk_current())) /* current key doesn't exist or isn't valid */ return 0; /* key couldn't be created */ memcpy(key_name, key->name, 16); - DEBUG(D_tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL)); + DEBUG(tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL)); if (tk_hmac_init(hctx, key) == 0) return 0; EVP_EncryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv); - DEBUG(D_tls) debug_printf("ticket created\n"); + DEBUG(tls) debug_printf("ticket created\n"); return 1; } else { time_t now = time(NULL); - DEBUG(D_tls) debug_printf("ticket_key_callback: retrieve session\n"); + DEBUG(tls) debug_printf("ticket_key_callback: retrieve session\n"); tlsp->resumption |= RESUME_CLIENT_SUGGESTED; if (!(key = tk_find(key_name)) || key->expire < now) { - DEBUG(D_tls) + DEBUG(tls) { debug_printf("ticket not usable (%s)\n", key ? "expired" : "not found"); if (key) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - now); @@ -2182,7 +2182,7 @@ else if (tk_hmac_init(hctx, key) == 0) return 0; EVP_DecryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv); - DEBUG(D_tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now); + DEBUG(tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now); /* The ticket lifetime and renewal are the same as the STEK lifetime and renewal, which is overenthusiastic. A factor of, say, 3x longer STEK would @@ -2239,7 +2239,7 @@ uschar * errstr; if (!servername) return SSL_TLSEXT_ERR_OK; -DEBUG(D_tls) debug_printf("Received TLS SNI %q%s\n", servername, +DEBUG(tls) debug_printf("Received TLS SNI %q%s\n", servername, reexpand_tls_files_for_sni ? "" : " (unused for certificate selection)"); /* Make the extension value available for expansion */ @@ -2304,7 +2304,7 @@ OCSP information. */ if ((rc = tls_expand_session_files(server_sni, state, &errstr)) != OK) goto bad; -DEBUG(D_tls) debug_printf("Switching SSL context.\n"); +DEBUG(tls) debug_printf("Switching SSL context.\n"); SSL_set_SSL_CTX(s, server_sni); return SSL_TLSEXT_ERR_OK; @@ -2332,7 +2332,7 @@ tls_server_alpn_cb(SSL * ssl, const uschar ** out, uschar * outlen, gstring * g = NULL; server_seen_alpn = TRUE; -DEBUG(D_tls) +DEBUG(tls) { debug_printf("Received TLS ALPN offer:"); for (int pos = 0, siz; pos < inlen; pos += siz+1) @@ -2405,7 +2405,7 @@ ocsp_resplist * olist = state->u_ocsp.server.olist; uschar * response_der; /*XXX blob */ int response_der_len; -DEBUG(D_tls) +DEBUG(tls) debug_printf("Received TLS status request (OCSP stapling); %s response list\n", olist ? "have" : "lack"); @@ -2433,7 +2433,7 @@ if (!olist) (OCSP_CERTID *) cid); resp_bn = ASN1_INTEGER_to_BN(res_cert_serial, NULL); - DEBUG(D_tls) + DEBUG(tls) { debug_printf("cert serial: %s\n", BN_bn2hex(cert_bn)); debug_printf("resp serial: %s\n", BN_bn2hex(resp_bn)); @@ -2441,7 +2441,7 @@ if (!olist) if (BN_cmp(cert_bn, resp_bn) == 0) { - DEBUG(D_tls) debug_printf("matched serial for ocsp\n"); + DEBUG(tls) debug_printf("matched serial for ocsp\n"); /*XXX TODO: check the rest of the list for duplicate matches. If any, need to also check the Issuer Name hash. @@ -2450,18 +2450,18 @@ if (!olist) break; } - DEBUG(D_tls) debug_printf("not match serial for ocsp\n"); + DEBUG(tls) debug_printf("not match serial for ocsp\n"); } if (!olist) { - DEBUG(D_tls) debug_printf("failed to find match for ocsp\n"); + DEBUG(tls) debug_printf("failed to find match for ocsp\n"); return SSL_TLSEXT_ERR_NOACK; } } #else if (olist->next) { - DEBUG(D_tls) debug_printf("OpenSSL version too early to support multi-leaf OCSP\n"); + DEBUG(tls) debug_printf("OpenSSL version too early to support multi-leaf OCSP\n"); return SSL_TLSEXT_ERR_NOACK; } #endif @@ -2485,7 +2485,7 @@ add_chain_to_store(X509_STORE * store, STACK_OF(X509) * sk, { int idx; -DEBUG(D_tls) +DEBUG(tls) { debug_printf("chain for %s:\n", debug_text); x509_stack_dump_cert_s_names(sk); @@ -2507,20 +2507,20 @@ OCSP_RESPONSE * rsp; OCSP_BASICRESP * bs; int i; -DEBUG(D_tls) debug_printf("Received TLS status callback (OCSP stapling):\n"); +DEBUG(tls) debug_printf("Received TLS status callback (OCSP stapling):\n"); len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); if(!p) { /* Expect this when we requested ocsp but got none */ if (SSL_session_reused(ssl) && tls_out.ocsp == OCSP_VFIED) { - DEBUG(D_tls) debug_printf(" null, but resumed; ocsp vfy stored with session is good\n"); + DEBUG(tls) debug_printf(" null, but resumed; ocsp vfy stored with session is good\n"); return 1; } if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher)) log_write(0, LOG_MAIN, "Required TLS certificate status not received"); else - DEBUG(D_tls) debug_printf(" null\n"); + DEBUG(tls) debug_printf(" null\n"); if (!cbinfo->u_ocsp.client.verify_required) return 1; @@ -2535,7 +2535,7 @@ if (!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len))) if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN, "Received TLS cert status response, parse error"); else - DEBUG(D_tls) debug_printf(" parse error\n"); + DEBUG(tls) debug_printf(" parse error\n"); return 0; } @@ -2545,7 +2545,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response"); else - DEBUG(D_tls) debug_printf(" error parsing response\n"); + DEBUG(tls) debug_printf(" error parsing response\n"); OCSP_RESPONSE_free(rsp); return 0; } @@ -2565,7 +2565,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses; #endif - DEBUG(D_tls) bp = BIO_new(BIO_s_mem()); + DEBUG(tls) bp = BIO_new(BIO_s_mem()); /* Use the CA & chain that verified the server cert to verify the stapled info */ /*XXX could we do an event here, for observability of ocsp? What reasonable data could we give access to? */ @@ -2583,7 +2583,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) && (have_verified_OCSP_signer = OCSP_resp_get0_signer(bs, &signer, SSL_get0_verified_chain(ssl)) == 1)) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("signer for OCSP basicres is in the verified chain;" " shortcut its verification\n"); } @@ -2605,7 +2605,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) } } - DEBUG(D_tls) + DEBUG(tls) { debug_printf("Untrusted intermediate cert stack (from SSL_get_peer_cert_chain()):\n"); x509_stack_dump_cert_s_names(SSL_get_peer_cert_chain(ssl)); @@ -2672,7 +2672,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) #endif OCSP_NOEXPLICIT)) <= 0) { - DEBUG(D_tls) debug_printf("OCSP_basic_verify() fail: returned %d\n", i); + DEBUG(tls) debug_printf("OCSP_basic_verify() fail: returned %d\n", i); if (ERR_peek_error()) { tls_out.ocsp = OCSP_FAILED; @@ -2695,7 +2695,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) deliver_host_address, deliver_host, (int)sizeof(peerdn), peerdn, errstr); } - DEBUG(D_tls) + DEBUG(tls) { uschar * s = NULL; int flen; @@ -2709,11 +2709,11 @@ if (!(bs = OCSP_response_get1_basic(rsp))) goto failed; } else - DEBUG(D_tls) debug_printf("no explicit trust for OCSP signing" + DEBUG(tls) debug_printf("no explicit trust for OCSP signing" " in the root CA certificate; ignoring\n"); } - DEBUG(D_tls) debug_printf("OCSP response well-formed and signed OK\n"); + DEBUG(tls) debug_printf("OCSP response well-formed and signed OK\n"); /*XXX So we have a good stapled OCSP status. How do we know it is for the cert of interest? OpenSSL 1.1.0 has a routine @@ -2744,7 +2744,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) status = OCSP_single_get0_status(single, &reason, &rev, &thisupd, &nextupd); - DEBUG(D_tls) + DEBUG(tls) { time_print(bp, "This OCSP Update", thisupd); if (nextupd) time_print(bp, "Next OCSP Update", nextupd); @@ -2753,14 +2753,14 @@ if (!(bs = OCSP_response_get1_basic(rsp))) EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE)) { tls_out.ocsp = OCSP_FAILED; - DEBUG(D_tls) ERR_print_errors(bp); + DEBUG(tls) ERR_print_errors(bp); cbinfo->u_ocsp.client.verify_errstr = US"(SSL_connect) Server certificate status is out-of-date"; log_write(0, LOG_MAIN, "OCSP dates invalid"); goto failed; } - DEBUG(D_tls) BIO_printf(bp, "Certificate status: %s\n", + DEBUG(tls) BIO_printf(bp, "Certificate status: %s\n", OCSP_cert_status_str(status)); switch(status) { @@ -2772,7 +2772,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) log_write(0, LOG_MAIN, "Server certificate revoked%s%s", reason != -1 ? "; reason: " : "", reason != -1 ? OCSP_crl_reason_str(reason) : ""); - DEBUG(D_tls) time_print(bp, "Revocation Time", rev); + DEBUG(tls) time_print(bp, "Revocation Time", rev); break; default: cbinfo->u_ocsp.client.verify_errstr = @@ -2793,7 +2793,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) tls_out.ocsp = OCSP_FAILED; i = cbinfo->u_ocsp.client.verify_required ? 0 : 1; good: - DEBUG(D_tls) + DEBUG(tls) { uschar * s = NULL; int dlen = (int) BIO_get_mem_data(bp, CSS &s); @@ -2921,7 +2921,7 @@ if (init_options) /* Should the server offer session resumption? */ if (!host && verify_check_host(&tls_resumption_hosts) == OK) { - DEBUG(D_tls) debug_printf("tls_resumption_hosts overrides openssl_options\n"); + DEBUG(tls) debug_printf("tls_resumption_hosts overrides openssl_options\n"); init_options &= ~SSL_OP_NO_TICKET; tlsp->resumption |= RESUME_SERVER_TICKET; /* server will give ticket on request */ tlsp->host_resumable = TRUE; @@ -2931,7 +2931,7 @@ if (init_options) #ifdef OPENSSL_MIN_PROTO_VERSION SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); #endif - DEBUG(D_tls) debug_printf("setting SSL CTX options: %016lx\n", init_options); + DEBUG(tls) debug_printf("setting SSL CTX options: %016lx\n", init_options); SSL_CTX_set_options(ctx, init_options); { uint64_t readback = SSL_CTX_clear_options(ctx, ~init_options); @@ -2941,7 +2941,7 @@ if (init_options) } } else - DEBUG(D_tls) debug_printf("no SSL CTX options to set\n"); + DEBUG(tls) debug_printf("no SSL CTX options to set\n"); /* We'd like to disable session cache unconditionally, but foolish Outlook Express clients then give up the first TLS connection and make a second one @@ -2959,12 +2959,12 @@ will never be used because we use a new context every time. */ if (!host) { if (state->lib_state.dh) - { DEBUG(D_tls) debug_printf("TLS: DH params were preloaded\n"); } + { DEBUG(tls) debug_printf("TLS: DH params were preloaded\n"); } else if (!init_dh(ctx, state->dhparam, errstr)) return DEFER; if (state->lib_state.ecdh) - { DEBUG(D_tls) debug_printf("TLS: ECDH curve was preloaded\n"); } + { DEBUG(tls) debug_printf("TLS: ECDH curve was preloaded\n"); } else if (!init_ecdh(ctx, errstr)) return DEFER; } @@ -2973,7 +2973,7 @@ if (!host) if (state->lib_state.conn_certs) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("TLS: %s certs were preloaded\n", host ? "client":"server"); } else @@ -2994,7 +2994,7 @@ else #ifndef DISABLE_OCSP if (!host && !(state->u_ocsp.server.verify_stack = sk_X509_new_null())) { - DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n"); + DEBUG(tls) debug_printf("failed to create stack for stapling verify\n"); return FAIL; } #endif @@ -3038,7 +3038,7 @@ else /* client */ { if (!(state->u_ocsp.client.verify_store = X509_STORE_new())) { - DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n"); + DEBUG(tls) debug_printf("failed to create store for stapling verify\n"); return FAIL; } @@ -3058,7 +3058,7 @@ SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback); The period appears to be also used for (server-generated) session tickets */ SSL_CTX_set_timeout(ctx, ssl_session_timeout); -DEBUG(D_tls) debug_printf("Initialized TLS\n"); +DEBUG(tls) debug_printf("Initialized TLS\n"); *caller_state = state; @@ -3105,7 +3105,7 @@ store_pool = POOL_PERM; s = string_sprintf("%s:%s:%u", ver, SSL_CIPHER_get_name(c), *bits); } store_pool = pool; -DEBUG(D_tls) debug_printf("Cipher: %s\n", s); +DEBUG(tls) debug_printf("Cipher: %s\n", s); return s; } @@ -3154,7 +3154,7 @@ if (!tlsp->peercert) /* Beware anonymous ciphers which lead to server_cert being NULL */ if (tlsp->peercert) if (!X509_NAME_oneline(X509_get_subject_name(tlsp->peercert), CS peerdn, siz)) - { DEBUG(D_tls) debug_printf("X509_NAME_oneline() error\n"); } + { DEBUG(tls) debug_printf("X509_NAME_oneline() error\n"); } else { peerdn[siz-1] = '\0'; /* paranoia */ @@ -3233,7 +3233,7 @@ uschar * expcerts, * expcrl; if (!expand_check(*certsp, US"tls_verify_certificates", &expcerts, errstr)) return DEFER; -DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts); +DEBUG(tls) debug_printf("tls_verify_certificates: %s\n", expcerts); *certsp = expcerts; if (expcerts && *expcerts) @@ -3316,11 +3316,11 @@ This is inconsistent with the need to verify the OCSP proof of the server cert. int i = sk_X509_NAME_num(names); if (!host) SSL_CTX_set_client_CA_list(sctx, names); - DEBUG(D_tls) debug_printf("Added %d additional certificate authorit%s\n", + DEBUG(tls) debug_printf("Added %d additional certificate authorit%s\n", i, i>1 ? "ies":"y"); } else - DEBUG(D_tls) + DEBUG(tls) debug_printf("Added dir for additional certificate authorities\n"); } } @@ -3356,13 +3356,13 @@ This is inconsistent with the need to verify the OCSP proof of the server cert. { file = NULL; dir = expcrl; - DEBUG(D_tls) debug_printf("SSL CRL value is a directory %s\n", dir); + DEBUG(tls) debug_printf("SSL CRL value is a directory %s\n", dir); } else { file = expcrl; dir = NULL; - DEBUG(D_tls) debug_printf("SSL CRL value is a file %s\n", file); + DEBUG(tls) debug_printf("SSL CRL value is a file %s\n", file); } if (X509_STORE_load_locations(cvstore, CS file, CS dir) == 0) return tls_error(US"X509_STORE_load_locations", host, NULL, errstr); @@ -3440,7 +3440,7 @@ if (len > 0) store_pool = POOL_PERM; tlsp->channelbinding = b64encode_taint(CUS s, (int)len, taintval); store_pool = old_pool; - DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp); + DEBUG(tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp); } } @@ -3508,7 +3508,7 @@ TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 */ if (state_server.lib_state.pri_string) - { DEBUG(D_tls) debug_printf("TLS: cipher list was preloaded\n"); } + { DEBUG(tls) debug_printf("TLS: cipher list was preloaded\n"); } else { if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, errstr)) @@ -3546,7 +3546,7 @@ verify_client_cert = TRUE; if (state_server.lib_state.cabundle) { - DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); + DEBUG(tls) debug_printf("TLS: CA bundle for server was preloaded\n"); setup_cert_verify(ctx, server_verify_optional, verify_callback_server); } else @@ -3627,7 +3627,7 @@ if ( tls_in.on_connect /* Not usable for STARTTLS */ case SSL_READ_EARLY_DATA_ERROR: { int err = SSL_get_error(ssl, SSL_READ_EARLY_DATA_ERROR); - DEBUG(D_tls) debug_printf("SSL_read_early_data: %d\n", err); + DEBUG(tls) debug_printf("SSL_read_early_data: %d\n", err); if (err == SSL_ERROR_SYSCALL) { if (!errno) @@ -3638,17 +3638,17 @@ if ( tls_in.on_connect /* Not usable for STARTTLS */ #endif return FAIL; } - DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno)); + DEBUG(tls) debug_printf(" - syscall %s\n", strerror(errno)); } return tls_error(US"SSL_read_early_data", NULL, NULL, errstr); } case SSL_READ_EARLY_DATA_SUCCESS: - DEBUG(D_tls) debug_printf("TLS: unexpected early data from client!\n"); + DEBUG(tls) debug_printf("TLS: unexpected early data from client!\n"); return tls_error(US"SSL_read_early_data", NULL, NULL, errstr); case SSL_READ_EARLY_DATA_FINISH: - DEBUG(D_tls) debug_printf("TLS: No early-data from client; good\n"); + DEBUG(tls) debug_printf("TLS: No early-data from client; good\n"); } if ( SSL_version(ssl) > TLS1_2_VERSION /* not sure is safe pre 1.3 */ @@ -3661,22 +3661,22 @@ if ( tls_in.on_connect /* Not usable for STARTTLS */ int len = gstring_length(banner); size_t n_bytes; - DEBUG(D_tls) debug_printf("TLS: writing early-data\n"); + DEBUG(tls) debug_printf("TLS: writing early-data\n"); if (!SSL_write_early_data(ssl, banner->s, len, &n_bytes)) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("SSL_write_early_data: %d\n", SSL_get_error(ssl, 0)); return tls_error(US"SSL_write_early_data", NULL, NULL, errstr); } if (n_bytes != len) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("SSL_write_early_data: wrote %d (expected %d)\n", (int)n_bytes, len); return tls_error(US"SSL_write_early_data", NULL, NULL, errstr); } - DEBUG(D_receive) + DEBUG(receive) { gstring_trim(banner, 2); debug_printf("SMTP>> %Y\n", banner); } /* Ensure smtp_start_session does not repeat the banner */ @@ -3686,7 +3686,7 @@ if ( tls_in.on_connect /* Not usable for STARTTLS */ } # endif /*EXIM_TLS_EARLY_BANNER*/ -DEBUG(D_tls) debug_printf("Calling SSL_accept\n"); +DEBUG(tls) debug_printf("Calling SSL_accept\n"); ERR_clear_error(); sigalrm_seen = FALSE; @@ -3703,7 +3703,7 @@ if (rc <= 0) break; case SSL_ERROR_ZERO_RETURN: - DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); + DEBUG(tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr); #ifndef DISABLE_EVENT (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL); @@ -3735,7 +3735,7 @@ if (rc <= 0) default: { uschar * s; - DEBUG(D_tls) debug_printf("Got SSL error %d\n", error); + DEBUG(tls) debug_printf("Got SSL error %d\n", error); if (error == SSL_ERROR_SYSCALL) { if (!errno) @@ -3747,7 +3747,7 @@ if (rc <= 0) return FAIL; } s = string_sprintf("syscall %s", strerror(errno)); - DEBUG(D_tls) debug_printf(" - %s\n", s); + DEBUG(tls) debug_printf(" - %s\n", s); } else s = string_sprintf("ret %d", error); @@ -3763,7 +3763,7 @@ if (rc <= 0) } } -DEBUG(D_tls) debug_printf("SSL_accept was successful\n"); +DEBUG(tls) debug_printf("SSL_accept was successful\n"); ERR_clear_error(); /* Even success can leave errors in the stack. Seen with anon-authentication ciphersuite negotiated. */ @@ -3771,14 +3771,14 @@ ERR_clear_error(); /* Even success can leave errors in the stack. Seen with if (SSL_session_reused(ssl)) { tls_in.resumption |= RESUME_USED; - DEBUG(D_tls) debug_printf("Session reused\n"); + DEBUG(tls) debug_printf("Session reused\n"); } #endif #ifdef EXIM_HAVE_ALPN /* If require-alpn, check server_seen_alpn here. Else abort TLS */ if (!tls_alpn || !*tls_alpn) - { DEBUG(D_tls) debug_printf("TLS: was not watching for ALPN\n"); } + { DEBUG(tls) debug_printf("TLS: was not watching for ALPN\n"); } else if (server_fail_alpn) { uschar * s = string_sprintf("Bad ALPN presented (%Y)", server_fail_alpn); @@ -3795,8 +3795,8 @@ else if (!server_seen_alpn) return FAIL; } else - { DEBUG(D_tls) debug_printf("TLS: no ALPN presented in handshake\n"); } -else DEBUG(D_tls) + { DEBUG(tls) debug_printf("TLS: no ALPN presented in handshake\n"); } +else DEBUG(tls) { const uschar * name; unsigned len; @@ -3826,7 +3826,7 @@ tls_in.ver = tlsver_name(ssl); tls_in.cipher = construct_cipher_name(ssl, tls_in.ver, &tls_in.bits); tls_in.cipher_stdname = cipher_stdname_ssl(ssl); -DEBUG(D_tls) +DEBUG(tls) { uschar buf[2048]; if (SSL_get_shared_ciphers(ssl, CS buf, sizeof(buf))) @@ -3908,7 +3908,7 @@ else if (state->lib_state.cabundle) { - DEBUG(D_tls) debug_printf("TLS: CA bundle for tpt was preloaded\n"); + DEBUG(tls) debug_printf("TLS: CA bundle for tpt was preloaded\n"); setup_cert_verify(ctx, client_verify_optional, verify_callback_client); } else @@ -3928,7 +3928,7 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) #else host->certname; #endif - DEBUG(D_tls) debug_printf("Cert hostname to check: %q\n", + DEBUG(tls) debug_printf("Cert hostname to check: %q\n", state->verify_cert_hostnames); } return OK; @@ -4007,7 +4007,7 @@ if (tlsp->host_resumable) open_db dbblock, * dbm_file; tlsp->resumption |= RESUME_CLIENT_REQUESTED; - DEBUG(D_tls) + DEBUG(tls) debug_printf("checking for resumable session for %s\n", tlsp->resume_index); if ((dbm_file = dbfn_open(US"tls", O_RDWR|O_CREAT, &dbblock, FALSE, FALSE))) { @@ -4019,7 +4019,7 @@ if (tlsp->host_resumable) len -= sizeof(dbdata_tls_session); if (!(d2i_SSL_SESSION(&ss, &sess_asn1, (long)len))) { - DEBUG(D_tls) + DEBUG(tls) { ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); @@ -4037,17 +4037,17 @@ if (tlsp->host_resumable) time_t now = time(NULL), expires = lifetime + dt->gen.time_stamp; if (expires < now) { - DEBUG(D_tls) debug_printf("session expired (by " TIME_T_FMT "s from %lus)\n", now - expires, lifetime); + DEBUG(tls) debug_printf("session expired (by " TIME_T_FMT "s from %lus)\n", now - expires, lifetime); dbfn_delete(dbm_file, tlsp->resume_index); } else if (SSL_set_session(ssl, ss)) { - DEBUG(D_tls) debug_printf("good session (" TIME_T_FMT "s left of %lus)\n", expires - now, lifetime); + DEBUG(tls) debug_printf("good session (" TIME_T_FMT "s left of %lus)\n", expires - now, lifetime); tlsp->resumption |= RESUME_CLIENT_SUGGESTED; tlsp->verify_override = dt->verify_override; tlsp->ocsp = dt->ocsp; } - else DEBUG(D_tls) + else DEBUG(tls) { ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); @@ -4056,7 +4056,7 @@ if (tlsp->host_resumable) } } else - DEBUG(D_tls) debug_printf("no session record\n"); + DEBUG(tls) debug_printf("no session record\n"); dbfn_close(dbm_file); } } @@ -4071,7 +4071,7 @@ tls_save_session_cb(SSL * ssl, SSL_SESSION * ss) exim_openssl_state_st * cbinfo = SSL_get_ex_data(ssl, tls_exdata_idx); tls_support * tlsp; -DEBUG(D_tls) debug_printf("tls_save_session_cb\n"); +DEBUG(tls) debug_printf("tls_save_session_cb\n"); if (!cbinfo || !(tlsp = cbinfo->tlsp)->host_resumable) return 0; @@ -4085,7 +4085,7 @@ if (SSL_SESSION_is_resumable(ss)) /* 1.1.1 */ uschar * s = dt->session; open_db dbblock, * dbm_file; - DEBUG(D_tls) debug_printf("session is resumable\n"); + DEBUG(tls) debug_printf("session is resumable\n"); tlsp->resumption |= RESUME_SERVER_TICKET; /* server gave us a ticket */ dt->verify_override = tlsp->verify_override; @@ -4096,7 +4096,7 @@ if (SSL_SESSION_is_resumable(ss)) /* 1.1.1 */ { dbfn_write(dbm_file, tlsp->resume_index, dt, dlen); dbfn_close(dbm_file); - DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n", + DEBUG(tls) debug_printf("wrote session (len %u) to db\n", (unsigned)dlen); } } @@ -4127,7 +4127,7 @@ tls_client_ssl_resume_prehandshake(SSL * ssl, tls_support * tlsp, { if (tlsp->host_resumable) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("tls_resumption_hosts overrides openssl_options, enabling tickets\n"); SSL_clear_options(ssl, SSL_OP_NO_TICKET); @@ -4152,7 +4152,7 @@ tls_client_resume_posthandshake(exim_openssl_client_tls_ctx * exim_client_ctx, { if (SSL_session_reused(exim_client_ctx->ssl)) { - DEBUG(D_tls) debug_printf("The session was reused\n"); + DEBUG(tls) debug_printf("The session was reused\n"); tlsp->resumption |= RESUME_USED; } } @@ -4178,7 +4178,7 @@ if (!expand_check(*tls_alpn, US"tls_alpn", &exp_alpn, errstr)) if (!exp_alpn) { - DEBUG(D_tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n"); + DEBUG(tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n"); *plist = NULL; } else @@ -4276,7 +4276,7 @@ tlsp->tlsa_usage = 0; # if defined(SUPPORT_DANE) && !defined(EXIM_HAVE_OPENSSL_OCSP_RESP_GET0_SIGNER) if (conn_args->dane && (require_ocsp || request_ocsp)) { - DEBUG(D_tls) debug_printf("OpenSSL version to early to combine OCSP" + DEBUG(tls) debug_printf("OpenSSL version to early to combine OCSP" " and DANE; disabling OCSP\n"); require_ocsp = request_ocsp = FALSE; } @@ -4327,7 +4327,7 @@ if (!expciphers) if (expciphers) { - DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers); + DEBUG(tls) debug_printf("required ciphers: %s\n", expciphers); if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers)) { tls_error(US"SSL_CTX_set_cipher_list", host, NULL, errstr); @@ -4352,7 +4352,7 @@ if (conn_args->dane) tls_error(US"context init", host, NULL, errstr); return FALSE; } - DEBUG(D_tls) debug_printf("since dane-mode conn, not loading the usual CA bundle\n"); + DEBUG(tls) debug_printf("since dane-mode conn, not loading the usual CA bundle\n"); } else @@ -4367,7 +4367,7 @@ if (ob->tls_sni) if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr)) return FALSE; if (!tlsp->sni) - { DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n"); } + { DEBUG(tls) debug_printf("Setting TLS SNI forced to fail, not sending\n"); } else if (!Ustrlen(tlsp->sni)) tlsp->sni = NULL; } @@ -4387,7 +4387,7 @@ if (ob->tls_alpn) return FALSE; } else - DEBUG(D_tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); + DEBUG(tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); } #else log_write(0, LOG_MAIN, @@ -4400,7 +4400,7 @@ if (ob->tls_alpn) will be very low. */ if (!conn_args->have_lbserver) /* wanted for tls_client_resmption_key() */ - { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); } + { DEBUG(tls) debug_printf("resumption not supported on continued-connection\n"); } else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK) tls_client_ctx_resume_prehandshake(exim_client_ctx, conn_args, tlsp, ob); #endif @@ -4417,7 +4417,7 @@ SSL_set_connect_state(exim_client_ctx->ssl); if (tlsp->sni) { - DEBUG(D_tls) debug_printf("Setting TLS SNI %q\n", tlsp->sni); + DEBUG(tls) debug_printf("Setting TLS SNI %q\n", tlsp->sni); SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni); } @@ -4467,7 +4467,7 @@ client_static_state->event_action = tb ? tb->event_action : NULL; /* There doesn't seem to be a built-in timeout on connection. */ -DEBUG(D_tls) debug_printf("Calling SSL_connect\n"); +DEBUG(tls) debug_printf("Calling SSL_connect\n"); sigalrm_seen = FALSE; ALARM(ob->command_timeout); rc = SSL_connect(exim_client_ctx->ssl); @@ -4489,7 +4489,7 @@ if (rc <= 0) return FALSE; } -DEBUG(D_tls) +DEBUG(tls) { debug_printf("SSL_connect succeeded\n"); tls_dump_keylog(exim_client_ctx->ssl); @@ -4507,7 +4507,7 @@ if (ob->tls_alpn) /* We requested. See what was negotiated. */ SSL_get0_alpn_selected(exim_client_ctx->ssl, &name, &len); if (len > 0) - { DEBUG(D_tls) debug_printf("ALPN negotiated %u: '%.*s'\n", len, (int)*name, name+1); } + { DEBUG(tls) debug_printf("ALPN negotiated %u: '%.*s'\n", len, (int)*name, name+1); } else if (verify_check_given_host(CUSS &ob->hosts_require_alpn, host) == OK) { /* Would like to send a relevant fatal Alert, but OpenSSL has no API */ @@ -4551,7 +4551,7 @@ tls_refill(unsigned lim) SSL * ssl = state_server.lib_state.lib_ssl; int error, inbytes; -DEBUG(D_tls) debug_printf("Calling SSL_read(tls_refill %p, %p, %u)\n", +DEBUG(tls) debug_printf("Calling SSL_read(tls_refill %p, %p, %u)\n", ssl, ssl_xfer_buffer, ssl_xfer_buffer_size); ERR_clear_error(); @@ -4580,7 +4580,7 @@ switch(error) break; case SSL_ERROR_ZERO_RETURN: - DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); + DEBUG(tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN) SSL_shutdown(ssl); @@ -4596,14 +4596,14 @@ switch(error) /* I'd like to get separated H= here, but too hard for now */ ERR_error_string_n(ERR_peek_error(), ssl_errstring, sizeof(ssl_errstring)); log_write(0, LOG_MAIN, "TLS error (SSL_read): on %s %s", conn_info, ssl_errstring); - DEBUG(D_tls) tls_debug_err(ssl, US"SSL_read", inbytes); + DEBUG(tls) tls_debug_err(ssl, US"SSL_read", inbytes); ssl_xfer_error = TRUE; return FALSE; } default: - DEBUG(D_tls) debug_printf("Got SSL error %d\n", error); - DEBUG(D_tls) if (error == SSL_ERROR_SYSCALL) + DEBUG(tls) debug_printf("Got SSL error %d\n", error); + DEBUG(tls) if (error == SSL_ERROR_SYSCALL) debug_printf(" - syscall %s\n", strerror(errno)); ssl_xfer_error = TRUE; return FALSE; @@ -4724,7 +4724,7 @@ SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl int inbytes; int error; -DEBUG(D_tls) debug_printf("Calling SSL_read(tls_read %p, %p, %u)\n", +DEBUG(tls) debug_printf("Calling SSL_read(tls_read %p, %p, %u)\n", ssl, buff, (unsigned int)len); ERR_clear_error(); @@ -4734,7 +4734,7 @@ error = SSL_get_error(ssl, inbytes); if (error == SSL_ERROR_NONE) return inbytes; -else DEBUG(D_tls) +else DEBUG(tls) if (error == SSL_ERROR_ZERO_RETURN) debug_printf("Got SSL_ERROR_ZERO_RETURN\n"); else @@ -4778,7 +4778,7 @@ gstring ** corkedp = ct_ctx ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked; gstring * corked = *corkedp; -DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, +DEBUG(tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__, buff, (unsigned long)len, more ? ", more" : ""); /* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when @@ -4814,11 +4814,11 @@ if (more || corked) for (int left = len; left > 0;) { - DEBUG(D_tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left); + DEBUG(tls) debug_printf("SSL_write(%p, %p, %d)\n", ssl, buff, left); ERR_clear_error(); outbytes = SSL_write(ssl, CS buff, left); error = SSL_get_error(ssl, outbytes); - DEBUG(D_tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); + DEBUG(tls) debug_printf("outbytes=%d error=%d\n", outbytes, error); switch (error) { case SSL_ERROR_NONE: /* the usual case */ @@ -4837,7 +4837,7 @@ for (int left = len; left > 0;) case SSL_ERROR_SYSCALL: if (errno == 0) - { DEBUG(D_tls) debug_printf("- SSL_ERROR_SYSCALL with zero errno\n"); } + { DEBUG(tls) debug_printf("- SSL_ERROR_SYSCALL with zero errno\n"); } else if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit) log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s", sender_fullhost ? sender_fullhost : US"", @@ -4846,7 +4846,7 @@ for (int left = len; left > 0;) log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before" " SMTP response and TLS close\n", sender_host_address); else - DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT," + DEBUG(tls) debug_printf("[%s] SSL_write: after QUIT," " client reset TCP before TLS close\n", sender_host_address); return -1; @@ -4877,10 +4877,10 @@ if ((o_ctx ? tls_out.active.sock : tls_in.active.sock) < 0) tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ -HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent(" SMTP(TLS shutdown)>>\n"); +HDEBUG(transport|tls|acl|v) debug_printf_indent(" SMTP(TLS shutdown)>>\n"); ERR_clear_error(); if ((rc = SSL_shutdown(ssl)) < 0) - DEBUG(D_tls) tls_debug_err(ssl, US"SSL_shutdown", rc); + DEBUG(tls) tls_debug_err(ssl, US"SSL_shutdown", rc); } /************************************************* @@ -4914,7 +4914,7 @@ if (*fdp < 0) return; /* TLS was not active */ if (do_shutdown > TLS_NO_SHUTDOWN) { int rc; - DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", + DEBUG(tls) debug_printf("tls_close(): shutting down TLS%s\n", do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : ""); tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ @@ -4934,7 +4934,7 @@ if (do_shutdown > TLS_NO_SHUTDOWN) ALARM_CLR(0); } - if (rc < 0) DEBUG(D_tls) tls_debug_err(*sslp, US"SSL_shutdown", rc); + if (rc < 0) DEBUG(tls) tls_debug_err(*sslp, US"SSL_shutdown", rc); } if (!o_ctx) /* server side */ @@ -4997,7 +4997,7 @@ normalise_ciphers(&expciphers, tls_require_ciphers); err = NULL; if (lib_ctx_new(&ctx, NULL, &err) == OK) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("tls_require_ciphers expands to %q\n", expciphers); if (!SSL_CTX_set_cipher_list(ctx, CS expciphers)) @@ -5124,7 +5124,7 @@ i = RAND_bytes(smallbuf, needed_len); if (i < 0) { - DEBUG(D_all) + DEBUG(all) debug_printf("OpenSSL RAND_pseudo_bytes() not supported by RAND method, using fallback.\n"); return vaguely_random_number_fallback(max); } @@ -5234,7 +5234,7 @@ for (uschar * s = exp; *s; /**/) break; if (*s != '+' && *s != '-') { - DEBUG(D_tls) debug_printf("malformed openssl option setting: " + DEBUG(tls) debug_printf("malformed openssl option setting: " "+ or - expected but found %q\n", s); return FALSE; } @@ -5244,10 +5244,10 @@ for (uschar * s = exp; *s; /**/) item_parsed = tls_openssl_one_option_parse(string_copyn(s, end-s), &item); if (!item_parsed) { - DEBUG(D_tls) debug_printf("openssl option setting unrecognised: %q\n", s); + DEBUG(tls) debug_printf("openssl option setting unrecognised: %q\n", s); return FALSE; } - DEBUG(D_tls) debug_printf("openssl option, %s %08lx: %08lx (%s)\n", + DEBUG(tls) debug_printf("openssl option, %s %08lx: %08lx (%s)\n", adding ? "adding to " : "removing from", result, item, s); if (adding) result |= item; diff --git a/src/src/tls.c b/src/src/tls.c index b79828e95..e280a1f3e 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -168,13 +168,13 @@ if (errno != EINVAL) /* not a symlink */ s = string_copyn(filename, s - filename); /* mem released by tls_set_watch */ -DEBUG(D_tls) debug_printf("watch dir '%s'\n", s); +DEBUG(tls) debug_printf("watch dir '%s'\n", s); if (inotify_add_watch(tls_watch_fd, CCS s, IN_ONESHOT | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF) >= 0) return TRUE; -DEBUG(D_tls) debug_printf("notify_add_watch: %s\n", strerror(errno)); +DEBUG(tls) debug_printf("notify_add_watch: %s\n", strerror(errno)); return FALSE; } # endif @@ -207,7 +207,7 @@ for (;;) { if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0) { s = US"open file"; goto bad; } - DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1); + DEBUG(tls) debug_printf("watch file '%s':\t%d\n", filename, fd1); EV_SET(&kev[kev_used++], (uintptr_t)fd1, EVFILT_VNODE, @@ -218,7 +218,7 @@ for (;;) NULL); cnt++; } - DEBUG(D_tls) debug_printf("watch dir '%s':\t%d\n", s, fd2); + DEBUG(tls) debug_printf("watch dir '%s':\t%d\n", s, fd2); EV_SET(&kev[kev_used++], (uintptr_t)fd2, EVFILT_VNODE, @@ -251,7 +251,7 @@ if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, NULL, 0, NULL) >= 0) s = US"kevent"; bad: -DEBUG(D_tls) +DEBUG(tls) if (errno) debug_printf("%s: %s: %s\n", __FUNCTION__, s, strerror(errno)); else @@ -274,7 +274,7 @@ BOOL rc = FALSE; if (!filename || !*filename) return TRUE; if (Ustrncmp(filename, "system", 6) == 0) return TRUE; -DEBUG(D_tls) debug_printf("tls_set_watch: '%s'\n", filename); +DEBUG(tls) debug_printf("tls_set_watch: '%s'\n", filename); if ( tls_watch_fd < 0 # ifdef EXIM_HAVE_INOTIFY @@ -285,7 +285,7 @@ if ( tls_watch_fd < 0 # endif ) { - DEBUG(D_tls) debug_printf("inotify_init: %s\n", strerror(errno)); + DEBUG(tls) debug_printf("inotify_init: %s\n", strerror(errno)); return FALSE; } @@ -301,7 +301,7 @@ else rc = tls_set_one_watch(filename); store_reset(r); -if (!rc) DEBUG(D_tls) debug_printf("tls_set_watch() fail on '%s': %s\n", filename, strerror(errno)); +if (!rc) DEBUG(tls) debug_printf("tls_set_watch() fail on '%s': %s\n", filename, strerror(errno)); return rc; } @@ -345,7 +345,7 @@ if (tls_watch_fd < 0) return; /* Close the files we had open for kevent */ for (int i = 0; i < kev_used; i++) { - DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident); + DEBUG(tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident); (void) close((int) kev[i].ident); kev[i].ident = (uintptr_t)-1; } @@ -409,7 +409,7 @@ if (tls_creds_expire && time(NULL) >= tls_creds_expire) generate a new one. Reload the rest of the creds also as the machinery is all there. */ - DEBUG(D_tls) debug_printf("selfsign cert rotate\n"); + DEBUG(tls) debug_printf("selfsign cert rotate\n"); tls_creds_expire = 0; tls_daemon_creds_reload(); return old_watch_fd; @@ -421,7 +421,7 @@ else if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5) Dump the set of watches and arrange to reload cached creds (which will set up new watches). */ - DEBUG(D_tls) debug_printf("watch triggered\n"); + DEBUG(tls) debug_printf("watch triggered\n"); tls_watch_trigger_time = tls_creds_expire = 0; tls_daemon_creds_reload(); return old_watch_fd; @@ -686,18 +686,18 @@ int cmp_sep = 0; if ((altnames = tls_cert_subject_altname(cert, US"dns"))) { int alt_sep = '\n'; - DEBUG(D_tls|D_lookup) debug_printf_indent("cert has SAN\n"); + DEBUG(tls|lookup) debug_printf_indent("cert has SAN\n"); while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))) { const uschar * an = altnames; - DEBUG(D_tls|D_lookup) debug_printf_indent(" %s in SANs?", cmpname); + DEBUG(tls|lookup) debug_printf_indent(" %s in SANs?", cmpname); while ((certname = string_nextinlist(&an, &alt_sep, NULL, 0))) if (is_name_match(cmpname, certname)) { - DEBUG(D_tls|D_lookup) debug_printf_indent(" yes (matched %s)\n", certname); + DEBUG(tls|lookup) debug_printf_indent(" yes (matched %s)\n", certname); return TRUE; } - DEBUG(D_tls|D_lookup) debug_printf_indent(" no (end of SAN list)\n"); + DEBUG(tls|lookup) debug_printf_indent(" no (end of SAN list)\n"); } } @@ -709,7 +709,7 @@ else if ((subjdn = tls_cert_subject(cert, NULL))) while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0))) { const uschar * sn = subjdn; - DEBUG(D_tls|D_lookup) debug_printf_indent(" %s in SN?", cmpname); + DEBUG(tls|lookup) debug_printf_indent(" %s in SN?", cmpname); while ((certname = string_nextinlist(&sn, &sn_sep, NULL, 0))) if ( *certname++ == 'C' && *certname++ == 'N' @@ -717,10 +717,10 @@ else if ((subjdn = tls_cert_subject(cert, NULL))) && is_name_match(cmpname, certname) ) { - DEBUG(D_tls|D_lookup) debug_printf_indent(" yes (matched %s)\n", certname); + DEBUG(tls|lookup) debug_printf_indent(" yes (matched %s)\n", certname); return TRUE; } - DEBUG(D_tls|D_lookup) debug_printf_indent(" no (end of CN)\n"); + DEBUG(tls|lookup) debug_printf_indent(" no (end of CN)\n"); } } return FALSE; @@ -747,13 +747,13 @@ if (path) unsetenv("SSLKEYLOGFILE"); else if (*path != '/') { - DEBUG(D_tls) + DEBUG(tls) debug_printf("prepending spooldir to env SSLKEYLOGFILE\n"); setenv("SSLKEYLOGFILE", CCS string_sprintf("%s/%s", spool_directory, path), 1); } else if (Ustrncmp(path, spool_directory, Ustrlen(spool_directory)) != 0) { - DEBUG(D_tls) + DEBUG(tls) debug_printf("removing env SSLKEYLOGFILE=%s: not under spooldir\n", path); unsetenv("SSLKEYLOGFILE"); } @@ -819,7 +819,7 @@ do { rc = waitpid(pid, &status, 0); } while (rc < 0 && errno == EINTR); -DEBUG(D_tls) +DEBUG(tls) debug_printf("tls_validate_require_cipher child " PID_T_FMT " ended: status=0x%x\n", pid, status); @@ -839,7 +839,7 @@ tls_client_resmption_key(tls_support * tlsp, hctx * h = &tlsp->resume_hctx; blob b; -DEBUG(D_tls) if (conn_args->host_lbserver) +DEBUG(tls) if (conn_args->host_lbserver) debug_printf("TLS: lbserver '%s'\n", conn_args->host_lbserver); # ifdef EXIM_HAVE_SHA2 @@ -863,7 +863,7 @@ exim_sha_update_string(h, ob->tls_alpn); # endif exim_sha_finish(h, &b); tlsp->resume_index = string_sprintf("%.*H", (int)b.len, b.data); -DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index); +DEBUG(tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index); #endif } diff --git a/src/src/transport.c b/src/src/transport.c index 6700cb8b6..371ce2cd9 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -300,7 +300,7 @@ normal cases, it is only ever executed once. */ for (int i = 0; i < 100; i++) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("writing data block fd=%d size=%d timeout=%d%s\n", fd, len, local_timeout, more ? " (more expected)" : ""); @@ -353,7 +353,7 @@ for (int i = 0; i < 100; i++) len -= rc; block += rc; transport_count += rc; - DEBUG(D_transport) debug_printf("write incomplete (%d)\n", rc); + DEBUG(transport) debug_printf("write incomplete (%d)\n", rc); goto CHECK_TIMEOUT; /* A few lines below */ } @@ -362,7 +362,7 @@ for (int i = 0; i < 100; i++) if (save_errno == EINTR) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("write interrupted before anything written\n"); goto CHECK_TIMEOUT; /* A few lines below */ } @@ -372,7 +372,7 @@ for (int i = 0; i < 100; i++) if (save_errno == EAGAIN) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("write temporarily locked out, waiting 1 sec\n"); sleep(1); @@ -390,7 +390,7 @@ for (int i = 0; i < 100; i++) /* Otherwise there's been an error */ - DEBUG(D_transport) debug_printf("writing error %d: %s\n", save_errno, + DEBUG(transport) debug_printf("writing error %d: %s\n", save_errno, strerror(save_errno)); errno = save_errno; return FALSE; @@ -548,7 +548,7 @@ for (const uschar * ptr = start; ptr < end; ptr++) if ((fl_len = chunk_ptr - deliver_out_buffer) > mlen) { - DEBUG(D_transport) debug_printf("flushing headers buffer\n"); + DEBUG(transport) debug_printf("flushing headers buffer\n"); /* If CHUNKING, prefix with BDAT (size) NON-LAST. Also, reap responses from previous SMTP commands. */ @@ -861,7 +861,7 @@ for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old) /* Header removed */ else - DEBUG(D_transport) debug_printf("removed header line:\n %s---\n", h->text); + DEBUG(transport) debug_printf("removed header line:\n %s---\n", h->text); } /* Add on any address-specific headers. If there are multiple addresses, @@ -888,7 +888,7 @@ if (addr) if (i == 1) { if (!sendfn(tctx, h->text, h->slen)) return FALSE; - DEBUG(D_transport) + DEBUG(transport) debug_printf("added header line(s):\n %s---\n", h->text); } } @@ -915,7 +915,7 @@ if (tblock && (list = CUS tblock->add_headers)) if (!sendfn(tctx, s, len)) return FALSE; if (s[len-1] != '\n' && !sendfn(tctx, US"\n", 1)) return FALSE; - DEBUG(D_transport) + DEBUG(transport) { debug_printf("added header line:\n %s", s); if (s[len-1] != '\n') debug_printf("\n"); @@ -1135,7 +1135,7 @@ if (tctx->options & topt_use_bdat) if (size > DELIVER_OUT_BUFFER_SIZE && hsize > 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("sending small initial BDAT; hsize=%d\n", hsize); if ( tctx->chunk_cb(tctx, hsize, 0) != OK || !transport_write_block(tctx, deliver_out_buffer, hsize, FALSE) @@ -1185,7 +1185,7 @@ if ( f.spool_file_wireformat size -= len; } - DEBUG(D_transport) debug_printf("using sendfile for body\n"); + DEBUG(transport) debug_printf("using sendfile for body\n"); while(size > 0) { @@ -1195,10 +1195,10 @@ if ( f.spool_file_wireformat return copied >= 0; } #else -DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n"); +DEBUG(transport) debug_printf("cannot use sendfile for body: no support\n"); #endif -DEBUG(D_transport) +DEBUG(transport) if (!(tctx->options & topt_no_body)) debug_printf("cannot use sendfile for body: %s\n", !f.spool_file_wireformat ? "spoolfile not wireformat" @@ -1325,7 +1325,7 @@ write_pid = (pid_t)(-1); } if (filter_pid < 0) goto TIDY_UP; /* errno set */ -DEBUG(D_transport) debug_printf("process " PID_T_FMT +DEBUG(transport) debug_printf("process " PID_T_FMT " running as transport filter: fd_write=%d fd_read=%d\n", filter_pid, fd_write, fd_read); @@ -1380,7 +1380,7 @@ if (write_pid < 0) testharness_pause_ms(250); -DEBUG(D_transport) +DEBUG(transport) debug_printf("process "PID_T_FMT " writing to transport filter\n", write_pid); /* Copy the message from the filter to the output fd. A read error leaves len @@ -1388,7 +1388,7 @@ DEBUG(D_transport) the case when the filter gets stuck, but it can be quite a long one. The default is 5m, but this is now configurable. */ -DEBUG(D_transport) debug_printf("copying from the filter\n"); +DEBUG(transport) debug_printf("copying from the filter\n"); /* Copy the output of the filter, remembering if the last character was NL. If no data is returned, that counts as "ended with NL" (default setting of the @@ -1406,7 +1406,7 @@ for (;;) ALARM_CLR(0); if (sigalrm_seen) { - DEBUG(D_transport) debug_printf("timed out reading from filter\n"); + DEBUG(transport) debug_printf("timed out reading from filter\n"); errno = ETIMEDOUT; f.transport_filter_timed_out = TRUE; goto TIDY_UP; @@ -1450,20 +1450,20 @@ if (!yield) /* Wait for the filter process to complete. */ -DEBUG(D_transport) debug_printf("waiting for filter process\n"); +DEBUG(transport) debug_printf("waiting for filter process\n"); if (filter_pid > 0 && (rc = child_close(filter_pid, 30)) != 0 && yield) { yield = FALSE; save_errno = ERRNO_FILTER_FAIL; tctx->addr->more_errno = rc; - DEBUG(D_transport) debug_printf("filter process returned %d\n", rc); + DEBUG(transport) debug_printf("filter process returned %d\n", rc); } /* Wait for the writing process to complete. If it ends successfully, read the results from its pipe, provided we haven't already had a filter process failure. */ -DEBUG(D_transport) debug_printf("waiting for writing process\n"); +DEBUG(transport) debug_printf("waiting for writing process\n"); if (write_pid > 0) { rc = child_close(write_pid, 30); @@ -1473,7 +1473,7 @@ if (write_pid > 0) BOOL ok; if (read(pfd[pipe_read], (void *)&ok, sizeof(BOOL)) != sizeof(BOOL)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("pipe read from writing process: %s\n", strerror(errno)); save_errno = ERRNO_FILTER_FAIL; yield = FALSE; @@ -1492,7 +1492,7 @@ if (write_pid > 0) yield = FALSE; save_errno = ERRNO_FILTER_FAIL; tctx->addr->more_errno = rc; - DEBUG(D_transport) debug_printf("writing process returned %d\n", rc); + DEBUG(transport) debug_printf("writing process returned %d\n", rc); } } (void)close(pfd[pipe_read]); @@ -1521,7 +1521,7 @@ if (yield) else errno = save_errno; /* From some earlier error */ -DEBUG(D_transport) +DEBUG(transport) { debug_printf("end of filtering transport writing: yield=%d\n", yield); if (!yield) @@ -1578,12 +1578,12 @@ open_db dbblock, * dbp; if (!is_new_message_id(message_id)) { - DEBUG(D_transport) debug_printf("message_id %s is not new format; " + DEBUG(transport) debug_printf("message_id %s is not new format; " "skipping wait-%s database update\n", message_id, tpname); return; } -DEBUG(D_transport) +DEBUG(transport) { debug_printf("updating wait-%s database\n", tpname); acl_level++; } /* Open the database (or transaction) for this transport */ @@ -1633,7 +1633,7 @@ for (host_item * host = hostlist; host; host = host->next) if (!is_new_message_id(s)) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("NOTE: old or corrupt message-id found in wait=%.200s" " hints DB; deleting records for %s\n", tpname, host->name); @@ -1669,7 +1669,7 @@ for (host_item * host = hostlist; host; host = host->next) if (already) { - DEBUG(D_transport) debug_printf("already listed for %s\n", host->name); + DEBUG(transport) debug_printf("already listed for %s\n", host->name); continue; } @@ -1712,7 +1712,7 @@ for (host_item * host = hostlist; host; host = host->next) /* Update the database */ dbfn_write(dbp, host->name, host_record, sizeof(dbdata_wait) + host_length); - DEBUG(D_transport) debug_printf("added %.*s to queue for %s\n", + DEBUG(transport) debug_printf("added %.*s to queue for %s\n", MESSAGE_ID_LENGTH, message_id, host->name); } @@ -1724,7 +1724,7 @@ else dbfn_close(dbp); out: - DEBUG(D_transport) acl_level--; + DEBUG(transport) acl_level--; return; } @@ -1777,7 +1777,7 @@ open_db dbblock, * dbp; int i; struct stat statbuf; -DEBUG(D_transport) +DEBUG(transport) { debug_printf("transport_check_waiting entered\n"); debug_printf(" sequence=%d local_max=%d global_max=%d\n", @@ -1791,7 +1791,7 @@ connection. */ if (connection_max_messages >= 0) local_message_max = connection_max_messages; if (local_message_max > 0 && continue_sequence >= local_message_max) { - DEBUG(D_transport) + DEBUG(transport) debug_printf_indent("max messages for one connection reached: returning\n"); goto retfalse; } @@ -1804,7 +1804,7 @@ if ( continue_wait_db O_RDWR, &dbblock, TRUE, TRUE)) ) { - DEBUG(D_transport) + DEBUG(transport) debug_printf_indent("no messages waiting for %s\n", hostname); goto retfalse; } @@ -1813,7 +1813,7 @@ if ( continue_wait_db if (!(host_record = dbfn_read(dbp, hostname))) { - DEBUG(D_transport) + DEBUG(transport) debug_printf_indent("no messages waiting for %s\n", hostname); goto dbclose_false; } @@ -1858,7 +1858,7 @@ while (1) if (!is_new_message_id(host_record->text + (i * MESSAGE_ID_LENGTH))) { uschar buffer[256]; - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("NOTE: old or corrupt message-id found in" " wait=%.200s hints DB; deleting records for %s\n", transport_name, hostname); @@ -1881,7 +1881,7 @@ while (1) for (i = 0; i < msgq_count; ++i) if (Ustrcmp(msgq[i].message_id, message_id) == 0) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("dropping current msg from list\n"); msgq[i].bKeep = FALSE; break; @@ -1899,7 +1899,7 @@ while (1) msgq[i].bKeep = FALSE; else if (!oicf_func || oicf_func(mid, oicf_data)) { - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("acceptable next: %s\n", mid); Ustrcpy_nt(new_message_id, mid); msgq[i].bKeep = FALSE; @@ -1911,7 +1911,7 @@ while (1) /* re-count */ for (msgq_actual = 0, i = 0; i < msgq_count; ++i) if (msgq[i].bKeep) msgq_actual++; - DEBUG(D_hints_lookup) + DEBUG(hints_lookup) debug_printf_indent("%d left in this record\n", msgq_actual); /* reassemble the host record, based on removed message ids, from in @@ -1980,7 +1980,7 @@ while (1) if (host_length <= 0) { - DEBUG(D_transport|D_hints_lookup) + DEBUG(transport|hints_lookup) debug_printf_indent("waiting messages already delivered\n"); goto dbclose_false; } @@ -1990,7 +1990,7 @@ while (1) if (!bContinuation) { - DEBUG(D_hints_lookup) debug_printf_indent("no further records\n"); + DEBUG(hints_lookup) debug_printf_indent("no further records\n"); Ustrcpy(new_message_id, message_id); goto dbclose_false; } @@ -2012,7 +2012,7 @@ if (continue_wait_db) else dbfn_close(dbp); -DEBUG(D_transport) +DEBUG(transport) { acl_level--; debug_printf("transport_check_waiting: TRUE (found %s)\n", new_message_id); @@ -2026,7 +2026,7 @@ dbclose_false: dbfn_close(dbp); retfalse: - DEBUG(D_transport) + DEBUG(transport) {acl_level--; debug_printf("transport_check_waiting: FALSE\n"); } return FALSE; } @@ -2134,12 +2134,12 @@ if (socket_fd != 0) (void)close(socket_fd); } -DEBUG(D_exec) debug_print_argv(argv); +DEBUG(exec) debug_print_argv(argv); exim_nullstd(); /* Ensure std{out,err} exist */ /* argv[0] should be untainted, from child_exec_exim() */ execv(CS argv[0], (char *const *)argv); -DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno)); +DEBUG(any) debug_printf("execv failed: %s\n", strerror(errno)); _exit(errno); /* Note: must be _exit(), NOT exit() */ } @@ -2268,7 +2268,7 @@ If the parent of the top address has an original part of "system-filter", this pipe was set up by the system filter, and we can permit the expansion of $recipients. */ -DEBUG(D_transport) +DEBUG(transport) { debug_printf("direct command:\n"); for (int i = 0; argv[i]; i++) @@ -2282,7 +2282,7 @@ if (flags & TSUC_EXPAND_ARGS) for (int i = 0; argv[i]; i++) { - DEBUG(D_expand) debug_printf_indent("arg %d\n", i); + DEBUG(expand) debug_printf_indent("arg %d\n", i); /* Handle special fudge for passing an address list */ @@ -2314,7 +2314,7 @@ if (flags & TSUC_EXPAND_ARGS) This is a hole in the taint-pretection, mitigated only in that shell-syntax metachars cannot be injected via this route. */ - DEBUG(D_transport) if (is_tainted(ad->address)) + DEBUG(transport) if (is_tainted(ad->address)) debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address); argv[i++] = ad->address; @@ -2339,7 +2339,7 @@ if (flags & TSUC_EXPAND_ARGS) /* We can never have more then the argv we will be loading into */ address_pipe_max_args = max_args - argcount + 1; - DEBUG(D_transport) + DEBUG(transport) debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args); /* We allocate an additional for (uschar *)0 */ @@ -2457,7 +2457,7 @@ if (flags & TSUC_EXPAND_ARGS) if ( f.running_in_test_harness && is_tainted(expanded_arg) && Ustrcmp(etext, "queryprogram router") == 0) { /* hack, would be good to not need it */ - DEBUG(D_transport) + DEBUG(transport) debug_printf("SPECIFIC TESTSUITE EXEMPTION: tainted arg '%s'\n", expanded_arg); } @@ -2468,7 +2468,7 @@ if (flags & TSUC_EXPAND_ARGS) } } - DEBUG(D_transport) + DEBUG(transport) { debug_printf("direct command after expansion:\n"); for (int i = 0; argv[i]; i++) diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 59af24ced..68ea552f3 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -520,13 +520,13 @@ struct servent *sp; host_item host; uschar * s; -DEBUG(D_transport) debug_printf("notify_comsat called\n"); +DEBUG(transport) debug_printf("notify_comsat called\n"); s = string_sprintf("%.200s@" OFF_T_FMT "\n", user, offset); if ((sp = getservbyname("biff", "udp")) == NULL) { - DEBUG(D_transport) debug_printf("biff/udp is an unknown service"); + DEBUG(transport) debug_printf("biff/udp is an unknown service"); return; } @@ -543,7 +543,7 @@ can be changed. (But actually, comsat is probably dying out anyway.) */ /****** if (host_find_byname(&host, NULL, 0, NULL, FALSE) == HOST_FIND_FAILED) { - DEBUG(D_transport) debug_printf("\"localhost\" unknown\n"); + DEBUG(transport) debug_printf("\"localhost\" unknown\n"); return; } ******/ @@ -556,7 +556,7 @@ for (host_item * h = &host; h; h = h->next) int sock, rc; int host_af = Ustrchr(h->address, ':') != NULL ? AF_INET6 : AF_INET; - DEBUG(D_transport) debug_printf("calling comsat on %s\n", h->address); + DEBUG(transport) debug_printf("calling comsat on %s\n", h->address); if ((sock = ip_socket(SOCK_DGRAM, host_af)) < 0) continue; @@ -567,7 +567,7 @@ for (host_item * h = &host; h; h = h->next) (void)close(sock); if (rc >= 0) break; - DEBUG(D_transport) + DEBUG(transport) debug_printf("send to comsat failed for %s: %s\n", strerror(errno), h->address); } @@ -602,7 +602,7 @@ int len = read(cfd, data, sizeof(data)); int sep = 0; const uschar * s; -DEBUG(D_transport) debug_printf("checking file format\n"); +DEBUG(transport) debug_printf("checking file format\n"); /* An empty file matches the current transport */ @@ -622,7 +622,7 @@ while ((s = string_nextinlist(&format, &sep, big_buffer, big_buffer_size))) for (transport_instance * tt = transports; tt; tt = tt->drinst.next) if (Ustrcmp(tp, tt->drinst.name) == 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("file format -> %s transport\n", tt->drinst.name); return tt; } @@ -710,7 +710,7 @@ for (struct dirent * ent; ent = readdir(dir); ) if (endptr == name + ovec[3]) { sum += size; - DEBUG(D_transport) + DEBUG(transport) debug_printf("check_dir_size: size from %s is " OFF_T_FMT "\n", name, size); /* pcre2_match_data_free(md); gen ctx needs no free */ @@ -718,7 +718,7 @@ for (struct dirent * ent; ent = readdir(dir); ) } } /* pcre2_match_data_free(md); gen ctx needs no free */ - DEBUG(D_transport) + DEBUG(transport) debug_printf("check_dir_size: regex did not match %s\n", name); } @@ -728,7 +728,7 @@ for (struct dirent * ent; ent = readdir(dir); ) if (Ustat(path, &statbuf) < 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("check_dir_size: stat error %d for %s: %s\n", errno, path, strerror(errno)); } @@ -740,7 +740,7 @@ for (struct dirent * ent; ent = readdir(dir); ) } closedir(dir); -DEBUG(D_transport) +DEBUG(transport) debug_printf("check_dir_size: dir=%s sum=" OFF_T_FMT " count=%d\n", dirname, sum, count); @@ -867,7 +867,7 @@ if (saved_size == 0) return DEFER; } -DEBUG(D_transport) debug_printf("copying MBX message from temporary file\n"); +DEBUG(transport) debug_printf("copying MBX message from temporary file\n"); /* Now construct the message's header from the time and the RFC822 file size, including CRLFs, which is the size of the input (temporary) file. */ @@ -987,7 +987,7 @@ if (deliver_dir && create_file != create_anywhere) if (Ustrncmp(rph, big_buffer, rlen) != 0) { yield = FALSE; - DEBUG(D_transport) debug_printf("Real path %q does not match %q\n", + DEBUG(transport) debug_printf("Real path %q does not match %q\n", big_buffer, deliver_dir); } } @@ -1189,7 +1189,7 @@ int maildir_save_errno; #endif -DEBUG(D_transport) debug_printf("appendfile transport entered\n"); +DEBUG(transport) debug_printf("appendfile transport entered\n"); /* An "address_file" or "address_directory" transport is used to deliver to files specified via .forward or an alias file. Prior to release 4.20, the @@ -1299,7 +1299,7 @@ else mbf_unix; } -DEBUG(D_transport) +DEBUG(transport) { debug_printf("appendfile: mode=%o notify_comsat=%d quota=" OFF_T_FMT "%s%s" @@ -1329,7 +1329,7 @@ DEBUG(D_transport) if (f.dont_deliver) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** delivery by %s transport bypassed by -N option\n", trname); addr->transport_return = OK; @@ -1366,7 +1366,7 @@ if (!isdirectory) && ob->create_file == create_belowhome) if (is_tainted(path)) { - DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); + DEBUG(transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } @@ -1388,7 +1388,7 @@ if (!isdirectory) addr->message = string_sprintf("failed to create directories for %s: %s", path, exim_errstr(errno)); - DEBUG(D_transport) debug_printf("%s transport: %s\n", trname, path); + DEBUG(transport) debug_printf("%s transport: %s\n", trname, path); return FALSE; } } @@ -1566,7 +1566,7 @@ if (!isdirectory) hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname, (unsigned int)(time(NULL)), (unsigned long)getpid()); - DEBUG(D_transport) debug_printf("lock name: %s\nhitch name: %s\n", lockname, + DEBUG(transport) debug_printf("lock name: %s\nhitch name: %s\n", lockname, hitchname); /* Lock file creation retry loop */ @@ -1608,14 +1608,14 @@ if (!isdirectory) if (ob->lockfile_timeout > 0 && Ustat(lockname, &statbuf) == 0 && time(NULL) - statbuf.st_ctime > ob->lockfile_timeout) { - DEBUG(D_transport) debug_printf("unlinking timed-out lock file\n"); + DEBUG(transport) debug_printf("unlinking timed-out lock file\n"); Uunlink(lockname); } - DEBUG(D_transport) debug_printf("link of hitching post failed - retrying\n"); + DEBUG(transport) debug_printf("link of hitching post failed - retrying\n"); continue; } - DEBUG(D_transport) debug_printf("lock file created\n"); + DEBUG(transport) debug_printf("lock file created\n"); break; } @@ -1809,7 +1809,7 @@ if (!isdirectory) int diffs = oldmode ^ mode; if (addr->mode > 0 || (diffs & oldmode) == diffs) { - DEBUG(D_transport) debug_printf("chmod %o %s\n", mode, filename); + DEBUG(transport) debug_printf("chmod %o %s\n", mode, filename); if (Uchmod(filename, mode) < 0) { addr->basic_errno = errno; @@ -2092,18 +2092,18 @@ if (!isdirectory) statbuf.st_dev == ostatbuf.st_dev && statbuf.st_ino == ostatbuf.st_ino) break; - DEBUG(D_transport) debug_printf("MBX lockfile %s changed " + DEBUG(transport) debug_printf("MBX lockfile %s changed " "between creation and locking\n", mbx_lockname); } - DEBUG(D_transport) debug_printf("failed to lock %s: %s\n", mbx_lockname, + DEBUG(transport) debug_printf("failed to lock %s: %s\n", mbx_lockname, strerror(errno)); (void)close(mbx_lockfd); mbx_lockfd = -1; } else { - DEBUG(D_transport) debug_printf("failed to fstat or get read lock on %s: %s\n", + DEBUG(transport) debug_printf("failed to fstat or get read lock on %s: %s\n", filename, strerror(errno)); } } @@ -2111,7 +2111,7 @@ if (!isdirectory) else break; /* No on-file locking required; break the open/lock loop */ - DEBUG(D_transport) + DEBUG(transport) debug_printf("fcntl(), flock(), or MBX locking failed - retrying\n"); (void)close(fd); @@ -2155,7 +2155,7 @@ if (!isdirectory) goto RETURN; } - DEBUG(D_transport) debug_printf("mailbox %s is locked\n", filename); + DEBUG(transport) debug_printf("mailbox %s is locked\n", filename); /* Save access time (for subsequent restoration), modification time (for restoration if updating fails), size of file (for comsat and for re-setting if @@ -2206,7 +2206,7 @@ else if (is_tainted(path)) if (ob->create_file == create_belowhome) { - DEBUG(D_transport) debug_printf("below-home: de-tainting path '%s'\n", path); + DEBUG(transport) debug_printf("below-home: de-tainting path '%s'\n", path); path = string_copy_taint(path, GET_UNTAINTED); } else @@ -2240,7 +2240,7 @@ else MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx))) return FALSE; - DEBUG(D_transport) debug_printf("using regex for file sizes: %s\n", + DEBUG(transport) debug_printf("using regex for file sizes: %s\n", ob->quota_size_regex); } @@ -2291,7 +2291,7 @@ else { *slash = 0; check_path = new_check_path; - DEBUG(D_transport) debug_printf("maildirfolder file exists: " + DEBUG(transport) debug_printf("maildirfolder file exists: " "quota check directory changed to %s\n", check_path); } } @@ -2322,7 +2322,7 @@ else MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx))) return FALSE; - DEBUG(D_transport) + DEBUG(transport) debug_printf("using regex for maildir directory selection: %s\n", ob->maildir_dir_regex); @@ -2339,7 +2339,7 @@ else if (!regex_match(dir_regex, s, -1, NULL)) { disable_quota = TRUE; - DEBUG(D_transport) debug_printf("delivery directory does not match " + DEBUG(transport) debug_printf("delivery directory does not match " "maildir_quota_directory_regex: disabling quota\n"); } } @@ -2402,7 +2402,7 @@ else { off_t size; int filecount = 0; - DEBUG(D_transport) + DEBUG(transport) debug_printf("quota checks on directory %s\n", check_path); size = check_dir_size(check_path, &filecount, re); if (mailbox_size < 0) mailbox_size = size; @@ -2417,7 +2417,7 @@ else if (mbformat == mbf_smail) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("delivering to new file in %s\n", path); filename = dataname = string_sprintf("%s/temp." PID_T_FMT ".%s", path, getpid(), primary_hostname); @@ -2441,7 +2441,7 @@ else else if (mbformat == mbf_maildir) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("delivering in maildir format in %s\n", path); GET_OPTION("maildir_tag"); @@ -2484,7 +2484,7 @@ else { if ((fd = Uopen(filename, O_WRONLY | O_CREAT | O_EXCL, mode)) >= 0) break; - DEBUG (D_transport) debug_printf ("open failed for %s: %s\n", + DEBUG(transport) debug_printf ("open failed for %s: %s\n", filename, strerror(errno)); } @@ -2492,7 +2492,7 @@ else if (i >= ob->maildir_retries) { - DEBUG(D_transport) + DEBUG(transport) { char buf[PATH_MAX]; debug_printf(" (euid=%ld egid=%ld cwd=%s)\n", @@ -2542,7 +2542,7 @@ else mailstore_basename = string_sprintf("%s/%s-%s", path, message_id, string_base62_64((long int)getpid())); - DEBUG(D_transport) + DEBUG(transport) debug_printf("delivering in mailstore format in %s\n", path); filename = string_sprintf("%s.tmp", mailstore_basename); @@ -2648,7 +2648,7 @@ else return FALSE; } - DEBUG(D_transport) debug_printf("Envelope file %s written\n", filename); + DEBUG(transport) debug_printf("Envelope file %s written\n", filename); /* Now open the data file, and ensure that it has the correct ownership and mode. */ @@ -2689,7 +2689,7 @@ else prefix line, and followed by any configured suffix line. If there are any writing errors, we must defer. */ -DEBUG(D_transport) debug_printf("writing to file %s\n", dataname); +DEBUG(transport) debug_printf("writing to file %s\n", dataname); yield = OK; errno = 0; @@ -2701,7 +2701,7 @@ included in the check). */ if (!disable_quota && ob->quota_value > 0) { - DEBUG(D_transport) + DEBUG(transport) { debug_printf("Exim quota = " OFF_T_FMT " old size = " OFF_T_FMT " this message = %d (%sincluded)\n", @@ -2714,24 +2714,24 @@ if (!disable_quota && ob->quota_value > 0) if (mailbox_size + (ob->quota_is_inclusive ? message_size:0) > ob->quota_value) if (!ob->quota_no_check) { - DEBUG(D_transport) debug_printf("mailbox quota exceeded\n"); + DEBUG(transport) debug_printf("mailbox quota exceeded\n"); yield = DEFER; errno = ERRNO_EXIMQUOTA; } else - DEBUG(D_transport) debug_printf("mailbox quota exceeded but ignored\n"); + DEBUG(transport) debug_printf("mailbox quota exceeded but ignored\n"); if (ob->quota_filecount_value > 0 && mailbox_filecount + (ob->quota_is_inclusive ? 1:0) > ob->quota_filecount_value) if (!ob->quota_filecount_no_check) { - DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n"); + DEBUG(transport) debug_printf("mailbox file count quota exceeded\n"); yield = DEFER; errno = ERRNO_EXIMQUOTA; filecount_msg = US" filecount"; } - else DEBUG(D_transport) if (ob->quota_filecount_no_check) + else DEBUG(transport) if (ob->quota_filecount_no_check) debug_printf("mailbox file count quota exceeded but ignored\n"); } @@ -2741,7 +2741,7 @@ if (verify_mode) addr->basic_errno = errno; addr->message = US"Over quota"; addr->transport_return = yield; - DEBUG(D_transport) + DEBUG(transport) debug_printf("appendfile (verify) yields %d with errno=%d more_errno=%d\n", yield, addr->basic_errno, addr->more_errno); @@ -2767,7 +2767,7 @@ if (yield == OK && ob->mbx_format) } save_fd = fd; fd = fileno(temp_file); - DEBUG(D_transport) debug_printf("writing to temporary file\n"); + DEBUG(transport) debug_printf("writing to temporary file\n"); } #endif /* SUPPORT_MBX */ @@ -2936,7 +2936,7 @@ if (!disable_quota && THRESHOLD_CHECK) off_t threshold = ob->quota_warn_threshold_value; if (ob->quota_warn_threshold_is_percent) threshold = (off_t)(((double)ob->quota_value * threshold) / 100); - DEBUG(D_transport) + DEBUG(transport) debug_printf("quota = " OFF_T_FMT " threshold = " OFF_T_FMT " old size = " OFF_T_FMT @@ -2990,14 +2990,14 @@ if (yield != OK) struct stat statbuf; if (Ustat("new", &statbuf) < 0) { - DEBUG(D_transport) debug_printf("maildir quota exceeded: " + DEBUG(transport) debug_printf("maildir quota exceeded: " "stat error %d for \"new\": %s\n", errno, strerror(errno)); } else /* Want a repeatable time when in test harness */ addr->more_errno = f.running_in_test_harness ? 10 : (int)time(NULL) - statbuf.st_mtime; - DEBUG(D_transport) + DEBUG(transport) debug_printf("maildir: time since \"new\" directory modified = %s\n", readconf_printtime(addr->more_errno)); } @@ -3017,7 +3017,7 @@ if (yield != OK) addr->message = US"mailbox is full"; #endif /* EDQUOT */ addr->user_message = US"mailbox is full"; - DEBUG(D_transport) debug_printf("System quota exceeded for %s%s%s\n", + DEBUG(transport) debug_printf("System quota exceeded for %s%s%s\n", dataname, isdirectory ? US"" : US": time since file read = ", isdirectory ? US"" : readconf_printtime(addr->more_errno)); @@ -3031,7 +3031,7 @@ if (yield != OK) "(MTA-imposed%s quota exceeded while writing to %s)", filecount_msg, dataname); addr->user_message = US"mailbox is full"; - DEBUG(D_transport) debug_printf("Exim%s quota exceeded for %s%s%s\n", + DEBUG(transport) debug_printf("Exim%s quota exceeded for %s%s%s\n", filecount_msg, dataname, isdirectory ? US"" : US": time since file read = ", isdirectory ? US"" : readconf_printtime(addr->more_errno)); @@ -3084,7 +3084,7 @@ if (yield != OK) fcntl() call (BSDI & FreeBSD do not). */ if (!isdirectory && ftruncate(fd, saved_size)) - DEBUG(D_transport) debug_printf("Error resetting file size\n"); + DEBUG(transport) debug_printf("Error resetting file size\n"); } /* Handle successful writing - we want the modification time to be now for @@ -3129,7 +3129,7 @@ else uschar *renamename = newname; fd = -1; - DEBUG(D_transport) debug_printf("renaming temporary file\n"); + DEBUG(transport) debug_printf("renaming temporary file\n"); /* If there is no rename name set, we are in a non-maildir, non-mailstore situation. The name is built by expanding the directory_file option, and @@ -3170,7 +3170,7 @@ else renamename = string_sprintf("%s/%s", path, renameleaf); if (Ulink(filename, renamename) < 0) { - DEBUG(D_transport) debug_printf("link failed: %s\n", + DEBUG(transport) debug_printf("link failed: %s\n", strerror(errno)); if (errno != EEXIST || i >= 4 || Ustrcmp(renameleaf, old_renameleaf) == 0) @@ -3182,7 +3182,7 @@ else break; } old_renameleaf = renameleaf; - DEBUG(D_transport) debug_printf("%s exists - trying again\n", + DEBUG(transport) debug_printf("%s exists - trying again\n", renamename); } else @@ -3240,7 +3240,7 @@ else else { - DEBUG(D_transport) debug_printf("renamed %s as %s\n", filename, + DEBUG(transport) debug_printf("renamed %s as %s\n", filename, renamename); filename = dataname = NULL; /* Prevents attempt to unlink at end */ } @@ -3263,7 +3263,7 @@ if (ob->notify_comsat && yield == OK && deliver_localpart) /* Pass back the final return code in the address structure */ -DEBUG(D_transport) +DEBUG(transport) debug_printf("appendfile yields %d with errno=%d more_errno=%d\n", yield, addr->basic_errno, addr->more_errno); @@ -3287,7 +3287,7 @@ if (mbx_lockfd >= 0) if (yield == OK && apply_lock(fd, F_WRLCK, ob->use_fcntl, 0, ob->use_flock, 0) >= 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("unlinking MBX lock file %s\n", mbx_lockname); Uunlink(mbx_lockname); } diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index ca89534ed..9937505e8 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -210,7 +210,7 @@ while (*s) if (rc == OK) /* Remove this address */ { - DEBUG(D_transport) + DEBUG(transport) debug_printf("discarding recipient %s (matched never_mail)\n", next); hit = TRUE; if (terminator == ',') e++; @@ -277,7 +277,7 @@ header_line * h; time_t now = time(NULL), once_repeat_sec = 0; FILE * ff = NULL, * fp; -DEBUG(D_transport) debug_printf("%s transport entered\n", trname); +DEBUG(transport) debug_printf("%s transport entered\n", trname); /* Set up for the good case */ @@ -291,7 +291,7 @@ it has to be expanded here. */ if (addr->reply) { - DEBUG(D_transport) debug_printf("taking data from address\n"); + DEBUG(transport) debug_printf("taking data from address\n"); from = addr->reply->from; reply_to = addr->reply->reply_to; to = addr->reply->to; @@ -312,7 +312,7 @@ else { const uschar * oncerepeat; - DEBUG(D_transport) debug_printf("taking data from transport\n"); + DEBUG(transport) debug_printf("taking data from transport\n"); GET_OPTION("once_repeat"); oncerepeat = ob->once_repeat; GET_OPTION("from"); from = ob->from; GET_OPTION("reply_to"); reply_to = ob->reply_to; @@ -374,7 +374,7 @@ if (ob->never_mail) if (!to && !cc && !bcc) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** all recipients removed by never_mail\n"); return OK; } @@ -384,7 +384,7 @@ if (ob->never_mail) if (f.dont_deliver) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** delivery by %s transport bypassed by -N option\n", trname); return FALSE; @@ -445,7 +445,7 @@ if (oncelog && *oncelog && to) goto END_OFF; } - DEBUG(D_transport) debug_printf("%d bytes read from %s\n", cache_size, oncelog); + DEBUG(transport) debug_printf("%d bytes read from %s\n", cache_size, oncelog); /* Scan the data for this recipient. Each entry in the file starts with a time_t sized time value, followed by the address, followed by a binary @@ -507,7 +507,7 @@ if (oncelog && *oncelog && to) goto END_OFF; } - DEBUG(D_transport) debug_printf("message previously sent to %s%s\n", to, + DEBUG(transport) debug_printf("message previously sent to %s%s\n", to, (once_repeat_sec > 0)? " and repeat time not reached" : ""); log_fd = logfile ? Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode) : -1; if (log_fd >= 0) @@ -517,13 +517,13 @@ if (oncelog && *oncelog && to) while(*ptr) ptr++; if(write(log_fd, log_buffer, ptr - log_buffer) != ptr-log_buffer || close(log_fd)) - DEBUG(D_transport) debug_printf("Problem writing log file %s for %s " + DEBUG(transport) debug_printf("Problem writing log file %s for %s " "transport\n", logfile, trname); } goto END_OFF; } - DEBUG(D_transport) debug_printf("%s %s\n", (then <= 0)? + DEBUG(transport) debug_printf("%s %s\n", (then <= 0)? "no previous message sent to" : "repeat time reached for", to); } @@ -558,7 +558,7 @@ if ((pid = child_open_exim(&fd, US"autoreply")) < 0) addr->basic_errno = errno; addr->message = string_sprintf("Failed to create child process to send " "message from %s transport: %s", trname, strerror(errno)); - DEBUG(D_transport) debug_printf("%s\n", addr->message); + DEBUG(transport) debug_printf("%s\n", addr->message); if (dbm_file) exim_dbclose(dbm_file); return FALSE; } @@ -624,7 +624,7 @@ if (ff) { const uschar * s = expand_string(big_buffer); int i; - if (!s) DEBUG(D_transport) + if (!s) DEBUG(transport) debug_printf("error while expanding line from file:\n %s\n %s\n", big_buffer, expand_string_message); if (!s) s = big_buffer; @@ -722,7 +722,7 @@ if (cache_fd >= 0) memcpy(cache_time, &now, sizeof(time_t)); if(write(cache_fd, from, size) != size) - DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s " + DEBUG(transport) debug_printf("Problem writing cache file %s for %s " "transport\n", oncelog, trname); } } @@ -753,7 +753,7 @@ message, we do not fail. */ if (rc != 0) if (rc == EXIT_NORECIPIENTS) { - DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n", + DEBUG(any) debug_printf("%s transport: message contained no recipients\n", trname); } else @@ -783,7 +783,7 @@ if (logfile) /* Use taint-unchecked routines for writing into log_buffer, trusting that we'll never expand it. */ - DEBUG(D_transport) debug_printf("logging message details\n"); + DEBUG(transport) debug_printf("logging message details\n"); g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, "%s\n", tod_stamp(tod_log)); if (from) g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " From: %s\n", from); @@ -798,10 +798,10 @@ if (logfile) if (headers) g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s\n", headers); if(write(log_fd, g->s, g->ptr) != g->ptr || close(log_fd)) - DEBUG(D_transport) debug_printf("Problem writing log file %s for %s " + DEBUG(transport) debug_printf("Problem writing log file %s for %s " "transport\n", logfile, trname); } - else DEBUG(D_transport) debug_printf("Failed to open log file %s for %s " + else DEBUG(transport) debug_printf("Failed to open log file %s for %s " "transport: %s\n", logfile, trname, strerror(errno)); } @@ -809,7 +809,7 @@ END_OFF: if (dbm_file) exim_dbclose(dbm_file); if (cache_fd > 0) (void)close(cache_fd); -DEBUG(D_transport) debug_printf("%s transport succeeded\n", trname); +DEBUG(transport) debug_printf("%s transport succeeded\n", trname); return FALSE; } diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index 322dfbb71..8fa29dff6 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -243,11 +243,11 @@ if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, CS format, ap)) return FALSE; } va_end(ap); -DEBUG(D_transport|D_v) debug_printf(" LMTP>> %Y", &gs); +DEBUG(transport|v) debug_printf(" LMTP>> %Y", &gs); rc = write(fd, gs.s, gs.ptr); gs.ptr -= 2; string_from_gstring(&gs); /* remove \r\n for debug and error message */ if (rc > 0) return TRUE; -DEBUG(D_transport) debug_printf("write failed: %s\n", strerror(errno)); +DEBUG(transport) debug_printf("write failed: %s\n", strerror(errno)); return FALSE; } @@ -327,7 +327,7 @@ for (;;) else if (errno == EINTR) { - DEBUG(D_transport) debug_printf("EINTR while reading LMTP response\n"); + DEBUG(transport) debug_printf("EINTR while reading LMTP response\n"); continue; } @@ -350,7 +350,7 @@ for (;;) if (ptr[count-1] != '\n') { - DEBUG(D_transport) + DEBUG(transport) { debug_printf("LMTP input line incomplete in one buffer:\n "); for (int i = 0; i < count; i++) @@ -370,7 +370,7 @@ for (;;) while (count > 0 && isspace(ptr[count-1])) count--; ptr[count] = 0; - DEBUG(D_transport|D_v) + DEBUG(transport|v) { uschar *s = ptr; uschar *t = ptr; @@ -483,7 +483,7 @@ const uschar * sockname = NULL; const uschar ** argv; uschar buffer[256]; -DEBUG(D_transport) debug_printf("%s transport entered\n", trname); +DEBUG(transport) debug_printf("%s transport entered\n", trname); /* Initialization ensures that either a command or a socket is specified, but not both. When a command is specified, call the common function for creating an @@ -491,7 +491,7 @@ argument list and expanding the items. */ if (ob->cmd) { - DEBUG(D_transport) debug_printf("using command %s\n", ob->cmd); + DEBUG(transport) debug_printf("using command %s\n", ob->cmd); sprintf(CS buffer, "%.50s transport", trname); if (!transport_set_up_command(&argv, ob->cmd, TSUC_EXPAND_ARGS, PANIC, addrlist, buffer, NULL)) @@ -519,7 +519,7 @@ leader, so we can kill it and all its children on an error. */ else { - DEBUG(D_transport) debug_printf("using socket %s\n", ob->skt); + DEBUG(transport) debug_printf("using socket %s\n", ob->skt); if (!(sockname = expand_string(ob->skt))) { addrlist->message = string_sprintf("Expansion of %q (socket setting " @@ -650,7 +650,7 @@ if (send_data) sigalrm_seen = FALSE; transport_write_timeout = timeout; Ustrcpy(big_buffer, US"sending data block"); /* For error messages */ - DEBUG(D_transport|D_v) + DEBUG(transport|v) debug_printf(" LMTP>> writing message and terminating \".\"\n"); transport_count = 0; @@ -795,14 +795,14 @@ RETURN: if (fd_in >= 0) (void)close(fd_in); if (fd_out >= 0) (void)fclose(out); -DEBUG(D_transport) +DEBUG(transport) debug_printf("%s transport yields %d\n", trname, yield); return yield; MINUS_N: - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** delivery by %s transport bypassed by -N option", trname); addrlist->transport_return = OK; diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index fd248113a..ada39f723 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -436,7 +436,7 @@ if (expand_arguments) uschar * p = Ustrstr(cmd, "pipe_addresses"); gstring * g = NULL; - DEBUG(D_transport) + DEBUG(transport) debug_printf("shell pipe command before expansion:\n %s\n", cmd); /* Allow $recipients in the expansion iff it comes from a system filter */ @@ -457,7 +457,7 @@ if (expand_arguments) for (address_item * ad = addr; ad; ad = ad->next) { - DEBUG(D_transport) if (is_tainted(ad->address)) + DEBUG(transport) if (is_tainted(ad->address)) debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address); /*XXX string_append_listele() ? */ @@ -482,12 +482,12 @@ if (expand_arguments) return FALSE; } - DEBUG(D_transport) + DEBUG(transport) debug_printf("shell pipe command after expansion:\n %s\n", argv[2]); } else { - DEBUG(D_transport) + DEBUG(transport) debug_printf("shell pipe command (no expansion):\n %s\n", cmd); argv[2] = cmd; } @@ -530,7 +530,7 @@ transport_ctx tctx = { ob->options | topt_not_socket /* set at initialization time */ }; -DEBUG(D_transport) debug_printf("%s transport entered\n", trname); +DEBUG(transport) debug_printf("%s transport entered\n", trname); /* Set up for the good case */ @@ -581,7 +581,7 @@ if (!cmd || !*cmd) } if (is_tainted(cmd)) { - DEBUG(D_transport) debug_printf("cmd '%s' is tainted\n", cmd); + DEBUG(transport) debug_printf("cmd '%s' is tainted\n", cmd); addr->message = string_sprintf("Tainted '%s' (command " "for %s transport) not permitted", cmd, trname); addr->transport_return = PANIC; @@ -680,7 +680,7 @@ envp[envcount] = NULL; if (f.dont_deliver) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** delivery by %s transport bypassed by -N option", trname); return FALSE; @@ -748,17 +748,17 @@ if (outpid == 0) { if (addr->return_file >= 0) if(write(addr->return_file, big_buffer, rc) != rc) - DEBUG(D_transport) debug_printf("Problem writing to return_file\n"); + DEBUG(transport) debug_printf("Problem writing to return_file\n"); count += rc; if (count > ob->max_output) { - DEBUG(D_transport) debug_printf("Too much output from pipe - killed\n"); + DEBUG(transport) debug_printf("Too much output from pipe - killed\n"); if (addr->return_file >= 0) { uschar *message = US"\n\n*** Too much output - remainder discarded ***\n"; rc = Ustrlen(message); if(write(addr->return_file, message, rc) != rc) - DEBUG(D_transport) debug_printf("Problem writing to return_file\n"); + DEBUG(transport) debug_printf("Problem writing to return_file\n"); } killpg(pid, SIGKILL); break; @@ -781,7 +781,7 @@ any debugging output is likely to be in the same order.) */ testharness_pause_ms(500); -DEBUG(D_transport) debug_printf("Writing message to pipe\n"); +DEBUG(transport) debug_printf("Writing message to pipe\n"); /* Arrange to time out writes if there is a timeout set. */ @@ -1113,7 +1113,7 @@ are complete before we pass this point. */ while (wait(&rc) >= 0); -DEBUG(D_transport) debug_printf("%s transport yielded %d\n", trname, +DEBUG(transport) debug_printf("%s transport yielded %d\n", trname, addr->transport_return); /* If there has been a problem, the message in addr->message contains details diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index 5bd02682e..ca106b2cb 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -127,7 +127,7 @@ dstpath = string_sprintf("%s/%s-%s", dstpath, message_id, suffix); if (link_file) { - DEBUG(D_transport) debug_printf("%s transport, linking %s => %s\n", + DEBUG(transport) debug_printf("%s transport, linking %s => %s\n", trname, srcpath, dstpath); if (linkat(sdfd, CCS filename, ddfd, CCS filename, 0) >= 0) @@ -138,7 +138,7 @@ if (link_file) } else /* use data copy */ { - DEBUG(D_transport) debug_printf("%s transport, copying %s => %s\n", + DEBUG(transport) debug_printf("%s transport, copying %s => %s\n", trname, srcpath, dstpath); if ( (s = dstpath, @@ -185,7 +185,7 @@ uschar * s, * dstdir; struct stat dstatbuf, sstatbuf; int ddfd = -1, sdfd = -1; -DEBUG(D_transport) +DEBUG(transport) debug_printf("%s transport entered\n", trname); #ifndef O_DIRECTORY @@ -242,7 +242,7 @@ can_link = (dstatbuf.st_dev == sstatbuf.st_dev); if (f.dont_deliver) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("*** delivery by %s transport bypassed by -N option\n", trname); addr->transport_return = OK; @@ -251,26 +251,26 @@ if (f.dont_deliver) /* Link or copy the header and data spool files */ -DEBUG(D_transport) +DEBUG(transport) debug_printf("%s transport, copying header file\n", trname); if (!copy_spool_files(tblock, addr, dstdir, sdfd, ddfd, can_link, -1)) goto RETURN; -DEBUG(D_transport) +DEBUG(transport) debug_printf("%s transport, copying data file\n", trname); if (!copy_spool_files(tblock, addr, dstdir, sdfd, ddfd, can_link, deliver_datafile)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("%s transport, copying data file failed, " "unlinking the header file\n", trname); Uunlink(string_sprintf("%s/%s-H", dstdir, message_id)); goto RETURN; } -DEBUG(D_transport) +DEBUG(transport) debug_printf("%s transport succeeded\n", trname); addr->transport_return = OK; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 537375e2e..da89808d3 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -335,7 +335,7 @@ if (tf) tf->search_parents = ob->dns_search_parents; tf->helo_data = ob->helo_data; - if (exp_bool(addrlist, US"transport", tblock->drinst.name, D_transport, + if (exp_bool(addrlist, US"transport", tblock->drinst.name, IS_DEBUG(transport), US"hosts_randomize", ob->hosts_randomize, ob->expand_hosts_randomize, &tf->hosts_randomize) != OK) return DEFER; @@ -607,7 +607,7 @@ switch(*errno_value) #ifdef SUPPORT_I18N case ERRNO_UTF8_FWD: /* no advertised SMTPUTF8, for international message */ *message = US"utf8 support required but not offered for forwarding"; - DEBUG(D_deliver|D_transport) debug_printf("%s\n", *message); + DEBUG(deliver|transport) debug_printf("%s\n", *message); return TRUE; #endif } @@ -892,7 +892,7 @@ if (limit_mail && limit_mail < sx->max_mail) sx->max_mail = limit_mail; if (limit_rcpt && limit_rcpt < sx->max_rcpt) sx->max_rcpt = limit_rcpt; if (limit_rcptdom) { - DEBUG(D_transport) debug_printf("will treat as !multi_domain\n"); + DEBUG(transport) debug_printf("will treat as !multi_domain\n"); sx->single_rcpt_domain = TRUE; } } @@ -956,7 +956,7 @@ if ((dbm_file = dbfn_open(US"misc", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) const uschar * ehlo_resp_key = ehlo_cache_key(sx); dbdata_ehlo_resp er = { .data = sx->ehlo_resp }; - HDEBUG(D_transport) + HDEBUG(transport) # ifndef DISABLE_ESMTP_LIMITS if (sx->ehlo_resp.limit_mail || sx->ehlo_resp.limit_rcpt || sx->ehlo_resp.limit_rcptdom) debug_printf("writing clr %04x/%04x cry %04x/%04x lim %05d/%05d/%05d\n", @@ -984,7 +984,7 @@ if ( sx->early_pipe_active && (dbm_file = dbfn_open(US"misc", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) { const uschar * ehlo_resp_key = ehlo_cache_key(sx); - HDEBUG(D_transport) + HDEBUG(transport) { const dbdata_ehlo_resp * er; @@ -1007,7 +1007,7 @@ open_db dbblock; open_db * dbm_file; if (!(dbm_file = dbfn_open(US"misc", O_RDONLY, &dbblock, FALSE, TRUE))) - { DEBUG(D_transport) debug_printf("ehlo-cache: no misc DB\n"); } + { DEBUG(transport) debug_printf("ehlo-cache: no misc DB\n"); } else { const uschar * ehlo_resp_key = ehlo_cache_key(sx); @@ -1016,11 +1016,11 @@ else if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp)))) { dbfn_close(dbm_file); - DEBUG(D_transport) debug_printf("no ehlo-resp record\n"); + DEBUG(transport) debug_printf("no ehlo-resp record\n"); } else if (time(NULL) - er->gen.time_stamp > retry_data_expire) { - DEBUG(D_transport) debug_printf("ehlo-resp record too old\n"); + DEBUG(transport) debug_printf("ehlo-resp record too old\n"); dbfn_close(dbm_file); if ((dbm_file = dbfn_open(US"misc", O_RDWR|O_CREAT, &dbblock, TRUE, TRUE))) { @@ -1030,7 +1030,7 @@ else } else { - DEBUG(D_transport) + DEBUG(transport) # ifndef DISABLE_ESMTP_LIMITS if (er->data.limit_mail || er->data.limit_rcpt || er->data.limit_rcptdom) debug_printf("EHLO response bits from cache:" @@ -1084,7 +1084,7 @@ for (au = auths, authnum = 0; au; au = au->drinst.next, authnum++) { authbits |= BIT(authnum); break; } } -DEBUG(D_transport) +DEBUG(transport) debug_printf("server offers %s AUTH, methods '%s', usable-bitmap 0x%04x\n", tls_out.active.sock >= 0 ? "crypted" : "plaintext", names, authbits); @@ -1126,11 +1126,11 @@ sx->pending_EHLO = FALSE; if (pending_BANNER) { - DEBUG(D_transport) debug_printf("%s expect banner\n", __FUNCTION__); + DEBUG(transport) debug_printf("%s expect banner\n", __FUNCTION__); (*countp)--; if (!smtp_reap_banner(sx)) { - DEBUG(D_transport) debug_printf("bad banner\n"); + DEBUG(transport) debug_printf("bad banner\n"); if (tls_out.active.sock >= 0) rc = DEFER; goto fail; } @@ -1152,11 +1152,11 @@ if (pending_EHLO) unsigned peer_offered; unsigned short authbits = 0, * ap; - DEBUG(D_transport) debug_printf("%s expect ehlo\n", __FUNCTION__); + DEBUG(transport) debug_printf("%s expect ehlo\n", __FUNCTION__); (*countp)--; if (!smtp_reap_ehlo(sx)) { - DEBUG(D_transport) debug_printf("bad response for EHLO\n"); + DEBUG(transport) debug_printf("bad response for EHLO\n"); if (tls_out.active.sock >= 0) rc = DEFER; goto fail; } @@ -1180,7 +1180,7 @@ if (pending_EHLO) if ( peer_offered != sx->peer_offered || (authbits = study_ehlo_auths(sx)) != *ap) { - HDEBUG(D_transport) + HDEBUG(transport) debug_printf("EHLO %s extensions changed, 0x%04x/0x%04x -> 0x%04x/0x%04x\n", tls_out.active.sock < 0 ? "cleartext" : "crypted", sx->peer_offered, *ap, peer_offered, authbits); @@ -1211,7 +1211,7 @@ if (pending_EHLO) || sx->peer_limit_rcptdom != sx->ehlo_resp.limit_rcptdom ) ) { - HDEBUG(D_transport) + HDEBUG(transport) { debug_printf("EHLO LIMITS changed:"); if (sx->peer_limit_mail != sx->ehlo_resp.limit_mail) @@ -1298,13 +1298,13 @@ responses before returning, except after I/O errors and timeouts. */ if (sx->pending_MAIL) { - DEBUG(D_transport) debug_printf("%s expect mail\n", __FUNCTION__); + DEBUG(transport) debug_printf("%s expect mail\n", __FUNCTION__); count--; sx->pending_MAIL = sx->RCPT_452 = FALSE; if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout)) { - DEBUG(D_transport) debug_printf("bad response for MAIL\n"); + DEBUG(transport) debug_printf("bad response for MAIL\n"); Ustrcpy(big_buffer, mail_command); /* Fits, because it came from there! */ if (errno == ERRNO_TLSFAILURE) return RESP_EHLO_ERR_TLS; @@ -1354,7 +1354,7 @@ while (count-- > 0) else { clearflag(addr, af_cont_conn); setflag(addr, af_new_conn); } - DEBUG(D_transport) debug_printf("%s expect rcpt for %s\n", __FUNCTION__, addr->address); + DEBUG(transport) debug_printf("%s expect rcpt for %s\n", __FUNCTION__, addr->address); if (smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout)) { @@ -1450,7 +1450,7 @@ while (count-- > 0) { if (!sx->RCPT_452) /* initialised at MAIL-ack above */ { - DEBUG(D_transport) + DEBUG(transport) debug_printf("%s: seen first 452 too-many-rcpts\n", __FUNCTION__); sx->RCPT_452 = TRUE; sx->next_addr = addr; @@ -1511,7 +1511,7 @@ previously or in this block, the response is ignored. */ if (pending_DATA != 0) { - DEBUG(D_transport) debug_printf("%s expect data\n", __FUNCTION__); + DEBUG(transport) debug_printf("%s expect data\n", __FUNCTION__); if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '3', ob->command_timeout)) { @@ -1532,7 +1532,7 @@ if (pending_DATA != 0) return RESP_MAIL_OR_DATA_ERROR; } (void)check_response(sx->conn_args.host, &errno, 0, sx->buffer, &code, &msg, &pass_message); - DEBUG(D_transport) debug_printf("%s\nerror for DATA ignored: pipelining " + DEBUG(transport) debug_printf("%s\nerror for DATA ignored: pipelining " "is in use and there were no good recipients\n", msg); } } @@ -1581,7 +1581,7 @@ driver_srcline = au->drinst.srcline; sx->outblock.authenticating = FALSE; } driver_srcfile = authenticator_name = NULL; driver_srcline = 0; -DEBUG(D_transport) debug_printf("%s authenticator yielded %s\n", +DEBUG(transport) debug_printf("%s authenticator yielded %s\n", au->drinst.name, rc_names[rc]); /* A temporary authentication failure must hold up delivery to @@ -1712,7 +1712,7 @@ if ( sx->esmtp if ( require_auth || verify_check_given_host(CUSS &ob->hosts_try_auth, host) == OK) { - DEBUG(D_transport) debug_printf("scanning authentication mechanisms\n"); + DEBUG(transport) debug_printf("scanning authentication mechanisms\n"); fail_reason = US"no common mechanisms were found"; #ifndef DISABLE_PIPE_CONNECT @@ -1737,7 +1737,7 @@ if ( sx->esmtp && !expand_check_condition(au->client_condition, au->drinst.name, US"client authenticator")) { - DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n", + DEBUG(transport) debug_printf("skipping %s authenticator: %s\n", au->drinst.name, "client_condition is false"); continue; } @@ -1771,7 +1771,7 @@ if ( sx->esmtp && !expand_check_condition(au->client_condition, au->drinst.name, US"client authenticator"))) { - DEBUG(D_transport) debug_printf("skipping %s authenticator: %s\n", + DEBUG(transport) debug_printf("skipping %s authenticator: %s\n", au->drinst.name, au->client ? "client_condition is false" : "not configured as a client"); @@ -1953,12 +1953,12 @@ if (!(new_sender_address = spool_sender_from_msgid(message_id))) message_local_identity = smtp_local_identity(new_sender_address, s_compare->tblock); -DEBUG(D_transport) +DEBUG(transport) debug_printf_indent("message local identity: %q\n", message_local_identity); current_local_identity = smtp_local_identity(s_compare->current_sender_address, s_compare->tblock); -DEBUG(D_transport) +DEBUG(transport) debug_printf_indent("current local identity: %q\n", current_local_identity); return Ustrcmp(current_local_identity, message_local_identity) == 0; @@ -2098,7 +2098,7 @@ if (sx->pending_BDAT) if (flags & tc_reap_prev && prev_cmd_count > 0) { - DEBUG(D_transport) debug_printf("look for %d responses" + DEBUG(transport) debug_printf("look for %d responses" " for previous pipelined cmds\n", prev_cmd_count); switch(sync_responses(sx, prev_cmd_count, 0)) @@ -2125,7 +2125,7 @@ if (flags & tc_reap_prev && prev_cmd_count > 0) if (sx->pending_BDAT) { - DEBUG(D_transport) debug_printf("look for one response for BDAT\n"); + DEBUG(transport) debug_printf("look for one response for BDAT\n"); if (!smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', ob->command_timeout)) @@ -2232,7 +2232,7 @@ sx->conn_args.ob = ob; #ifdef EXPERIMENTAL_SRV_SMTPS if ((sx->smtps = sx->conn_args.host->tls_needs == SRV_TLS_ON_CONNECT)) { - DEBUG(D_transport) debug_printf("tls-on-connect required by smtp context\n"); + DEBUG(transport) debug_printf("tls-on-connect required by smtp context\n"); } else #endif @@ -2242,12 +2242,12 @@ else if ((sx->smtps = strcmpic(ob->protocol, US"smtps") == 0 || strcmpic(ob->protocol, US"submissions") == 0)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf(" tls-on-connect required by transport option\n"); } else if ((sx->lmtp = strcmpic(ob->protocol, US"lmtp") == 0)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf(" LMTP required by transport option\n"); } else if (strcmpic(ob->protocol, US"smtp") != 0) @@ -2372,7 +2372,7 @@ if (continue_hostname && continue_proxy_cipher) # endif else { - DEBUG(D_transport) + DEBUG(transport) # ifdef SUPPORT_DANE if (continue_proxy_dane != sx->conn_args.dane) debug_printf( @@ -2385,7 +2385,7 @@ if (continue_hostname && continue_proxy_cipher) smtp_debug_cmd(US"QUIT", 0); if (write(0, "QUIT\r\n", 6) < 0) - DEBUG(D_any) debug_printf("stupid compiler\n"); + DEBUG(any) debug_printf("stupid compiler\n"); close(0); tls_out.active.sock = -1; continue_hostname = continue_proxy_cipher = NULL; @@ -2401,7 +2401,7 @@ specially so they can be identified for retries. */ if (!continue_hostname || atrn_domains) { - if (sx->verify) HDEBUG(D_verify) + if (sx->verify) HDEBUG(verify) debug_printf("interface=%s port=%d\n", sx->conn_args.interface, sx->port); /* Get the actual port the connection will use, into sx->conn_args.host */ @@ -2431,7 +2431,7 @@ if (!continue_hostname || atrn_domains) # endif return FAIL; } - else DEBUG(D_transport) + else DEBUG(transport) debug_printf("lack of DNSSEC traceability precludes DANE\n"); } #endif /*DANE*/ @@ -2448,7 +2448,7 @@ if (!continue_hostname || atrn_domains) if (atrn_mode && *atrn_mode == 'P') { - DEBUG(D_transport) + DEBUG(transport) debug_printf("ATRN mode: TCP%s connection already present\n", tls_out.active.sock >= 0 ? "/TLS" : ""); sx->cctx.sock = 0; @@ -2480,13 +2480,13 @@ if (!continue_hostname || atrn_domains) if ( read_ehlo_cache_entry(sx) && sx->ehlo_resp.cleartext_features & OPTION_EARLY_PIPE) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("Using cached cleartext PIPECONNECT\n"); sx->early_pipe_active = TRUE; sx->peer_offered = sx->ehlo_resp.cleartext_features; } } - else DEBUG(D_transport) + else DEBUG(transport) debug_printf("helo needs $sending_ip_address; avoid early-pipelining\n"); CONNECT_RETRY: @@ -2513,7 +2513,7 @@ if (!continue_hostname || atrn_domains) if (sx->conn_args.host->tls_needs == SRV_TLS_ON_CONNECT) { SRV_SMTPS_RETRY: - DEBUG(D_transport) + DEBUG(transport) debug_printf(" TCP connect failed for port %d;" " retrying with require-STARTTLS on tpt option port\n", sx->port); sx->smtps = FALSE; @@ -2729,13 +2729,13 @@ goto SEND_QUIT; if ( (ob->hosts_require_auth || ob->hosts_try_auth) && f.smtp_in_early_pipe_no_auth) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("may need to auth, so pipeline no further\n"); if (smtp_write_command(sx, SCMD_FLUSH, NULL) < 0) goto SEND_FAILED; if (sync_responses(sx, 2, 0) != RESP_NOERROR) { - HDEBUG(D_transport) + HDEBUG(transport) debug_printf("failed reaping pipelined cmd responses\n"); goto RESPONSE_FAILED; } @@ -2748,7 +2748,7 @@ goto SEND_QUIT; goto RESPONSE_FAILED; } else - DEBUG(D_transport) + DEBUG(transport) debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n"); #ifndef DISABLE_PIPE_CONNECT @@ -2820,7 +2820,7 @@ goto SEND_QUIT; if ( (sx->peer_offered & (OPTION_PIPE | OPTION_EARLY_PIPE)) == (OPTION_PIPE | OPTION_EARLY_PIPE)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("PIPECONNECT usable in future for this IP\n"); sx->ehlo_resp.cleartext_auths = study_ehlo_auths(sx); write_ehlo_cache_entry(sx); @@ -2884,12 +2884,12 @@ else if (sx->conn_args.host->port != continue_host_port) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("Closing continued connection due to port mismatch:" " %d/%d\n", sx->conn_args.host->port, continue_host_port); smtp_debug_cmd(US"QUIT", 0); if (write(0, "QUIT\r\n", 6) < 0) - DEBUG(D_any) debug_printf("stupid compiler\n"); + DEBUG(any) debug_printf("stupid compiler\n"); close(0); tls_out.active.sock = -1; continue_hostname = continue_proxy_cipher = NULL; @@ -2919,7 +2919,7 @@ else ) { sx->pipelining_used = pipelining_active = !!(smtp_peer_options & OPTION_PIPE); - HDEBUG(D_transport) debug_printf("continued connection, %s TLS\n", + HDEBUG(transport) debug_printf("continued connection, %s TLS\n", continue_proxy_cipher ? "proxied" : "verify conn with"); tls_out.certificate_verified = !!(continue_flags & CTF_CV); @@ -2931,7 +2931,7 @@ else #endif return OK; } - HDEBUG(D_transport) debug_printf("continued connection, no TLS\n"); + HDEBUG(transport) debug_printf("continued connection, no TLS\n"); } /* If TLS is available on this connection, whether continued or not, attempt to @@ -2965,7 +2965,7 @@ if ( smtp_peer_options & OPTION_TLS { if (sync_responses(sx, 2, 0) != RESP_NOERROR) { - HDEBUG(D_transport) + HDEBUG(transport) debug_printf("failed reaping pipelined cmd responses\n"); close(sx->cctx.sock); sx->cctx.sock = -1; @@ -3017,7 +3017,7 @@ if ( smtp_peer_options & OPTION_TLS be called again to try in clear on a new connection, if the options permit it for this host. */ TLS_CONN_FAILED: - DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr); + DEBUG(tls) debug_printf("TLS session fail: %s\n", tls_errstr); # ifdef SUPPORT_DANE if (sx->conn_args.dane) @@ -3051,7 +3051,7 @@ if ( smtp_peer_options & OPTION_TLS if (sx->inblock.ptr != sx->inblock.ptrend) { - DEBUG(D_tls) + DEBUG(tls) { int i = sx->inblock.ptrend - sx->inblock.ptr; debug_printf("unused data in input buffer after ack for STARTTLS:\n" @@ -3111,7 +3111,7 @@ if (tls_out.active.sock >= 0) sx->peer_offered = sx->ehlo_resp.crypted_features; if ((sx->early_pipe_active = !!(sx->ehlo_resp.crypted_features & OPTION_EARLY_PIPE))) - DEBUG(D_transport) debug_printf("Using cached crypted PIPECONNECT\n"); + DEBUG(transport) debug_printf("Using cached crypted PIPECONNECT\n"); } #endif #ifdef EXPERIMENTAL_ESMTP_LIMITS @@ -3143,7 +3143,7 @@ if (tls_out.active.sock >= 0) else { greeting_cmd = US"HELO"; - DEBUG(D_transport) + DEBUG(transport) debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n"); } @@ -3287,7 +3287,7 @@ if ( !continue_hostname && (!atrn_domains || atrn_mode && *atrn_mode == 'C') && verify_check_given_host(CUSS &ob->hosts_avoid_pipelining, sx->conn_args.host) != OK) smtp_peer_options |= OPTION_PIPE; - DEBUG(D_transport) debug_printf("%susing PIPELINING\n", + DEBUG(transport) debug_printf("%susing PIPELINING\n", smtp_peer_options & OPTION_PIPE ? "" : "not "); if ( sx->peer_offered & OPTION_CHUNKING @@ -3295,7 +3295,7 @@ if ( !continue_hostname && (!atrn_domains || atrn_mode && *atrn_mode == 'C') smtp_peer_options |= OPTION_CHUNKING; if (smtp_peer_options & OPTION_CHUNKING) - DEBUG(D_transport) debug_printf("CHUNKING usable\n"); + DEBUG(transport) debug_printf("CHUNKING usable\n"); #ifndef DISABLE_PRDR if ( sx->peer_offered & OPTION_PRDR @@ -3303,12 +3303,12 @@ if ( !continue_hostname && (!atrn_domains || atrn_mode && *atrn_mode == 'C') smtp_peer_options |= OPTION_PRDR; if (smtp_peer_options & OPTION_PRDR) - DEBUG(D_transport) debug_printf("PRDR usable\n"); + DEBUG(transport) debug_printf("PRDR usable\n"); #endif /* Note if the server supports DSN */ smtp_peer_options |= sx->peer_offered & OPTION_DSN; - DEBUG(D_transport) debug_printf("%susing DSN\n", + DEBUG(transport) debug_printf("%susing DSN\n", sx->peer_offered & OPTION_DSN ? "" : "not "); #ifndef DISABLE_PIPE_CONNECT @@ -3319,7 +3319,7 @@ if ( !continue_hostname && (!atrn_domains || atrn_mode && *atrn_mode == 'C') && ( sx->ehlo_resp.cleartext_features | sx->ehlo_resp.crypted_features) & OPTION_EARLY_PIPE) { - DEBUG(D_transport) debug_printf("PIPECONNECT usable in future for this IP\n"); + DEBUG(transport) debug_printf("PIPECONNECT usable in future for this IP\n"); sx->ehlo_resp.crypted_auths = study_ehlo_auths(sx); write_ehlo_cache_entry(sx); } @@ -3384,7 +3384,7 @@ if (sx->addrlist->prop.utf8_msg) sx->utf8_needed = !sx->addrlist->prop.utf8_downcvt && !sx->addrlist->prop.utf8_downcvt_maybe; - DEBUG(D_transport) if (!sx->utf8_needed) + DEBUG(transport) if (!sx->utf8_needed) debug_printf("utf8: %s downconvert\n", sx->addrlist->prop.utf8_downcvt ? "mandatory" : "optional"); } @@ -3517,7 +3517,7 @@ works because the NULL setting is passed back to the calling process, and remote_max_parallel is forced to 1 when delivering over an existing connection, */ -HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); +HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(close)>>\n"); if (sx->send_quit) { shutdown(sx->cctx.sock, SHUT_WR); @@ -3785,7 +3785,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; && Ustrcmp(addr->domain, sx->first_addr->domain) != 0 /* dom diff from first */ ) { - DEBUG(D_transport) debug_printf("skipping different domain %s\n", addr->domain); + DEBUG(transport) debug_printf("skipping different domain %s\n", addr->domain); /* Ensure the smtp-response reaper does not think the address had a RCPT command sent for it. Reset to PENDING_DEFER in smtp_deliver(), where we @@ -3849,7 +3849,7 @@ for (addr = sx->first_addr, address_count = 0, pipe_limit = 100; if (sx->RCPT_452) { - DEBUG(D_transport) debug_printf("seen 452 too-many-rcpts\n"); + DEBUG(transport) debug_printf("seen 452 too-many-rcpts\n"); sx->RCPT_452 = FALSE; /* sx->next_addr has been reset for fast_retry */ return sw_mrc_ok; @@ -3932,7 +3932,7 @@ do if (rc <= 0) { - DEBUG(D_transport) if (rc == 0) debug_printf("%s: timed out\n", __FUNCTION__); + DEBUG(transport) if (rc == 0) debug_printf("%s: timed out\n", __FUNCTION__); goto done; } @@ -3940,11 +3940,11 @@ do if (p[0].revents & POLLERR || p[1].revents & POLLERR) { - DEBUG(D_transport) debug_printf("poll: err cond on %s fd\n", + DEBUG(transport) debug_printf("poll: err cond on %s fd\n", p[0].revents & POLLERR ? "tls" : "proxy"); if (!(p[0].revents & POLLIN || p[1].events & POLLIN)) goto done; - DEBUG(D_transport) debug_printf("- but also readable; no exit yet\n"); + DEBUG(transport) debug_printf("- but also readable; no exit yet\n"); } } while (rc < 0 || !(p[0].revents & POLLIN || p[1].revents & POLLIN)); @@ -4113,7 +4113,7 @@ if (sx->conn_args.dane) if ( a->transport_return == PENDING_DEFER && Ustrcmp(dane_domain, a->domain) != 0) { - DEBUG(D_transport) debug_printf("DANE: holding %s for later\n", a->domain); + DEBUG(transport) debug_printf("DANE: holding %s for later\n", a->domain); dane_held = TRUE; a->transport_return = DANE; } @@ -4152,7 +4152,7 @@ if (tblock->filter_command) ) { smtp_peer_options &= ~OPTION_CHUNKING; - DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n"); + DEBUG(transport) debug_printf("CHUNKING not usable due to transport filter\n"); } } @@ -4251,7 +4251,7 @@ if ( !(smtp_peer_options & OPTION_CHUNKING) #ifndef DISABLE_PIPE_CONNECT case -5: /* TLS first-read error */ - case -4: HDEBUG(D_transport) + case -4: HDEBUG(transport) debug_printf("failed reaping pipelined cmd responses\n"); #endif default: goto RESPONSE_FAILED; /* I/O error, or any MAIL/DATA error */ @@ -4321,7 +4321,7 @@ else sigalrm_seen = FALSE; transport_write_timeout = ob->data_timeout; smtp_command = US"sending data block"; /* For error messages */ - DEBUG(D_transport|D_v) + DEBUG(transport|v) if (smtp_peer_options & OPTION_CHUNKING) debug_printf(" will write message using CHUNKING\n"); else @@ -4406,7 +4406,7 @@ else (oicf)smtp_are_same_identities, (void*)&t_compare); if (!tcw) { - HDEBUG(D_transport) debug_printf("will pipeline QUIT\n"); + HDEBUG(transport) debug_printf("will pipeline QUIT\n"); tctx.options |= topt_no_flush; } @@ -4490,7 +4490,7 @@ else sx->send_tlsclose = FALSE; /* avoid later repeat */ } #endif - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(shutdown)>>\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(shutdown)>>\n"); shutdown(sx->cctx.sock, SHUT_WR); /* flush output buffer, with TCP FIN */ } tls_out.smtp_quit = TRUE; @@ -4514,7 +4514,7 @@ else #ifndef DISABLE_PIPE_CONNECT case RESP_EHLO_ERR_TLS: /* TLS first-read error */ - case RESP_EPIPE_EHLO_ERR: HDEBUG(D_transport) + case RESP_EPIPE_EHLO_ERR: HDEBUG(transport) debug_printf("failed reaping pipelined cmd responses\n"); #endif default: goto RESPONSE_FAILED; /* I/O error, or any MAIL/DATA error */ @@ -4693,7 +4693,7 @@ else else sprintf(CS sx->buffer, "%.500s\n", addr->unique); - DEBUG(D_deliver) debug_printf("S:journalling %s", sx->buffer); + DEBUG(deliver) debug_printf("S:journalling %s", sx->buffer); len = Ustrlen(CS sx->buffer); if (write(journal_fd, sx->buffer, len) != len) log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for " @@ -4740,7 +4740,7 @@ else else sprintf(CS sx->buffer, "%.500s\n", addr->unique); - DEBUG(D_deliver) debug_printf("journalling(PRDR) %s\n", sx->buffer); + DEBUG(deliver) debug_printf("journalling(PRDR) %s\n", sx->buffer); len = Ustrlen(CS sx->buffer); if (write(journal_fd, sx->buffer, len) != len) log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for " @@ -4902,7 +4902,7 @@ if (!sx->ok) *message_defer = TRUE; } #ifdef TIOCOUTQ - DEBUG(D_transport) if (sx->cctx.sock >= 0) + DEBUG(transport) if (sx->cctx.sock >= 0) { int n; if (ioctl(sx->cctx.sock, TIOCOUTQ, &n) == 0) @@ -4972,7 +4972,7 @@ hosts_nopass_tls. */ happy: -DEBUG(D_transport) +DEBUG(transport) debug_printf("ok=%d send_quit=%d send_rset=%d continue_more=%d " "yield=%d first_address is %sNULL\n", sx->ok, sx->send_quit, sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : ""); @@ -4980,7 +4980,7 @@ DEBUG(D_transport) if (sx->completed_addr && sx->ok && sx->send_quit) if (mail_limit = continue_sequence >= sx->max_mail) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("reached limit %u for MAILs per conn\n", sx->max_mail); /* We will close the smtp session and connection, and clear continue_hostname. Then if there are further addrs for the message we will @@ -5037,7 +5037,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) &pass_message); if (!sx->send_quit) { - DEBUG(D_transport) debug_printf("H=%s [%s] %s\n", + DEBUG(transport) debug_printf("H=%s [%s] %s\n", host->name, host->address, msg); } } @@ -5220,7 +5220,7 @@ if (sx->send_quit) means we (client) take the TIME_WAIT state, so the server (which likely has a higher connection rate) does not have to. */ - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(shutdown)>>\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(shutdown)>>\n"); shutdown(sx->cctx.sock, SHUT_WR); } @@ -5264,7 +5264,7 @@ if (sx->send_quit || tcw_done && !tcw) && fcntl(sx->cctx.sock, F_SETFL, O_NONBLOCK) == 0) for (int i = 16, n; /* drain socket */ (n = read(sx->cctx.sock, sx->inbuffer, sizeof(sx->inbuffer))) > 0 && i > 0; - i--) HDEBUG(D_transport|D_acl|D_v) + i--) HDEBUG(transport|acl|v) { int m = MIN(n, 64); debug_printf_indent(" SMTP(drain %d bytes)<< %.*s\n", n, m, sx->inbuffer); @@ -5272,7 +5272,7 @@ if (sx->send_quit || tcw_done && !tcw) debug_printf("0x%02x\n", sx->inbuffer[m]); } } -HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); +HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(close)>>\n"); (void)close(sx->cctx.sock); sx->cctx.sock = -1; continue_hostname = NULL; @@ -5296,7 +5296,7 @@ if (dane_held) to get the domain string for SNI */ sx->first_addr = a; - DEBUG(D_transport) debug_printf("DANE: go-around for %s\n", a->domain); + DEBUG(transport) debug_printf("DANE: go-around for %s\n", a->domain); } } continue_sequence = 1; /* for consistency */ @@ -5493,7 +5493,7 @@ uschar * expanded_hosts = NULL, * pistring; uschar * tid = string_sprintf("%s transport", trname); host_item * hostlist = addrlist->host_list, * host = NULL; -DEBUG(D_transport) +DEBUG(transport) { debug_printf("%s transport entered\n", trname); for (address_item * addr = addrlist; addr; addr = addr->next) @@ -5551,7 +5551,7 @@ if (!hostlist || (ob->hosts_override && ob->hosts)) return FALSE; /* Only top address has status */ } - DEBUG(D_transport) debug_printf("using the transport's hosts: %s\n", + DEBUG(transport) debug_printf("using the transport's hosts: %s\n", ob->hosts); /* If the transport's host list contains no '$' characters, and we are not @@ -5575,7 +5575,7 @@ if (!hostlist || (ob->hosts_override && ob->hosts)) addrlist->transport_return = f.search_find_defer ? DEFER : PANIC; return FALSE; /* Only top address has status */ } - DEBUG(D_transport) + DEBUG(transport) debug_printf("expanded list of hosts %q to %q\n", s, expanded_hosts); s = expanded_hosts; } @@ -5596,7 +5596,7 @@ if (!hostlist || (ob->hosts_override && ob->hosts)) /* Get the hosts_randomize transport option, expanding if needed */ { BOOL randomize; - if (exp_bool(addrlist, US"transport", tblock->drinst.name, D_transport, + if (exp_bool(addrlist, US"transport", tblock->drinst.name, IS_DEBUG(transport), US"hosts_randomize", ob->hosts_randomize, ob->expand_hosts_randomize, &randomize)) { @@ -5636,7 +5636,7 @@ connection). */ else if (hostlist->mx == MX_NONE && !continue_hostname) { BOOL randomize; - if (exp_bool(addrlist, US"transport", tblock->drinst.name, D_transport, + if (exp_bool(addrlist, US"transport", tblock->drinst.name, IS_DEBUG(transport), US"hosts_randomize", ob->hosts_randomize, ob->expand_hosts_randomize, &randomize)) { @@ -5757,7 +5757,7 @@ retry_non_continued: if (total_hosts_tried > 0) { - DEBUG(D_transport|D_acl|D_v) + DEBUG(transport|acl|v) debug_printf("Clearing TFO as not first host for message\n"); ob->hosts_try_fastopen = US""; } @@ -5788,12 +5788,12 @@ retry_non_continued: if (host->status >= hstatus_unusable) { - DEBUG(D_transport) debug_printf("%s has no address and is unusable - skipping\n", + DEBUG(transport) debug_printf("%s has no address and is unusable - skipping\n", host->name); continue; } - DEBUG(D_transport) debug_printf("getting address for %s\n", host->name); + DEBUG(transport) debug_printf("getting address for %s\n", host->name); /* The host name is permitted to have an attached port. Find it, and strip it from the name. Just remember it for now. */ @@ -5836,7 +5836,7 @@ retry_non_continued: retry_add_item(addrlist, string_sprintf("R:%s", host->name), 0); expired = FALSE; if (rc == HOST_FIND_AGAIN) hosts_defer++; else hosts_fail++; - DEBUG(D_transport) debug_printf("rc = %s for %s\n", (rc == HOST_FIND_AGAIN)? + DEBUG(transport) debug_printf("rc = %s for %s\n", (rc == HOST_FIND_AGAIN)? "HOST_FIND_AGAIN" : "HOST_FIND_FAILED", host->name); host->status = hstatus_unusable; @@ -5905,7 +5905,7 @@ retry_non_continued: &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) == OK) ) { - DEBUG(D_transport) debug_printf("first-pass routing only\n"); + DEBUG(transport) debug_printf("first-pass routing only\n"); expired = FALSE; for (address_item * addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) @@ -5959,7 +5959,7 @@ retry_non_continued: || Ustrcmp(interface, sending_ip_address) != 0) ) { - DEBUG(D_transport) debug_printf_indent( + DEBUG(transport) debug_printf_indent( "tpt interface option mismatch with continued-connection\n"); /* Close the conn and recheck retry info */ continue_host_tried = FALSE; @@ -5984,7 +5984,7 @@ retry_non_continued: If either of these retry records are actually read, the keys used are returned to save recomputing them later. */ - if (exp_bool(addrlist, US"transport", trname, D_transport, + if (exp_bool(addrlist, US"transport", trname, IS_DEBUG(transport), US"retry_include_ip_address", ob->retry_include_ip_address, ob->expand_retry_include_ip_address, &incl_ip) != OK) continue; /* with next host */ @@ -5992,7 +5992,7 @@ retry_non_continued: host_is_expired = retry_check_address(addrlist->domain, host, pistring, incl_ip, &retry_host_key, &retry_message_key); - DEBUG(D_transport) debug_printf("%s [%s]%s retry-status = %s\n", host->name, + DEBUG(transport) debug_printf("%s [%s]%s retry-status = %s\n", host->name, host->address ? host->address : US"", pistring, host->status == hstatus_usable ? "usable" : host->status == hstatus_unusable ? "unusable" @@ -6035,7 +6035,7 @@ retry_non_continued: || host->status != hstatus_unusable_expired || host->last_try > received_time.tv_sec) continue; - DEBUG(D_transport) debug_printf("trying expired host %s [%s]%s\n", + DEBUG(transport) debug_printf("trying expired host %s [%s]%s\n", host->name, host->address, pistring); host_is_expired = TRUE; } @@ -6058,7 +6058,7 @@ retry_non_continued: serialize_key = string_sprintf("host-serialize-%s", host->name); if (!enq_start(serialize_key, 1)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("skipping host %s because another Exim process " "is connected to it\n", host->name); hosts_serial++; @@ -6078,11 +6078,11 @@ retry_non_continued: /* Obscure situation; at least one case (bug 3059, fixed) where a previous host try returned DEFER, but having moved all recipients away from DEFER (the waiting-to-be-done state). */ - DEBUG(D_transport) debug_printf("no pending recipients\n"); + DEBUG(transport) debug_printf("no pending recipients\n"); goto END_TRANSPORT; } - DEBUG(D_transport) debug_printf("delivering %s to %s [%s] (%s%s)\n", + DEBUG(transport) debug_printf("delivering %s to %s [%s] (%s%s)\n", message_id, host->name, host->address, addrlist->address, addrlist->next ? ", ..." : ""); @@ -6104,7 +6104,7 @@ retry_non_continued: addr->special_action = '*'; addr->message = US"delivery bypassed by -N option"; } - DEBUG(D_transport) + DEBUG(transport) { debug_printf("*** delivery by %s transport bypassed by -N option\n" "*** host and remaining hosts:\n", trname); @@ -6146,13 +6146,13 @@ retry_non_continued: if (!host_is_expired && ++unexpired_hosts_tried >= ob->hosts_max_try) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("hosts_max_try limit reached with this host\n"); for (host_item * h = host; h; h = h->next) if (h->mx != host->mx) { nexthost = h; unexpired_hosts_tried--; - DEBUG(D_transport) debug_printf("however, a higher MX host exists " + DEBUG(transport) debug_printf("however, a higher MX host exists " "and will be tried\n"); break; } @@ -6256,7 +6256,7 @@ retry_non_continued: if (!retry_host_key) { BOOL incl_ip; - if (exp_bool(addrlist, US"transport", trname, D_transport, + if (exp_bool(addrlist, US"transport", trname, IS_DEBUG(transport), US"retry_include_ip_address", ob->retry_include_ip_address, ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ @@ -6302,7 +6302,7 @@ retry_non_continued: if (!retry_message_key) { BOOL incl_ip; - if (exp_bool(addrlist, US"transport", trname, D_transport, + if (exp_bool(addrlist, US"transport", trname, IS_DEBUG(transport), US"retry_include_ip_address", ob->retry_include_ip_address, ob->expand_retry_include_ip_address, &incl_ip) != OK) incl_ip = TRUE; /* error; use most-specific retry record */ @@ -6364,12 +6364,12 @@ retry_non_continued: if (timedout) { unexpired_hosts_tried--; - DEBUG(D_transport) debug_printf("temporary delivery error(s) override " + DEBUG(transport) debug_printf("temporary delivery error(s) override " "hosts_max_try (message older than host's retry time)\n"); } } - DEBUG(D_transport) + DEBUG(transport) { if (unexpired_hosts_tried >= ob->hosts_max_try) debug_printf("reached transport hosts_max_try limit %d\n", @@ -6391,8 +6391,8 @@ retry_non_continued: { int fd = cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0; - DEBUG(D_transport) debug_printf("no hosts match already-open connection\n"); - DEBUG(D_transport) debug_printf(" SMTP>>QUIT\n"); + DEBUG(transport) debug_printf("no hosts match already-open connection\n"); + DEBUG(transport) debug_printf(" SMTP>>QUIT\n"); #ifndef DISABLE_TLS /* A TLS conn could be open for a cutthrough, but not for a plain continued- transport */ @@ -6410,7 +6410,7 @@ retry_non_continued: (void) write(fd, US"QUIT\r\n", 6); #endif - DEBUG(D_transport) debug_printf(" SMTP(close)>>\n"); + DEBUG(transport) debug_printf(" SMTP(close)>>\n"); (void) close(fd); cutthrough.cctx.sock = -1; continue_hostname = NULL; @@ -6422,7 +6422,7 @@ retry_non_continued: ob->delay_after_cutoff is FALSE. The second time round we will try those hosts that haven't been tried since the message arrived. */ - DEBUG(D_transport) + DEBUG(transport) { debug_printf("all IP addresses skipped or deferred at least one address\n"); if (expired && !ob->delay_after_cutoff && cutoff_retry == 0) @@ -6466,13 +6466,13 @@ for (address_item * addr = addrlist; addr; addr = addr->next) if (host) if (total_hosts_tried >= ob->hosts_max_try_hardlimit) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("hosts_max_try_hardlimit reached: behave as if all " "hosts were tried\n"); } else { - DEBUG(D_transport) + DEBUG(transport) debug_printf("hosts_max_try limit caused some hosts to be skipped\n"); setflag(addr, af_retry_skipped); } @@ -6543,7 +6543,7 @@ if (update_waiting && tblock->connection_max_messages != 1) END_TRANSPORT: -DEBUG(D_transport) debug_printf("Leaving %s transport\n", trname); +DEBUG(transport) debug_printf("Leaving %s transport\n", trname); return TRUE; /* Each address has its status */ } diff --git a/src/src/transports/tf_maildir.c b/src/src/transports/tf_maildir.c index fdbe01e71..28a5f6dd3 100644 --- a/src/src/transports/tf_maildir.c +++ b/src/src/transports/tf_maildir.c @@ -50,7 +50,7 @@ int i; struct stat statbuf; const char * const subdirs[] = { "/tmp", "/new", "/cur" }; -DEBUG(D_transport) +DEBUG(transport) debug_printf("ensuring maildir directories exist in %s\n", path); /* First ensure that the path we have is a directory; if it does not exist, @@ -102,7 +102,7 @@ for (i = 0; i < 4; i++) addr->basic_errno = errno; return FALSE; } - DEBUG(D_transport) + DEBUG(transport) debug_printf("created directory %s%s\n", path, mdir); break; /* out of the race loop */ } @@ -145,7 +145,7 @@ if (maildirfolder_create_regex) { const pcre2_code * re; - DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n"); + DEBUG(transport) debug_printf("checking for maildirfolder requirement\n"); if (!(re = regex_compile(maildirfolder_create_regex, MCS_NOFLAGS, &addr->message, pcre_gen_cmp_ctx))) @@ -156,7 +156,7 @@ if (maildirfolder_create_regex) uschar *fname = string_sprintf("%s/maildirfolder", path); if (Ustat(fname, &statbuf) == 0) { - DEBUG(D_transport) debug_printf("maildirfolder already exists\n"); + DEBUG(transport) debug_printf("maildirfolder already exists\n"); } else { @@ -168,12 +168,12 @@ if (maildirfolder_create_regex) return FALSE; } (void)close(fd); - DEBUG(D_transport) debug_printf("created maildirfolder file\n"); + DEBUG(transport) debug_printf("created maildirfolder file\n"); } } else { - DEBUG(D_transport) debug_printf("maildirfolder file not required\n"); + DEBUG(transport) debug_printf("maildirfolder file not required\n"); } } @@ -207,7 +207,7 @@ len = Ustrlen(buffer); if (lseek(fd, 0, SEEK_END) >= 0) { len = write(fd, buffer, len); - DEBUG(D_transport) + DEBUG(transport) debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer); } } @@ -265,7 +265,7 @@ for (struct dirent *ent; ent = readdir(dir); ) if (dir_regex && !regex_match(dir_regex, name, -1, NULL)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("skipping %s/%s: dir_regex does not match\n", path, name); continue; } @@ -275,7 +275,7 @@ for (struct dirent *ent; ent = readdir(dir); ) s = string_sprintf("%s/%s", path, name); if (Ustat(s, &statbuf) < 0) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("maildir_compute_size: stat error %d for %s: %s\n", errno, s, strerror(errno)); continue; @@ -283,7 +283,7 @@ for (struct dirent *ent; ent = readdir(dir); ) if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("skipping %s/%s: not a directory\n", s, name); continue; } @@ -306,7 +306,7 @@ for (struct dirent *ent; ent = readdir(dir); ) } closedir(dir); -DEBUG(D_transport) +DEBUG(transport) { if (timestamp_only) debug_printf("maildir_compute_size (timestamp_only): %ld\n", @@ -366,11 +366,11 @@ the same thing. */ filename = string_sprintf("%s/maildirsize", path); -DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path); +DEBUG(transport) debug_printf("looking for maildirsize in %s\n", path); if ((fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600)) < 0) { if (errno != ENOENT) return -1; - DEBUG(D_transport) + DEBUG(transport) debug_printf("%s does not exist: recalculating\n", filename); goto RECALCULATE; } @@ -381,7 +381,7 @@ compute the maildir size from the file. */ if ((count = read(fd, buffer, sizeof(buffer))) >= sizeof(buffer)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("maildirsize file too big (%d): recalculating\n", count); goto RECALCULATE; } @@ -389,7 +389,7 @@ buffer[count] = 0; /* Ensure string terminated */ /* Read the quota parameters from the first line of the data. */ -DEBUG(D_transport) +DEBUG(transport) debug_printf("reading quota parameters from maildirsize data\n"); for (;;) @@ -404,7 +404,7 @@ for (;;) else if (*endptr == 'C') cached_quota_filecount = (int)n; if (!isalpha(*endptr++)) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("quota parameter number not followed by letter in " "\"%.*s\": recalculating maildirsize\n", (int)(endptr - buffer), buffer); @@ -413,7 +413,7 @@ for (;;) if (*endptr == '\n' || !*endptr) break; if (*endptr++ != ',') { - DEBUG(D_transport) + DEBUG(transport) debug_printf("quota parameter not followed by comma in " "\"%.*s\": recalculating maildirsize\n", (int)(endptr - buffer), buffer); @@ -427,7 +427,7 @@ for (;;) if (cached_quota != ob->quota_value || cached_quota_filecount != ob->quota_filecount_value) { - DEBUG(D_transport) + DEBUG(transport) debug_printf("cached quota is out of date: recalculating\n" " quota=" OFF_T_FMT " cached_quota=" OFF_T_FMT " filecount_quota=%d " "cached_quota_filecount=%d\n", ob->quota_value, @@ -438,7 +438,7 @@ if (cached_quota != ob->quota_value || /* Quota values agree; parse the rest of the data to get the sizes. At this stage, *endptr points either to 0 or to '\n'. */ -DEBUG(D_transport) +DEBUG(transport) debug_printf("computing maildir size from maildirsize data\n"); for (; *endptr++ == '\n' && *endptr; ) @@ -462,7 +462,7 @@ if (!*endptr) { if (size < 0 || filecount < 0) { - DEBUG(D_transport) debug_printf("negative value in maildirsize " + DEBUG(transport) debug_printf("negative value in maildirsize " "(size=" OFF_T_FMT " count=%d): recalculating\n", size, filecount); goto RECALCULATE; } @@ -477,7 +477,7 @@ if (!*endptr) struct stat statbuf; if (linecount > 1) { - DEBUG(D_transport) debug_printf("over quota and maildirsize has " + DEBUG(transport) debug_printf("over quota and maildirsize has " "more than 1 entry: recalculating\n"); goto RECALCULATE; } @@ -486,7 +486,7 @@ if (!*endptr) if (time(NULL) - statbuf.st_mtime > 15*60) { - DEBUG(D_transport) debug_printf("over quota and maildirsize is older " + DEBUG(transport) debug_printf("over quota and maildirsize is older " "than 15 minutes: recalculating\n"); goto RECALCULATE; } @@ -502,7 +502,7 @@ else uschar *tempname; struct timeval tv; - DEBUG(D_transport) + DEBUG(transport) { const uschar * p = endptr; while (p > buffer && p[-1] != '\n') p--; @@ -545,12 +545,12 @@ else /* If any of the directories have been modified since the last timestamp we saw, we have to junk this maildirsize file. */ - DEBUG(D_transport) debug_printf("checking subdirectory timestamps\n"); + DEBUG(transport) debug_printf("checking subdirectory timestamps\n"); new_latest = 0; (void)maildir_compute_size(path, NULL, &new_latest , NULL, dir_regex, TRUE); if (new_latest > old_latest) { - DEBUG(D_transport) debug_printf("abandoning maildirsize because of " + DEBUG(transport) debug_printf("abandoning maildirsize because of " "a later subdirectory modification\n"); (void)Uunlink(filename); (void)close(fd); @@ -560,7 +560,7 @@ else /* Return the sizes and the file descriptor, if any */ -DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT +DEBUG(transport) debug_printf("returning maildir size=" OFF_T_FMT " filecount=%d\n", size, filecount); *returned_size = size; *returned_filecount = filecount; diff --git a/src/src/utf8.c b/src/src/utf8.c index 6cb104ddd..df741f5cf 100644 --- a/src/src/utf8.c +++ b/src/src/utf8.c @@ -159,7 +159,7 @@ res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-'; if ((rc = punycode_encode(ucs4_len, p, NULL, &p_len, CS res+4)) != PUNYCODE_SUCCESS) { - DEBUG(D_expand) debug_printf("l_u2a: bad '%s'\n", punycode_strerror(rc)); + DEBUG(expand) debug_printf("l_u2a: bad '%s'\n", punycode_strerror(rc)); free(p); if (err) *err = US punycode_strerror(rc); return NULL; @@ -179,7 +179,7 @@ punycode_uint * p; int rc; uschar * s, * res; -DEBUG(D_expand) debug_printf("l_a2u: '%s'\n", alabel); +DEBUG(expand) debug_printf("l_a2u: '%s'\n", alabel); alabel += 4; p_len = Ustrlen(alabel); p = store_get((p_len+1) * sizeof(*p), alabel); @@ -222,7 +222,7 @@ const uschar * l, * d; if (!*utf8) return string_copy(utf8); -DEBUG(D_expand) debug_printf("addr from utf8 <%s>", utf8); +DEBUG(expand) debug_printf("addr from utf8 <%s>", utf8); for (const uschar * s = utf8; *s; s++) if (*s == '@') @@ -233,12 +233,12 @@ for (const uschar * s = utf8; *s; s++) ) return NULL; l = string_sprintf("%s@%s", l, d); - DEBUG(D_expand) debug_printf(" -> <%s>\n", l); + DEBUG(expand) debug_printf(" -> <%s>\n", l); return l; } l = string_localpart_utf8_to_alabel(utf8, err); -DEBUG(D_expand) debug_printf(" -> <%s>\n", l); +DEBUG(expand) debug_printf(" -> <%s>\n", l); return l; } diff --git a/src/src/verify.c b/src/src/verify.c index 931aff6e2..910da5104 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -51,7 +51,7 @@ dbdata_callout_cache *cache_record; if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length))) { - HDEBUG(D_verify) debug_printf_indent("callout cache: no %s record found for %s\n", type, key); + HDEBUG(verify) debug_printf_indent("callout cache: no %s record found for %s\n", type, key); return NULL; } @@ -65,7 +65,7 @@ now = time(NULL); if (now - cache_record->gen.time_stamp > expire) { - HDEBUG(D_verify) debug_printf_indent("callout cache: %s record expired for %s\n", type, key); + HDEBUG(verify) debug_printf_indent("callout cache: %s record expired for %s\n", type, key); return NULL; } @@ -92,7 +92,7 @@ if (type[0] == 'd' && cache_record->result != ccache_reject) cache_record->random_result = ccache_unknown; } -HDEBUG(D_verify) debug_printf_indent("callout cache: found %s record for %s\n", type, key); +HDEBUG(verify) debug_printf_indent("callout cache: found %s record for %s\n", type, key); return cache_record; } @@ -119,11 +119,11 @@ stage, unless caching has been disabled. */ if (options & vopt_callout_no_cache) { - HDEBUG(D_verify) debug_printf_indent("callout cache: disabled by no_cache\n"); + HDEBUG(verify) debug_printf_indent("callout cache: disabled by no_cache\n"); } else if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) { - HDEBUG(D_verify) debug_printf_indent("callout cache: not available\n"); + HDEBUG(verify) debug_printf_indent("callout cache: not available\n"); } else { @@ -153,7 +153,7 @@ else if ( cache_record->result == ccache_reject || *from_address == 0 && cache_record->result == ccache_reject_mfnull) { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: domain gave initial rejection, or " "does not accept HELO or MAIL FROM:<>\n"); setflag(addr, af_verify_nsfail); @@ -174,14 +174,14 @@ else if (options & vopt_callout_random) switch(cache_record->random_result) { case ccache_accept: - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: domain accepts random addresses\n"); *failure_ptr = US"random"; dbfn_close(dbm_file); return TRUE; /* Default yield is OK */ case ccache_reject: - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: domain rejects random addresses\n"); *opt_ptr = options & ~vopt_callout_random; new_domain_record->random_result = ccache_reject; @@ -189,7 +189,7 @@ else break; default: - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: need to check random address handling " "(not cached or cache expired)\n"); dbfn_close(dbm_file); @@ -206,7 +206,7 @@ else if (cache_record->postmaster_result == ccache_reject) { setflag(addr, af_verify_pmfail); - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: domain does not accept " "RCPT TO:\n"); *yield = FAIL; @@ -218,7 +218,7 @@ else } if (cache_record->postmaster_result == ccache_unknown) { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: need to check RCPT " "TO: (not cached or cache expired)\n"); dbfn_close(dbm_file); @@ -230,7 +230,7 @@ else that the value in the cache record is preserved (with its old timestamp). */ - HDEBUG(D_verify) debug_printf_indent("callout cache: domain accepts RCPT " + HDEBUG(verify) debug_printf_indent("callout cache: domain accepts RCPT " "TO:\n"); *pm_ptr = NULL; new_domain_record->postmaster_result = ccache_accept; @@ -253,12 +253,12 @@ else if (cache_address_record->result == ccache_accept) { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: address record is positive\n"); } else { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf_indent("callout cache: address record is negative\n"); addr->user_message = US"Previous (cached) callout verification failure"; *failure_ptr = US"recipient"; @@ -296,13 +296,13 @@ Otherwise the value is ccache_accept, ccache_reject, or ccache_reject_mfnull. */ if (dom_rec->result != ccache_unknown) if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) { - HDEBUG(D_verify) debug_printf_indent("callout cache: not available\n"); + HDEBUG(verify) debug_printf_indent("callout cache: not available\n"); } else { (void)dbfn_write(dbm_file, domain, dom_rec, (int)sizeof(dbdata_callout_cache)); - HDEBUG(D_verify) debug_printf_indent("wrote callout cache domain record for %s:\n" + HDEBUG(verify) debug_printf_indent("wrote callout cache domain record for %s:\n" " result=%d postmaster=%d random=%d\n", domain, dom_rec->result, @@ -319,13 +319,13 @@ if (done && addr_rec->result != ccache_unknown) dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE); if (!dbm_file) { - HDEBUG(D_verify) debug_printf_indent("no callout cache available\n"); + HDEBUG(verify) debug_printf_indent("no callout cache available\n"); } else { (void)dbfn_write(dbm_file, address_key, addr_rec, (int)sizeof(dbdata_callout_cache_address)); - HDEBUG(D_verify) debug_printf_indent("wrote %s callout cache address record for %s\n", + HDEBUG(verify) debug_printf_indent("wrote %s callout cache address record for %s\n", addr_rec->result == ccache_accept ? "positive" : "negative", address_key); } @@ -389,7 +389,7 @@ if (addr->transport == cutthrough.addr.transport) /* Match! Send the RCPT TO, set done from the response */ - DEBUG(D_verify) + DEBUG(verify) debug_printf("already-open verify connection matches recipient\n"); done = @@ -418,7 +418,7 @@ if (addr->transport == cutthrough.addr.transport) cancel_cutthrough_connection(TRUE, US"recipient rejected"); if (!resp || errno == ETIMEDOUT) { - HDEBUG(D_verify) debug_printf("SMTP timeout\n"); + HDEBUG(verify) debug_printf("SMTP timeout\n"); } else if (errno == 0) { @@ -538,7 +538,7 @@ if (options & vopt_is_recipient) transport_instance * tp = addr->transport; from_address = addr->prop.errors_address ? addr->prop.errors_address : sender_address; - DEBUG(D_verify) + DEBUG(verify) debug_printf(" return-path from routed addr: %s\n", from_address); GET_OPTION("return_path"); @@ -549,7 +549,7 @@ if (options & vopt_is_recipient) from_address = new_return_path; else if (!f.expand_string_forcedfail) return DEFER; - DEBUG(D_verify) + DEBUG(verify) debug_printf(" return-path from transport: %s\n", from_address); } } @@ -587,7 +587,7 @@ if (cached_callout_lookup(addr, address_key, from_address, if (!addr->transport) { - HDEBUG(D_verify) debug_printf("cannot callout via null transport\n"); + HDEBUG(verify) debug_printf("cannot callout via null transport\n"); } else if (Ustrcmp(addr->transport->drinst.driver_name, "smtp") != 0) @@ -665,7 +665,7 @@ coding means skipping this whole loop and doing the append separately. */ if (!host->address) { - DEBUG(D_verify) debug_printf("no IP address for host name %s: skipping\n", + DEBUG(verify) debug_printf("no IP address for host name %s: skipping\n", host->name); continue; } @@ -674,7 +674,7 @@ coding means skipping this whole loop and doing the append separately. */ if (time(NULL) - callout_start_time >= callout_overall) { - HDEBUG(D_verify) debug_printf("overall timeout for callout exceeded\n"); + HDEBUG(verify) debug_printf("overall timeout for callout exceeded\n"); break; } @@ -888,13 +888,13 @@ tls_retry_connection: '2', callout))) break; - HDEBUG(D_acl|D_v) + HDEBUG(acl|v) debug_printf_indent("problem after random/rset/mfrom; reopen conn\n"); random_local_part = NULL; #ifndef DISABLE_TLS tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT); #endif - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(close)>>\n"); (void)close(sx->cctx.sock); sx->cctx.sock = -1; #ifndef DISABLE_EVENT @@ -979,7 +979,7 @@ tls_retry_connection: for cutthrough. But no way to handle a subsequent rcpt, so just refuse any */ cancel_cutthrough_connection(TRUE, US"postmaster verify"); - HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n"); + HDEBUG(acl|v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n"); done = smtp_write_command(sx, SCMD_FLUSH, "RSET\r\n") >= 0 && smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', callout); @@ -1040,7 +1040,7 @@ no_conn: switch(errno) { case ETIMEDOUT: - HDEBUG(D_verify) debug_printf("SMTP timeout\n"); + HDEBUG(verify) debug_printf("SMTP timeout\n"); sx->send_quit = FALSE; break; @@ -1120,7 +1120,7 @@ no_conn: if (expand_string_nonempty(addr->transport->filter_command)) { cutthrough.delivery= FALSE; - HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n"); + HDEBUG(acl|v) debug_printf("Cutthrough cancelled by presence of transport filter\n"); } #ifndef DISABLE_DKIM /* DKIM signing needs to add a header after seeing the whole body, so we @@ -1129,7 +1129,7 @@ no_conn: if (expand_string_nonempty(ob->dkim.dkim_domain)) { cutthrough.delivery= FALSE; - HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n"); + HDEBUG(acl|v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n"); } #endif #ifdef EXPERIMENTAL_ARC @@ -1137,7 +1137,7 @@ no_conn: if (expand_string_nonempty(ob->arc_sign)) { cutthrough.delivery= FALSE; - HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of ARC signing\n"); + HDEBUG(acl|v) debug_printf("Cutthrough cancelled by presence of ARC signing\n"); } #endif } @@ -1153,7 +1153,7 @@ no_conn: && !sx->lmtp ) { - HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for %s\n", + HDEBUG(acl|v) debug_printf_indent("holding verify callout open for %s\n", cutthrough.delivery ? "cutthrough delivery" : "potential further verifies and delivery"); @@ -1217,7 +1217,7 @@ no_conn: sx->cctx.tls_ctx = NULL; } #endif - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(close)>>\n"); (void)close(sx->cctx.sock); sx->cctx.sock = -1; smtp_debug_cmd_report(); @@ -1296,7 +1296,7 @@ int vopt, rc; get rewritten. */ addr2 = *addr; -HDEBUG(D_acl) debug_printf_indent("----------- %s cutthrough setup ------------\n", +HDEBUG(acl) debug_printf_indent("----------- %s cutthrough setup ------------\n", rcpt_count > 1 ? "more" : "start"); vopt = transport_sender @@ -1307,7 +1307,7 @@ rc = verify_address(&addr2, -1, vopt, CUTTHROUGH_CMD_TIMEOUT, -1, -1, NULL, NULL, NULL); addr->message = addr2.message; addr->user_message = addr2.user_message; -HDEBUG(D_acl) debug_printf_indent("----------- end cutthrough setup ------------\n"); +HDEBUG(acl) debug_printf_indent("----------- end cutthrough setup ------------\n"); return rc; } @@ -1334,7 +1334,7 @@ if( return TRUE; } -HDEBUG(D_transport|D_acl) debug_printf_indent("cutthrough_send failed: %s\n", strerror(errno)); +HDEBUG(transport|acl) debug_printf_indent("cutthrough_send failed: %s\n", strerror(errno)); return FALSE; } @@ -1489,7 +1489,7 @@ if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only) /* We share a routine with the mainline transport to handle header add/remove/rewrites, but having a separate buffered-output function (for now) */ -HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n"); +HDEBUG(acl) debug_printf_indent("----------- start cutthrough headers send -----------\n"); tctx.u.fd = cutthrough.cctx.sock; tctx.tblock = cutthrough.addr.transport; @@ -1502,7 +1502,7 @@ tctx.options = topt_use_crlf; if (!transport_headers_send(&tctx, &cutthrough_write_chunk)) return FALSE; -HDEBUG(D_acl) debug_printf_indent("----------- done cutthrough headers send ------------\n"); +HDEBUG(acl) debug_printf_indent("----------- done cutthrough headers send ------------\n"); return TRUE; } @@ -1536,10 +1536,10 @@ if(fd >= 0) cutthrough.is_tls = FALSE; } #endif - HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n"); + HDEBUG(transport|acl|v) debug_printf_indent(" SMTP(close)>>\n"); (void)close(fd); smtp_debug_cmd_report(); - HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why); + HDEBUG(acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why); } ctctx.outblock.ptr = ctbuffer; } @@ -1557,7 +1557,7 @@ void release_cutthrough_connection(const uschar * why) { if (cutthrough.cctx.sock < 0) return; -HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why); +HDEBUG(acl) debug_printf_indent("release cutthrough conn: %s\n", why); cutthrough.cctx.sock = -1; cutthrough.cctx.tls_ctx = NULL; cutthrough.delivery = cutthrough.callout_hold_only = FALSE; @@ -1575,7 +1575,7 @@ uschar * cutthrough_finaldot(void) { uschar res; -HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> .\n"); +HDEBUG(transport|acl|v) debug_printf_indent(" SMTP>> .\n"); /* Assume data finshed with new-line */ if( !cutthrough_puts(US".", 1) @@ -1745,7 +1745,7 @@ verify_address(address_item * vaddr, int fd, int options, int callout, uschar * pm_mailfrom, BOOL * routed) { BOOL allok = TRUE; -BOOL full_info = fd >= 0 ? debug_selector != 0 : FALSE; +BOOL full_info = fd >= 0 ? ANY_DEBUG : FALSE; BOOL expn = (options & vopt_expn) != 0; BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0; int i; @@ -1792,7 +1792,7 @@ if (parse_find_at(address) == NULL) address = US rewrite_address_qualify(address, options & vopt_is_recipient); } -DEBUG(D_verify) +DEBUG(verify) { debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf("%s %s\n", f.address_test_mode? "Testing" : "Verifying", address); @@ -1864,7 +1864,7 @@ while (addr_new) addr_new = addr->next; addr->next = NULL; - DEBUG(D_verify) + DEBUG(verify) { debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); debug_printf("Considering %s\n", addr->address); @@ -2036,11 +2036,11 @@ while (addr_new) if (host_list) { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf("Attempting full verification using callout\n"); if (host_checking && !f.host_checking_callout) { - HDEBUG(D_verify) + HDEBUG(verify) debug_printf("... callout omitted by default when host testing\n" "(Use -bhc if you want the callouts to happen.)\n"); } @@ -2061,14 +2061,14 @@ while (addr_new) } else if (local_verify) { - HDEBUG(D_verify) debug_printf("Attempting quota verification\n"); + HDEBUG(verify) debug_printf("Attempting quota verification\n"); deliver_set_expansions(addr); deliver_local(addr, TRUE); rc = addr->transport_return; } else - HDEBUG(D_verify) debug_printf("Cannot do callout: neither router nor " + HDEBUG(verify) debug_printf("Cannot do callout: neither router nor " "transport provided a host list, or transport is not smtp\n"); } } @@ -2675,7 +2675,7 @@ for (int i = 0; i < 3 && !done; i++) while (isspace(es[-1])) es--; ss = *es ? string_copyn(s, es - s) : s; - HDEBUG(D_verify) debug_printf("verifying %.*s header address %s\n", + HDEBUG(verify) debug_printf("verifying %.*s header address %s\n", (int)(endname - h->text), h->text, ss); /* See if we have already verified this address as an envelope sender, @@ -2688,7 +2688,7 @@ for (int i = 0; i < 3 && !done; i++) || vaddr->special_action > 256)) /* Callout was done */ { new_ok = vaddr->special_action & 255; - HDEBUG(D_verify) debug_printf("previously checked as envelope sender\n"); + HDEBUG(verify) debug_printf("previously checked as envelope sender\n"); } /* Otherwise we run the verification now. We must restore the shortened @@ -2819,7 +2819,7 @@ sender_ident = NULL; if (rfc1413_query_timeout <= 0 || verify_check_host(&rfc1413_hosts) != OK) return; -DEBUG(D_ident) debug_printf("doing ident callback\n"); +DEBUG(ident) debug_printf("doing ident callback\n"); /* Set up a connection to the ident port of the remote host. Bind the local end to the incoming interface address. If the sender host address is an IPv6 @@ -2830,7 +2830,7 @@ if ((ident_conn_ctx.sock = ip_socket(SOCK_STREAM, host_af)) < 0) return; if (ip_bind(ident_conn_ctx.sock, host_af, interface_address, 0) < 0) { - DEBUG(D_ident) debug_printf("bind socket for ident failed: %s\n", + DEBUG(ident) debug_printf("bind socket for ident failed: %s\n", strerror(errno)); goto END_OFF; } @@ -2850,7 +2850,7 @@ if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port, log_write(0, LOG_MAIN, "ident connection to %s timed out", sender_host_address); else - DEBUG(D_ident) debug_printf("ident connection to %s failed: %s\n", + DEBUG(ident) debug_printf("ident connection to %s failed: %s\n", sender_host_address, strerror(errno)); goto END_OFF; } @@ -2929,7 +2929,7 @@ or Received: lines into which it gets inserted. We keep a maximum of 127 characters. The deconst cast is ok as we fed a nonconst to string_printing() */ sender_ident = US string_printing(string_copyn(p, 127)); -DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident); +DEBUG(ident) debug_printf("sender_ident = %s\n", sender_ident); END_OFF: (void)close(ident_conn_ctx.sock); @@ -3252,7 +3252,7 @@ do a check on the name and all its aliases. */ if (!sender_host_name) { - HDEBUG(D_host_lookup) + HDEBUG(host_lookup) debug_printf_indent("sender host name required, to match against %s\n", ss); expand_level++; if (host_lookup_failed || host_name_lookup() != OK) @@ -3518,7 +3518,7 @@ if ((rc = verify_address(&vaddr, -1, vopt_is_recipient | vopt_quota, where, '\0', msg); } -DEBUG(D_verify) debug_printf_indent("verify_quota: len %d\n", len); +DEBUG(verify) debug_printf_indent("verify_quota: len %d\n", len); if (write(1, msg, len) != 0) ; return; } @@ -3542,7 +3542,7 @@ if (!pos_cache && !neg_cache) return FALSE; if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) { - HDEBUG(D_verify) debug_printf_indent("quota cache: not available\n"); + HDEBUG(verify) debug_printf_indent("quota cache: not available\n"); return FALSE; } if (!(cache_address_record = (dbdata_callout_cache_address *) @@ -3570,7 +3570,7 @@ if (!pos_cache && !neg_cache) return; if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE))) { - HDEBUG(D_verify) debug_printf_indent("quota cache: not available\n"); + HDEBUG(verify) debug_printf_indent("quota cache: not available\n"); return; } @@ -3578,7 +3578,7 @@ cache_address_record.result = yield == OK ? ccache_accept : ccache_reject; (void)dbfn_write(dbm_file, rcpt, &cache_address_record, (int)sizeof(dbdata_callout_cache_address)); -HDEBUG(D_verify) debug_printf_indent("wrote %s quota cache record for %s\n", +HDEBUG(verify) debug_printf_indent("wrote %s quota cache record for %s\n", yield == OK ? "positive" : "negative", rcpt); dbfn_close(dbm_file); @@ -3613,7 +3613,7 @@ const uschar * where = US"socketpair"; if (cached_quota_lookup(rcpt, &yield, pos_cache, neg_cache)) { - HDEBUG(D_verify) debug_printf_indent("quota cache: address record is %s\n", + HDEBUG(verify) debug_printf_indent("quota cache: address record is %s\n", yield == OK ? "positive" : "negative"); if (yield != OK) { @@ -3656,7 +3656,7 @@ close(pfd[pipe_write]); if (pid < 0) { - DEBUG(D_verify) debug_printf_indent(" fork: %s\n", strerror(save_errno)); + DEBUG(verify) debug_printf_indent(" fork: %s\n", strerror(save_errno)); } else { @@ -3679,19 +3679,19 @@ else m > 0 ? string_copyn_taint(s, m, GET_UNTAINTED) : NULL; } - DEBUG(D_verify) debug_printf_indent("verify call response:" + DEBUG(verify) debug_printf_indent("verify call response:" " len %d yield %s errno '%s' where '%s' msg '%s'\n", n, rc_names[yield], strerror(save_errno), recipient_verify_failure, *msg); if ( yield == OK || save_errno == 0 && Ustrcmp(recipient_verify_failure, "quota") == 0) cache_quota_write(rcpt, yield, pos_cache, neg_cache); - else DEBUG(D_verify) + else DEBUG(verify) debug_printf_indent("result not cacheable\n"); } else { - DEBUG(D_verify) + DEBUG(verify) debug_printf_indent("verify call response: waitpid status 0x%04x\n", status); } } @@ -3702,7 +3702,7 @@ errno = save_errno; return yield; fail: -DEBUG(D_verify) debug_printf_indent("verify_quota_call fail in %s\n", where); +DEBUG(verify) debug_printf_indent("verify_quota_call fail in %s\n", where); return yield; } diff --git a/src/src/xclient.c b/src/src/xclient.c index 817469308..33e49b766 100644 --- a/src/src/xclient.c +++ b/src/src/xclient.c @@ -148,7 +148,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) goto fatal_501; } - DEBUG(D_transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); + DEBUG(transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); cmd = XCLIENT_CMD_UNKNOWN; for (struct xclient_cmd * x = xclient_cmds + 1; x < xclient_cmds + nelem(xclient_cmds); x++) @@ -177,7 +177,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) Uskip_nonwhite(&s); len = s - word; - DEBUG(D_transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); + DEBUG(transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); if (len == 0) { s = US"XCLIENT: zero-length value for param"; goto fatal_501; } commit 38d5bdbaf26a17849ba2c58bd3e230415b8851fe Author: Jeremy Harris Date: Fri Feb 20 19:41:09 2026 +0000 Logging: handle noncontiguous channel list diff --git a/src/src/log.c b/src/src/log.c index 49caac524..8c5ab8e68 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1383,8 +1383,14 @@ const uschar * const * end = names + count; while (start < end) { const uschar * const * middle = start + (end - start)/2; - int c = Ustrncmp(word, *middle, len); - if (c == 0) + int c; + + /* Work around empty list element pointers */ + + while (!*middle && middle < end) middle++; + while (!*middle && middle >= start) middle--; + + if ((c = Ustrncmp(word, *middle, len)) == 0) if ((*middle)[len]) c = -1; else commit 9ebb81bbf93d099233e9d89ebbf184094a230020 Author: Jeremy Harris Date: Sat Feb 21 14:40:26 2026 +0000 Debug/logging: use explicit channel numbers diff --git a/src/scripts/source_checks b/src/scripts/source_checks index a7013f98c..0d52da6a2 100644 --- a/src/scripts/source_checks +++ b/src/scripts/source_checks @@ -32,6 +32,21 @@ done <<-END acl.c controls_list END +# Tables with one-arg macros as items +# (ignoring #ifdef lines) +while read file table +do + : $file $table + < $file \ + perl -e '$/= undef; while (<>) { print $1 if /(?<='$table'\[\])\s*=\s*{\s?(([^}]*)+)}/m }' \ + | awk '!/^\s*#/ {split($0,a,"[()]");print a[2]}' \ + | LC_ALL=C sort -c \ + || { echo "Table $table in $file is not alphabetically ordered" >&2 ; exit 1; } +done <<-END + globals.c debug_channels + globals.c log_channels +END + # Tables with just string items while read file table do @@ -42,8 +57,6 @@ do | LC_ALL=C sort -c \ || { echo "Table $table in $file is not alphabetically ordered" >&2 ; exit 1; } done <<-END - globals.c debug_chan_names - globals.c log_chan_names expand.c item_table expand.c op_table_underscore expand.c op_table_main diff --git a/src/src/debug.c b/src/src/debug.c index 1c45d2586..a2f575a17 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -518,8 +518,7 @@ while (chan = string_nextinlist(&channels, &sep, buf, sizeof(buf))) unsigned bit = Ustrcmp(chan, "any") == 0 ? BIT_TABLE_IDX_IS_ANY - : chan_name_to_idx(chan, Ustrlen(chan), - debug_chan_names, debug_options_count); + : chan_name_to_num(chan, Ustrlen(chan), debug_channels, debug_chan_count); if (bit && DEBUG_BIT(bit)) return TRUE; } return FALSE; @@ -536,7 +535,7 @@ if (!*selector) } decode_bits(*selector, DEBUG_SELECTOR_SIZE, debug_notall_names, string, - debug_chan_names, debug_options_count, DCB_DEBUG | flags); + debug_channels, debug_chan_count, DCB_DEBUG | flags); } void diff --git a/src/src/exim.c b/src/src/exim.c index d7c64f8a4..57d9cab4a 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -4295,7 +4295,7 @@ if (checking && commandline_checks_require_admin && !f.admin_user) /* Handle the decoding of logging options. */ decode_bits(log_selector, log_selector_size, log_notall_names, - log_selector_string, log_chan_names, log_options_count, DCB_LOG); + log_selector_string, log_channels, log_chan_count, DCB_LOG); DEBUG(any) { diff --git a/src/src/functions.h b/src/src/functions.h index 13fa362a4..97170ac13 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -143,8 +143,8 @@ extern void bdat_flush_data(void); extern void cancel_cutthrough_connection(BOOL, const uschar *); extern gstring *cat_file(FILE *, gstring *, const uschar *); extern gstring *cat_file_tls(void *, gstring *, const uschar *); -extern unsigned chan_name_to_idx(const uschar *, unsigned, - const uschar * const *, unsigned); +extern unsigned chan_name_to_num(const uschar *, unsigned, + bit_table *, unsigned); extern void check_deliver_addrs_not_freed(void (*)(const uschar*, const uschar*, void*), void *); extern int check_host(void *, const uschar *, const uschar **, uschar **); @@ -196,7 +196,7 @@ extern void debug_enable(void); extern void debug_trigger_fire(void); extern void decode_bits(bitmask_word_t *, size_t, const uschar * const *, - const uschar *, const uschar * const *, int, int); + const uschar *, bit_table *, int, int); extern void delete_pid_file(void); extern void deliver_local(address_item *, BOOL); extern address_item *deliver_make_addr(const uschar *, BOOL); diff --git a/src/src/globals.c b/src/src/globals.c index 0d47bfbfb..87424cadf 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -116,7 +116,7 @@ const uschar *tls_verify_hosts = NULL; int tls_watch_fd = -1; time_t tls_watch_trigger_time = (time_t)0; #else /*DISABLE_TLS*/ -uschar *tls_advertise_hosts = NULL; +const uschar *tls_advertise_hosts = NULL; #endif #ifndef DISABLE_PRDR @@ -656,47 +656,49 @@ uschar *dccifd_options = US"header"; int debug_fd = -1; FILE *debug_file = NULL; -/* List of names for debug channels. Must be in alphabetical order. -The initial few entries are dummies. */ - -const uschar * const debug_chan_names[] = { - [BIT_TABLE_IDX_USABLE] = US"acl", /* 4 */ - US"auth", - US"deliver", - US"dns", - US"dnsbl", /* 8 */ - US"exec", - US"expand", - US"filter", - US"hints_lookup", - US"host_lookup", - US"ident", - US"interface", - US"lists", /* 16 */ - US"load", - US"local_scan", - US"lookup", - US"macro", - US"memory", - US"noutf8", - US"pid", - US"process_info", /* 24 */ - US"queue_run", - US"receive", - US"regex", - US"resolver", - US"retry", - US"rewrite", - US"route", - US"timestamp", /* 32 */ - US"tls", - US"transport", - US"uid", - US"v", - US"verify", +/* List of names for debug channels. Must be in alphabetical order. */ + +#define DEBUG_CHAN(chan) {.name = US #chan, .logchan_bit = __LINE__ - D_iota} + +enum { D_iota = __LINE__ + 2 - BIT_TABLE_IDX_USABLE }; +bit_table debug_channels[] = { + DEBUG_CHAN(acl), /* 4 */ + DEBUG_CHAN(auth), + DEBUG_CHAN(deliver), + DEBUG_CHAN(dns), + DEBUG_CHAN(dnsbl), /* 8 */ + DEBUG_CHAN(exec), + DEBUG_CHAN(expand), + DEBUG_CHAN(filter), + DEBUG_CHAN(hints_lookup), + DEBUG_CHAN(host_lookup), + DEBUG_CHAN(ident), + DEBUG_CHAN(interface), + DEBUG_CHAN(lists), /* 16 */ + DEBUG_CHAN(load), + DEBUG_CHAN(local_scan), + DEBUG_CHAN(lookup), + DEBUG_CHAN(macro), + DEBUG_CHAN(memory), + DEBUG_CHAN(noutf8), + DEBUG_CHAN(pid), + DEBUG_CHAN(process_info), /* 24 */ + DEBUG_CHAN(queue_run), + DEBUG_CHAN(receive), + DEBUG_CHAN(regex), + DEBUG_CHAN(resolver), + DEBUG_CHAN(retry), + DEBUG_CHAN(rewrite), + DEBUG_CHAN(route), + DEBUG_CHAN(timestamp), /* 32 */ + DEBUG_CHAN(tls), + DEBUG_CHAN(transport), + DEBUG_CHAN(uid), + DEBUG_CHAN(v), + DEBUG_CHAN(verify), }; - -int debug_options_count = nelem(debug_chan_names); +#undef DEBUG_CHAN +int debug_chan_count = nelem(debug_channels); /* Channel settings for "default" debug (just a "-d" used) */ @@ -958,6 +960,8 @@ uschar *log_file_path = US LOG_FILE_PATH const uschar * const log_notall_names[] = { NULL }; /* Table for selectors for log_write() calls. +It is used for translating Li_* values, using the position in this table, +to Lt_* values and name strings. Must have names that are in both enum logwrite_bit and logging_test_bit. */ #define BIT_TABLE(chan) {.name = US #chan, .logchan_bit = Lt_##chan } @@ -986,16 +990,14 @@ int logwrite_options_count = nelem(logwrite_options); /* List of names for logging channels. Must be in alphabetical order. Must match enum logging_test_bit (macros.h). -This is a superset of logwrite_options[]. -The initial few entries are dummies. */ +This is a superset of logwrite_options[]. */ -#define LOG_CHAN(name) [Lt_##name] = US #name +#define LOG_CHAN(chan) {.name = US #chan, .logchan_bit = Lt_##chan} -const uschar * const log_chan_names[] = { +bit_table log_channels[] = { LOG_CHAN(8bitmime), LOG_CHAN(acl_warn_skipped), LOG_CHAN(address_rewrite), - [Lt_DUMMY_all] = US"all", LOG_CHAN(all_parents), LOG_CHAN(arguments), LOG_CHAN(connection_id), @@ -1066,7 +1068,7 @@ const uschar * const log_chan_names[] = { LOG_CHAN(unknown_in_list), }; #undef LOG_CHAN -int log_options_count = nelem(log_chan_names); +int log_chan_count = nelem(log_channels); const uschar *log_ports = NULL; int log_reject_target = 0; diff --git a/src/src/globals.h b/src/src/globals.h index b0c1dd44a..a12d0de87 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -476,7 +476,7 @@ extern uschar *dccifd_address; /* address of the dccifd daemon */ extern uschar *dccifd_options; /* options for the dccifd daemon */ #endif -extern const uschar * const debug_chan_names[]; /* channel names */ +extern bit_table debug_channels[]; /* names + numbers */ extern const uschar * debug_defaults; /* chans for "-d" */ extern const uschar * const debug_notall_names[]; /* chans not in "all" */ extern bitmask_word_t * debug_selector; /* Debugging bits */ @@ -484,7 +484,7 @@ extern bitmask_word_t * debug_selector; /* Debugging bits */ extern int debug_fd; /* The fd for debug_file */ extern FILE *debug_file; /* Where to write debugging info */ -extern int debug_options_count; /* Size of table */ +extern int debug_chan_count; /* Size of table */ extern unsigned debug_pretrigger_bsize; extern uschar *debug_pretrigger_buf; /* circular buffer for precapture */ extern BOOL debug_startup; /* Pre-config-read debugging */ @@ -675,9 +675,9 @@ extern const uschar * log_default_names[]; /* Init list for log_selector */ extern int log_default_count; /* Size of table */ extern uschar *log_file_path; /* If unset, use default */ extern const uschar *log_ports; /* If set, port numbers to log */ -extern const uschar * const log_chan_names[]; /* Table of options */ +extern bit_table log_channels[]; /* Table of options */ +extern int log_chan_count; /* Size of table */ extern const uschar * const log_notall_names[]; /* chans not in "all" */ -extern int log_options_count; /* Size of table */ extern int log_reject_target; /* Target log for ACL rejections */ extern bitmask_word_t log_selector[]; /* Bit map of logging options */ extern uschar *log_selector_string; /* As supplied in the config */ diff --git a/src/src/log.c b/src/src/log.c index 8c5ab8e68..80308805b 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1368,33 +1368,28 @@ syslog_open = FALSE; Arguments: word The name to search for len Number of chars in name - names List of channel names + channels List of channel names + numbers count Number of list entries, incl. leading specials -Return index, or zero for not-found +Return channel number, or zero for not-found */ unsigned -chan_name_to_idx(const uschar * word, unsigned len, - const uschar * const * names, unsigned count) +chan_name_to_num(const uschar * word, unsigned len, + bit_table * channels, unsigned count) { -const uschar * const * start = names + BIT_TABLE_IDX_USABLE; -const uschar * const * end = names + count; +bit_table * start = channels; +bit_table * end = channels + count; while (start < end) { - const uschar * const * middle = start + (end - start)/2; + bit_table * middle = start + (end - start)/2; int c; - /* Work around empty list element pointers */ - - while (!*middle && middle < end) middle++; - while (!*middle && middle >= start) middle--; - - if ((c = Ustrncmp(word, *middle, len)) == 0) - if ((*middle)[len]) + if ((c = Ustrncmp(word, middle->name, len)) == 0) + if (middle->name[len]) c = -1; else - return middle - names; /* Found */ + return middle->logchan_bit; if (c < 0) end = middle; @@ -1427,7 +1422,7 @@ Arguments: selsize number of words in the bit string notall list of words to exclude from "all" string the configured string - options table of option names + options table of option names & channel-numbers count size of table flags DCB_LOG, DCB_DEBUG, DCB_FROM_CONFIG @@ -1437,7 +1432,7 @@ Returns: nothing on success - bomb out on failure void decode_bits(bitmask_word_t * selector, size_t selsize, const uschar * const * notall, const uschar * string, - const uschar * const * options, int count, int flags) + bit_table * options, int count, int flags) { uschar * errmsg; @@ -1496,18 +1491,18 @@ else for(;;) { memset(selector, -1, sizeof(*selector)*selsize); for (const uschar * const * p = notall; *p; p++) - bit_clear(selector, chan_name_to_idx(*p, Ustrlen(*p), options, count)); + bit_clear(selector, chan_name_to_num(*p, Ustrlen(*p), options, count)); } else memset(selector, 0, sizeof(*selector)*selsize); else { - unsigned idx = chan_name_to_idx(s, len, options, count); + unsigned idx = chan_name_to_num(s, len, options, count); if (!idx) { - errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", flags & DCB_LOG ? "log" : "debug", - adding ? '+' : '-', len, s); + errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", + flags & DCB_LOG ? "log" : "debug", adding ? '+' : '-', len, s); goto ERROR_RETURN; } @@ -1562,7 +1557,7 @@ void logging_modify_channels(const uschar * string) { decode_bits(log_selector, log_selector_size, log_notall_names, string, - log_chan_names, log_options_count, DCB_LOG); + log_channels, log_chan_count, DCB_LOG); } @@ -1580,7 +1575,7 @@ bit_set(log_selector, BIT_TABLE_IDX_NONZERO); for (const uschar * const * p = log_default_names; p < log_default_names + log_default_count; p++) bit_set(log_selector, - chan_name_to_idx(*p, Ustrlen(*p), log_chan_names, log_options_count)); + chan_name_to_num(*p, Ustrlen(*p), log_channels, log_chan_count)); } diff --git a/src/src/macros.h b/src/src/macros.h index 628bac32f..bc4a76b65 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -339,7 +339,7 @@ use inlinable functions. */ /* Debugging control */ -#define DEBUG_SELECTOR_SIZE (BITWORD(debug_options_count) + 1) +#define DEBUG_SELECTOR_SIZE (BITWORD(debug_chan_count) + 1) static inline bitmask_word_t bit_test(bitmask_word_t *, unsigned); extern bitmask_word_t * debug_selector; /* Debugging bits */ diff --git a/src/src/readconf.c b/src/src/readconf.c index ba91ad0fc..b57241212 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -508,10 +508,9 @@ options_logging(void) { uschar buf[EXIM_DRIVERNAME_MAX]; -for (const uschar * const * p = log_chan_names + BIT_TABLE_IDX_USABLE; - p < log_chan_names + log_options_count; p++) if (*p) +for (bit_table * p = log_channels; p < log_channels + log_chan_count; p++) { - spf(buf, sizeof(buf), US"_LOG_%T", *p); + spf(buf, sizeof(buf), US"_LOG_%T", p->name); builtin_macro_create(buf); } } commit ef14c52eb0694572cbbebc4e7e33a90e7814f36c Author: Bernard Quatermass Date: Sun Feb 22 14:03:47 2026 +0000 Remove AVE/KAV/MKS content scanning diff --git a/src/src/EDITME b/src/src/EDITME index ec187e919..a74e64228 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -602,13 +602,6 @@ SUPPORT_DANE=yes # DISABLE_MAL_SOCK=yes # DISABLE_MAL_CMDLINE=yes -# These scanners are claimed to be no longer existent. - -DISABLE_MAL_AVE=yes -DISABLE_MAL_KAV=yes -DISABLE_MAL_MKS=yes - - #------------------------------------------------------------------------------ # If built with TLS, Exim includes code to support DKIM (DomainKeys Identified # Mail, RFC4871) signing and verification. Verification of signatures is diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index e99b10c16..b9080f1a2 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -205,12 +205,9 @@ Do not put spaces between # and the 'define'. #define DISABLE_MAL_FFROTD #define DISABLE_MAL_FFROT6D #define DISABLE_MAL_DRWEB -#define DISABLE_MAL_AVE #define DISABLE_MAL_FSECURE -#define DISABLE_MAL_KAV #define DISABLE_MAL_SOPHIE #define DISABLE_MAL_CLAM -#define DISABLE_MAL_MKS #define DISABLE_MAL_AVAST #define DISABLE_MAL_SOCK #define DISABLE_MAL_CMDLINE diff --git a/src/src/malware.c b/src/src/malware.c index 6ee646147..afbf435ea 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -24,24 +24,15 @@ typedef enum { #ifndef DISABLE_MAL_DRWEB M_DRWEB, #endif -#ifndef DISABLE_MAL_AVE - M_AVES, -#endif #ifndef DISABLE_MAL_FSECURE M_FSEC, #endif -#ifndef DISABLE_MAL_KAV - M_KAVD, -#endif #ifndef DISABLE_MAL_SOPHIE M_SOPHIE, #endif #ifndef DISABLE_MAL_CLAM M_CLAMD, #endif -#ifndef DISABLE_MAL_MKS - M_MKSD, -#endif #ifndef DISABLE_MAL_AVAST M_AVAST, #endif @@ -71,24 +62,15 @@ static struct scan #ifndef DISABLE_MAL_DRWEB { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM }, #endif -#ifndef DISABLE_MAL_AVE - { M_AVES, US"aveserver", US"/var/run/aveserver", MC_UNIX }, -#endif #ifndef DISABLE_MAL_FSECURE { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX }, #endif -#ifndef DISABLE_MAL_KAV - { M_KAVD, US"kavdaemon", US"/var/run/AvpCtl", MC_UNIX }, -#endif #ifndef DISABLE_MAL_SOPHIE { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX }, #endif #ifndef DISABLE_MAL_CLAM { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE }, #endif -#ifndef DISABLE_MAL_MKS - { M_MKSD, US"mksd", NULL, MC_NONE }, -#endif #ifndef DISABLE_MAL_AVAST { M_AVAST, US"avast", US"/var/run/avast/scan.sock", MC_STRM }, #endif @@ -166,13 +148,6 @@ static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\ static const pcre2_code * fsec_re = NULL; #endif -#ifndef DISABLE_MAL_KAV -static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$"; -static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$"; -static const pcre2_code * kav_re_sus = NULL; -static const pcre2_code * kav_re_inf = NULL; -#endif - #ifndef DISABLE_MAL_AVAST static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]"; static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)"; @@ -193,22 +168,6 @@ static const pcre2_code * fprot6d_re_virus = NULL; /******************************************************************************/ -#ifndef DISABLE_MAL_KAV -/* Routine to check whether a system is big- or little-endian. - Ripped from http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-7.html - Needed for proper kavdaemon implementation. Sigh. */ -# define BIG_MY_ENDIAN 0 -# define LITTLE_MY_ENDIAN 1 -static int test_byte_order(void); -static inline int -test_byte_order() -{ - short int word = 0x0001; - char *byte = CS &word; - return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN); -} -#endif - BOOL malware_ok = FALSE; /* Gross hacks for the -bmalware option; perhaps we should just create @@ -398,138 +357,6 @@ return fd_ready(sock, tmo) } #endif - - -#ifndef DISABLE_MAL_MKS -/* ============= private routines for the "mksd" scanner type ============== */ - -# include - -static inline int -mksd_writev (int sock, struct iovec * iov, int iovcnt) -{ -int i; - -for (;;) - { - do - i = writev (sock, iov, iovcnt); - while (i < 0 && errno == EINTR); - if (i <= 0) - { - (void) malware_panic_defer( - US"unable to write to mksd UNIX socket (/var/run/mksd/socket)"); - return -1; - } - for (;;) /* check for short write */ - if (i >= iov->iov_len) - { - if (--iovcnt == 0) - return 0; - i -= iov->iov_len; - iov++; - } - else - { - iov->iov_len -= i; - iov->iov_base = CS iov->iov_base + i; - break; - } - } -} - -static inline int -mksd_read_lines (int sock, uschar *av_buffer, int av_buffer_size, time_t tmo) -{ -client_conn_ctx cctx = {.sock = sock}; -int offset = 0; -int i; - -do - { - i = ip_recv(&cctx, av_buffer+offset, av_buffer_size-offset, tmo); - if (i <= 0) - { - (void) malware_panic_defer(US"unable to read from mksd UNIX socket (/var/run/mksd/socket)"); - return -1; - } - - offset += i; - /* offset == av_buffer_size -> buffer full */ - if (offset == av_buffer_size) - { - (void) malware_panic_defer(US"malformed reply received from mksd"); - return -1; - } - } while (av_buffer[offset-1] != '\n'); - -av_buffer[offset] = '\0'; -return offset; -} - -static inline int -mksd_parse_line(struct scan * scanent, char * line) -{ -char *p; - -switch (*line) - { - case 'O': /* OK */ - return OK; - - case 'E': - case 'A': /* ERR */ - if ((p = strchr (line, '\n')) != NULL) - *p = '\0'; - return m_panic_defer(scanent, NULL, - string_sprintf("scanner failed: %s", line)); - - default: /* VIR */ - if ((p = strchr (line, '\n')) != NULL) - { - *p = '\0'; - if ( p-line > 5 - && line[3] == ' ' - && (p = strchr(line+4, ' ')) != NULL - && p-line > 4 - ) - { - *p = '\0'; - malware_name = string_copy(US line+4); - return OK; - } - } - return m_panic_defer(scanent, NULL, - string_sprintf("malformed reply received: %s", line)); - } -} - -static int -mksd_scan_packed(struct scan * scanent, int sock, const uschar * scan_filename, - time_t tmo) -{ -struct iovec iov[3]; -const char *cmd = "MSQ\n"; -uschar av_buffer[1024]; - -iov[0].iov_base = (void *) cmd; -iov[0].iov_len = 3; -iov[1].iov_base = (void *) scan_filename; -iov[1].iov_len = Ustrlen(scan_filename); -iov[2].iov_base = (void *) (cmd + 3); -iov[2].iov_len = 1; - -if (mksd_writev (sock, iov, 3) < 0) - return DEFER; - -if (mksd_read_lines (sock, av_buffer, sizeof (av_buffer), tmo) < 0) - return DEFER; - -return mksd_parse_line (scanent, CS av_buffer); -} -#endif /* MKSD */ - - #ifndef DISABLE_MAL_CLAM static int clamd_option(clamd_address * cd, const uschar * optstr, int * subsep) @@ -983,76 +810,6 @@ badseek: err = errno; } /* drweb */ #endif -#ifndef DISABLE_MAL_AVE - case M_AVES: /* "aveserver" scanner type -------------------------------- */ - { - uschar buf[32768]; - int result; - - /* read aveserver's greeting and see if it is ready (2xx greeting) */ - buf[0] = 0; - recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo); - - if (buf[0] != '2') /* aveserver is having problems */ - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unavailable (Responded: %s).", - ((buf[0] != 0) ? buf : US "nothing") ), - malware_daemon_ctx.sock); - - /* prepare our command */ - (void)string_format(buf, sizeof(buf), "SCAN bPQRSTUW %s\r\n", - eml_filename); - - /* and send it */ - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s %s\n", - scanner_name, buf); - if (m_sock_send(malware_daemon_ctx.sock, buf, Ustrlen(buf), &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - malware_name = NULL; - result = 0; - /* read response lines, find malware name and final response */ - while (recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo) > 0) - { - if (buf[0] == '2') - break; - if (buf[0] == '5') /* aveserver is having problems */ - { - result = m_panic_defer(scanent, CUS callout_address, - string_sprintf("unable to scan file %s (Responded: %s).", - eml_filename, buf)); - break; - } - if (Ustrncmp(buf,"322",3) == 0) - { - uschar *p = Ustrchr(&buf[4], ' '); - *p = '\0'; - malware_name = string_copy(&buf[4]); - } - } - - if (m_sock_send(malware_daemon_ctx.sock, US"quit\r\n", 6, &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - /* read aveserver's greeting and see if it is ready (2xx greeting) */ - buf[0] = 0; - recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo); - - if (buf[0] != '2') /* aveserver is having problems */ - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to quit dialogue (Responded: %s).", - ((buf[0] != 0) ? buf : US "nothing") ), - malware_daemon_ctx.sock); - - if (result == DEFER) - { - (void)close(malware_daemon_ctx.sock); - return DEFER; - } - break; - } /* aveserver */ -#endif - #ifndef DISABLE_MAL_FSECURE case M_FSEC: /* "fsecure" scanner type ---------------------------------- */ { @@ -1138,120 +895,6 @@ badseek: err = errno; } /* fsecure */ #endif -#ifndef DISABLE_MAL_KAV - case M_KAVD: /* "kavdaemon" scanner type -------------------------------- */ - { - time_t t; - uschar tmpbuf[1024]; - uschar * scanrequest; - int kav_rc; - unsigned long kav_reportlen; - int bread; - const pcre2_code *kav_re; - uschar *p; - - /* get current date and time, build scan request */ - time(&t); - /* pdp note: before the eml_filename parameter, this scanned the - directory; not finding documentation, so we'll strip off the directory. - The side-effect is that the test framework scanning may end up in - scanning more than was requested, but for the normal interface, this is - fine. */ - - strftime(CS tmpbuf, sizeof(tmpbuf), "%d %b %H:%M:%S", localtime(&t)); - scanrequest = string_sprintf("<0>%s:%s", CS tmpbuf, eml_filename); - p = Ustrrchr(scanrequest, '/'); - if (p) - *p = '\0'; - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", - scanner_name, scanner_options); - - /* send scan request */ - if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - /* wait for result */ - if (!recv_len(malware_daemon_ctx.sock, tmpbuf, 2, tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"unable to read 2 bytes from socket.", malware_daemon_ctx.sock); - - /* get errorcode from one nibble */ - kav_rc = tmpbuf[ test_byte_order()==LITTLE_MY_ENDIAN ? 0 : 1 ] & 0x0F; - switch(kav_rc) - { - case 5: case 6: /* improper kavdaemon configuration */ - return m_panic_defer_3(scanent, CUS callout_address, - US"please reconfigure kavdaemon to NOT disinfect or remove infected files.", - malware_daemon_ctx.sock); - case 1: - return m_panic_defer_3(scanent, CUS callout_address, - US"reported 'scanning not completed' (code 1).", malware_daemon_ctx.sock); - case 7: - return m_panic_defer_3(scanent, CUS callout_address, - US"reported 'kavdaemon damaged' (code 7).", malware_daemon_ctx.sock); - } - - /* code 8 is not handled, since it is ambiguous. It appears mostly on - bounces where part of a file has been cut off */ - - /* "virus found" return codes (2-4) */ - if (kav_rc > 1 && kav_rc < 5) - { - int report_flag = 0; - - /* setup default virus name */ - malware_name = US"unknown"; - - report_flag = tmpbuf[ test_byte_order() == LITTLE_MY_ENDIAN ? 1 : 0 ]; - - /* read the report, if available */ - if (report_flag == 1) - { - /* read report size */ - if (!recv_len(malware_daemon_ctx.sock, &kav_reportlen, 4, tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"cannot read report size", malware_daemon_ctx.sock); - - /* it's possible that avp returns av_buffer[1] == 1 but the - reportsize is 0 (!?) */ - if (kav_reportlen > 0) - { - /* set up match regex, depends on retcode */ - if (kav_rc == 3) - { - if (!kav_re_sus) kav_re_sus = m_pcre_compile(kav_re_sus_str, FALSE, &errstr); - kav_re = kav_re_sus; - } - else - { - if (!kav_re_inf) kav_re_inf = m_pcre_compile(kav_re_inf_str, FALSE, &errstr); - kav_re = kav_re_inf; - } - - /* read report, linewise. Using size from stream to read amount of data - from same stream is safe enough. */ - /* coverity[tainted_data] */ - while (kav_reportlen > 0) - { - if ((bread = recv_line(malware_daemon_ctx.sock, tmpbuf, sizeof(tmpbuf), tmo)) < 0) - break; - kav_reportlen -= bread+1; - - /* try matcher on the line, grab substring */ - if ((malware_name = m_pcre_exec(kav_re, tmpbuf))) - break; - } - } - } - } - else /* no virus found */ - malware_name = NULL; - - break; - } -#endif - #ifndef DISABLE_MAL_CMDLINE case M_CMDL: /* "cmdline" scanner type ---------------------------------- */ { @@ -1953,41 +1596,6 @@ badseek: err = errno; } #endif -#ifndef DISABLE_MAL_MKS - case M_MKSD: /* "mksd" scanner type ------------------------------------- */ - { - char *mksd_options_end; - int mksd_maxproc = 1; /* default, if no option supplied */ - int retval; - - if (scanner_options) - { - mksd_maxproc = (int)strtol(CS scanner_options, &mksd_options_end, 10); - if ( *scanner_options == '\0' - || *mksd_options_end != '\0' - || mksd_maxproc < 1 - || mksd_maxproc > 32 - ) - return m_panic_defer(scanent, CUS callout_address, - string_sprintf("invalid option '%s'", scanner_options)); - } - - if((malware_daemon_ctx.sock = ip_unixsocket(US "/var/run/mksd/socket", &errstr)) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - malware_name = NULL; - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan\n", scanner_name); - - if ((retval = mksd_scan_packed(scanent, malware_daemon_ctx.sock, eml_filename, tmo)) != OK) - { - close (malware_daemon_ctx.sock); - return retval; - } - break; - } -#endif - #ifndef DISABLE_MAL_AVAST case M_AVAST: /* "avast" scanner type ----------------------------------- */ { @@ -2287,12 +1895,6 @@ if (!drweb_re) if (!fsec_re) fsec_re = regex_must_compile(fsec_re_str, MCS_NOFLAGS, TRUE); #endif -#ifndef DISABLE_MAL_KAV -if (!kav_re_sus) - kav_re_sus = regex_must_compile(kav_re_sus_str, MCS_NOFLAGS, TRUE); -if (!kav_re_inf) - kav_re_inf = regex_must_compile(kav_re_inf_str, MCS_NOFLAGS, TRUE); -#endif #ifndef DISABLE_MAL_AVAST if (!ava_re_clean) ava_re_clean = regex_must_compile(ava_re_clean_str, MCS_NOFLAGS, TRUE); commit 369500e6c650f925a1057265744459cea45ccc16 Author: Jeremy Harris Date: Sun Feb 22 09:51:51 2026 +0000 tidying diff --git a/src/src/daemon.c b/src/src/daemon.c index c63a10838..a078b1050 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -1784,12 +1784,10 @@ if (f.inetd_wait_mode) (void) close(2); exim_nullstd(); + /* If we want debug, it must go to a file in the log directory */ + if (debug_file == stderr) { - /* need a call to log_write before call to open debug_file, so that - log.c:file_path has been initialised. This is unfortunate. */ - log_write(0, LOG_MAIN, "debugging Exim in inetd wait mode starting"); - fclose(debug_file); debug_file = NULL; exim_nullstd(); /* re-open fd2 after we just closed it again */ diff --git a/src/src/debug.c b/src/src/debug.c index a2f575a17..585519a14 100644 --- a/src/src/debug.c +++ b/src/src/debug.c @@ -217,7 +217,7 @@ va_end(ap); } void -debug_vprintf(int indent, const char *format, va_list ap) +debug_vprintf(int indent, const char * format, va_list ap) { int save_errno = errno; @@ -245,7 +245,7 @@ if (debug_ptr == debug_buffer) } DEBUG(pid) - debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid()); + debug_ptr += sprintf(CS debug_ptr, PID_T_FMT " ", getpid()); /* Set up prefix if outputting for host checking and not debugging */ @@ -309,10 +309,10 @@ if (debug_ptr[-1] == '\n') { if (debug_prefix_length > 0) { - uschar *p = debug_buffer; int left = sizeof(debug_buffer) - (debug_ptr - debug_buffer) - 1; - while ((p = Ustrchr(p, '\n') + 1) != debug_ptr && - left >= debug_prefix_length) + for (uschar * p = debug_buffer; + (p = Ustrchr(p, '\n') + 1) != debug_ptr && left >= debug_prefix_length; + ) { int len = debug_ptr - p; memmove(p + debug_prefix_length, p, len + 1); @@ -353,10 +353,8 @@ if (debug_ptr[-1] == '\n') } } else - { fprintf(debug_file, "%s", CS debug_buffer); - fflush(debug_file); - } + debug_ptr = debug_buffer; debug_prefix_length = 0; } diff --git a/src/src/deliver.c b/src/src/deliver.c index 55ccf1b45..8d3721c30 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -8600,7 +8600,7 @@ if (addr_failed) f.disable_logging = addr_failed->transport ? addr_failed->transport->disable_logging : FALSE; - DEBUG(D_deliver) + DEBUG(deliver) debug_printf("processing failed address %s\n", addr_failed->address); /* There are only two ways an address in a bounce message can get here: diff --git a/src/src/exim.c b/src/src/exim.c index 57d9cab4a..164b926a9 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1807,6 +1807,20 @@ return qrunners; } +static void +set_debug_stream(void) +{ +debug_file = stderr; +debug_fd = fileno(debug_file); +} + +static void +set_verb_opt_mode(void) +{ +debug_modify_channel(US"+v"); +set_debug_stream(); +} + /************************************************* * Entry point and high-level code * *************************************************/ @@ -2549,8 +2563,7 @@ on the second character (the one after '-'), to save some effort. */ else { list_options = TRUE; - debug_modify_channel(US"+v"); - debug_file = stderr; + set_verb_opt_mode(); } break; @@ -3340,8 +3353,7 @@ on the second character (the one after '-'), to save some effort. */ if (!*argrest) { f.dont_deliver = TRUE; - debug_modify_channel(US"+v"); - debug_file = stderr; + set_verb_opt_mode(); } else badarg = TRUE; break; @@ -3868,10 +3880,7 @@ on the second character (the one after '-'), to save some effort. */ case 'v': if (!*argrest) - { - debug_modify_channel(US"+v"); - debug_file = stderr; - } + set_verb_opt_mode(); else badarg = TRUE; break; @@ -3988,8 +3997,7 @@ to run in the foreground. */ if (ANY_DEBUG) { - debug_file = stderr; - debug_fd = fileno(debug_file); + set_debug_stream(); f.background_daemon = FALSE; testharness_pause_ms(100); /* lets caller finish */ @@ -5355,9 +5363,7 @@ if (verify_address_mode || f.address_test_mode) else { flags |= vopt_is_recipient; - debug_modify_channel(US"+v"); - debug_file = stderr; - debug_fd = fileno(debug_file); + set_verb_opt_mode(); DEBUG(verify) debug_print_ids(US"Address testing:"); } @@ -5553,8 +5559,8 @@ if (host_checking) smtp_out_fd = fileno(stdout); f.sender_local = FALSE; f.sender_host_notsocket = TRUE; - debug_file = stderr; - debug_fd = fileno(debug_file); + set_debug_stream(); + dprintf(smtp_out_fd, "\n**** SMTP testing session as if from host %s\n" "**** but without any ident (RFC 1413) callback.\n" "**** This is not for real!\n\n", diff --git a/src/src/log.c b/src/src/log.c index 80308805b..fb256bee2 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1628,13 +1628,15 @@ resulting in certain setup not having been done. Hack this for now so we do not segfault; note that nondefault log locations (set via log_file_path) will not work for that case. */ -if (!*file_path) set_file_path(); +if (!*file_path) + set_file_path(); -if ((debug_fd = open_log(lt_debug, tag_name)) != -1) - debug_file = fdopen(debug_fd, "w"); -else +if ((debug_fd = open_log(lt_debug, tag_name)) < 0) log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log"); +debug_file = fdopen(debug_fd, "w"); +setbuf(debug_file, NULL); + debug_print_ids(US"debug enabled:"); } @@ -1645,8 +1647,11 @@ debug_logging_from_spool(const uschar * filename) if (debug_fd < 0) { Ustrncpy(debuglog_name, filename, sizeof(debuglog_name)-1); - if ((debug_fd = log_open_as_exim(filename)) >= 0) - debug_file = fdopen(debug_fd, "w"); + if ((debug_fd = log_open_as_exim(filename)) < 0) + return; + + debug_file = fdopen(debug_fd, "w"); + setbuf(debug_file, NULL); DEBUG(deliver) debug_print_ids(US"debug enabled by spoolfile\n"); } /* diff --git a/src/src/macros.h b/src/src/macros.h index bc4a76b65..4ca6b6b4d 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -365,18 +365,17 @@ masks, alternating between sequential bit index and corresponding mask. */ #define IOTA(iota) (__LINE__ - iota) #define IOTA_INIT(zero) (__LINE__ - zero + 1) -/*XXX*/ -/* Options bits for debugging. DEBUG_BIT() declares both a bit index and the -corresponding mask. Di_all is a special value recognized by decode_bits(). -These must match the debug_options table in globals.c . - -Exim's code assumes in a number of places that the debug_selector is one -word, and this is exposed in the local_scan ABI. The D_v and D_local_scan bit -masks are part of the local_scan API so are #defined in local_scan.h . -XXX => v & local_scan must live in word zero - -Thanks to the "one word", debug bits beyond 31 are not available on 32b-int -systems, and coding must account for that. */ +/* Options bits for debugging. +Because of the history of debug within Exim, we have to generate various +meta-info bits. Also, we want to be able to determine quickly when debug +is not enabled (that being the common case). On the other hand we want to +have many individually selectable debug channels; possibly more than there +are bits in a single word. So we use a multiword array of bits, and reserve +some in the first word for the meta-info. One of those is a single bit OR +of all the channel bits, giving us the fast test. Code testing the specific +channel enables is then out-of-line and can be slow. We use the channel +names in the sourcecode, converting to channel numbers to do the test against +the array of bits. */ /* Special bits used for debug and logging control. These are summarizing sets of enabled channels, and are in the first word of the selector array for quick @@ -393,53 +392,6 @@ access. */ class##i_##name = IOTA(class##i_iota), \ class##_##name = BITMASK_IDX_TO_BIT(class##i_##name) -/*XXX This fails with the Sun Studio compiler: the bitfield -defns for 31, 32, 33 spit warnings, and we get unexpected debug -output for (at least) macro and regex channels. I suspect it has -elected to use a signed 32b int as its enum type, which is not unfair. - -( - C23 lets you spec the underlying type for an enum: - enum pet : unsigned char { CAT, DOG, ROCK }; -) - -We really only need the enum to give us an auto-inc for assgning bitnums. -But we also have IOTA. Could we use that for #defines for the bitmasks? -We'd have to list everthing twice... hmm. Losing the hard link between -the bit-idx & bitmask would not be good. - -Could we live totally without the bitnum? BIT_SET etc use? -MMM, prob not. - -Could we do bit-in-word mask rather than plain bitmask? -But how does that work for combining bits? -(currently we can just bitwise-or) -Though, for L-bits we just say we do not. -Make the same restriction on D-bits? It could work, -but currently DEBUG is keyed on the plain bitmask; -it would have to change to being the idx. -OK, so redefine DEBUG in the way LOGGING is done. -And perhaps a multi-bit version (macro-vararg) for combined-bit use. -Nope, this isn't working out. - -We also probably want a dedicated bit (? in word zero of the -array-of-words?) to say that at least one debug bit is set - -so that a fast test can be inlined. - -Next up, one more level of indirection: -use buildconfig.c to write the C and/or CPP code needed. -Expand the defn of BIT_TABLE() and struct bit_table -to be { name, BITWORD(idx), BITMASK(idx) } -Enhance decode_bits() to cope with that. -[ preferably, logging should use this also ] -buildconfig.c writes both debug_options[] (for decoding text spec in -cmdline and in config file) -AND an enum with all the named index bits (cf. Di_acl in macros.h) -NOTE that D_v and D_local_scan masks are defined in local_scan.h -and changing those will be a pain. -NOTE the existence of debug_notall[]. -*/ - /* Bits for debug triggers */ @@ -451,7 +403,7 @@ enum { /* Options bits for logging. Those that have values < BITWORDSIZE can be used in calls to log_write(). The others are put into later words in log_selector and are only ever tested independently, so they do not need bit mask -declarations. The Li_all value is recognized specially by decode_bits(). +declarations. The "all" name string is recognized specially by decode_bits(). Add also to log_options[] when creating new ones. */ #define LOG_BIT(name) BIT_TABLE_BIT(L, name) @@ -480,22 +432,21 @@ enum logwrite_bit { /* Bit numbers used by the LOGGING() macro */ -enum logging_test_bit { /* Must be in alpha order, matching log_chan_names[] */ +enum logging_test_bit { /* names matching log_channels[] */ Lt_all = BIT_TABLE_IDX_ALL, /* 0 */ Lt_8bitmime = BIT_TABLE_IDX_USABLE, /* 4 */ Lt_acl_warn_skipped, Lt_address_rewrite, - Lt_DUMMY_all, /* 7 */ - Lt_all_parents, + Lt_all_parents, /* 7 */ Lt_arguments, Lt_connection_id, Lt_connection_reject, Lt_delay_delivery, Lt_deliver_time, Lt_delivery_size, - Lt_dkim, /* 15 */ - Lt_dkim_verbose, + Lt_dkim, + Lt_dkim_verbose, /* 15 */ Lt_dmarc, Lt_dmarc_verbose, Lt_dnslist_defer, @@ -510,8 +461,8 @@ enum logging_test_bit { /* Must be in alpha order, matching log_chan_names[] */ Lt_millisec, Lt_msg_id, Lt_msg_id_created, - Lt_outgoing_interface, /* 31 */ - Lt_outgoing_port, + Lt_outgoing_interface, + Lt_outgoing_port, /* 31 */ Lt_pid, Lt_pipelining, Lt_protocol_detail, @@ -526,8 +477,8 @@ enum logging_test_bit { /* Must be in alpha order, matching log_chan_names[] */ Lt_rejected_header, Lt_retry_defer, Lt_return_path_on_delivery, - Lt_sender_on_delivery, /* 47 */ - Lt_sender_verify_fail, + Lt_sender_on_delivery, + Lt_sender_verify_fail, /* 47 */ Lt_size_reject, Lt_skip_delivery, Lt_smtp_confirmation, @@ -542,8 +493,8 @@ enum logging_test_bit { /* Must be in alpha order, matching log_chan_names[] */ Lt_subject, Lt_tls_certificate_verified, Lt_tls_cipher, - Lt_tls_on_connect, /* 63 */ - Lt_tls_peerdn, + Lt_tls_on_connect, + Lt_tls_peerdn, /* 63 */ Lt_tls_resumption, Lt_tls_sni, Lt_unknown_in_list, diff --git a/src/src/os.c b/src/src/os.c index dbf2e899b..40cf62762 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -11,9 +11,6 @@ # include # include # include -#else -// # define IS_DEBUG(x) (debug_selector & (x ? x : D_any)) -// # define DEBUG(x) if (IS_DEBUG(D_##x)) /* for cppcheck */ #endif #ifndef CS commit 6bb19a2ef5233b3129b71b6a062b6df80fa8a480 Author: Jeremy Harris Date: Mon Feb 23 17:07:41 2026 +0000 Logging: remove mainlog-only channel control diff --git a/src/exim_monitor/em_main.c b/src/exim_monitor/em_main.c index d85cefdba..bf03f0a75 100644 --- a/src/exim_monitor/em_main.c +++ b/src/exim_monitor/em_main.c @@ -159,7 +159,6 @@ from modules such as store.c when things go drastically wrong (e.g. malloc() failing). In normal use they won't get obeyed. Arguments: - selector not relevant when running a utility flags not relevant when running a utility format a printf() format ... arguments for format @@ -168,7 +167,7 @@ Returns: nothing */ void -log_write(bitmask_word_t selector, int flags, const char *format, ...) +log_write(int flags, const char *format, ...) { va_list ap; va_start(ap, format); @@ -179,7 +178,7 @@ va_end(ap); void -log_write_die(bitmask_word_t selector, int flags, const char *format, ...) +log_write_die(int flags, const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/src/src/acl.c b/src/src/acl.c index 17d9904d1..87bc06ee8 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1252,7 +1252,7 @@ if (log_message && log_message != user_message) if (!logged) { int length = Ustrlen(text) + 1; - log_write(0, LOG_MAIN, "%s", text); + log_write(LOG_MAIN, "%s", text); logged = store_malloc(sizeof(string_item) + length); logged->text = US logged + sizeof(string_item); memcpy(logged->text, text, length); @@ -1270,7 +1270,7 @@ Log an error. */ if (where > ACL_WHERE_NOTSMTP) { - log_write(0, LOG_MAIN|LOG_PANIC, "ACL \"warn\" with \"message\" setting " + log_write(LOG_MAIN|LOG_PANIC, "ACL \"warn\" with \"message\" setting " "found in a non-message (%s) ACL: cannot specify header lines here: " "message ignored", acl_wherenames[where]); return; @@ -2634,7 +2634,7 @@ else switch(mode) anchor = &ratelimiters_cmd; break; default: - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "internal ACL error: unknown ratelimit mode %d", mode); /*NOTREACHED*/ break; @@ -3417,7 +3417,7 @@ for (; cb; cb = cb->next) case ACLC_ATRN_DOMAINS: if (is_tainted(arg)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to used tainted value '%s' for atrn_domains%#s", arg, config_lineno @@ -3997,7 +3997,7 @@ for (; cb; cb = cb->next) else { logbits |= LOG_MAIN|LOG_REJECT; - log_write(0, LOG_MAIN|LOG_PANIC, "unknown log name %q in " + log_write(LOG_MAIN|LOG_PANIC, "unknown log name %q in " "\"log_reject_target\" in %s ACL", ss, acl_wherenames[where]); } } @@ -4033,7 +4033,7 @@ for (; cb; cb = cb->next) Uskip_whitespace(&s); if (logbits == 0) logbits = LOG_MAIN; - log_write(0, logbits, "%s", string_printing(s)); + log_write(logbits, "%s", string_printing(s)); break; } @@ -4214,7 +4214,7 @@ for (; cb; cb = cb->next) break; default: - log_write_die(0, LOG_MAIN, "internal ACL error: unknown " + log_write_die(LOG_MAIN, "internal ACL error: unknown " "condition %d", cb->type); break; } @@ -4270,7 +4270,7 @@ if ((BIT(rc) & msgcond[verb]) != 0) if (!expmessage) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand ACL message %q: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to expand ACL message %q: %s", user_message, expand_string_message); } else if (expmessage[0] != 0) *user_msgptr = expmessage; @@ -4283,7 +4283,7 @@ if ((BIT(rc) & msgcond[verb]) != 0) if (!expmessage) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand ACL message %q: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to expand ACL message %q: %s", log_message, expand_string_message); } else if (expmessage[0] != 0) @@ -4497,7 +4497,7 @@ acl_text = ss; if (is_tainted(acl_text) && !f.running_in_test_harness) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to use tainted ACL text %q", acl_text); /* Avoid leaking info to an attacker */ *log_msgptr = US"internal configuration error"; @@ -4733,13 +4733,13 @@ while ((acl_current = acl)) acl_warn(where, *user_msgptr, *log_msgptr); else if (cond == DEFER && LOGGING(acl_warn_skipped)) if (config_lineno > 0) - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s Warning: ACL 'warn' statement skipped (in %s at line %d of %s):" " condition test deferred%s%s", host_and_ident(TRUE), acl_name, config_lineno, config_filename, *log_msgptr ? US": " : US"", *log_msgptr ? *log_msgptr : US""); else - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s Warning: ACL 'warn' statement skipped (in %s):" " condition test deferred%s%s", host_and_ident(TRUE), acl_name, @@ -4748,7 +4748,7 @@ while ((acl_current = acl)) break; default: - log_write_die(0, LOG_MAIN, "internal ACL error: unknown verb %d", + log_write_die(LOG_MAIN, "internal ACL error: unknown verb %d", acl->verb); break; } @@ -5026,7 +5026,7 @@ if (rc == DISCARD) { if (where > ACL_WHERE_NOTSMTP || where == ACL_WHERE_PREDATA) { - log_write(0, LOG_MAIN|LOG_PANIC, "\"discard\" verb not allowed in %s " + log_write(LOG_MAIN|LOG_PANIC, "\"discard\" verb not allowed in %s " "ACL", acl_wherenames[where]); return ERROR; } @@ -5037,7 +5037,7 @@ if (rc == DISCARD) if (rc == FAIL_DROP && where == ACL_WHERE_MAILAUTH) { - log_write(0, LOG_MAIN|LOG_PANIC, "\"drop\" verb not allowed in %s " + log_write(LOG_MAIN|LOG_PANIC, "\"drop\" verb not allowed in %s " "ACL", acl_wherenames[where]); return ERROR; } diff --git a/src/src/atrn.c b/src/src/atrn.c index ab56189f4..9d12d672d 100644 --- a/src/src/atrn.c +++ b/src/src/atrn.c @@ -31,7 +31,7 @@ if (acl_smtp_atrn && !atrn_mode && (exp_acl = expand_string(acl_smtp_atrn)) && !*exp_acl) exp_acl = NULL; if (!exp_acl || !authenticated_id || sender_address) - return synprot_error(L_smtp_protocol_error, + return synprot_error(TRUE, !exp_acl ? 502 : !authenticated_id ? 530 : 503, NULL, !exp_acl ? US"ATRN command used when not advertised" @@ -39,8 +39,9 @@ if (!exp_acl || !authenticated_id || sender_address) : US"ATRN is not permitted inside a transaction" ); -log_write(L_etrn, LOG_MAIN, "ATRN '%s' received from %s", - smtp_cmd_argument, host_and_ident(FALSE)); +if (LOGGING(etrn)) + log_write(LOG_MAIN, "ATRN '%s' received from %s", + smtp_cmd_argument, host_and_ident(FALSE)); if ((rc = acl_check(ACL_WHERE_ATRN, NULL, exp_acl, user_msgp, log_msgp)) != OK) return smtp_handle_acl_fail(ACL_WHERE_ATRN, rc, *user_msgp, *log_msgp); diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index 356fc6e50..3e950b7b7 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -127,14 +127,14 @@ sasl_callback_t cbs[] = { if (!ob->server_mech) ob->server_mech = string_copy(ablock->public_name); if (!(expanded_hostname = expand_string(ob->server_hostname))) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't expand server_hostname [%s]: %s", a->name, ob->server_hostname, expand_string_message); realm_expanded = NULL; if ( ob->server_realm && !(realm_expanded = CS expand_string(ob->server_realm))) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't expand server_realm [%s]: %s", a->name, ob->server_realm, expand_string_message); @@ -145,16 +145,16 @@ cbs[0].proc = (int(*)(void)) &mysasl_config; cbs[0].context = ob->server_mech; if (sasl_server_init(cbs, "exim") != SASL_OK) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL library.", a->name); if (sasl_server_new(CS ob->server_service, CS expanded_hostname, realm_expanded, NULL, NULL, NULL, 0, &conn) != SASL_OK) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL server connection.", a->name); if (sasl_listmech(conn, NULL, "", ":", "", CCSS &list, &len, NULL) != SASL_OK) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't get Cyrus SASL mechanism list.", a->name); sep = ':'; @@ -180,7 +180,7 @@ while ( (buffer = string_nextinlist(&listptr, &sep, NULL, 0)) && strcmpic(buffer,ob->server_mech) ); if (!buffer) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "Cyrus SASL doesn't know about mechanism %s.", a->name, ob->server_mech); store_reset(rs_point); @@ -378,7 +378,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) HDEBUG(auth) debug_printf("Cyrus SASL library will not tell us the username: %s\n", sasl_errstring(rc, NULL, NULL)); - log_write(0, LOG_REJECT, "%s authenticator (%s): " + log_write(LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL username fetch problem: %s", auname, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); @@ -397,7 +397,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) /* these are considered permanent failure codes */ HDEBUG(auth) debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL)); - log_write(0, LOG_REJECT, "%s authenticator (%s): " + log_write(LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL permanent failure: %s", auname, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); @@ -427,7 +427,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) HDEBUG(auth) debug_printf("Cyrus SASL library will not tell us the SSF: %s\n", sasl_errstring(rc, NULL, NULL)); - log_write(0, LOG_REJECT, "%s authenticator (%s): " + log_write(LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL SSF value not available: %s", auname, ob->server_mech, sasl_errstring(rc, NULL, NULL)); sasl_dispose(&conn); @@ -441,7 +441,7 @@ for (rc = SASL_CONTINUE; rc == SASL_CONTINUE; ) { HDEBUG(auth) debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf); - log_write(0, LOG_REJECT, "%s authenticator (%s): " + log_write(LOG_REJECT, "%s authenticator (%s): " "Cyrus SASL SSF %d not supported by Exim", auname, ob->server_mech, negotiated_ssf); sasl_dispose(&conn); sasl_done(); diff --git a/src/src/auths/gsasl.c b/src/src/auths/gsasl.c index 3f9432bdf..2b8e14647 100644 --- a/src/src/auths/gsasl.c +++ b/src/src/auths/gsasl.c @@ -193,7 +193,7 @@ initialise the once. */ if (!gsasl_ctx) { if ((rc = gsasl_init(&gsasl_ctx)) != GSASL_OK) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise GNU SASL library: %s (%s)", a->name, gsasl_strerror_name(rc), gsasl_strerror(rc)); @@ -205,7 +205,7 @@ if (!gsasl_ctx) HDEBUG(auth) if (!once) { if ((rc = gsasl_server_mechlist(gsasl_ctx, &once)) != GSASL_OK) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "failed to retrieve list of mechanisms: %s (%s)", a->name, gsasl_strerror_name(rc), gsasl_strerror(rc)); @@ -213,7 +213,7 @@ HDEBUG(auth) if (!once) } if (!gsasl_client_support_p(gsasl_ctx, CCS ob->server_mech)) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "GNU SASL does not support mechanism %q", a->name, ob->server_mech); @@ -308,7 +308,7 @@ if (cb_state->currently == CURRENTLY_CLIENT) else if (cb_state->currently == CURRENTLY_SERVER) rc = server_callback(ctx, sctx, prop, cb_state->ablock); else - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "unhandled callback state, bug in Exim", cb_state->ablock->drinst.name); /* NOTREACHED */ @@ -522,7 +522,7 @@ do { case GSASL_BASE64_ERROR: HDEBUG(auth) debug_printf("GNU SASL permanent error: %s (%s)\n", gsasl_strerror_name(rc), gsasl_strerror(rc)); - log_write(0, LOG_REJECT, "%s authenticator (%s):\n " + log_write(LOG_REJECT, "%s authenticator (%s):\n " "GNU SASL permanent failure: %s (%s)", auname, ob->server_mech, gsasl_strerror_name(rc), gsasl_strerror(rc)); @@ -605,7 +605,7 @@ switch (exim_rc) case DEFER: sasl_error_should_defer = TRUE; return GSASL_AUTHENTICATION_ERROR; case FAIL: return GSASL_AUTHENTICATION_ERROR; - default: log_write_die(0, LOG_CONFIG_FOR, "%s authenticator: " + default: log_write_die(LOG_CONFIG_FOR, "%s authenticator: " "Unhandled return from checking %s: %d", ablock->drinst.name, label, exim_rc); } diff --git a/src/src/auths/spa.c b/src/src/auths/spa.c index 4b7f9cc95..65bab458b 100644 --- a/src/src/auths/spa.c +++ b/src/src/auths/spa.c @@ -110,7 +110,7 @@ if (!ablock->public_name) /* Both username and password must be set for a client */ if ((ob->spa_username == NULL) != (ob->spa_password == NULL)) - log_write_die(0, LOG_CONFIG_FOR, "%s authenticator:\n " + log_write_die(LOG_CONFIG_FOR, "%s authenticator:\n " "one of client_username and client_password cannot be set without " "the other", ablock->drinst.name); ablock->client = ob->spa_username != NULL; diff --git a/src/src/child.c b/src/src/child.c index 8796b4354..b61d3e4c8 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -164,8 +164,7 @@ DEBUG(exec) debug_print_argv(CUSS argv); exim_nullstd(); /* Make sure std{in,out,err} exist */ execv(CS argv[0], (char *const *)argv); -log_write(0, - LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), +log_write(LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), "re-exec of exim (%s) with %s failed: %s", exim_path, argv[first_special], strerror(errno)); @@ -343,7 +342,7 @@ pid_t pid; if (is_tainted(argv[0])) { - log_write(0, LOG_MAIN | LOG_PANIC, "Attempt to exec tainted path: '%s'", argv[0]); + log_write(LOG_MAIN | LOG_PANIC, "Attempt to exec tainted path: '%s'", argv[0]); errno = EPERM; return (pid_t)(-1); } diff --git a/src/src/daemon.c b/src/src/daemon.c index a078b1050..c10924426 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -128,7 +128,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno) { uschar *emsg = was_errno <= 0 ? US"" : string_sprintf(": %s", strerror(was_errno)); -log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg); +log_write(LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg); if (smtp_out_fd >= 0) smtp_printf("421 %s\r\n", SP_NO_MORE, smtp_msg); } @@ -219,7 +219,7 @@ if ((smtp_in_fd = dup(accept_socket)) < 0) if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr), &ifsize) < 0) { - log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), + log_write(LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), "getsockname() failed: %s", strerror(errno)); smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", SP_NO_MORE); goto ERROR_RETURN; @@ -254,9 +254,9 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max) smtp_accept_count, smtp_accept_max); smtp_printf("421 Too many concurrent SMTP connections; " "please try again later.\r\n", SP_NO_MORE); - log_write(L_connection_reject, - LOG_MAIN, "Connection from %Y refused: too many connections", - whofrom); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN, "Connection from %Y refused: too many connections", + whofrom); goto ERROR_RETURN; } @@ -273,9 +273,9 @@ if (smtp_load_reserve >= 0) DEBUG(any) debug_printf("rejecting SMTP connection: load average = %.2f\n", (double)load_average/1000.0); smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE); - log_write(L_connection_reject, - LOG_MAIN, "Connection from %Y refused: load average = %.2f", - whofrom, (double)load_average/1000.0); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN, "Connection from %Y refused: load average = %.2f", + whofrom, (double)load_average/1000.0); goto ERROR_RETURN; } } @@ -295,7 +295,7 @@ if (smtp_accept_max_per_host) if (!expanded) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " + log_write(LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " "failed for %Y: %s", whofrom, expand_string_message); } /* For speed, interpret a decimal number inline here */ @@ -305,7 +305,7 @@ if (smtp_accept_max_per_host) while (isdigit(*s)) max_for_this_host = max_for_this_host * 10 + *s++ - '0'; if (*s) - log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " + log_write(LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host " "for %Y contains non-digit: %s", whofrom, expanded); } } @@ -344,9 +344,9 @@ if ( smtp_slots host_accept_count, max_for_this_host); smtp_printf("421 Too many concurrent SMTP connections " "from this IP address; please try again later.\r\n", SP_NO_MORE); - log_write(L_connection_reject, - LOG_MAIN, "Connection from %Y refused: too many connections " - "from that IP address", whofrom); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN, "Connection from %Y refused: too many connections " + "from that IP address", whofrom); search_tidyup(); goto ERROR_RETURN; } @@ -391,19 +391,20 @@ if (pid == 0) if (list && verify_check_host(&list) == OK) logging_modify_channels(US"-smtp_connection"); - else if (LOGGING(connection_id)) - log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y " - "Ci=%s (TCP/IP connection count = %d)", - whofrom, connection_id, smtp_accept_count); - else - log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %Y " - "(TCP/IP connection count = %d)", whofrom, smtp_accept_count); + else if (LOGGING(smtp_connection)) + if (LOGGING(connection_id)) + log_write(LOG_MAIN, "SMTP connection from %Y " + "Ci=%s (TCP/IP connection count = %d)", + whofrom, connection_id, smtp_accept_count); + else + log_write(LOG_MAIN, "SMTP connection from %Y " + "(TCP/IP connection count = %d)", whofrom, smtp_accept_count); } /* If the listen backlog was over the monitoring level, log it. */ if (smtp_listen_backlog > smtp_backlog_monitor) - log_write(0, LOG_MAIN, "listen backlog %d I=[%s]:%d", + log_write(LOG_MAIN, "listen backlog %d I=[%s]:%d", smtp_listen_backlog, interface_address, interface_port); /* Get the local interface address into permanent store */ @@ -429,7 +430,7 @@ if (pid == 0) { if (!f.expand_string_forcedfail) { - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand %q " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand %q " "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); smtp_printf("421 Local configuration error; " @@ -658,20 +659,20 @@ if (pid == 0) /* Log the queueing here, when it will get a message id attached, but not if queue_only is set (case 0). */ - if (local_queue_only) switch(queue_only_reason) + if (LOGGING(delay_delivery) && local_queue_only) switch(queue_only_reason) { - case 1: log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: too many connections " - "(%d, max %d)", smtp_accept_count, smtp_accept_queue); + case 1: log_write(LOG_MAIN, + "no immediate delivery: too many connections (%d, max %d)", + smtp_accept_count, smtp_accept_queue); break; - case 2: log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: more than %d messages " + case 2: log_write(LOG_MAIN, + "no immediate delivery: more than %d messages " "received in one connection", smtp_accept_queue_per_connection); break; - case 3: log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: load average %.2f", + case 3: log_write(LOG_MAIN, + "no immediate delivery: load average %.2f", (double)load_average/1000.0); break; } @@ -729,7 +730,7 @@ if (pid == 0) else { cancel_cutthrough_connection(TRUE, US"delivery fork failed"); - log_write(0, LOG_MAIN|LOG_PANIC, "daemon: delivery process fork " + log_write(LOG_MAIN|LOG_PANIC, "daemon: delivery process fork " "failed: %s", strerror(errno)); } } @@ -776,7 +777,7 @@ descriptors are closed, in order to drop the connection. */ if (smtp_out_fd >= 0) { if (close(smtp_out_fd) != 0 && errno != ECONNRESET && errno != EPIPE) - log_write(0, LOG_MAIN|LOG_PANIC, "daemon: close(smtp_out_fd) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "daemon: close(smtp_out_fd) failed: %s", strerror(errno)); smtp_out_fd = -1; } @@ -784,7 +785,7 @@ if (smtp_out_fd >= 0) if (smtp_in_fd >= 0) { if (close(smtp_in_fd) != 0 && errno != ECONNRESET && errno != EPIPE) - log_write(0, LOG_MAIN|LOG_PANIC, "daemon: close(smtp_in_fd) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "daemon: close(smtp_in_fd) failed: %s", strerror(errno)); smtp_in_fd = -1; } @@ -963,7 +964,7 @@ if (!*pid_file_path) pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory); if (pid_file_path[0] != '/') - log_write_die(0, LOG_PANIC_DIE, + log_write_die(LOG_PANIC_DIE, "pid file path %s must be absolute\n", pid_file_path); } @@ -998,7 +999,7 @@ if (pid_len < 2 || pid_len >= (int)sizeof(pid_line)) goto cleanup; path = string_copy(pid_file_path); if ((base = Ustrrchr(path, '/')) == NULL) /* should not happen, but who knows */ - log_write_die(0, LOG_MAIN, "pid file path %q does not contain a '/'", pid_file_path); + log_write_die(LOG_MAIN, "pid file path %q does not contain a '/'", pid_file_path); dir = base != path ? path : US"/"; *base++ = '\0'; @@ -1015,7 +1016,7 @@ if (dir_fd < 0 || fstat(dir_fd, &sb) != 0 || !S_ISDIR(sb.st_mode)) goto cleanup; if (fchdir(dir_fd) != 0) goto cleanup; base_fd = open(CS base, O_RDONLY | base_flags); if (fchdir(cwd_fd) != 0) - log_write_die(0, LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); + log_write_die(LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); if (base_fd >= 0) { @@ -1046,7 +1047,7 @@ if (operation == PID_WRITE) if (fchdir(dir_fd) != 0) goto cleanup; error = unlink(CS base); if (fchdir(cwd_fd) != 0) - log_write_die(0, LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); + log_write_die(LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); if (error) goto cleanup; (void)close(base_fd); base_fd = -1; @@ -1055,7 +1056,7 @@ if (operation == PID_WRITE) if (fchdir(dir_fd) != 0) goto cleanup; base_fd = open(CS base, O_WRONLY | O_CREAT | O_EXCL | base_flags, base_mode); if (fchdir(cwd_fd) != 0) - log_write_die(0, LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); + log_write_die(LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); if (base_fd < 0) goto cleanup; if (fchmod(base_fd, base_mode) != 0) goto cleanup; if (write(base_fd, pid_line, pid_len) != pid_len) goto cleanup; @@ -1072,7 +1073,7 @@ else if (fchdir(dir_fd) != 0) goto cleanup; error = unlink(CS base); if (fchdir(cwd_fd) != 0) - log_write_die(0, LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); + log_write_die(LOG_MAIN, "can't return to previous working dir: %s", strerror(errno)); if (error) goto cleanup; } } @@ -1244,7 +1245,7 @@ bad2: Uunlink(sa_un.sun_path); #endif bad: - log_write(0, LOG_MAIN|LOG_PANIC, "%s %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "%s %s: %s", __FUNCTION__, where, strerror(errno)); close(fd); return; @@ -1364,7 +1365,7 @@ switch (buf[0]) if (sendto(daemon_notifier_fd, qsbuf, len, 0, (const struct sockaddr *)&sa_un, msg.msg_namelen) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s: sendto: %s\n", __FUNCTION__, strerror(errno)); break; } @@ -1400,7 +1401,7 @@ else DEBUG(any) debug_printf("inetd wait timeout %d expired, ending daemon\n", inetd_wait_timeout); - log_write(0, LOG_MAIN, "exim %s daemon terminating, inetd wait timeout reached.\n", + log_write(LOG_MAIN, "exim %s daemon terminating, inetd wait timeout reached.\n", version_string); daemon_die(); /* Does not return */ } @@ -1562,7 +1563,7 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ #ifndef DISABLE_QUEUE_RAMP if (*queuerun_msgid) { - log_write(0, LOG_MAIN, "notify triggered queue run"); + log_write(LOG_MAIN, "notify triggered queue run"); extra[extracount++] = queuerun_msgid; /* Trigger only the */ extra[extracount++] = queuerun_msgid; /* one message */ } @@ -1597,7 +1598,7 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ #ifndef DISABLE_QUEUE_RAMP if (*queuerun_msgid) { - log_write(0, LOG_MAIN, "notify triggered queue run"); + log_write(LOG_MAIN, "notify triggered queue run"); f.queue_2stage = FALSE; queue_run(q, queuerun_msgid, queuerun_msgid, FALSE); } @@ -1609,7 +1610,7 @@ if (is_multiple_qrun()) /* we are managing periodic runs */ if (pid < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fork of queue-runner " + log_write(LOG_MAIN|LOG_PANIC, "daemon: fork of queue-runner " "process failed: %s", strerror(errno)); log_close_all(); } @@ -1774,7 +1775,7 @@ if (f.inetd_wait_mode) listen_socket_count = 1; (void) close(3); if (dup2(0, 3) == -1) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "failed to dup inetd socket safely away: %s", strerror(errno)); fd_polls[0].fd = 3; @@ -1801,7 +1802,7 @@ if (f.inetd_wait_mode) if (tcp_nodelay) if (setsockopt(3, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) - log_write_die(0, LOG_MAIN, "failed to set socket NODELAY: %s", + log_write_die(LOG_MAIN, "failed to set socket NODELAY: %s", strerror(errno)); } @@ -1962,13 +1963,13 @@ if (f.daemon_listen && !f.inetd_wait_mode) uschar * end; default_smtp_port[pct] = Ustrtol(s, &end, 0); if (*end) - log_write_die(0, LOG_CONFIG, "invalid SMTP port: %s", s); + log_write_die(LOG_CONFIG, "invalid SMTP port: %s", s); } else { struct servent * smtp_service = getservbyname(CS s, "tcp"); if (!smtp_service) - log_write_die(0, LOG_CONFIG, "TCP port %q not found", s); + log_write_die(LOG_CONFIG, "TCP port %q not found", s); default_smtp_port[pct] = ntohs(smtp_service->s_port); } default_smtp_port[pct] = 0; @@ -1994,7 +1995,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) { struct servent * smtp_service = getservbyname(CS s, "tcp"); if (!smtp_service) - log_write_die(0, LOG_CONFIG, "TCP port %q not found", s); + log_write_die(LOG_CONFIG, "TCP port %q not found", s); g = string_append_listele_fmt(g, ':', FALSE, "%d", (int)ntohs(smtp_service->s_port)); } @@ -2033,7 +2034,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) if (ipa->port > 0) continue; if (!*daemon_smtp_port) - log_write_die(0, LOG_MAIN, "no port specified for interface " + log_write_die(LOG_MAIN, "no port specified for interface " "%s and daemon_smtp_port is unset; cannot start daemon", ipa->address[0] == 0 ? US"\"all IPv4\"" : ipa->address[1] == 0 ? US"\"all IPv6\"" : ipa->address); @@ -2172,7 +2173,7 @@ if (f.background_daemon) { BOOL daemon_listen = f.daemon_listen; pid_t pid = exim_fork(US"daemon"); - if (pid < 0) log_write_die(0, LOG_MAIN, + if (pid < 0) log_write_die(LOG_MAIN, "fork() failed when starting daemon: %s", strerror(errno)); if (pid > 0) exim_exit(EXIT_SUCCESS); /* in parent process, just exit */ (void)setsid(); /* release controlling terminal */ @@ -2217,11 +2218,11 @@ if (f.daemon_listen && !f.inetd_wait_mode) { if (check_special_case(0, addresses, ipa, FALSE)) { - log_write(0, LOG_MAIN, "Failed to create IPv6 socket for wildcard " + log_write(LOG_MAIN, "Failed to create IPv6 socket for wildcard " "listening (%s): will use IPv4", strerror(errno)); goto SKIP_SOCKET; } - log_write_die(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s", + log_write_die(LOG_PANIC_DIE, "IPv%c socket creation failed: %s", af == AF_INET6 ? '6' : '4', strerror(errno)); } @@ -2232,7 +2233,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) #ifdef IPV6_V6ONLY if (af == AF_INET6 && wildcard && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) - log_write(0, LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard " + log_write(LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard " "socket failed (%s): carrying on without it", strerror(errno)); #endif /* IPV6_V6ONLY */ @@ -2241,7 +2242,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) smtp port for listening. */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - log_write_die(0, LOG_MAIN, "setting SO_REUSEADDR on socket " + log_write_die(LOG_MAIN, "setting SO_REUSEADDR on socket " "failed when starting daemon: %s", strerror(errno)); /* Set TCP_NODELAY; Exim does its own buffering. There is a switch to @@ -2280,10 +2281,10 @@ if (f.daemon_listen && !f.inetd_wait_mode) : US"(any IPv4)" : ipa->address; if (daemon_startup_retries <= 0) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "socket bind() to port %d for address %s failed: %s: " "daemon abandoned", ipa->port, addr, msg); - log_write(0, LOG_MAIN, "socket bind() to port %d for address %s " + log_write(LOG_MAIN, "socket bind() to port %d for address %s " "failed: %s: waiting %s before trying again (%d more %s)", ipa->port, addr, msg, readconf_printtime(daemon_startup_sleep), daemon_startup_retries, (daemon_startup_retries > 1)? "tries" : "try"); @@ -2332,7 +2333,7 @@ if (f.daemon_listen && !f.inetd_wait_mode) where the IPv6 socket accepts both kinds of call. */ if (!check_special_case(errno, addresses, ipa, TRUE)) - log_write_die(0, LOG_PANIC_DIE, "listen() failed on interface %s: %s", + log_write_die(LOG_PANIC_DIE, "listen() failed on interface %s: %s", wildcard ? af == AF_INET6 ? US"(any IPv6)" : US"(any IPv4)" : ipa->address, strerror(errno)); @@ -2450,7 +2451,7 @@ if (f.inetd_wait_mode) else sprintf(CS p, "with no wait timeout"); - log_write(0, LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT + log_write(LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", launched with listening socket, %s", version_string, getpid(), big_buffer); daemon_process_info = US"pre-listening socket"; @@ -2593,7 +2594,7 @@ else if (f.daemon_listen) p += sprintf(CS p, " ..."); } - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", %s, listening for %s", version_string, getpid(), qinfo, big_buffer); daemon_process_info = @@ -2603,7 +2604,7 @@ else if (f.daemon_listen) else /* no listening sockets, only queue-runs */ { const uschar * s = describe_queue_runners(); - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "exim %s daemon started: pid=" PID_T_FMT ", %s, not listening for SMTP", version_string, getpid(), s); daemon_process_info = string_sprintf("%s, not listening", s); @@ -2838,7 +2839,7 @@ for (;;) || select_failed != accept_retry_select_failed || accept_retry_count >= 50) { - log_write(0, LOG_MAIN | (accept_retry_count >= 50 ? LOG_PANIC : 0), + log_write(LOG_MAIN | (accept_retry_count >= 50 ? LOG_PANIC : 0), "%d %s() failure%s: %s", accept_retry_count, accept_retry_select_failed ? "select" : "accept", @@ -2853,7 +2854,7 @@ for (;;) } else if (accept_retry_count > 0) { - log_write(0, LOG_MAIN, "%d %s() failure%s: %s", + log_write(LOG_MAIN, "%d %s() failure%s: %s", accept_retry_count, accept_retry_select_failed ? "select" : "accept", accept_retry_count == 1 ? "" : "s", @@ -2912,7 +2913,7 @@ for (;;) if (sighup_seen) { - log_write(0, LOG_MAIN, "pid " PID_T_FMT ": SIGHUP received: re-exec daemon", + log_write(LOG_MAIN, "pid " PID_T_FMT ": SIGHUP received: re-exec daemon", getpid()); close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count); unlink_notifier_socket(); @@ -2921,7 +2922,7 @@ for (;;) sighup_argv[0] = exim_path; exim_nullstd(); execv(CS exim_path, (char *const *)sighup_argv); - log_write_die(0, LOG_MAIN, "pid " PID_T_FMT ": exec of %s failed: %s", + log_write_die(LOG_MAIN, "pid " PID_T_FMT ": exec of %s failed: %s", getpid(), exim_path, strerror(errno)); /*NOTREACHED*/ } diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 7c0351a4f..7a0354b06 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -124,7 +124,7 @@ priv_restore(); if (*fdp < 0) { - log_write(0, LOG_MAIN, "%s", + log_write(LOG_MAIN, "%s", string_open_failed("database lock file %s", filename)); errno = 0; /* Indicates locking failure */ return FALSE; @@ -147,7 +147,7 @@ ALARM_CLR(0); if (sigalrm_seen) errno = ETIMEDOUT; if (rc < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to get %s lock for %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Failed to get %s lock for %s: %s", rdonly ? "read" : "write", filename, errno == ETIMEDOUT ? "timed out" : strerror(errno)); (void)close(*fdp); *fdp = -1; @@ -251,7 +251,7 @@ if (!dbblock->dbptr) { errno = save_errno; if (lof && save_errno != ENOENT) - log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s", + log_write(LOG_MAIN, "%s", string_open_failed("DB file %s", filename)); else DEBUG(hints_lookup) @@ -309,7 +309,7 @@ if (!dbblock->dbptr) { errno = save_errno; if (save_errno != ENOENT) - log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s", + log_write(LOG_MAIN, "%s", string_open_failed("DB file %s", filename)); else DEBUG(hints_lookup) @@ -521,7 +521,7 @@ void * yield = dbfn_read_with_length(dbblock, key, &rlen); if (yield) { if (rlen == length) return yield; - log_write(0, LOG_MAIN|LOG_PANIC, "Bad db record size for '%s'", key); + log_write(LOG_MAIN|LOG_PANIC, "Bad db record size for '%s'", key); dbfn_delete(dbblock, key); } return NULL; diff --git a/src/src/dcc.c b/src/src/dcc.c index 9341607b7..7426d2a15 100644 --- a/src/src/dcc.c +++ b/src/src/dcc.c @@ -103,8 +103,7 @@ for (int i = 0; i < 2; i++) if (!data_file) { /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, - "DCC: error while opening spool file"); + log_write(LOG_MAIN|LOG_PANIC, "DCC: error while opening spool file"); return DEFER; } @@ -118,7 +117,7 @@ if (dccifd_address) if(sscanf(CS dccifd_address, "%" mac_expanded_string(SOCKIP_USE) "s %u", sockip, &portnr) != 2) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DCC: warning - invalid dccifd address: '%s'", dccifd_address); (void)fclose(data_file); return DEFER; @@ -178,7 +177,7 @@ if(Ustrcmp(sockip, "")) { DEBUG(acl) debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); - log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); + log_write(LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno)); /* if we cannot create the socket, defer the mail */ (void)fclose(data_file); return retval; @@ -188,7 +187,7 @@ if(Ustrcmp(sockip, "")) { DEBUG(acl) debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); - log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); + log_write(LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno)); /* if we cannot contact the socket, defer the mail */ (void)fclose(data_file); return retval; @@ -204,7 +203,7 @@ else { DEBUG(acl) debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); - log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); + log_write(LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno)); /* if we cannot create the socket, defer the mail */ (void)fclose(data_file); return retval; @@ -214,7 +213,7 @@ else { DEBUG(acl) debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); - log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); + log_write(LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno)); /* if we cannot contact the socket, defer the mail */ (void)fclose(data_file); return retval; @@ -286,7 +285,7 @@ if(shutdown(sockfd, SHUT_WR) < 0) { DEBUG(acl) debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno)); - log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno)); + log_write(LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno)); /* If there is a problem with the shutdown() * defer the mail. */ (void)fclose(data_file); @@ -358,10 +357,10 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) dcc_result = US"R"; retval = FAIL; if(sender_host_name) - log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC", + log_write(LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC", sender_host_name, sender_host_address, sender_address); else - log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC", + log_write(LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC", sender_host_address, sender_address); break; case 'S': @@ -385,7 +384,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) dcc_return_text = US"Temporary error with DCC"; dcc_result = US"T"; retval = DEFER; - log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer); + log_write(LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer); break; default: DEBUG(acl) @@ -393,7 +392,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) dcc_return_text = US"Unknown DCC response"; dcc_result = US"T"; retval = DEFER; - log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", big_buffer); + log_write(LOG_MAIN,"Unknown DCC response: %s\n", big_buffer); break; } } @@ -403,7 +402,7 @@ while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) * there must be something wrong. */ DEBUG(acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0" " character is %c - This is wrong!\n", line, bufoffset, big_buffer[bufoffset]); - log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer); + log_write(LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer); } } else if(line == 2) diff --git a/src/src/deliver.c b/src/src/deliver.c index 8d3721c30..93d79af08 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -318,7 +318,7 @@ static int open_msglog_file(uschar *filename, int mode, uschar **error) { if (Ustrstr(filename, US"/../")) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Attempt to open msglog file path with upward-traversal: '%s'\n", filename); for (int i = 2; i > 0; i--) @@ -856,7 +856,7 @@ if (action) event_data = ev_data; if (!(s = expand_string(action)) && *expand_string_message) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to expand event_action %s in %s: %s\n", event, transport_name ? transport_name : US"main", expand_string_message); @@ -1295,7 +1295,7 @@ if (LOGGING(deliver_time)) /* string_cat() always leaves room for the terminator. Release the store we used to build the line after writing it. */ -log_write(0, flags, "%Y", g); +log_write(flags, "%Y", g); #ifndef DISABLE_EVENT if (!msg) msg_event_raise(US"msg:delivery", addr); @@ -1369,8 +1369,8 @@ of error number is negative, and all the retry ones are less than any others. */ -log_write(addr->basic_errno <= ERRNO_RETRY_BASE ? L_retry_defer : 0, logflags, - "== %Y", g); +if (addr->basic_errno > ERRNO_RETRY_BASE || LOGGING(retry_defer)) + log_write(logflags, "== %Y", g); store_reset(reset_point); return; @@ -1446,7 +1446,7 @@ if (driver_kind) else deliver_msglog("%s %.*s\n", now, g->ptr, g->s); -log_write(0, LOG_MAIN, "** %Y", g); +log_write(LOG_MAIN, "** %Y", g); store_reset(reset_point); return; @@ -1555,7 +1555,7 @@ if (addr->return_file >= 0 && addr->return_filename) { FILE * f = Ufopen(addr->return_filename, "rb"); if (!f) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to open %s to log output " + log_write(LOG_MAIN|LOG_PANIC, "failed to open %s to log output " "from %s transport: %s", addr->return_filename, tb->drinst.name, strerror(errno)); else @@ -1567,7 +1567,7 @@ if (addr->return_file >= 0 && addr->return_filename) while (p > big_buffer && isspace(p[-1])) p--; *p = 0; sp = string_printing(big_buffer); - log_write(0, LOG_MAIN, "<%s>: %s transport output: %s", + log_write(LOG_MAIN, "<%s>: %s transport output: %s", addr->address, tb->drinst.name, sp); } (void)fclose(f); @@ -1796,7 +1796,7 @@ for (address_item * addr2 = addr->next; addr2; addr2 = addr2->next) addr2->message = addr->message; } -if (logit) log_write(0, LOG_MAIN|LOG_PANIC, "%s", addr->message); +if (logit) log_write(LOG_MAIN|LOG_PANIC, "%s", addr->message); deliver_set_expansions(NULL); } @@ -2317,7 +2317,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0) # ifdef SETRLIMIT_NOT_SUPPORTED if (errno != ENOSYS && errno != ENOTSUP) # endif - log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_CORE) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_CORE) failed: %s", strerror(errno)); } #endif @@ -2446,7 +2446,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0) ) ) ) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s", + log_write(LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s", ret == -1 ? strerror(errno) : "short write"); /* Now any messages */ @@ -2457,7 +2457,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0) if( (ret = write(pfd[pipe_write], &message_length, sizeof(int))) != sizeof(int) || message_length > 0 && (ret = write(pfd[pipe_write], s, message_length)) != message_length ) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s", + log_write(LOG_MAIN|LOG_PANIC, "Failed writing transport results to pipe: %s", ret == -1 ? strerror(errno) : "short write"); } } @@ -2474,7 +2474,7 @@ better than returning an error - if forking is failing it is probably best not to try other deliveries for this message. */ if (pid < 0) - log_write_die(0, LOG_MAIN, "Fork failed for local delivery to %s", + log_write_die(LOG_MAIN, "Fork failed for local delivery to %s", addr->address); /* Read the pipe to get the delivery status codes and error messages. Our copy @@ -2510,7 +2510,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next) || llen > 64*4 /* limit from rfc 5821, times I18N factor */ ) { - log_write(0, LOG_MAIN|LOG_PANIC, "bad local_part length read" + log_write(LOG_MAIN|LOG_PANIC, "bad local_part length read" " from delivery subprocess"); break; } @@ -2518,7 +2518,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next) /* coverity[tainted_data] */ if (read(pfd[pipe_read], big_buffer, llen) != llen) { - log_write(0, LOG_MAIN|LOG_PANIC, "bad local_part read" + log_write(LOG_MAIN|LOG_PANIC, "bad local_part read" " from delivery subprocess"); break; } @@ -2541,7 +2541,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next) else { - log_write(0, LOG_MAIN|LOG_PANIC, "failed to read delivery status for %s " + log_write(LOG_MAIN|LOG_PANIC, "failed to read delivery status for %s " "from delivery subprocess", addr2->unique); break; } @@ -2573,14 +2573,14 @@ if (!shadowing) DEBUG(deliver) debug_printf("journalling %s", big_buffer); len = Ustrlen(big_buffer); if (write(journal_fd, big_buffer, len) != len) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to update journal for %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to update journal for %s: %s", big_buffer, strerror(errno)); } /* Ensure the journal file is pushed out to disk. */ if (EXIMfsync(journal_fd) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to fsync journal: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to fsync journal: %s", strerror(errno)); } @@ -2595,7 +2595,7 @@ resets SIGCHLD to SIG_DFL, but this code should still be robust. */ while ((rc = wait(&status)) != pid) if (rc < 0 && errno == ECHILD) /* Process has vanished */ { - log_write(0, LOG_MAIN, "%s transport process vanished unexpectedly", + log_write(LOG_MAIN, "%s transport process vanished unexpectedly", addr->transport->drinst.driver_name); status = 0; break; @@ -2608,7 +2608,7 @@ if ((status & 0xffff) != 0) int code = (msb == 0)? (lsb & 0x7f) : msb; if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT)) addr->special_action = SPECIAL_FREEZE; - log_write(0, LOG_MAIN|LOG_PANIC, "%s transport process returned non-zero " + log_write(LOG_MAIN|LOG_PANIC, "%s transport process returned non-zero " "status 0x%04x: %s %d", addr->transport->drinst.driver_name, status, @@ -2630,7 +2630,7 @@ if (addr->special_action == SPECIAL_WARN) DEBUG(deliver) debug_printf("Warning message requested by transport\n"); if (!(warn_message = expand_string(warn_message))) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %q (warning " + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand %q (warning " "message for %s transport): %s", addr->transport->warn_message, addr->transport->drinst.name, expand_string_message); @@ -2676,7 +2676,7 @@ if (!tp->max_parallel) return FALSE; max_parallel = (unsigned) expand_string_integer(tp->max_parallel, TRUE); if (expand_string_message) { - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand max_parallel option " + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand max_parallel option " "in %s transport (%s): %s", trname, addr->address, expand_string_message); return TRUE; @@ -2802,7 +2802,7 @@ while (addr_local) deliver_set_expansions(NULL); if (!batch_id) { - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand batch_id option " + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand batch_id option " "in %s transport (%s): %s", trname, addr->address, expand_string_message); batch_count = tp->batch_max; @@ -2859,7 +2859,7 @@ while (addr_local) deliver_set_expansions(NULL); if (!bid) { - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand batch_id option " + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand batch_id option " "in %s transport (%s): %s", trname, next->address, expand_string_message); ok = FALSE; @@ -3064,7 +3064,7 @@ while (addr_local) if (Ustrcmp(stp->drinst.name, tp->shadow) == 0) break; if (!stp) - log_write(0, LOG_MAIN|LOG_PANIC, "shadow transport %q not found ", + log_write(LOG_MAIN|LOG_PANIC, "shadow transport %q not found ", tp->shadow); /* Pick off the addresses that have succeeded, and make clones. Put into @@ -3854,7 +3854,7 @@ if (msg) addr->transport_return = DEFER; addr->special_action = SPECIAL_FREEZE; addr->message = msg; - log_write(0, LOG_MAIN|LOG_PANIC, "Delivery status for %s: %s\n", + log_write(LOG_MAIN|LOG_PANIC, "Delivery status for %s: %s\n", addr->address, addr->message); } @@ -4147,7 +4147,7 @@ for (;;) /* Normally we do not repeat this loop */ pid_t endedpid = waitpid(pid, &status, 0); if (endedpid == pid) goto PROCESS_DONE; if (endedpid != (pid_t)(-1) || errno != EINTR) - log_write_die(0, LOG_MAIN, "Unexpected error return " + log_write_die(LOG_MAIN, "Unexpected error return " "%d (errno = %d) from waitpid() for process %ld", (int)endedpid, errno, (long)pid); } @@ -4171,7 +4171,7 @@ for (;;) /* Normally we do not repeat this loop */ /* This situation is an error, but it's probably better to carry on looking for another process than to give up (as we used to do). */ - log_write(0, LOG_MAIN|LOG_PANIC, "Process %ld finished: not found in remote " + log_write(LOG_MAIN|LOG_PANIC, "Process %ld finished: not found in remote " "transport process list", (long)pid); } /* End of the "for" loop */ @@ -4270,7 +4270,7 @@ while (parcount > max) address_item * doneaddr = par_wait(reason); if (!doneaddr) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "remote delivery process count got out of step"); parcount = 0; } @@ -4302,7 +4302,7 @@ ssize_t ret; /* complain to log if someone tries with buffer sizes we can't handle*/ if (size > BIG_BUFFER_SIZE-1) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Failed writing transport result to pipe: can't handle buffers > %d bytes. truncating!\n", BIG_BUFFER_SIZE-1); /*NOTREACHED*/ @@ -4313,13 +4313,13 @@ that help? */ /* convert size to human readable string prepended by id and subid */ if (PIPE_HEADER_SIZE != snprintf(CS pipe_header, PIPE_HEADER_SIZE+1, "%c%c%05ld", id, subid, (long)size)) - log_write_die(0, LOG_MAIN, "header snprintf failed\n"); + log_write_die(LOG_MAIN, "header snprintf failed\n"); DEBUG(deliver) debug_printf("header write id:%c,subid:%c,size:%ld,final:%s\n", id, subid, (long)size, pipe_header); if ((ret = writev(fd, iov, 2)) != total_len) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Failed writing transport result to pipe (%ld of %ld bytes): %s", (long)ret, (long)total_len, ret == -1 ? strerror(errno) : "short write"); } @@ -4945,7 +4945,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe if ( (deliver_datafile = Uopen(fname, EXIM_CLOEXEC | O_RDWR | O_APPEND, 0)) < 0) - log_write_die(0, LOG_MAIN, "Failed to reopen %s for remote " + log_write_die(LOG_MAIN, "Failed to reopen %s for remote " "parallel delivery: %s", fname, strerror(errno)); } @@ -5550,7 +5550,7 @@ for (;;) if ((yield = expand_string(string_from_gstring(para)))) return yield; -log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand string from " +log_write(LOG_MAIN|LOG_PANIC, "Failed to expand string from " "bounce_message_file or warn_message_file (%s): %s", which, expand_string_message); return NULL; @@ -5884,14 +5884,14 @@ const uschar * s = expand_string(filename); FILE * fp = NULL; if (!s || !*s) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand %s: '%s'\n", optname, filename); else if (*s != '/' || is_tainted(s)) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s is not %s after expansion: '%s'\n", optname, *s == '/' ? "untainted" : "absolute", s); else if (!(fp = Ufopen(s, "rb"))) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s " + log_write(LOG_MAIN|LOG_PANIC, "Failed to open %s for %s " "message texts: %s", s, reason, strerror(errno)); return fp; } @@ -5950,7 +5950,7 @@ if (!(bounce_recipient = addr_failed->prop.errors_address)) /* Make a subprocess to send a message, using its stdin */ if ((pid = child_open_exim(&fd, US"bounce-message")) < 0) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Process " PID_T_FMT " (parent " PID_T_FMT ") failed to " "create child process to send failure message: %s", getpid(), getppid(), strerror(errno)); @@ -6359,7 +6359,7 @@ wording. */ } deliver_msglog("Process failed (%d) when writing error message " "to %s%s", rc, bounce_recipient, s); - log_write(0, LOG_MAIN, "Process failed (%d) when writing error message " + log_write(LOG_MAIN, "Process failed (%d) when writing error message " "to %s%s", rc, bounce_recipient, s); } @@ -6618,7 +6618,7 @@ if (addr_senddsn) if (pid < 0) /* Creation of child failed */ { - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Process " PID_T_FMT " (parent " PID_T_FMT ") failed to " "create child process to send success-dsn message: %s", getpid(), getppid(), strerror(errno)); @@ -6877,13 +6877,13 @@ give up; if the message has been around for sufficiently long, remove it. */ struct stat statbuf; if (Ustat(spool_fname(US"input", message_subdir, spoolname, US""), &statbuf) == 0) - log_write(0, LOG_MAIN, "Format error in spool file %s: " + log_write(LOG_MAIN, "Format error in spool file %s: " "size=" OFF_T_FMT, spoolname, statbuf.st_size); else - log_write(0, LOG_MAIN, "Format error in spool file %s", spoolname); + log_write(LOG_MAIN, "Format error in spool file %s", spoolname); } else - log_write(0, LOG_MAIN, "Error reading spool file %s: %s", spoolname, + log_write(LOG_MAIN, "Error reading spool file %s: %s", spoolname, strerror(errno)); /* If we managed to read the envelope data, received_time contains the @@ -6906,7 +6906,7 @@ give up; if the message has been around for sufficiently long, remove it. */ Uunlink(spool_fname(US"input", message_subdir, id, US"-D")); Uunlink(spool_fname(US"input", message_subdir, id, US"-H")); Uunlink(spool_fname(US"input", message_subdir, id, US"-J")); - log_write(0, LOG_MAIN, "Message removed because older than %s", + log_write(LOG_MAIN, "Message removed because older than %s", readconf_printtime(keep_malformed)); } @@ -6954,7 +6954,7 @@ Otherwise it might be needed again. */ } else if (errno != ENOENT) { - log_write(0, LOG_MAIN|LOG_PANIC, "attempt to open journal for reading gave: " + log_write(LOG_MAIN|LOG_PANIC, "attempt to open journal for reading gave: " "%s", strerror(errno)); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } @@ -6965,7 +6965,7 @@ Otherwise it might be needed again. */ { (void)close(deliver_datafile); deliver_datafile = -1; - log_write(0, LOG_MAIN, "Spool error: no recipients for %s", fname); + log_write(LOG_MAIN, "Spool error: no recipients for %s", fname); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } } @@ -6995,7 +6995,7 @@ if (f.deliver_freeze) if (timeout_frozen_after > 0 && message_age >= timeout_frozen_after) { - log_write(0, LOG_MAIN, "cancelled by timeout_frozen_after"); + log_write(LOG_MAIN, "cancelled by timeout_frozen_after"); process_recipients = RECIP_FAIL_TIMEOUT; } @@ -7004,7 +7004,7 @@ if (f.deliver_freeze) fails. */ else if (!*sender_address && message_age >= ignore_bounce_errors_after) - log_write(0, LOG_MAIN, "Unfrozen by errmsg timer"); + log_write(LOG_MAIN, "Unfrozen by errmsg timer"); /* If this is a bounce message, or there's no auto thaw, or we haven't reached the auto thaw time yet, and this delivery is not forced by an admin @@ -7024,7 +7024,7 @@ if (f.deliver_freeze) { (void)close(deliver_datafile); deliver_datafile = -1; - log_write(L_skip_delivery, LOG_MAIN, "Message is frozen"); + if (LOGGING(skip_delivery)) log_write(LOG_MAIN, "Message is frozen"); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } @@ -7034,9 +7034,9 @@ if (f.deliver_freeze) if (forced) { f.deliver_manual_thaw = TRUE; - log_write(0, LOG_MAIN, "Unfrozen by forced delivery"); + log_write(LOG_MAIN, "Unfrozen by forced delivery"); } - else log_write(0, LOG_MAIN, "Unfrozen by auto-thaw"); + else log_write(LOG_MAIN, "Unfrozen by auto-thaw"); } /* We get here if any of the rules for unfreezing have triggered. */ @@ -7059,7 +7059,7 @@ if (message_logs) if ((fd = open_msglog_file(fname, SPOOL_MODE, &error)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't %s message log %s: %s", error, + log_write(LOG_MAIN|LOG_PANIC, "Couldn't %s message log %s: %s", error, fname, strerror(errno)); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } @@ -7068,7 +7068,7 @@ if (message_logs) if (!(message_log = fdopen(fd, "a"))) { - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s", fname, strerror(errno)); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } @@ -7081,7 +7081,7 @@ the addresses. */ if (give_up) { struct passwd *pw = getpwuid(real_uid); - log_write(0, LOG_MAIN, "cancelled by %s", + log_write(LOG_MAIN, "cancelled by %s", pw ? US pw->pw_name : string_sprintf("uid %ld", (long int)real_uid)); process_recipients = RECIP_FAIL; } @@ -7153,7 +7153,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) { (void)close(deliver_datafile); deliver_datafile = -1; - log_write(0, LOG_MAIN|LOG_PANIC, "Error in system filter: %s", + log_write(LOG_MAIN|LOG_PANIC, "Error in system filter: %s", string_printing(filter_message)); return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */ } @@ -7177,7 +7177,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) { process_recipients = RECIP_DEFER; deliver_msglog("Delivery deferred by system filter\n"); - log_write(0, LOG_MAIN, "Delivery deferred by system filter"); + log_write(LOG_MAIN, "Delivery deferred by system filter"); } /* The filter can request that a message be frozen, but this does not @@ -7230,7 +7230,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) } } - log_write(0, LOG_MAIN, "cancelled by system filter%s%.*s", colon, loglen, + log_write(LOG_MAIN, "cancelled by system filter%s%.*s", colon, loglen, logmsg); } @@ -7241,9 +7241,9 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) { process_recipients = RECIP_IGNORE; if (addr_new) - log_write(0, LOG_MAIN, "original recipients ignored (system filter)"); + log_write(LOG_MAIN, "original recipients ignored (system filter)"); else - log_write(0, LOG_MAIN, "=> discarded (system filter)"); + log_write(LOG_MAIN, "=> discarded (system filter)"); } /* If any new addresses were created by the filter, fake up a "parent" @@ -7274,7 +7274,7 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT) while (p) { if (parent->child_count == USHRT_MAX) - log_write_die(0, LOG_MAIN, "system filter generated more " + log_write_die(LOG_MAIN, "system filter generated more " "than %d delivery addresses", USHRT_MAX); parent->child_count++; p->parent = parent; @@ -7518,7 +7518,7 @@ if (process_recipients != RECIP_IGNORE) int start, end, dom; if (!parse_extract_address(addr, &errmsg, &start, &end, &dom, TRUE)) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to parse address '%.100s': %s\n", addr, errmsg); else { @@ -8292,7 +8292,7 @@ if ( mua_wrapper need to do the failure logging. */ if (addr != addr_failed) - log_write(0, LOG_MAIN, "** %s routing yielded a %s delivery", + log_write(LOG_MAIN, "** %s routing yielded a %s delivery", addr->address, which); /* Always write an error to the caller */ @@ -8371,7 +8371,7 @@ if (addr_local || addr_remote) if ((journal_fd = Uopen(fname, EXIM_CLOEXEC | O_WRONLY|O_APPEND|O_CREAT|O_EXCL, SPOOL_MODE)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open journal file %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Couldn't open journal file %s: %s", fname, strerror(errno)); return DELIVER_NOT_ATTEMPTED; } @@ -8388,10 +8388,10 @@ if (addr_local || addr_remote) ) { int ret = Uunlink(fname); - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s", fname, strerror(errno)); if(ret && errno != ENOENT) - log_write_die(0, LOG_MAIN, "failed to unlink %s: %s", + log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); return DELIVER_NOT_ATTEMPTED; } @@ -8461,7 +8461,7 @@ if (addr_remote) if (remote_sort_domains) sort_remote_deliveries(); if (!do_remote_deliveries(FALSE)) { - log_write(0, LOG_MAIN, "** mua_wrapper is set but recipients cannot all " + log_write(LOG_MAIN, "** mua_wrapper is set but recipients cannot all " "be delivered in one transaction"); fprintf(stderr, "delivery to smarthost failed (configuration problem)\n"); @@ -8524,7 +8524,7 @@ if (mua_wrapper) address_item * nextaddr; for (address_item * addr = addr_defer; addr; addr = nextaddr) { - log_write(0, LOG_MAIN, "** %s mua_wrapper forced failure for deferred " + log_write(LOG_MAIN, "** %s mua_wrapper forced failure for deferred " "delivery", addr->address); nextaddr = addr->next; addr->next = addr_failed; @@ -8623,7 +8623,7 @@ if (addr_failed) { if ( !testflag(addr_failed, af_retry_timedout) && !addr_failed->prop.ignore_error) - log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message " + log_write(LOG_MAIN|LOG_PANIC, "internal error: bounce message " "failure is neither frozen nor ignored (it's been ignored)"); addr_failed->prop.ignore_error = TRUE; @@ -8645,7 +8645,7 @@ if (addr_failed) #ifndef DISABLE_EVENT msg_event_raise(US"msg:fail:delivery", addr); #endif - log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s", + log_write(LOG_MAIN, "%s%s%s%s: error ignored%s", addr->address, !addr->parent ? US"" : US" <", !addr->parent ? US"" : addr->parent->address, @@ -8705,12 +8705,12 @@ if (!addr_defer) rc = Urename(fname, moname); } if (rc < 0) - log_write_die(0, LOG_MAIN, "failed to move %s to the " + log_write_die(LOG_MAIN, "failed to move %s to the " "msglog.OLD directory", fname); } else if (Uunlink(fname) < 0) - log_write_die(0, LOG_MAIN, "failed to unlink %s: %s", + log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); } @@ -8718,19 +8718,19 @@ if (!addr_defer) fname = spool_fname(US"input", message_subdir, id, US"-D"); if (Uunlink(fname) < 0) - log_write_die(0, LOG_MAIN, "failed to unlink %s: %s", + log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); fname = spool_fname(US"input", message_subdir, id, US"-H"); if (Uunlink(fname) < 0) - log_write_die(0, LOG_MAIN, "failed to unlink %s: %s", + log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); /* Log the end of this message, with queue time if requested. */ if (LOGGING(queue_time_overall)) - log_write(0, LOG_MAIN, "Completed QT=%s", string_timesince(&received_time)); + log_write(LOG_MAIN, "Completed QT=%s", string_timesince(&received_time)); else - log_write(0, LOG_MAIN, "Completed"); + log_write(LOG_MAIN, "Completed"); /* Unset deliver_freeze so that we won't try to move the spool files further down */ f.deliver_freeze = FALSE; @@ -8964,7 +8964,7 @@ else if (addr_defer != (address_item *)(+1)) of a race problem. */ deliver_msglog("*** Frozen%s\n", frozen_info); - log_write(0, LOG_MAIN, "Frozen%s", frozen_info); + log_write(LOG_MAIN, "Frozen%s", frozen_info); } /* If there have been any updates to the non-recipients list, or other things @@ -9006,7 +9006,7 @@ if (remove_journal) uschar * fname = spool_fname(US"input", message_subdir, id, US"-J"); if (Uunlink(fname) < 0 && errno != ENOENT) - log_write_die(0, LOG_MAIN, "failed to unlink %s: %s", fname, + log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); /* Move the message off the spool if requested */ @@ -9153,8 +9153,7 @@ return; /* compiler quietening; control does not reach here. */ #ifndef DISABLE_TLS fail: - log_write(0, - LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), + log_write(LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE), "delivery re-exec %s failed: %s", where, strerror(errno)); /* Get here if exec_type == CEE_EXEC_EXIT. diff --git a/src/src/directory.c b/src/src/directory.c index 45e18615f..054b125b4 100644 --- a/src/src/directory.c +++ b/src/src/directory.c @@ -88,7 +88,7 @@ while (c && *p) return TRUE; bad: - if (panic) log_write_die(0, LOG_MAIN, + if (panic) log_write_die(LOG_MAIN, "Failed to %s directory %q: %s\n", p, path, exim_errstr(errno)); return FALSE; } diff --git a/src/src/dns.c b/src/src/dns.c index ce152535a..6b233f85b 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -73,7 +73,7 @@ if (stat(CS utilname, &statbuf) >= 0) pid = child_open(argv, NULL, 0000, &infd, &outfd, FALSE, US"fakens-search"); if (pid < 0) - log_write_die(0, LOG_MAIN, "failed to run fakens: %s", + log_write_die(LOG_MAIN, "failed to run fakens: %s", strerror(errno)); len = 0; @@ -93,7 +93,7 @@ if (stat(CS utilname, &statbuf) >= 0) len += rc; if (rc < 0) - log_write_die(0, LOG_MAIN, "read from fakens failed: %s", + log_write_die(LOG_MAIN, "read from fakens failed: %s", strerror(errno)); switch(child_close(pid, 0)) @@ -949,7 +949,7 @@ if (dnsa->answerlen < 0) switch (h_errno) { if (try_again_recursion) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "dns_again_means_nonexist recursion seen for %s" " (assuming nonexist)", name); return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), @@ -1148,7 +1148,7 @@ for (int i = 0; i <= dns_cname_loops; i++) /* Control reaches here after 10 times round the CNAME loop. Something isn't right... */ -log_write(0, LOG_MAIN, "CNAME loop for %s encountered", orig_name); +log_write(LOG_MAIN, "CNAME loop for %s encountered", orig_name); errstr = US"cname_loop"; not_good: diff --git a/src/src/dnsbl.c b/src/src/dnsbl.c index 297f1ba07..7a885927d 100644 --- a/src/src/dnsbl.c +++ b/src/src/dnsbl.c @@ -82,7 +82,7 @@ int qlen, yield; query = string_sprintf("%s.%s", prepend, domain); if ((qlen = Ustrlen(query)) >= 256) { - log_write(0, LOG_MAIN|LOG_PANIC, "dnslist query is too long " + log_write(LOG_MAIN|LOG_PANIC, "dnslist query is too long " "(ignored): %s...", query); yield = FAIL; goto out; @@ -242,7 +242,7 @@ if (cb->rc == DNS_SUCCEED) if (host_aton(da->address, address) == 1) if ((address[0] & 0xff000000) != 0x7f000000) /* 127.0.0.0/8 */ - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DNS list lookup for %s at %s returned %s;" " not in 127.0/8 and discarded", keydomain, domain, da->address); @@ -325,7 +325,7 @@ if (cb->rc == DNS_SUCCEED) ) ok = TRUE; else - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DNS list lookup for %s at %s returned %s;" " not in 127.0/8 and discarded", keydomain, domain, da->address); @@ -383,7 +383,7 @@ if (cb->rc == DNS_SUCCEED) if (cb->rc != DNS_NOMATCH && cb->rc != DNS_NODATA) { - log_write(L_dnslist_defer, LOG_MAIN, + if (LOGGING(dnslist_defer)) log_write(LOG_MAIN, "DNS list lookup defer (probably timeout) for %s: %s", query, defer_return == OK ? US"assumed in list" : defer_return == FAIL ? US"assumed not in list" : @@ -515,7 +515,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) else if (strcmpic(domain, US"+exclude_unknown") == 0) defer_return = FAIL; else if (strcmpic(domain, US"+defer_unknown") == 0) defer_return = DEFER; else - log_write(0, LOG_MAIN|LOG_PANIC, "unknown item in dnslist (ignored): %s", + log_write(LOG_MAIN|LOG_PANIC, "unknown item in dnslist (ignored): %s", domain); continue; } @@ -574,7 +574,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) for (const uschar * t = domain; *t; t++) if (!isalnum(*t) && *t != '-' && *t != '.' && *t != '_') { - log_write(0, LOG_MAIN, "dnslists domain %q contains " + log_write(LOG_MAIN, "dnslists domain %q contains " "strange characters - is this right?", domain); break; } @@ -584,7 +584,7 @@ while ((domain = string_nextinlist(&list, &sep, NULL, 0))) if (domain_txt != domain) for (const uschar * t = domain_txt; *t; t++) if (!isalnum(*t) && *t != '-' && *t != '.' && *t != '_') { - log_write(0, LOG_MAIN, "dnslists domain %q contains " + log_write(LOG_MAIN, "dnslists domain %q contains " "strange characters - is this right?", domain_txt); break; } diff --git a/src/src/drtables.c b/src/src/drtables.c index 3bb55ea91..8ba2d62af 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -87,7 +87,7 @@ Ustrcpy(new->name, li->name); if (tree_insertnode(&lookups_tree, new)) li->acq_num = lookup_list_count++; else - log_write(0, LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name); + log_write(LOG_MAIN|LOG_PANIC, "Duplicate lookup name '%s'", li->name); } @@ -172,14 +172,14 @@ info = (lookup_module_info *) dlsym(dl, "_lookup_module_info"); if ((errormsg = dlerror())) { EARLY_DEBUG(any, "%s does not appear to be a lookup module (%s)\n", name, errormsg); - log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)", name, errormsg); + log_write(LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)", name, errormsg); dlclose(dl); return FALSE; } if (info->magic != LOOKUP_MODULE_INFO_MAGIC) { EARLY_DEBUG(any, "Lookup module %s is not compatible with this version of Exim\n", name); - log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim", name); + log_write(LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim", name); dlclose(dl); return FALSE; } @@ -342,7 +342,7 @@ if ((errormsg = dlerror())) { EARLY_DEBUG(any, "%s does not appear to be a '%s' module (%s)\n", name, name, errormsg); - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s does not contain the expected module info symbol (%s)", name, errormsg); dlclose(dl); return NULL; @@ -350,7 +350,7 @@ if ((errormsg = dlerror())) if (mi->dyn_magic != MISC_MODULE_MAGIC) { EARLY_DEBUG(any, "Module %s is not compatible with this version of Exim\n", name); - log_write(0, LOG_MAIN|LOG_PANIC, "Module %s is not compatible with this version of Exim", name); + log_write(LOG_MAIN|LOG_PANIC, "Module %s is not compatible with this version of Exim", name); dlclose(dl); return FALSE; } @@ -490,7 +490,7 @@ DEBUG(lookup) debug_printf_indent("Total %d built-in lookups\n", lookup_list_cou if (!(dd = open_module_dir())) { EARLY_DEBUG(lookup, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR); } else @@ -512,7 +512,7 @@ else else { EARLY_DEBUG(any, "%s\n", errstr); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr); + log_write(LOG_MAIN|LOG_PANIC, "%s", errstr); } } } diff --git a/src/src/exim.c b/src/src/exim.c index 164b926a9..d06e3eda8 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -51,7 +51,7 @@ static void * function_store_malloc(PCRE2_SIZE size, void * tag) { if (size > INT_MAX) - log_write_die(0, LOG_MAIN, "excessive memory alloc request"); + log_write_die(LOG_MAIN, "excessive memory alloc request"); return store_malloc((int)size); } @@ -67,7 +67,7 @@ static void * function_store_get(PCRE2_SIZE size, void * tag) { if (size > INT_MAX) - log_write_die(0, LOG_MAIN, "excessive memory alloc request"); + log_write_die(LOG_MAIN, "excessive memory alloc request"); return store_get((int)size, GET_UNTAINTED); /* loses track of taint */ } @@ -262,8 +262,8 @@ void * buf[STACKDUMP_MAX]; char ** ss; int nptrs = backtrace(buf, STACKDUMP_MAX); -log_write(0, LOG_MAIN|LOG_PANIC, "backtrace"); -log_write(0, LOG_MAIN|LOG_PANIC, "---"); +log_write(LOG_MAIN|LOG_PANIC, "backtrace"); +log_write(LOG_MAIN|LOG_PANIC, "---"); /* This function is officially not callable from a signal handler, as it calls malloc() for the returned data. However, it seems to work - and we @@ -273,12 +273,12 @@ A alternative might be backtrace_symbols_fd(). */ if ((ss = backtrace_symbols(buf, nptrs))) { for (int i = 0; i < nptrs; i++) - log_write(0, LOG_MAIN|LOG_PANIC, "\t%s", ss[i]); + log_write(LOG_MAIN|LOG_PANIC, "\t%s", ss[i]); free(ss); } else - log_write(0, LOG_MAIN|LOG_PANIC, "backtrace_symbols: %s", strerror(errno)); -log_write(0, LOG_MAIN|LOG_PANIC, "---"); + log_write(LOG_MAIN|LOG_PANIC, "backtrace_symbols: %s", strerror(errno)); +log_write(LOG_MAIN|LOG_PANIC, "---"); #endif } #undef STACKDUMP_MAX @@ -290,25 +290,25 @@ segv_handler(int sig, siginfo_t * info, void * uctx) { if (!panic_coredump) { - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr); + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr); # if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR) switch (info->si_code) { - case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break; - case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break; - case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break; - case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break; + case SEGV_MAPERR: log_write(LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break; + case SEGV_ACCERR: log_write(LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break; + case SEGV_BNDERR: log_write(LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break; + case SEGV_PKUERR: log_write(LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break; } # endif } if (panic_coredump) - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (deliberate trap)"); + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (deliberate trap)"); else if (US info->si_addr < US 4096) - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)"); + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)"); else - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)"); + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)"); if (process_info_len > 0) - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%s: %.*s)", + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (%s: %.*s)", process_purpose, process_info_len, process_info); stackdump(); signal(SIGSEGV, SIG_DFL); @@ -318,9 +318,9 @@ kill(getpid(), sig); #else segv_handler(int sig) { -log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)"); +log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)"); if (process_info_len > 0) - log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info); + log_write(LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info); stackdump(); signal(SIGSEGV, SIG_DFL); kill(getpid(), sig); @@ -424,7 +424,7 @@ if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec <= 0) (void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */ (void)sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask); /* Block SIGALRM */ if (setitimer(ITIMER_REAL, itval, NULL) < 0) /* Start timer */ - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "setitimer() failed: %s", strerror(errno)); (void)sigfillset(&sigmask); /* All signals */ (void)sigdelset(&sigmask, SIGALRM); /* Remove SIGALRM */ @@ -672,7 +672,7 @@ for (int i = 0; i <= 2; i++) if (fstat(i, &statbuf) < 0 && errno == EBADF) { if (devnull < 0) devnull = open("/dev/null", O_RDWR); - if (devnull < 0) log_write_die(0, LOG_MAIN, "%s", + if (devnull < 0) log_write_die(LOG_MAIN, "%s", string_open_failed("/dev/null", NULL)); if (devnull != i) (void)dup2(devnull, i); } @@ -787,16 +787,16 @@ if (euid == root_uid || euid != uid || egid != gid || igflag) { struct passwd * pw = getpwuid(uid); if (!pw) - log_write_die(0, LOG_MAIN, "cannot run initgroups(): " + log_write_die(LOG_MAIN, "cannot run initgroups(): " "no passwd entry for uid=%ld", (long int)uid); if (initgroups(pw->pw_name, gid) != 0) - log_write_die(0,LOG_MAIN,"initgroups failed for uid=%ld: %s", + log_write_die(LOG_MAIN,"initgroups failed for uid=%ld: %s", (long int)uid, strerror(errno)); } if (setgid(gid) < 0 || setuid(uid) < 0) - log_write_die(0, LOG_MAIN, "unable to set gid=%ld or uid=%ld " + log_write_die(LOG_MAIN, "unable to set gid=%ld or uid=%ld " "(euid=%ld): %s", (long int)gid, (long int)uid, (long int)euid, msg); } @@ -925,7 +925,7 @@ exim_chown_failure(int fd, const uschar *name, uid_t owner, gid_t group) { int saved_errno = errno; /* from the preceeding chown call */ #if 1 -log_write(0, LOG_MAIN|LOG_PANIC, +log_write(LOG_MAIN|LOG_PANIC, __FILE__ ":%d: chown(%s, %d:%d) failed (%s)." " Please contact the authors and refer to https://bugs.exim.org/show_bug.cgi?id=2391", __LINE__, name?name:US"", owner, group, strerror(errno)); @@ -940,9 +940,9 @@ struct stat buf; if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf))) { if (buf.st_uid == owner && buf.st_gid == group) return 0; - log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); + log_write(LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name); } -else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); +else log_write(LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno)); #endif errno = saved_errno; @@ -2239,7 +2239,7 @@ unprivileged = (real_uid != root_uid && original_euid != root_uid); /* Allocate an empty bitmask for debug channels */ -debug_modify_channel(US""); + debug_modify_channel(US""); /* Scan the program's arguments. Some can be dealt with right away; others are simply recorded for checking and handling afterwards. Do a high-level switch @@ -4028,7 +4028,7 @@ else #ifdef RLIMIT_NOFILE if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno)); rlp.rlim_cur = rlp.rlim_max = 0; } @@ -4044,7 +4044,7 @@ else { rlp.rlim_cur = rlp.rlim_max = 256; if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NOFILE) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno)); } } @@ -4053,7 +4053,7 @@ else #ifdef RLIMIT_NPROC if (getrlimit(RLIMIT_NPROC, &rlp) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s", strerror(errno)); rlp.rlim_cur = rlp.rlim_max = 0; } @@ -4068,7 +4068,7 @@ else rlp.rlim_cur = rlp.rlim_max = 1000; # endif if (setrlimit(RLIMIT_NPROC, &rlp) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s", strerror(errno)); } #endif @@ -4249,7 +4249,7 @@ defined) */ /* Now in directory "/" */ if (cleanup_environment() == FALSE) - log_write_die(0, LOG_PANIC_DIE, "Can't cleanup environment"); + log_write_die(LOG_PANIC_DIE, "Can't cleanup environment"); /* If an action on specific messages is requested, or if a daemon or queue @@ -4348,28 +4348,24 @@ log_write() from here will cause the ultimate panic collapse if the complete file name exceeds the buffer length. */ if (Ustrlen(log_file_path) > 200) - log_write_die(0, LOG_MAIN, - "log_file_path is longer than 200 chars: aborting"); + log_write_die(LOG_MAIN, "log_file_path is longer than 200 chars: aborting"); if (Ustrlen(pid_file_path) > 200) - log_write_die(0, LOG_MAIN, - "pid_file_path is longer than 200 chars: aborting"); + log_write_die(LOG_MAIN, "pid_file_path is longer than 200 chars: aborting"); if (Ustrlen(spool_directory) > 200) - log_write_die(0, LOG_MAIN, - "spool_directory is longer than 200 chars: aborting"); + log_write_die(LOG_MAIN, "spool_directory is longer than 200 chars: aborting"); /* Length check on the process name given to syslog for its TAG field, which is only permitted to be 32 characters or less. See RFC 3164. */ if (Ustrlen(syslog_processname) > 32) - log_write_die(0, LOG_MAIN, - "syslog_processname is longer than 32 chars: aborting"); + log_write_die(LOG_MAIN, "syslog_processname is longer than 32 chars: aborting"); if (log_oneline) if (f.admin_user) { - log_write(0, LOG_MAIN, "%s", log_oneline); + log_write(LOG_MAIN, "%s", log_oneline); return EXIT_SUCCESS; } else @@ -4464,7 +4460,7 @@ if ( removed_privilege if (deliver_drop_privilege) f.really_exim = TRUE; /* let logging work normally */ else - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "exim user lost privilege for using %s option", f.trusted_config? "-D" : "-C"); @@ -4511,7 +4507,7 @@ if ( (IS_DEBUG(any) || LOGGING(arguments)) if (p + len + 8 >= big_buffer + big_buffer_size) { Ustrcpy(p, US" ..."); - log_write(0, LOG_MAIN, "%s", big_buffer); + log_write(LOG_MAIN, "%s", big_buffer); Ustrcpy(big_buffer, US"..."); p = big_buffer + 3; } @@ -4528,7 +4524,7 @@ if ( (IS_DEBUG(any) || LOGGING(arguments)) } if (LOGGING(arguments)) - log_write(0, LOG_MAIN, "%s", big_buffer); + log_write(LOG_MAIN, "%s", big_buffer); else debug_printf("%s\n", big_buffer); } @@ -4687,7 +4683,7 @@ if (smtp_input) if (real_uid == root_uid || real_uid == exim_uid || interface_port < 1024) { - if (mua_wrapper) log_write_die(0, LOG_MAIN, "Input from " + if (mua_wrapper) log_write_die(LOG_MAIN, "Input from " "inetd is not supported when mua_wrapper is set"); f.is_inetd = TRUE; sender_host_address = host_ntoa(-1, (struct sockaddr *)(&inetd_sock), @@ -5209,7 +5205,7 @@ if (!originator_login || f.running_in_test_harness) if (!originator_name) originator_name = US""; } if (!originator_login) - log_write_die(0, LOG_MAIN, "Failed to get user name for uid %d", + log_write_die(LOG_MAIN, "Failed to get user name for uid %d", (int)real_uid); } @@ -5238,7 +5234,7 @@ if (f.daemon_listen || f.inetd_wait_mode || is_multiple_qrun()) if (mua_wrapper) { fprintf(stderr, "Daemon cannot be run when mua_wrapper is set\n"); - log_write_die(0, LOG_MAIN, "Daemon cannot be run when " + log_write_die(LOG_MAIN, "Daemon cannot be run when " "mua_wrapper is set"); } @@ -5514,7 +5510,7 @@ if (raw_active_hostname) if (!nah) { if (!f.expand_string_forcedfail) - log_write_die(0, LOG_MAIN, "failed to expand %q " + log_write_die(LOG_MAIN, "failed to expand %q " "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); } @@ -5571,7 +5567,8 @@ if (host_checking) if (verify_check_host(&hosts_connection_nolog) == OK) logging_modify_channels(US"-smtp_connection -smtp_no_mail"); - log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); + if (LOGGING(smtp_connection)) + log_write(LOG_MAIN, "%s", smtp_get_connection_info()); /* NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails, because a log line has already been written for all its failure exists @@ -5763,7 +5760,8 @@ if (smtp_input) memset(sender_host_cache, 0, sizeof(sender_host_cache)); if (verify_check_host(&hosts_connection_nolog) == OK) logging_modify_channels(US"-smtp_connection -smtp_no_mail"); - log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info()); + if (LOGGING(smtp_connection)) + log_write(LOG_MAIN, "%s", smtp_get_connection_info()); if (!smtp_start_session()) exim_exit(EXIT_SUCCESS); @@ -5778,10 +5776,10 @@ else thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); if (expand_string_message) if (thismessage_size_limit == -1) - log_write_die(0, LOG_MAIN, "failed to expand " + log_write_die(LOG_MAIN, "failed to expand " "message_size_limit: %s", expand_string_message); else - log_write_die(0, LOG_MAIN, "invalid value for " + log_write_die(LOG_MAIN, "invalid value for " "message_size_limit: %s", expand_string_message); setvbuf(stdin, NULL, _IONBF, 0); @@ -6169,19 +6167,17 @@ for (BOOL more = TRUE; more; ) if (local_queue_only) { cancel_cutthrough_connection(TRUE, US"no delivery; queueing"); - switch(queue_only_reason) + if (LOGGING(delay_delivery)) switch(queue_only_reason) { case 2: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: more than %d messages " - "received in one connection", smtp_accept_queue_per_connection); + log_write(LOG_MAIN, "no immediate delivery: more than %d messages " + "received in one connection", smtp_accept_queue_per_connection); break; case 3: - log_write(L_delay_delivery, - LOG_MAIN, "no immediate delivery: load average %.2f", + log_write(LOG_MAIN, "no immediate delivery: load average %.2f", (double)load_average/1000.0); - break; + break; } } @@ -6227,7 +6223,7 @@ for (BOOL more = TRUE; more; ) if (pid < 0) { cancel_cutthrough_connection(TRUE, US"delivery fork failed"); - log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery " + log_write(LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery " "process: %s", strerror(errno)); } else @@ -6242,7 +6238,7 @@ for (BOOL more = TRUE; more; ) int status; while (wait(&status) != pid); if ((status & 0x00ff) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "process " PID_T_FMT " crashed with signal %d while delivering %s", pid, status & 0x00ff, message_id); if (mua_wrapper && (status & 0xffff) != 0) diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index ef5953700..07350b25f 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -69,7 +69,7 @@ string_format_trc(uschar * buf, int len, const uschar * func, unsigned line, const char * fmt, ...) { return FALSE; } void -log_write(bitmask_word_t selector, int flags, const char *format, ...) +log_write(int flags, const char *format, ...) { } const uschar * parse_find_address_end_gen(const uschar * s, BOOL b) {return NULL; } diff --git a/src/src/exim_dbutil.c b/src/src/exim_dbutil.c index cb7fb75aa..d3ae57f34 100644 --- a/src/src/exim_dbutil.c +++ b/src/src/exim_dbutil.c @@ -188,7 +188,6 @@ from modules such as store.c when things go drastically wrong (e.g. malloc() failing). In normal use they won't get obeyed. Arguments: - selector not relevant when running a utility flags not relevant when running a utility format a printf() format ... arguments for format @@ -197,7 +196,7 @@ Returns: nothing */ void -log_write(bitmask_word_t selector, int flags, const char *format, ...) +log_write(int flags, const char *format, ...) { va_list ap; va_start(ap, format); @@ -207,7 +206,7 @@ va_end(ap); } void -log_write_die(bitmask_word_t selector, int flags, const char *format, ...) +log_write_die(int flags, const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/src/src/expand.c b/src/src/expand.c index 8da904d59..0c6366bac 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1005,7 +1005,7 @@ const uschar * ss = expand_string(condition); if (!ss) { if (!f.expand_string_forcedfail && !f.search_find_defer) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand condition %q " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand condition %q " "for %s %s: %s", condition, m1, m2, expand_string_message); return FALSE; } @@ -2021,7 +2021,7 @@ switch (vp->type) if (!(s = *((uschar **)(val)))) return US""; if (!(domain = Ustrrchr(s, '@'))) return s; if (domain - s > sizeof(var_buffer) - 1) - log_write_die(0, LOG_MAIN, "local part longer than " SIZE_T_FMT + log_write_die(LOG_MAIN, "local part longer than " SIZE_T_FMT " in string expansion", sizeof(var_buffer)); return string_copyn(s, domain - s); @@ -2063,7 +2063,7 @@ switch (vp->type) } } if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0) - log_write_die(0, LOG_MAIN, "deliver_datafile lseek: %s", + log_write_die(LOG_MAIN, "deliver_datafile lseek: %s", strerror(errno)); if ((len = read(deliver_datafile, body, len)) > 0) { @@ -2171,7 +2171,7 @@ switch (vp->type) table_count = mi->variables_count; goto sublist; } - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to find %s module for %s: %s", US val, name, errstr); return US""; } @@ -2194,7 +2194,7 @@ switch (vp->type) table_count = li->variables_count; goto sublist; } - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to find %s module for %s%s%s", US val, name, errstr ? ": " : "", errstr); return US""; @@ -4788,7 +4788,7 @@ if (is_tainted(s)) { expand_string_message = string_sprintf("attempt to expand tainted string '%s'", s); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + log_write(LOG_MAIN|LOG_PANIC, "%s", expand_string_message); goto EXPAND_FAILED; } @@ -6044,7 +6044,7 @@ while (*s) /* known to be untainted */ expand_string_message = string_sprintf("attempt to use tainted string '%s' for %s", sub[i], name); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + log_write(LOG_MAIN|LOG_PANIC, "%s", expand_string_message); goto EXPAND_FAILED; } val[i] = (int)Ustrtol(sub[i], &ret, 10); @@ -7174,7 +7174,7 @@ while (*s) /* known to be untainted */ { expand_string_message = string_sprintf("dlopen %q failed: %s", argv[0], dlerror()); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + log_write(LOG_MAIN|LOG_PANIC, "%s", expand_string_message); goto EXPAND_FAILED; } t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), argv[0]); @@ -7190,7 +7190,7 @@ while (*s) /* known to be untainted */ { expand_string_message = string_sprintf("dlsym %q in %q failed: " "%s", argv[1], argv[0], dlerror()); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message); + log_write(LOG_MAIN|LOG_PANIC, "%s", expand_string_message); goto EXPAND_FAILED; } @@ -7211,7 +7211,7 @@ while (*s) /* known to be untainted */ if (status == FAIL_FORCED) f.expand_string_forcedfail = TRUE; else if (status != FAIL) - log_write(0, LOG_MAIN|LOG_PANIC, "dlfunc{%s}{%s} failed (%d): %s", + log_write(LOG_MAIN|LOG_PANIC, "dlfunc{%s}{%s} failed (%d): %s", argv[0], argv[1], status, expand_string_message); goto EXPAND_FAILED; } @@ -8993,7 +8993,7 @@ int fd, off = 0, len; if ((fd = exim_open2(CS filename, O_RDONLY)) < 0) { - log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file '%s' for reading: %s", + log_write(LOG_MAIN | LOG_PANIC, "unable to open file '%s' for reading: %s", filename, strerror(errno)); return NULL; } @@ -9003,7 +9003,7 @@ do if ((len = read(fd, big_buffer + off, big_buffer_size - 2 - off)) < 0) { (void) close(fd); - log_write(0, LOG_MAIN|LOG_PANIC, "unable to read file: %s", filename); + log_write(LOG_MAIN|LOG_PANIC, "unable to read file: %s", filename); return NULL; } off += len; @@ -9078,7 +9078,7 @@ tree_walk(tree_unusable, (twalk_compat) assert_variable_notin, &e); check_deliver_addrs_not_freed(assert_variable_notin, &e); if (e.var_name) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "live variable '%s' destroyed by reset_store at %s:%d\n- value '%.64s'", e.var_name, filename, linenumber, e.var_data); } diff --git a/src/src/functions.h b/src/src/functions.h index 97170ac13..062891e72 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -309,7 +309,7 @@ extern const uschar *local_part_quote(const uschar *); extern void log_close_all(void); extern int log_open_as_exim(const uschar * const); extern gstring *log_portnum(gstring *, int); -extern void log_write_die(bitmask_word_t, int, const char * format, ...) +extern void log_write_die(int, const char * format, ...) PRINTF_FUNCTION(3,4) NORETURN; extern void logging_modify_channels(const uschar *); extern void logging_set_defaults(void); @@ -643,7 +643,7 @@ extern int strncmpic(const uschar *, const uschar *, int); extern uschar *strstric(const uschar *, const uschar *, BOOL); extern const uschar *strstric_c(const uschar *, const uschar *, BOOL); -extern int synprot_error(int, int, uschar *, uschar *); +extern int synprot_error(BOOL, int, uschar *, uschar *); extern int test_harness_fudged_queue_time(int); extern void tcp_init(void); @@ -1344,7 +1344,7 @@ static inline int exim_open2(const char * pathname, int flags) { if (!is_tainted(pathname)) return open(pathname, flags); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +log_write(LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); errno = EACCES; return -1; } @@ -1352,7 +1352,7 @@ static inline int exim_open(const char *pathname, int flags, mode_t mode) { if (!is_tainted(pathname)) return open(pathname, flags, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +log_write(LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); errno = EACCES; return -1; } @@ -1361,7 +1361,7 @@ static inline int exim_openat(int dirfd, const char * pathname, int flags) { if (!is_tainted(pathname)) return openat(dirfd, pathname, flags); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +log_write(LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); errno = EACCES; return -1; } @@ -1369,7 +1369,7 @@ static inline int exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode) { if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +log_write(LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); errno = EACCES; return -1; } @@ -1379,7 +1379,7 @@ static inline FILE * exim_fopen(const char * pathname, const char * mode) { if (!is_tainted(pathname)) return fopen(pathname, mode); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); +log_write(LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname); errno = EACCES; return NULL; } @@ -1388,7 +1388,7 @@ static inline DIR * exim_opendir(const uschar * name) { if (!is_tainted(name)) return opendir(CCS name); -log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name); +log_write(LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name); errno = EACCES; return NULL; } diff --git a/src/src/globals.c b/src/src/globals.c index 87424cadf..cf121c6f0 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -959,35 +959,6 @@ uschar *log_file_path = US LOG_FILE_PATH const uschar * const log_notall_names[] = { NULL }; -/* Table for selectors for log_write() calls. -It is used for translating Li_* values, using the position in this table, -to Lt_* values and name strings. -Must have names that are in both enum logwrite_bit and logging_test_bit. */ - -#define BIT_TABLE(chan) {.name = US #chan, .logchan_bit = Lt_##chan } - -bit_table logwrite_options[] = { - BIT_TABLE(address_rewrite), - BIT_TABLE(all_parents), - BIT_TABLE(connection_reject), - BIT_TABLE(delay_delivery), - BIT_TABLE(dnslist_defer), - BIT_TABLE(etrn), - BIT_TABLE(host_lookup_failed), - BIT_TABLE(lost_incoming_connection), - BIT_TABLE(queue_run), - BIT_TABLE(retry_defer), - BIT_TABLE(size_reject), - BIT_TABLE(skip_delivery), - BIT_TABLE(smtp_connection), - BIT_TABLE(smtp_incomplete_transaction), - BIT_TABLE(smtp_protocol_error), - BIT_TABLE(smtp_syntax_error), -}; -#undef BIT_TABLE -int logwrite_options_count = nelem(logwrite_options); - - /* List of names for logging channels. Must be in alphabetical order. Must match enum logging_test_bit (macros.h). This is a superset of logwrite_options[]. */ diff --git a/src/src/globals.h b/src/src/globals.h index a12d0de87..9d581ae67 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -684,8 +684,6 @@ extern uschar *log_selector_string; /* As supplied in the config */ extern FILE *log_stderr; /* Copy of stderr for log use, or NULL */ extern BOOL log_timezone; /* TRUE to include the timezone in log lines */ extern uschar *login_sender_address; /* The actual sender address */ -extern bit_table logwrite_options[]; /* Options usable for logwrite() */ -extern int logwrite_options_count; /* Size of table */ extern tree_node *lookups_tree; /* Tree of available lookups */ extern unsigned lookup_list_count; /* Number of entries in the list */ extern uschar *lookup_dnssec_authenticated; /* AD status of dns lookup */ diff --git a/src/src/header.c b/src/src/header.c index 3a513fd2a..e9d83c092 100644 --- a/src/src/header.c +++ b/src/src/header.c @@ -109,7 +109,7 @@ gs.size = HEADER_ADD_BUFFER_SIZE; gs.ptr = 0; if (!string_vformat(&gs, SVFMT_REBUFFER, format, ap)) - log_write_die(0, LOG_MAIN, "string too long in header_add: " + log_write_die(LOG_MAIN, "string too long in header_add: " "%.100Y ...", &gs); if (gs.s != buf) store_release_above(buf); diff --git a/src/src/hintsdb.h b/src/src/hintsdb.h index dbce3dbaa..6bea085ac 100644 --- a/src/src/hintsdb.h +++ b/src/src/hintsdb.h @@ -119,7 +119,7 @@ DEBUG(hints_lookup) : "??"); if (is_tainted(name) || is_tainted(dirname)) { - log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); + log_write(LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); dbp = NULL; } else @@ -143,7 +143,7 @@ DEBUG(hints_lookup) : "??"); if (is_tainted(name) || is_tainted(dirname)) { - log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); + log_write(LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); dbp = NULL; } else diff --git a/src/src/hintsdb/hints_bdb.h b/src/src/hintsdb/hints_bdb.h index 5a5065302..dd5cd888f 100644 --- a/src/src/hintsdb/hints_bdb.h +++ b/src/src/hintsdb/hints_bdb.h @@ -72,7 +72,7 @@ at DB release 4.3. */ static inline void dbfn_bdb_error_callback(const DB_ENV * dbenv, const char * pfx, const char * msg) { -log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg); +log_write(LOG_MAIN, "Berkeley DB error: %s", msg); } diff --git a/src/src/host.c b/src/src/host.c index 5f8f985d4..c7f8ba961 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -113,7 +113,7 @@ slow_lookup_log milliseconds static void log_long_lookup(const uschar * type, const uschar * data, unsigned long msec) { -log_write(0, LOG_MAIN, "Long %s lookup for '%s': %lu msec", +log_write(LOG_MAIN, "Long %s lookup for '%s': %lu msec", type, data, msec); } @@ -684,7 +684,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0))) int port = host_address_extract_port(s); /* Leaves just the IP address */ if (!(ipv = string_is_ip_address(s, NULL))) - log_write_die(0, LOG_MAIN, "Malformed IP address %q in %s", + log_write_die(LOG_MAIN, "Malformed IP address %q in %s", s, name); /* Skip IPv6 addresses if IPv6 is disabled. */ @@ -960,7 +960,7 @@ if (Ustrchr(address, ':') != NULL) { int len = Ustrcspn(p, ":%"); if (len == 0) nulloffset = ci; - if (ci > 7) log_write_die(0, LOG_MAIN, + if (ci > 7) log_write_die(LOG_MAIN, "Internal error: invalid IPv6 address %q passed to host_aton()", address); else component[ci++] = p; @@ -1459,7 +1459,7 @@ if (Ustrchr(sender_host_address, ':') != NULL) { struct in6_addr addr6; if (inet_pton(AF_INET6, CS sender_host_address, &addr6) != 1) - log_write_die(0, LOG_MAIN, "unable to parse %q as an " + log_write_die(LOG_MAIN, "unable to parse %q as an " "IPv6 address", sender_host_address); #if HAVE_GETIPNODEBYADDR hosts = getipnodebyaddr(CS &addr6, sizeof(addr6), AF_INET6, &h_errno); @@ -1470,7 +1470,7 @@ if (Ustrchr(sender_host_address, ':') != NULL) else { if (inet_pton(AF_INET, CS sender_host_address, &addr) != 1) - log_write_die(0, LOG_MAIN, "unable to parse %q as an " + log_write_die(LOG_MAIN, "unable to parse %q as an " "IPv4 address", sender_host_address); #if HAVE_GETIPNODEBYADDR hosts = getipnodebyaddr(CS &addr, sizeof(addr), AF_INET, &h_errno); @@ -1670,7 +1670,7 @@ while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, US rr->data, (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { - log_write(0, LOG_MAIN, "host name alias list truncated for %s", + log_write(LOG_MAIN, "host name alias list truncated for %s", sender_host_address); break; } @@ -1735,9 +1735,9 @@ NB host_lookup_msg must be in permanent store. */ if (!sender_host_name) { - if (host_checking || !f.log_testing_mode) - log_write(L_host_lookup_failed, LOG_MAIN, "no host name found for IP " - "address %s", sender_host_address); + if ((host_checking || !f.log_testing_mode) && LOGGING(host_lookup_failed)) + log_write(LOG_MAIN, "no host name found for IP address %s", + sender_host_address); host_lookup_msg = US" (failed to find host name from IP address)"; host_lookup_failed = TRUE; yield = FAIL; @@ -2112,7 +2112,7 @@ so we pass that back. */ if (!host->address) { - uschar *msg = + uschar * msg = #ifndef STAND_ALONE !message_id[0] && smtp_in_fd >= 0 ? string_sprintf("no IP address found for host %s (during %s)", host->name, @@ -2122,8 +2122,8 @@ if (!host->address) HDEBUG(host_lookup) debug_printf_indent("%s\n", msg); if (temp_error) goto RETURN_AGAIN; - if (host_checking || !f.log_testing_mode) - log_write(L_host_lookup_failed, LOG_MAIN, "%s", msg); + if ((host_checking || !f.log_testing_mode) && LOGGING(host_lookup_failed)) + log_write(LOG_MAIN, "%s", msg); return HOST_FIND_FAILED; } @@ -2619,7 +2619,7 @@ if (whichrrs & HOST_FIND_BY_SRV) if (rc == DNS_SUCCEED && dnssec_require && !dns_is_secure(dnsa)) { - log_write(L_host_lookup_failed, LOG_MAIN, + if (LOGGING(host_lookup_failed)) log_write(LOG_MAIN, "dnssec fail on SRV for %.256s", host->name); rc = DNS_FAIL; } @@ -3249,7 +3249,7 @@ switch (rc) } return OK; } - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DANE error: TLSA lookup for %s not DNSSEC", host->name); /*FALLTRHOUGH*/ diff --git a/src/src/ip.c b/src/src/ip.c index d8772287f..70ec05a39 100644 --- a/src/src/ip.c +++ b/src/src/ip.c @@ -41,7 +41,7 @@ ip_socket(int type, int af) { int sock = socket(af, type, 0); if (sock < 0) - log_write(0, LOG_MAIN, "IPv%c socket creation failed: %s", + log_write(LOG_MAIN, "IPv%c socket creation failed: %s", (af == AF_INET6)? '6':'4', strerror(errno)); return sock; } @@ -77,7 +77,7 @@ ip_addrinfo(const uschar *address, struct sockaddr_in6 *saddr) #ifdef IPV6_USE_INET_PTON if (inet_pton(AF_INET6, CCS address, &saddr->sin6_addr) != 1) - log_write_die(0, LOG_MAIN, "unable to parse %q as an " + log_write_die(LOG_MAIN, "unable to parse %q as an " "IP address", address); saddr->sin6_family = AF_INET6; @@ -90,7 +90,7 @@ ip_addrinfo(const uschar *address, struct sockaddr_in6 *saddr) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; if ((rc = getaddrinfo(CCS address, NULL, &hints, &res)) != 0 || res == NULL) - log_write_die(0, LOG_MAIN, "unable to parse %q as an " + log_write_die(LOG_MAIN, "unable to parse %q as an " "IP address: %s", address, rc == 0 ? "NULL result returned" : gai_strerror(rc)); else @@ -163,7 +163,7 @@ union sockaddr_46 sin; int s_len = ip_addr(&sin, af, address, port); int rc = bind(sock, (struct sockaddr *)&sin, s_len); if (rc < 0) - log_write(0, LOG_MAIN, "bind of [%s]:%d failed", address, port); + log_write(LOG_MAIN, "bind of [%s]:%d failed", address, port); return rc; } @@ -573,7 +573,7 @@ ip_keepalive(int sock, const uschar *address, BOOL torf) int fodder = 1; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, US (&fodder), sizeof(fodder)) != 0) - log_write(0, LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s " + log_write(LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s " "failed: %s", torf? "to":"from", address, strerror(errno)); } diff --git a/src/src/local_scan.h b/src/src/local_scan.h index f3a2e8257..f3ed1addb 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -212,7 +212,7 @@ extern void header_add_at_position(BOOL, uschar *, BOOL, int, const char *, . extern void header_remove(int, const uschar *); extern BOOL header_testname(const header_line *, const uschar *, int, BOOL); extern BOOL header_testname_incomplete(const header_line *, const uschar *, int, BOOL); -extern void log_write(bitmask_word_t, int, const char *format, ...) PRINTF_FUNCTION(3,4); +extern void log_write(int, const char *format, ...) PRINTF_FUNCTION(2,3); extern int lss_b64decode(uschar *, uschar **); extern uschar *lss_b64encode(uschar *, int); extern int lss_match_domain(uschar *, uschar *); diff --git a/src/src/log.c b/src/src/log.c index fb256bee2..959b2b5e5 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -581,7 +581,7 @@ if (!panic_save_buffer) if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE))) memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE); -log_write_die(0, LOG_PANIC_DIE, "Cannot open %s log file %q: %s: " +log_write_die(LOG_PANIC_DIE, "Cannot open %s log file %q: %s: " "euid=%d egid=%d", log_names[type], buffer, strerror(errno), euid, getegid()); /* Never returns */ } @@ -701,7 +701,7 @@ if (!panic_save_buffer) if ((panic_save_buffer = US malloc(LOG_BUFFER_SIZE))) memcpy(panic_save_buffer, log_buffer, LOG_BUFFER_SIZE); -log_write_die(0, LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d " +log_write_die(LOG_PANIC_DIE, "failed to write to %s: length=%d result=%d " "errno=%d (%s)", name, length, rc, save_errno, save_errno == 0 ? "write incomplete" : strerror(save_errno)); /* Never returns */ @@ -824,8 +824,6 @@ Malloc is used directly because the store functions may call log_write(). If a message_id exists, we include it after the timestamp. Arguments: - selector write to main log or LOG_INFO only if this value is zero, or if - its bit is set in log_selector[0] flags each bit indicates some independent action: LOG_SENDER add raw sender to the message LOG_RECIPIENTS add raw recipients list to message @@ -843,11 +841,10 @@ Returns: nothing */ static void -log_vwrite(bitmask_word_t selector, int flags, const char * format, va_list ap) +log_vwrite(int flags, const char * format, va_list ap) { int paniclogfd; ssize_t written_len; -BOOL will_log = FALSE; gstring gs = { .size = LOG_BUFFER_SIZE-2 }, * g = &gs; /* If panic_recurseflag is set, we have failed to open the panic log. This is @@ -945,7 +942,7 @@ if (!path_inspected) should work since we have now set up the routing. */ if (multiple) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "More than one path given in log_file_path: using %s", file_path); } @@ -962,12 +959,6 @@ DEBUG(any|v) va_list aq; string_fmt_append_noextend(g, "LOG:"); - /* Show the selector that was passed into the call. */ - - for (unsigned bitnum = 0; bitnum < logwrite_options_count; bitnum++) - if (bitnum < BITWORDSIZE && selector & BIT(bitnum)) - string_fmt_append_noextend(g, " %s", logwrite_options[bitnum].name); - string_fmt_append_noextend(g, "%s%s%s%s\n ", flags & LOG_MAIN ? " MAIN" : "", flags & LOG_PANIC ? " PANIC" : "", @@ -998,7 +989,7 @@ DEBUG(any|v) /* If no log file is specified, we are in a mess. */ if (!(flags & (LOG_MAIN|LOG_PANIC|LOG_REJECT))) - log_write_die(0, LOG_MAIN, "log_write called with no log flags set"); + log_write_die(LOG_MAIN, "log_write called with no log flags set"); /* There are some weird circumstances in which logging is disabled. */ @@ -1070,31 +1061,13 @@ gs.size = LOG_BUFFER_SIZE; string_fmt_append_noextend(g, "\n"); string_from_gstring(g); -/* See if the selector means we will log, given the enabled channels */ - -if (!selector) - will_log = TRUE; -else while (selector) - { - bitmask_word_t w = selector & ~(selector - 1); /* lowest set bit */ - unsigned bitnum = 0; - /* This relies on the ordering of logwrite_options[] */ - while (BIT(bitnum) != w) bitnum++; - if (bit_test(log_selector, logwrite_options[bitnum].logchan_bit)) - { - will_log = TRUE; - break; - } - selector &= ~w; /* clear that bit */ - } - /* Handle loggable errors when running a utility, or when address testing. Write to log_stderr unless debugging (when it will already have been written), or unless there is no log_stderr (expn called from daemon, for example). */ if (!f.really_exim || f.log_testing_mode) { - if (!ANY_DEBUG && log_stderr && will_log) + if (!ANY_DEBUG && log_stderr) if (host_checking) /*XXX +20 wrong if logging millisec or with-TZ */ fprintf(log_stderr, "LOG: %s", CS log_buffer + 20); /* no timestamp */ @@ -1111,7 +1084,7 @@ been opened, but we don't want to keep on writing to it for too long after it has been renamed. Therefore, do a stat() and see if the inode has changed, and if so, re-open. */ -if (flags & LOG_MAIN && will_log) +if (flags & LOG_MAIN) { if ( logging_mode & LOG_MODE_SYSLOG && (syslog_duplication || !(flags & (LOG_REJECT|LOG_PANIC)))) @@ -1320,11 +1293,11 @@ if (flags & LOG_PANIC) /* The public interface */ void -log_write(bitmask_word_t selector, int flags, const char * format, ...) +log_write(int flags, const char * format, ...) { va_list ap; va_start(ap, format); -log_vwrite(selector, flags, format, ap); +log_vwrite(flags, format, ap); va_end(ap); } @@ -1333,11 +1306,11 @@ We have this as a wrapper so that we can mark it as never returning, for the benefit of static analysers. */ void -log_write_die(bitmask_word_t selector, int flags, const char * format, ...) +log_write_die(int flags, const char * format, ...) { va_list ap; va_start(ap, format); -log_vwrite(selector, flags | LOG_PANIC_DIE, format, ap); +log_vwrite(flags | LOG_PANIC_DIE, format, ap); UNREACHABLE; } @@ -1540,14 +1513,14 @@ if (flags & DCB_DEBUG) { if (flags & DCB_FROM_CONFIG) { - log_write(0, LOG_CONFIG|LOG_PANIC, "%s", errmsg); + log_write(LOG_CONFIG|LOG_PANIC, "%s", errmsg); return; } fprintf(stderr, "exim: %s\n", errmsg); exim_exit(EXIT_FAILURE); } else - log_write_die(0, LOG_CONFIG, "%s", errmsg); + log_write_die(LOG_CONFIG, "%s", errmsg); } @@ -1612,9 +1585,9 @@ if (debug_file) if (tag_name && (Ustrchr(tag_name, '/') != NULL)) { - log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", + log_write(LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", tag_name); - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s", tag_name); return; } @@ -1632,7 +1605,7 @@ if (!*file_path) set_file_path(); if ((debug_fd = open_log(lt_debug, tag_name)) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log"); + log_write(LOG_MAIN|LOG_PANIC, "unable to open debug log"); debug_file = fdopen(debug_fd, "w"); setbuf(debug_file, NULL); diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c index ef541bdf0..37d7d1747 100644 --- a/src/src/lookups/dnsdb.c +++ b/src/src/lookups/dnsdb.c @@ -509,7 +509,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) if (rc < 0) { - log_write(0, LOG_MAIN, "host name alias list truncated: type=%s " + log_write(LOG_MAIN, "host name alias list truncated: type=%s " "domain=%s", dns_text_type(type), domain); break; } @@ -526,7 +526,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0))) (DN_EXPAND_ARG4_TYPE)buf, LCL_BUF_SIZE); if (rc < 0) { - log_write(0, LOG_MAIN, "responsible-mailbox truncated: type=%s " + log_write(LOG_MAIN, "responsible-mailbox truncated: type=%s " "domain=%s", dns_text_type(type), domain); break; } diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c index 4fb8f0c27..dac2b4963 100644 --- a/src/src/lookups/dsearch.c +++ b/src/src/lookups/dsearch.c @@ -32,7 +32,7 @@ struct stat statbuf; if (is_tainted(dirname)) { - log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", dirname); + log_write(LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", dirname); errno = EACCES; } else if (Ustat(dirname, &statbuf) >= 0) diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c index 04a728ac5..f7f703905 100644 --- a/src/src/lookups/lf_sqlperform.c +++ b/src/src/lookups/lf_sqlperform.c @@ -64,7 +64,7 @@ if (Ustrncmp(query, "servers", 7) == 0) int qsep = 0; const uschar * s, * ss, * qserverlist; - log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obsolete syntax used for lookup"); + log_write(LOG_MAIN|LOG_CONFIG_IN, "WARNING: obsolete syntax used for lookup"); s = query + 7; skip_whitespace(&s); diff --git a/src/src/lookups/nmh.c b/src/src/lookups/nmh.c index c4c7ee7fd..fc01a4ecf 100644 --- a/src/src/lookups/nmh.c +++ b/src/src/lookups/nmh.c @@ -106,7 +106,7 @@ if (connect(fd, (const struct sockaddr *)&s_un, (socklen_t)slen) < 0) { (void) close(fd); *errmsg= string_sprintf("connect '%s': %s", server, strerror(errno)); - log_write(0, LOG_MAIN|LOG_PANIC, "nmh lookup: %s\n", *errmsg); + log_write(LOG_MAIN|LOG_PANIC, "nmh lookup: %s\n", *errmsg); return -1; } return fd; @@ -292,7 +292,7 @@ if (i != gstring_length(g)) if (!poll_one_fd(sock, POLLIN, read_timeout * 1000)) { *errmsg = US"read timed out"; - log_write(0, LOG_MAIN|LOG_PANIC, "Timeout on nmh lookup on %q\n", filename); + log_write(LOG_MAIN|LOG_PANIC, "Timeout on nmh lookup on %q\n", filename); return DEFER; } if (read(sock, resp, 1) != 1) diff --git a/src/src/lookups/readsock.c b/src/src/lookups/readsock.c index b78ea7405..3f6922014 100644 --- a/src/src/lookups/readsock.c +++ b/src/src/lookups/readsock.c @@ -252,7 +252,7 @@ if (!cctx->tls_ctx) FILE * fp = fdopen(cctx->sock, "rb"); if (!fp) { - log_write(0, LOG_MAIN|LOG_PANIC, "readsock fdopen: %s\n", strerror(errno)); + log_write(LOG_MAIN|LOG_PANIC, "readsock fdopen: %s\n", strerror(errno)); goto out; } ALARM(timeout); diff --git a/src/src/macros.h b/src/src/macros.h index 4ca6b6b4d..574082c0a 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -406,6 +406,20 @@ and are only ever tested independently, so they do not need bit mask declarations. The "all" name string is recognized specially by decode_bits(). Add also to log_options[] when creating new ones. */ +/*XXX The use of this facility in calls to log_write() forces the presence and +maintenance of this separate table. It would be good to lose it. Why cannot +the LOGWRITE() macro be tested at the call point? +- currently we debug-output the log call even when a requested log channel + is not enabled. A naive replacement would lose that. +- the fn arg only controls LOG_MAIN log output, not LOG_REJECT or LOG_PANIC + - are there such cases? + - receive.c 2359, 3330 + - smtp_in.c 2620, 3706, 5088, 5136 + - all main+reject + - though the docs say only "a log line is written", so a quiet behaviour + change could be argued for +*/ + #define LOG_BIT(name) BIT_TABLE_BIT(L, name) /* Bit numbers used by calls to log_write() */ diff --git a/src/src/malware.c b/src/src/malware.c index afbf435ea..1f6e8bcfb 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -195,13 +195,13 @@ for (; *p; ++p) static inline int malware_panic_defer(const uschar * str) { -log_write(0, LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str); +log_write(LOG_MAIN|LOG_PANIC, "malware acl condition: %s", str); return DEFER; } static inline int malware_log_defer(const uschar * str) { -log_write(0, LOG_MAIN, "malware acl condition: %s", str); +log_write(LOG_MAIN, "malware acl condition: %s", str); return DEFER; } /* --- m_*_defer --- */ @@ -1753,7 +1753,7 @@ badseek: err = errno; } else if (regex_match(ava_re_error, buf, slen, NULL)) { - log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf); + log_write(LOG_MAIN, "internal scanner error (ignored): %s", buf); break; } @@ -1762,7 +1762,7 @@ badseek: err = errno; goto endloop; - default: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen", + default: log_write(LOG_PANIC, "%s:%d:%s: should not happen", __FILE__, __LINE__, __FUNCTION__); } } diff --git a/src/src/match.c b/src/src/match.c index 4ef9d3560..20d19e18a 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -41,7 +41,7 @@ is_tainted_metadata(const uschar * s) { /* Not enforcing for now, only logging; will enforce in a future release */ if (is_tainted(s)) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to use tainted list metadata %s", s); return FALSE; } @@ -286,7 +286,7 @@ li = search_findtype_partial(pattern, &partial, &affix, &affixlen, &starflags, &opts); *semicolon = ';'; if (!li) - log_write_die(0, LOG_MAIN, "%s", search_error_message); + log_write_die(LOG_MAIN, "%s", search_error_message); /* Partial matching is not appropriate for certain lookups (e.g. when looking up user@domain for sender rejection). There's a flag to disable it. */ @@ -302,7 +302,7 @@ for; partial matching is all handled inside search_find(). Note that there is no search_close() because of the caching arrangements. */ if (!(handle = search_open(filename, li, 0, NULL, NULL))) - log_write_die(0, LOG_MAIN, "%s", search_error_message); + log_write_die(LOG_MAIN, "%s", search_error_message); result = search_find(handle, filename, keyquery, partial, affix, affixlen, starflags, &expand_setup, opts); @@ -530,7 +530,7 @@ else "assume not in this list\n", *listptr); return FAIL; } - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand %q while checking " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand %q while checking " "a list: %s", *listptr, expand_string_message); return DEFER; } @@ -682,7 +682,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) const uschar * listname = readconf_find_option(listptr); if (!*listname) listname = string_sprintf("%q", *listptr); - log_write_die(0, LOG_MAIN, "%s", + log_write_die(LOG_MAIN, "%s", string_open_failed("%s when checking %s", sss, listname)); goto cppcheck_silencing; } @@ -749,7 +749,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) (void)fclose(f); if (!include_defer) goto DEFER_RETURN; - log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error); + log_write(LOG_MAIN, "%s: accepted by +include_defer", error); goto OK_RETURN; /* The ERROR return occurs when checking hosts, when either a forward @@ -771,10 +771,10 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if (!include_unknown) { if (LOGGING(unknown_in_list)) - log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); + log_write(LOG_MAIN, "list matching forced to fail: %s", error); goto FAIL_RETURN; } - log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); + log_write(LOG_MAIN, "%s: accepted by +include_unknown", error); goto OK_RETURN; } } @@ -807,7 +807,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if (is_tainted_metadata(ss)) goto BAD_TAINT; if (!(t = tree_search(*anchorptr, ss+1))) { - log_write(0, LOG_MAIN|LOG_PANIC, "unknown named%s list %q", + log_write(LOG_MAIN|LOG_PANIC, "unknown named%s list %q", type == MCL_DOMAIN ? " domain" : type == MCL_HOST ? " host" : type == MCL_ADDRESS ? " address" : @@ -947,7 +947,7 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) } if (include_defer) { - log_write(0, LOG_MAIN, "%s: accepted by +include_defer", error); + log_write(LOG_MAIN, "%s: accepted by +include_defer", error); return OK; } if (!search_error_message) search_error_message = error; @@ -971,10 +971,10 @@ while ((sss = string_nextinlist(&list, &sep, NULL, 0))) if (!include_unknown) { if (LOGGING(unknown_in_list)) - log_write(0, LOG_MAIN, "list matching forced to fail: %s", error); + log_write(LOG_MAIN, "list matching forced to fail: %s", error); return FAIL; } - log_write(0, LOG_MAIN, "%s: accepted by +include_unknown", error); + log_write(LOG_MAIN, "%s: accepted by +include_unknown", error); return OK; } } @@ -1133,7 +1133,7 @@ empty. Otherwise, a subject with no domain is a serious configuration error. */ if (!sdomain && *subject) { - log_write(0, LOG_MAIN|LOG_PANIC, "no @ found in the subject of an " + log_write(LOG_MAIN|LOG_PANIC, "no @ found in the subject of an " "address list match: subject=%q pattern=%q", subject, pattern); return FAIL; } @@ -1160,7 +1160,7 @@ but write a panic log entry. However, *@ matching will be honoured. */ if (*s == ';') { if (Ustrncmp(pattern, "partial-", 8) == 0) - log_write(0, LOG_MAIN|LOG_PANIC, "partial matching is not applicable to " + log_write(LOG_MAIN|LOG_PANIC, "partial matching is not applicable to " "whole-address lookups: ignored \"partial-\" in %q", pattern); return match_check_string(subject, pattern, -1, cb->flags, valueptr); } @@ -1238,7 +1238,7 @@ if (pattern[0] == '@' && pattern[1] == '@') /* End of chain loop; panic if too many times */ if (watchdog <= 0) - log_write_die(0, LOG_MAIN, "Loop detected in lookup of " + log_write_die(LOG_MAIN, "Loop detected in lookup of " "local part of %s in %s", subject, pattern); /* Otherwise the local part check has failed, so the whole match diff --git a/src/src/mime.c b/src/src/mime.c index 604e920fa..a22e19b42 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -783,7 +783,7 @@ while(1) mime_current_boundary = NULL; if (!mime_decoded_filename) /* decoding failed */ { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "MIME acl condition warning - could not decode RFC822 MIME part to file."); rc = DEFER; goto out; diff --git a/src/src/miscmods/arc.c b/src/src/miscmods/arc.c index 2176fc5a9..846272d7f 100644 --- a/src/src/miscmods/arc.c +++ b/src/src/miscmods/arc.c @@ -149,7 +149,7 @@ arc_init(void * dummy) uschar * errstr = NULL; if ((arc_dkim_mod_info = misc_mod_find(US"dkim", &errstr))) return TRUE; -log_write(0, LOG_MAIN, "arc: %s", errstr); +log_write(LOG_MAIN, "arc: %s", errstr); return FALSE; } @@ -1436,7 +1436,7 @@ errstr = (((fn_t *) arc_dkim_mod_info->functions)[DKIM_SIGN_DATA]) (&hhash, hm, privkey, sig); if (errstr) { - log_write(0, LOG_MAIN, "ARC: %s signing: %s\n", why, errstr); + log_write(LOG_MAIN, "ARC: %s signing: %s\n", why, errstr); DEBUG(transport) debug_printf("private key, or private-key file content, was: '%s'\n", privkey); @@ -1861,7 +1861,7 @@ if ((rheaders = arc_sign_scan_headers(&arc_sign_ctx, sigheaders))) if (!(arc_sign_find_ar(headers, identity, &ar))) { - log_write(0, LOG_MAIN, "ARC: no Authentication-Results header for signing"); + log_write(LOG_MAIN, "ARC: no Authentication-Results header for signing"); goto ret_sigheaders; } @@ -1929,11 +1929,11 @@ out: bad_bodyhash_ret: - log_write(0, LOG_MAIN, "ARC: bad message body-hash"); + log_write(LOG_MAIN, "ARC: bad message body-hash"); goto ret_sigheaders; bad_arg_ret: - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "ARC: bad signing-specification (%s) '%s'", s, orig_signspec); ret_sigheaders: g = sigheaders; diff --git a/src/src/miscmods/dkim.c b/src/src/miscmods/dkim.c index b36bbebf9..7ba5966a0 100644 --- a/src/src/miscmods/dkim.c +++ b/src/src/miscmods/dkim.c @@ -260,7 +260,7 @@ if ( dkim_collect_input && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK) { dkim_collect_error = pdkim_errstr(rc); - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DKIM: validation error: %.100s", dkim_collect_error); dkim_collect_input = 0; } @@ -304,7 +304,7 @@ dkim_signatures = NULL; if (dkim_collect_error) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DKIM: Error during validation, disabling signature verification: %.100s", dkim_collect_error); f.dkim_disable_verify = TRUE; @@ -318,7 +318,7 @@ dkim_collect_input = 0; rc = pdkim_feed_finish(dkim_verify_ctx, (pdkim_signature **)&dkim_signatures, &errstr); if (rc != PDKIM_OK && errstr && *errstr) - log_write(0, LOG_MAIN, "DKIM: validation error: %s", errstr); + log_write(LOG_MAIN, "DKIM: validation error: %s", errstr); /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */ @@ -468,7 +468,7 @@ else break; } -log_write(0, LOG_MAIN, "%Y", logmsg); +log_write(LOG_MAIN, "%Y", logmsg); return; } @@ -610,7 +610,7 @@ if (dkim_verify_signers && *dkim_verify_signers) if (!dkim_verify_signers_expanded) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "expansion of dkim_verify_signers option failed: %s", expand_string_message); return DEFER; @@ -973,7 +973,7 @@ if (dkim_domain) pdkim_canon = PDKIM_CANON_SIMPLE; else { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n", dkim_canon_expanded); pdkim_canon = PDKIM_CANON_RELAXED; @@ -1122,7 +1122,7 @@ CLEANUP: return sigbuf; pk_bad: - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc)); bad: sigbuf = NULL; @@ -1131,7 +1131,7 @@ bad: expand_bad: *errstr = string_sprintf("failed to expand %s: %s", errwhen, expand_string_message); - log_write(0, LOG_MAIN | LOG_PANIC, "%s", *errstr); + log_write(LOG_MAIN | LOG_PANIC, "%s", *errstr); goto bad; } diff --git a/src/src/miscmods/dkim_transport.c b/src/src/miscmods/dkim_transport.c index 05a5e65a1..570513c78 100644 --- a/src/src/miscmods/dkim_transport.c +++ b/src/src/miscmods/dkim_transport.c @@ -30,7 +30,7 @@ if (dkim->dkim_strict) { /* Set errno to something halfway meaningful */ *errp = EACCES; - log_write(0, LOG_MAIN, "DKIM: message could not be signed," + log_write(LOG_MAIN, "DKIM: message could not be signed," " and dkim_strict is set. Deferring message delivery."); return FALSE; } diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index 8bbf84841..a354b475c 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -88,13 +88,13 @@ dmarc_ctx.nscount = 0; libdm_status = opendmarc_policy_library_init(&dmarc_ctx); if (libdm_status != DMARC_PARSE_OKAY) { - log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to init library: %s", + log_write(LOG_MAIN|LOG_PANIC, "DMARC failure to init library: %s", opendmarc_policy_status_to_str(libdm_status)); dmarc_abort = TRUE; } else if (opendmarc_tld_read_file(CS dmarc_tld_file, NULL, NULL, NULL)) { - log_write(0, LOG_MAIN|LOG_PANIC, "DMARC failure to load tld list '%s': %s", + log_write(LOG_MAIN|LOG_PANIC, "DMARC failure to load tld list '%s': %s", dmarc_tld_file, strerror(errno)); dmarc_abort = TRUE; } @@ -105,7 +105,7 @@ if (!dmarc_abort) int is_ipv6 = string_is_ip_address(sender_host_address, NULL) == 6; if (!(dmarc_pctx = opendmarc_policy_connect_init(sender_host_address, is_ipv6))) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "DMARC failure creating policy context: ip=%s", sender_host_address); dmarc_abort = TRUE; } @@ -191,7 +191,7 @@ else if (!dmarc_abort) : opendmarc_policy_store_from_domain(dmarc_pctx, dmarc_header_from_sender); if (libdm_status != DMARC_PARSE_OKAY) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to store header From: in DMARC: %s, header was '%s'", opendmarc_policy_status_to_str(libdm_status), header_from); dmarc_abort = TRUE; @@ -251,7 +251,7 @@ if (!dmarc_abort && !sender_host_authenticated) libdm_status = opendmarc_policy_store_spf(dmarc_pctx, spf_sender_domain, dmarc_spf_result, origin, spf_human_readable); if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s", + log_write(LOG_MAIN|LOG_PANIC, "failure to store spf for DMARC: %s", opendmarc_policy_status_to_str(libdm_status)); } @@ -281,7 +281,7 @@ The EDITME provides a DMARC_API variable */ DEBUG(receive) debug_printf_indent("DMARC adding DKIM sender domain = %s\n", sig->domain); if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to store dkim (%s) for DMARC: %s", sig->domain, opendmarc_policy_status_to_str(libdm_status)); @@ -356,7 +356,7 @@ The EDITME provides a DMARC_API variable */ store_release_above(dmarc_used_domain + Ustrlen(dmarc_used_domain)+1); if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to read domainname used for DMARC lookup: %s", opendmarc_policy_status_to_str(libdm_status)); @@ -411,7 +411,7 @@ The EDITME provides a DMARC_API variable */ libdm_status = opendmarc_policy_fetch_alignment(dmarc_pctx, &dmarc_dkim_alignment, &dmarc_spf_alignment); if (libdm_status != DMARC_PARSE_OKAY) - log_write(0, LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s", + log_write(LOG_MAIN|LOG_PANIC, "failure to read DMARC alignment: %s", opendmarc_policy_status_to_str(libdm_status)); if (has_dmarc_record) diff --git a/src/src/miscmods/dmarc_common.c b/src/src/miscmods/dmarc_common.c index 0449f9f0e..9f1c7b02c 100644 --- a/src/src/miscmods/dmarc_common.c +++ b/src/src/miscmods/dmarc_common.c @@ -66,13 +66,13 @@ dmarc_init(void * dummy) uschar * errstr; if (!(dmarc_spf_mod_info = misc_mod_find(US"spf", &errstr))) { - log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); + log_write(LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); return FALSE; } if (!(dmarc_dkim_mod_info = misc_mod_find(US"dkim", &errstr))) { - log_write(0, LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); + log_write(LOG_MAIN|LOG_PANIC, "dmarc: %s", errstr); return FALSE; } @@ -202,7 +202,7 @@ for (int c = 0; ruf[c]; c++) if (!moan_send_message(recipient, ERRMESS_DMARC_FORENSIC, eblock, header_list, NULL, NULL)) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to send DMARC forensic report to %s", recipient); } } @@ -347,7 +347,7 @@ if (!(s = dmarc_history_file) || !(s = expand_string(s)) || !*s) if (!host_checking) /* -bh mode: nothing written except debug */ if ((history_file_fd = log_open_as_exim(s)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s: %s", s, strerror(errno)); return; @@ -445,7 +445,7 @@ if (!host_checking) string_from_gstring(g), gstring_length(g)); if (written_len == 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s", dmarc_history_file); (void)close(history_file_fd); return; diff --git a/src/src/miscmods/pdkim/pdkim.c b/src/src/miscmods/pdkim/pdkim.c index a3250ab6e..122f3f225 100644 --- a/src/src/miscmods/pdkim/pdkim.c +++ b/src/src/miscmods/pdkim/pdkim.c @@ -1554,7 +1554,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "DKIM: hash setup error, possibly nonhandled hashtype"); break; } @@ -1588,7 +1588,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if ((*err = exim_dkim_signing_init(CUS sig->privkey, &sctx))) { - log_write(0, LOG_MAIN|LOG_PANIC, "signing_init: %s", *err); + log_write(LOG_MAIN|LOG_PANIC, "signing_init: %s", *err); return PDKIM_ERR_RSA_PRIVKEY; } sig->keytype = sctx.keytype; @@ -1748,7 +1748,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if ((*err = exim_dkim_sign(&sctx, hm, &hhash, &sig->sighash))) { - log_write(0, LOG_MAIN|LOG_PANIC, "signing: %s", *err); + log_write(LOG_MAIN|LOG_PANIC, "signing: %s", *err); return PDKIM_ERR_RSA_SIGNING; } @@ -1815,7 +1815,7 @@ for (pdkim_signature * sig = ctx->sig; sig; sig = sig->next) if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err))) { - log_write(0, LOG_MAIN, "DKIM: %s%s %s%s [failed key import]", + log_write(LOG_MAIN, "DKIM: %s%s %s%s [failed key import]", sig->domain ? "d=" : "", sig->domain ? sig->domain : US"", sig->selector ? "s=" : "", sig->selector ? sig->selector : US""); goto NEXT_VERIFY; @@ -1968,7 +1968,7 @@ for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++) { sig->hashtype = hashtype; break; } if (hashtype >= nelem(pdkim_hashes)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "DKIM: unrecognised hashname '%s'", hashname); return NULL; } diff --git a/src/src/miscmods/perl.c b/src/src/miscmods/perl.c index c94836f0b..bc6248e3f 100644 --- a/src/src/miscmods/perl.c +++ b/src/src/miscmods/perl.c @@ -129,7 +129,7 @@ const uschar * s; if (items != 1) croak("Usage: Exim::log_write(string)"); s = US SvPV(ST(0), len); -log_write(0, LOG_MAIN, "%.*s", (int)len, s); +log_write(LOG_MAIN, "%.*s", (int)len, s); } /* Do a DNS lookup using Exim's facilities. diff --git a/src/src/miscmods/socks.c b/src/src/miscmods/socks.c index 5860af2ad..c97cee1d6 100644 --- a/src/src/miscmods/socks.c +++ b/src/src/miscmods/socks.c @@ -101,7 +101,7 @@ int len, i, j; switch(method) { default: - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Unrecognised socks auth method %d", method); return FAIL; case AUTH_NONE: @@ -130,7 +130,7 @@ switch(method) return OK; } - log_write(0, LOG_MAIN|LOG_PANIC, "socks auth failed"); + log_write(LOG_MAIN|LOG_PANIC, "socks auth failed"); errno = EPROTO; return FAIL; } @@ -175,7 +175,7 @@ for (rnd = random_number(weights), i = 0; i < nproxies; i++) return i; } -log_write(0, LOG_MAIN|LOG_PANIC, +log_write(LOG_MAIN|LOG_PANIC, "%s unknown error (memory/cpu corruption?)", __FUNCTION__); return -1; } @@ -283,7 +283,7 @@ for(;;) break; } - log_write(0, LOG_MAIN, "%s: %s", __FUNCTION__, strerror(errno)); + log_write(LOG_MAIN, "%s: %s", __FUNCTION__, strerror(errno)); sob->is_failed = TRUE; } diff --git a/src/src/miscmods/spf.c b/src/src/miscmods/spf.c index f01ab7a98..aeed3b888 100644 --- a/src/src/miscmods/spf.c +++ b/src/src/miscmods/spf.c @@ -282,11 +282,11 @@ but is broken now (May 18th, 2020) */ GET_OPTION("spf_smtp_comment_template"); if (!(s = expand_string(spf_smtp_comment_template))) - log_write_die(0, LOG_MAIN, "expansion of spf_smtp_comment_template failed"); + log_write_die(LOG_MAIN, "expansion of spf_smtp_comment_template failed"); SPF_server_set_explanation(spf_server, CCS s, &spf_response); if (SPF_response_errcode(spf_response) != SPF_E_SUCCESS) - log_write_die(0, LOG_MAIN, "%s", SPF_strerror(SPF_response_errcode(spf_response))); + log_write_die(LOG_MAIN, "%s", SPF_strerror(SPF_response_errcode(spf_response))); return TRUE; } diff --git a/src/src/miscmods/xclient.c b/src/src/miscmods/xclient.c index 8657c6982..3c6c11984 100644 --- a/src/src/miscmods/xclient.c +++ b/src/src/miscmods/xclient.c @@ -320,11 +320,11 @@ if (!(errmsg = xclient_smtp_command(smtp_cmd_data, &resp, &fatal))) return TRUE; } else if (fatal) - *donep = synprot_error(L_smtp_syntax_error, resp, NULL, errmsg); + *donep = synprot_error(FALSE, resp, NULL, errmsg); else { smtp_printf("%d %s\r\n", SP_NO_MORE, resp, errmsg); - log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s", + log_write(LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: %s", host_and_ident(FALSE), errmsg); } diff --git a/src/src/moan.c b/src/src/moan.c index a5d3c0977..6827bbb23 100644 --- a/src/src/moan.c +++ b/src/src/moan.c @@ -34,7 +34,7 @@ uschar * s; GET_OPTION("dsn_from"); if (!(s = expand_string(dsn_from))) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand dsn_from (using default): %s", expand_string_message); s = expand_string(US DEFAULT_DSN_FROM); } @@ -449,10 +449,10 @@ if (status != 0) { uschar *msg = US"Child mail process returned status"; if (status == -257) - log_write(0, LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno, + log_write(LOG_MAIN, "%s %d: errno=%d: %s", msg, status, errno, strerror(errno)); else - log_write(0, LOG_MAIN, "%s %d", msg, status); + log_write(LOG_MAIN, "%s %d", msg, status); return FALSE; } @@ -526,13 +526,13 @@ switch(ident) case ERRMESS_BADARGADDRESS: case ERRMESS_BADNOADDRESS: case ERRMESS_BADADDRESS: - log_write(0, LOG_MAIN, "%s: at least one malformed recipient address: " + log_write(LOG_MAIN, "%s: at least one malformed recipient address: " "%s - %s", msg, eblock->text1, eblock->text2); break; case ERRMESS_IGADDRESS: case ERRMESS_NOADDRESS: - log_write(0, LOG_MAIN, "%s: no recipient addresses", msg); + log_write(LOG_MAIN, "%s: no recipient addresses", msg); break; /* This error has already been logged. */ @@ -540,35 +540,35 @@ switch(ident) break; case ERRMESS_VLONGHEADER: - log_write(0, LOG_MAIN, "%s: excessively long message header section read " + log_write(LOG_MAIN, "%s: excessively long message header section read " "(more than %d characters)", msg, header_maxsize); break; case ERRMESS_VLONGHDRLINE: - log_write(0, LOG_MAIN, "%s: excessively long message header line read " + log_write(LOG_MAIN, "%s: excessively long message header line read " "(more than %d characters)", msg, header_line_maxsize); break; case ERRMESS_TOOBIG: - log_write(0, LOG_MAIN, "%s: message too big (limit set to %d)", msg, + log_write(LOG_MAIN, "%s: message too big (limit set to %d)", msg, thismessage_size_limit); break; case ERRMESS_TOOMANYRECIP: - log_write(0, LOG_MAIN, "%s: too many recipients (max set to %d)", msg, + log_write(LOG_MAIN, "%s: too many recipients (max set to %d)", msg, recipients_max_expanded); break; case ERRMESS_LOCAL_SCAN: - log_write(0, LOG_MAIN, "%s: rejected by local_scan: %s", msg, eblock->text1); + log_write(LOG_MAIN, "%s: rejected by local_scan: %s", msg, eblock->text1); break; case ERRMESS_LOCAL_ACL: - log_write(0, LOG_MAIN, "%s: rejected by non-SMTP ACL: %s", msg, eblock->text1); + log_write(LOG_MAIN, "%s: rejected by non-SMTP ACL: %s", msg, eblock->text1); break; default: - log_write(0, LOG_MAIN|LOG_PANIC, "%s: unknown error number %d", msg, + log_write(LOG_MAIN|LOG_PANIC, "%s: unknown error number %d", msg, ident); break; } @@ -773,7 +773,7 @@ while ((item = string_nextinlist(&listptr, &sep, NULL, 0))) yield = expand_string_copy(newaddress); deliver_domain = deliver_localpart = NULL; if (yield == NULL) - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to expand %s when processing " + log_write(LOG_MAIN|LOG_PANIC, "Failed to expand %s when processing " "errors_copy: %s", newaddress, expand_string_message); break; } @@ -820,17 +820,17 @@ FILE * f; for (const error_block * e = eblock; e; e = e->next) if (e->text2) - log_write(0, LOG_MAIN, "%s router: skipped error: %s in %q", + log_write(LOG_MAIN, "%s router: skipped error: %s in %q", rname, e->text1, e->text2); else - log_write(0, LOG_MAIN, "%s router: skipped error: %s", rname, + log_write(LOG_MAIN, "%s router: skipped error: %s", rname, e->text1); if (!syntax_errors_to) return TRUE; if (!(s = expand_string(syntax_errors_to))) { - log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname, + log_write(LOG_MAIN, "%s router failed to expand %s: %s", rname, syntax_errors_to, expand_string_message); return FALSE; } @@ -857,7 +857,7 @@ if (custom) { if (!(s = expand_string(custom))) { - log_write(0, LOG_MAIN, "%s router failed to expand %s: %s", rname, + log_write(LOG_MAIN, "%s router failed to expand %s: %s", rname, custom, expand_string_message); return FALSE; } diff --git a/src/src/os.c b/src/src/os.c index 40cf62762..42860de04 100644 --- a/src/src/os.c +++ b/src/src/os.c @@ -492,7 +492,7 @@ ip_address_item *last = NULL; ip_address_item *next; if (getifaddrs(&ifalist) != 0) - log_write_die(0, LOG_PANIC_DIE, "Unable to call getifaddrs: %d %s", + log_write_die(LOG_PANIC_DIE, "Unable to call getifaddrs: %d %s", errno, strerror(errno)); for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next) @@ -637,7 +637,7 @@ if ((vs = socket(FAMILY, SOCK_DGRAM, 0)) < 0) vs = socket(AF_INET, SOCK_DGRAM, 0); if (vs < 0) #endif - log_write_die(0, LOG_PANIC_DIE, "Unable to create IPv4 socket to find interface " + log_write_die(LOG_PANIC_DIE, "Unable to create IPv4 socket to find interface " "addresses: %d %s", errno, strerror(errno)); } @@ -653,7 +653,7 @@ ifc.V_ifc_flags = 0; #endif if (ioctl(vs, V_GIFCONF, CS &ifc) < 0) - log_write_die(0, LOG_PANIC_DIE, "Unable to get interface configuration: %d %s", + log_write_die(LOG_PANIC_DIE, "Unable to get interface configuration: %d %s", errno, strerror(errno)); /* If the buffer is big enough, the ioctl sets the value of ifc.V_ifc_len to @@ -697,7 +697,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len) ifreq.ifr_addr.sa_len : sizeof(ifreq.ifr_addr)) + sizeof(ifreq.V_ifr_name); if (len > sizeof(addrbuf)) - log_write_die(0, LOG_PANIC_DIE, "Address for %s interface is absurdly long", + log_write_die(LOG_PANIC_DIE, "Address for %s interface is absurdly long", ifreq.V_ifr_name); #endif @@ -721,7 +721,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len) { continue; /************* - log_write(0, LOG_PANIC_DIE, "Unable to get flags for %s interface: %d %s", + log_write(LOG_PANIC_DIE, "Unable to get flags for %s interface: %d %s", ifreq.V_ifr_name, errno, strerror(errno)); *************/ } @@ -734,7 +734,7 @@ for (char * cp = buf; cp < buf + ifc.V_ifc_len; cp += len) #ifndef SIOCGIFCONF_GIVES_ADDR if (ioctl(vs, V_GIFADDR, CS &ifreq) < 0) - log_write_die(0, LOG_PANIC_DIE, "Unable to get IP address for %s interface: " + log_write_die(LOG_PANIC_DIE, "Unable to get IP address for %s interface: " "%d %s", ifreq.V_ifr_name, errno, strerror(errno)); addrp = &ifreq.V_ifr_addr; diff --git a/src/src/priv.c b/src/src/priv.c index 2bc0c213d..2c1044bc0 100644 --- a/src/src/priv.c +++ b/src/src/priv.c @@ -27,7 +27,7 @@ void priv_drop_temp(const uid_t temp_uid, const gid_t temp_gid) { if (priv_state != PRIV_RESTORED) - log_write_die(0, LOG_PANIC_DIE, + log_write_die(LOG_PANIC_DIE, "priv_drop_temp: unexpected priv_state %d != %d", priv_state, PRIV_RESTORED); @@ -39,19 +39,19 @@ if (priv_euid == root_uid) priv_egid = getegid(); priv_ngroups = getgroups(nelem(priv_groups), priv_groups); if (priv_ngroups < 0) - log_write_die(0, LOG_PANIC_DIE, "getgroups: %s", strerror(errno)); + log_write_die(LOG_PANIC_DIE, "getgroups: %s", strerror(errno)); if (priv_ngroups > 0 && setgroups(1, &temp_gid) != 0) - log_write_die(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); + log_write_die(LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); if (setegid(temp_gid) != 0) - log_write_die(0, LOG_PANIC_DIE, "setegid(%d): %s", temp_gid, strerror(errno)); + log_write_die(LOG_PANIC_DIE, "setegid(%d): %s", temp_gid, strerror(errno)); if (seteuid(temp_uid) != 0) - log_write_die(0, LOG_PANIC_DIE, "seteuid(%d): %s", temp_uid, strerror(errno)); + log_write_die(LOG_PANIC_DIE, "seteuid(%d): %s", temp_uid, strerror(errno)); if (geteuid() != temp_uid) - log_write_die(0, LOG_PANIC_DIE, "getdeuid() != %d", temp_uid); + log_write_die(LOG_PANIC_DIE, "getdeuid() != %d", temp_uid); if (getegid() != temp_gid) - log_write_die(0, LOG_PANIC_DIE, "getegid() != %d", temp_gid); + log_write_die(LOG_PANIC_DIE, "getegid() != %d", temp_gid); } priv_state = PRIV_DROPPED; @@ -63,22 +63,22 @@ void priv_restore(void) { if (priv_state != PRIV_DROPPED) - log_write_die(0, LOG_PANIC_DIE, "priv_restore: unexpected priv_state %d != %d", priv_state, PRIV_DROPPED); + log_write_die(LOG_PANIC_DIE, "priv_restore: unexpected priv_state %d != %d", priv_state, PRIV_DROPPED); priv_state = PRIV_RESTORING; if (priv_euid == root_uid) { if (seteuid(priv_euid) != 0) - log_write_die(0, LOG_PANIC_DIE, "seteuid(%d): %s", priv_euid, strerror(errno)); + log_write_die(LOG_PANIC_DIE, "seteuid(%d): %s", priv_euid, strerror(errno)); if (setegid(priv_egid) != 0) - log_write_die(0, LOG_PANIC_DIE, "setegid(%d): %s", priv_egid, strerror(errno)); + log_write_die(LOG_PANIC_DIE, "setegid(%d): %s", priv_egid, strerror(errno)); if (priv_ngroups > 0 && setgroups(priv_ngroups, priv_groups) != 0) - log_write_die(0, LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); + log_write_die(LOG_PANIC_DIE, "setgroups: %s", strerror(errno)); if (geteuid() != priv_euid) - log_write_die(0, LOG_PANIC_DIE, "getdeuid() != %d", priv_euid); + log_write_die(LOG_PANIC_DIE, "getdeuid() != %d", priv_euid); if (getegid() != priv_egid) - log_write_die(0, LOG_PANIC_DIE, "getdegid() != %d", priv_egid); + log_write_die(LOG_PANIC_DIE, "getdegid() != %d", priv_egid); } priv_state = PRIV_RESTORED; diff --git a/src/src/queue.c b/src/src/queue.c index ec71a5021..6eeca6eb6 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -418,14 +418,13 @@ if (!recurse) deliver_selectstring_sender); log_detail = string_copy(big_buffer); - if (q->name) - log_write(L_queue_run, LOG_MAIN, "Start %s'%s' queue run: %s", - atrn_mode ? "ODMR " : "", - q->name, log_detail); - else - log_write(L_queue_run, LOG_MAIN, "Start %squeue run: %s", - atrn_mode ? "ODMR " : "", - log_detail); + if (LOGGING(queue_run)) + if (q->name) + log_write(LOG_MAIN, "Start %s'%s' queue run: %s", + atrn_mode ? "ODMR " : "", q->name, log_detail); + else + log_write(LOG_MAIN, "Start %squeue run: %s", + atrn_mode ? "ODMR " : "", log_detail); single_id = start_id && stop_id && !q->queue_2stage && Ustrcmp(start_id, stop_id) == 0; @@ -496,10 +495,11 @@ for (int i = queue_run_in_order ? -1 : 0; if (!q->queue_run_force && deliver_queue_load_max >= 0) if ((load_average = os_getloadavg()) > deliver_queue_load_max) { - log_write(L_queue_run, LOG_MAIN, "Abandon queue run: %s (load %.2f, max %.2f)", - log_detail, - (double)load_average/1000.0, - (double)deliver_queue_load_max/1000.0); + if (LOGGING(queue_run)) + log_write(LOG_MAIN, "Abandon queue run: %s (load %.2f, max %.2f)", + log_detail, + (double)load_average/1000.0, + (double)deliver_queue_load_max/1000.0); i = subcount; /* Don't process other directories */ break; } @@ -582,7 +582,7 @@ for (int i = queue_run_in_order ? -1 : 0; if (f.deliver_freeze && !q->deliver_force_thaw) { - log_write(L_skip_delivery, LOG_MAIN, "Message is frozen"); + if (LOGGING(skip_delivery)) log_write(LOG_MAIN, "Message is frozen"); wanted = FALSE; } @@ -657,7 +657,7 @@ for (int i = queue_run_in_order ? -1 : 0; pretty cheap. */ if (pipe(pfd) < 0) - log_write_die(0, LOG_MAIN, "failed to create pipe in queue " + log_write_die(LOG_MAIN, "failed to create pipe in queue " "runner process " PID_T_FMT ": %s", queue_run_pid, strerror(errno)); queue_run_pipe = pfd[pipe_write]; /* To ensure it gets passed on. */ @@ -702,7 +702,7 @@ single_item_retry: ? EXIT_FAILURE : EXIT_SUCCESS); } if (pid < 0) - log_write_die(0, LOG_MAIN, "fork of delivery process from " + log_write_die(LOG_MAIN, "fork of delivery process from " "queue runner " PID_T_FMT " failed\n", queue_run_pid); /* Close the writing end of the synchronizing pipe in this process, @@ -727,7 +727,7 @@ single_item_retry: /* If the process crashed, tell somebody */ else if (status & 0x00ff) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "queue run: process %d crashed with signal %d while delivering %s", (int)pid, status & 0x00ff, fq->text); @@ -750,7 +750,7 @@ single_item_retry: set_process_info("running queue: waiting for children of %d", pid); if ((status = read(pfd[pipe_read], buffer, sizeof(buffer))) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, status > 0 ? + log_write(LOG_MAIN|LOG_PANIC, status > 0 ? "queue run: unexpected data on pipe" : "queue run: error on pipe: %s", strerror(errno)); (void)close(pfd[pipe_read]); @@ -832,11 +832,11 @@ if (q->queue_2stage) if (!recurse) { - if (q->name) - log_write(L_queue_run, LOG_MAIN, "End '%s' queue run: %s", - q->name, log_detail); - else - log_write(L_queue_run, LOG_MAIN, "End queue run: %s", log_detail); + if (LOGGING(queue_run)) + if (q->name) + log_write(LOG_MAIN, "End '%s' queue run: %s", q->name, log_detail); + else + log_write(LOG_MAIN, "End queue run: %s", log_detail); /* If no ATRN messages were sent, try to close the channel semi-cleanly. XXX is this the best place to be doing this? We really ought to be @@ -1368,7 +1368,7 @@ switch(action) if (spool_write_header(id, SW_MODIFYING, &errmsg) >= 0) { printf("is now frozen\n"); - log_write(0, LOG_MAIN, "frozen by %s", username); + log_write(LOG_MAIN, "frozen by %s", username); } else { @@ -1392,7 +1392,7 @@ switch(action) if (spool_write_header(id, SW_MODIFYING, &errmsg) >= 0) { printf("is no longer frozen\n"); - log_write(0, LOG_MAIN, "unfrozen by %s", username); + log_write(LOG_MAIN, "unfrozen by %s", username); } else { @@ -1479,7 +1479,7 @@ switch(action) int start, end, dom; if (!parse_extract_address(addr, &err, &start, &end, &dom, TRUE)) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to parse address '%.100s'\n: %s", addr, err); else { @@ -1498,8 +1498,8 @@ switch(action) } (void) event_raise(event_action, US"msg:complete", NULL, NULL); #endif - log_write(0, LOG_MAIN, "removed by %s", username); - log_write(0, LOG_MAIN, "Completed"); + log_write(LOG_MAIN, "removed by %s", username); + log_write(LOG_MAIN, "Completed"); } break; } @@ -1521,7 +1521,7 @@ switch(action) { printf("has been modified\n"); for (int i = 0; i < recipients_count; i++) - log_write(0, LOG_MAIN, "address <%s> marked delivered by %s", + log_write(LOG_MAIN, "address <%s> marked delivered by %s", recipients_list[i].address, username); } else @@ -1586,7 +1586,7 @@ switch(action) if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE; #endif receive_add_recipient(recipient, -1); - log_write(0, LOG_MAIN, "recipient <%s> added by %s", + log_write(LOG_MAIN, "recipient <%s> added by %s", recipient, username); } else if (action == MSG_MARK_DELIVERED) @@ -1603,7 +1603,7 @@ switch(action) else { tree_add_nonrecipient(recipients_list[i].address); - log_write(0, LOG_MAIN, "address <%s> marked delivered by %s", + log_write(LOG_MAIN, "address <%s> marked delivered by %s", recipient, username); } } @@ -1613,7 +1613,7 @@ switch(action) if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE; #endif sender_address = recipient; - log_write(0, LOG_MAIN, "sender address changed to <%s> by %s", + log_write(LOG_MAIN, "sender address changed to <%s> by %s", recipient, username); } } diff --git a/src/src/rda.c b/src/src/rda.c index 36992e16c..66f4d1239 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -621,7 +621,7 @@ we have to create the subprocess to do everything as the given user. The results of processing are passed back via a pipe. */ if (pipe(pfd) != 0) - log_write_die(0, LOG_MAIN, "creation of pipe for filter or " + log_write_die(LOG_MAIN, "creation of pipe for filter or " ":include: failed for %s: %s", rname, strerror(errno)); /* Ensure that SIGCHLD is set to SIG_DFL before forking, so that the child @@ -800,7 +800,7 @@ bad: /* Back in the main process: panic if the fork did not succeed. */ if (pid < 0) - log_write_die(0, LOG_MAIN, "fork failed for %s", rname); + log_write_die(LOG_MAIN, "fork failed for %s", rname); /* Read the pipe to get the data from the filter/forward. Our copy of the writing end must be closed first, as otherwise read() won't return zero on an @@ -967,7 +967,7 @@ WAIT_EXIT: while ((rc = wait(&status)) != pid) if (rc < 0 && errno == ECHILD) /* Process has vanished */ { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "redirection process " PID_T_FMT " vanished unexpectedly", pid); goto FINAL_EXIT; } @@ -982,10 +982,10 @@ if (had_disaster) status, readerror, *error ? US": error=" : US"", *error ? *error : US""); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error); + log_write(LOG_MAIN|LOG_PANIC, "%s", *error); } else if (status != 0) - log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status " + log_write(LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status " "%04x from redirect subprocess (but data correctly received)", rname, status); diff --git a/src/src/readconf.c b/src/src/readconf.c index b57241212..972c8eb53 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -830,7 +830,7 @@ while (isalnum(*s) || *s == '_') { if (namelen >= sizeof(name) - 1) { - log_write(0, LOG_PANIC|LOG_CONFIG_IN, + log_write(LOG_PANIC|LOG_CONFIG_IN, "macro name too long (maximum is " SIZE_T_FMT " characters)", sizeof(name) - 1); return FALSE; } @@ -841,7 +841,7 @@ name[namelen] = 0; Uskip_whitespace(&s); if (*s++ != '=') { - log_write(0, LOG_PANIC|LOG_CONFIG_IN, + log_write(LOG_PANIC|LOG_CONFIG_IN, "malformed macro definition %q", line); return FALSE; } @@ -868,7 +868,7 @@ for (m = macros; m; m = m->next) { if (!m->command_line && !redef) { - log_write(0, LOG_CONFIG|LOG_PANIC, "macro %q is already " + log_write(LOG_CONFIG|LOG_PANIC, "macro %q is already " "defined (use \"==\" if you want to redefine it)", name); return FALSE; } @@ -877,7 +877,7 @@ for (m = macros; m; m = m->next) if (m->namelen < namelen && Ustrstr(name, m->name) != NULL) { - log_write(0, LOG_CONFIG|LOG_PANIC, "%q cannot be defined as " + log_write(LOG_CONFIG|LOG_PANIC, "%q cannot be defined as " "a macro because previously defined macro %q is a substring", name, m->name); return FALSE; @@ -887,7 +887,7 @@ for (m = macros; m; m = m->next) macro is permitted (there is even an example). * * if (m->namelen > namelen && Ustrstr(m->name, name) != NULL) - * log_write_die(0, LOG_CONFIG|"%q cannot be defined as " + * log_write_die(LOG_CONFIG|"%q cannot be defined as " * "a macro because it is a substring of previously defined macro %q", * name, m->name); */ @@ -907,7 +907,7 @@ if (redef) } else { - log_write(0, LOG_CONFIG|LOG_PANIC, "can't redefine an undefined macro " + log_write(LOG_CONFIG|LOG_PANIC, "can't redefine an undefined macro " "%q", name); return FALSE; } @@ -1081,7 +1081,7 @@ for (;;) /* EOF at top level */ if (cstate_stack_ptr >= 0) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "Unexpected end of configuration file: .endif missing"); if (len != 0) break; /* EOF after continuation */ @@ -1150,7 +1150,7 @@ for (;;) if (c->pushpop > 0) { if (cstate_stack_ptr >= CSTATE_STACK_SIZE - 1) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, ".%s nested too deeply", c->name); cstate_stack[++cstate_stack_ptr] = cstate; cstate = next_cstate[cstate][macro_found ? c->action1 : c->action2]; @@ -1162,7 +1162,7 @@ for (;;) else { if (cstate_stack_ptr < 0) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, ".%s without matching .ifdef", c->name); cstate = (c->pushpop < 0)? cstate_stack[cstate_stack_ptr--] : next_cstate[cstate][macro_found ? c->action1 : c->action2]; @@ -1211,7 +1211,7 @@ for (;;) we need to check the permissions/ownership of the containing folder */ if (*ss != '/') if (include_if_exists) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, ".include specifies a non-absolute path %q", ss); else ss = string_sprintf("%s/%s", config_directory, ss); @@ -1229,7 +1229,7 @@ for (;;) save->lineno = config_lineno; if (!(config_file = Ufopen(ss, "rb"))) - log_write_die(0, LOG_CONFIG_IN, "failed to open included " + log_write_die(LOG_CONFIG_IN, "failed to open included " "configuration file %s", ss); config_filename = string_copy(ss); @@ -1334,7 +1334,7 @@ if (isalpha(Uskip_whitespace(&s))) name[p] = 0; if (broken) { - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "exim item name too long (>%d), unable to use %q (truncated)", len, name); } @@ -1507,7 +1507,7 @@ optionlist *ol; uschar name2[EXIM_DRIVERNAME_MAX]; sprintf(CS name2, "*set_%.50s", name); if (!(ol = find_option(name2, oltop, last))) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Exim internal error: missing set flag for %s", name); return data_block ? (BOOL *)(US data_block + ol->v.offset) : (BOOL *)ol->v.value; @@ -1535,7 +1535,7 @@ extra_chars_error(const uschar *s, const uschar *t1, const uschar *t2, const usc { uschar *comment = US""; if (*s == '#') comment = US" (# is comment only at line start)"; -log_write_die(0, LOG_CONFIG_IN, +log_write_die(LOG_CONFIG_IN, "extra characters follow %s%s%s%s", t1, t2, t3, comment); } @@ -1576,7 +1576,7 @@ next->key = string_dequote(&p); Uskip_whitespace(&p); if (!*p) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "missing rewrite replacement string"); next->flags = 0; @@ -1607,12 +1607,12 @@ while (*p) switch (*p++) case 'S': next->flags |= rewrite_smtp; if (next->key[0] != '^' && Ustrncmp(next->key, "\\N^", 3) != 0) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "rewrite rule has the S flag but is not a regular expression"); break; default: - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "unknown rewrite flag character '%c' " "(could be missing quotes round replacement item)", p[-1]); break; @@ -1684,7 +1684,7 @@ ss = s; yield = string_dequote(&s); if (s == ss+1 || s[-1] != '\"') - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "missing quote at end of string value for %s", name); if (*s != 0) extra_chars_error(s, US"string value for ", name, US""); @@ -1713,7 +1713,7 @@ else /* "smtp_receive_timeout", opt_time, &smtp_receive_timeout */ smtp_receive_timeout = readconf_readtime(str, 0, FALSE); if (smtp_receive_timeout < 0) - log_write_die(0, LOG_CONFIG_IN, "invalid time value for %s", + log_write_die(LOG_CONFIG_IN, "invalid time value for %s", name); } } @@ -1786,7 +1786,7 @@ ptr = 0; with a letter. */ if (!isalpha( Uskip_whitespace(&s) )) - log_write_die(0, LOG_CONFIG_IN, "option setting expected: %s", s); + log_write_die(LOG_CONFIG_IN, "option setting expected: %s", s); /* Read the name of the option, and skip any subsequent white space. If it turns out that what we read was "hide", set the flag indicating that @@ -1826,11 +1826,11 @@ is set twice, is a disaster. */ if (!(ol = find_option(name + offset, oltop, last))) { if (!unknown_txt) return FALSE; - log_write_die(0, LOG_CONFIG_IN, CS unknown_txt, name); + log_write_die(LOG_CONFIG_IN, CS unknown_txt, name); } if ((ol->type & opt_set) && !(ol->type & (opt_rep_con | opt_rep_str))) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "%q option set for the second time", name); ol->type |= opt_set | issecure; @@ -1842,13 +1842,13 @@ applies only to boolean values. */ if (type < opt_bool || type > opt_bool_last) { if (offset != 0) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "negation prefix applied to a non-boolean option"); if (!*s) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "unexpected end of line (data missing) after %s", name); if (*s != '=') - log_write_die(0, LOG_CONFIG_IN, "missing \"=\" after %s", name); + log_write_die(LOG_CONFIG_IN, "missing \"=\" after %s", name); } /* If a boolean wasn't preceded by "no[t]_" it can be followed by = and @@ -1989,7 +1989,7 @@ switch (type) ol3 = find_option(name2, oltop, last); if (!ol2 || !ol3) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "rewrite rules not available for driver"); if (data_block) @@ -2012,7 +2012,7 @@ switch (type) } if ((*flagptr & (rewrite_all_envelope | rewrite_smtp)) != 0) - log_write_die(0, LOG_CONFIG_IN, "rewrite rule specifies a " + log_write_die(LOG_CONFIG_IN, "rewrite rule specifies a " "non-header rewrite - not allowed at transport time -"); } break; @@ -2047,7 +2047,7 @@ switch (type) case opt_uid: if (!route_finduser(sptr, &pw, &uid)) - log_write_die(0, LOG_CONFIG_IN, "user %s was not found", sptr); + log_write_die(LOG_CONFIG_IN, "user %s was not found", sptr); if (data_block) *(uid_t *)(US data_block + ol->v.offset) = uid; else @@ -2108,7 +2108,7 @@ switch (type) case opt_gid: if (!route_findgroup(sptr, &gid)) - log_write_die(0, LOG_CONFIG_IN, "group %s was not found", sptr); + log_write_die(LOG_CONFIG_IN, "group %s was not found", sptr); if (data_block) *((gid_t *)(US data_block + ol->v.offset)) = gid; else @@ -2130,7 +2130,7 @@ switch (type) const uschar *op = expand_string (sptr); if (op == NULL) - log_write_die(0, LOG_CONFIG_IN, "failed to expand %s: %s", + log_write_die(LOG_CONFIG_IN, "failed to expand %s: %s", name, expand_string_message); p = op; @@ -2151,7 +2151,7 @@ switch (type) /* If p is tainted we trap. Not sure that can happen */ (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE); if (!route_finduser(big_buffer, NULL, &uid)) - log_write_die(0, LOG_CONFIG_IN, "user %s was not found", + log_write_die(LOG_CONFIG_IN, "user %s was not found", big_buffer); list[ptr++] = uid; } @@ -2172,7 +2172,7 @@ switch (type) const uschar *op = expand_string (sptr); if (!op) - log_write_die(0, LOG_CONFIG_IN, "failed to expand %s: %s", + log_write_die(LOG_CONFIG_IN, "failed to expand %s: %s", name, expand_string_message); p = op; @@ -2193,7 +2193,7 @@ switch (type) /* If p is tainted we trap. Not sure that can happen */ (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE); if (!route_findgroup(big_buffer, &gid)) - log_write_die(0, LOG_CONFIG_IN, "group %s was not found", + log_write_die(LOG_CONFIG_IN, "group %s was not found", big_buffer); list[ptr++] = gid; } @@ -2246,7 +2246,7 @@ switch (type) boolvalue = TRUE; else if (strcmpic(name2, US"false") == 0 || strcmpic(name2, US"no") == 0) boolvalue = FALSE; - else log_write_die(0, LOG_CONFIG_IN, + else log_write_die(LOG_CONFIG_IN, "%q is not a valid value for the %q option", name2, name); if (*s != 0) extra_chars_error(s, string_sprintf("%q ", name2), US"for boolean option ", name); @@ -2315,7 +2315,7 @@ switch (type) lvalue = strtol(CS s, CSS &endptr, intbase); if (endptr == s) - log_write_die(0, LOG_CONFIG_IN, "%sinteger expected for %s", + log_write_die(LOG_CONFIG_IN, "%sinteger expected for %s", inttype, name); if (errno != ERANGE && *endptr) @@ -2339,7 +2339,7 @@ switch (type) } if (errno == ERANGE || lvalue > INT_MAX || lvalue < INT_MIN) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "absolute value of integer %q is too large (overflow)", s); if (Uskip_whitespace(&endptr)) @@ -2363,7 +2363,7 @@ switch (type) int_eximarith_t lvalue = strtol(CS s, CSS &endptr, intbase); if (endptr == s) - log_write_die(0, LOG_CONFIG_IN, "%sinteger expected for %s", + log_write_die(LOG_CONFIG_IN, "%sinteger expected for %s", inttype, name); if (errno != ERANGE && *endptr) @@ -2387,7 +2387,7 @@ switch (type) lvalue = (lvalue + 512)/1024; } - if (errno == ERANGE) log_write_die(0, LOG_CONFIG_IN, + if (errno == ERANGE) log_write_die(LOG_CONFIG_IN, "absolute value of integer %q is too large (overflow)", s); if (Uskip_whitespace(&endptr)) @@ -2404,15 +2404,15 @@ switch (type) case opt_fixed: if (sscanf(CS s, "%d%n", &value, &count) != 1) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "fixed-point number expected for %s", name); - if (value < 0) log_write_die(0, LOG_CONFIG_IN, + if (value < 0) log_write_die(LOG_CONFIG_IN, "integer %q is too large (overflow)", s); value *= 1000; - if (value < 0) log_write_die(0, LOG_CONFIG_IN, + if (value < 0) log_write_die(LOG_CONFIG_IN, "integer %q is too large (overflow)", s); /* We get a coverity error here for using count, as it derived @@ -2446,7 +2446,7 @@ switch (type) case opt_time: value = readconf_readtime(s, 0, FALSE); if (value < 0) - log_write_die(0, LOG_CONFIG_IN, "invalid time value for %s", + log_write_die(LOG_CONFIG_IN, "invalid time value for %s", name); if (data_block) *((int *)(US data_block + ol->v.offset)) = value; @@ -2477,10 +2477,10 @@ switch (type) } value = readconf_readtime(s, terminator, FALSE); if (value < 0) - log_write_die(0, LOG_CONFIG_IN, "invalid time value for %s", + log_write_die(LOG_CONFIG_IN, "invalid time value for %s", name); if (count > 1 && value <= list[count]) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "time value out of order for %s", name); list[count+1] = value; if (snext == NULL) break; @@ -2489,7 +2489,7 @@ switch (type) } if (count > list[0] - 2) - log_write_die(0, LOG_CONFIG_IN, "too many time values for %s", + log_write_die(LOG_CONFIG_IN, "too many time values for %s", name); if (count > 0 && list[2] == 0) count = 0; list[1] = count; @@ -2505,7 +2505,7 @@ switch (type) uschar * errstr; const lookup_info * li = lookup_find(US ol->v.value, &errstr); if (!li) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "failed to find %s module for %s: %s", US ol->v.value, name, errstr); oltop = li->options; @@ -2518,7 +2518,7 @@ switch (type) uschar * errstr; const misc_module_info * mi = misc_mod_find(US ol->v.value, &errstr); if (!mi) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "failed to find %s module for %s: %s", US ol->v.value, name, errstr); oltop = mi->options; @@ -3176,10 +3176,10 @@ if (Ustrncmp(s, "_cache", 6) == 0) } if (!isspace(*s)) - log_write_die(0, LOG_CONFIG_IN, "unrecognized configuration line"); + log_write_die(LOG_CONFIG_IN, "unrecognized configuration line"); if (*numberp >= max) - log_write_die(0, LOG_CONFIG_IN, "too many named %ss (max is %d)\n", + log_write_die(LOG_CONFIG_IN, "too many named %ss (max is %d)\n", tname, max); Uskip_whitespace(&s); @@ -3191,7 +3191,7 @@ t->name[s-ss] = 0; Uskip_whitespace(&s); if (!tree_insertnode(anchorp, t)) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "duplicate name %q for a named %s", t->name, tname); t->data.ptr = nb; @@ -3199,7 +3199,7 @@ nb->number = *numberp; *numberp += 1; nb->hide = hide; -if (*s++ != '=') log_write_die(0, LOG_CONFIG_IN, +if (*s++ != '=') log_write_die(LOG_CONFIG_IN, "missing '=' after %q", t->name); Uskip_whitespace(&s); nb->string = read_string(s, t->name); @@ -3248,7 +3248,7 @@ if (sscanf(CS s, "%d, %15[0123456789smhdw.], %lf, %15s", threshold, bstring, *limit = readconf_readtime(lstring, 0, TRUE); if (*base >= 0 && *limit >= 0) return; } -log_write_die(0, LOG_MAIN, "malformed ratelimit data: %s", s); +log_write_die(LOG_MAIN, "malformed ratelimit data: %s", s); } @@ -3394,10 +3394,10 @@ if (config_file) } else if (!filename) - log_write_die(0, LOG_MAIN, "non-existent configuration file(s): " + log_write_die(LOG_MAIN, "non-existent configuration file(s): " "%s", config_main_filelist); else - log_write_die(0, LOG_MAIN, "%s", + log_write_die(LOG_MAIN, "%s", string_open_failed("configuration file %s", filename)); /* Now, once we found and opened our configuration file, we change the directory @@ -3415,7 +3415,7 @@ privileges and the file isn't /dev/null (which *should* be 0666). */ if (f.trusted_config && Ustrcmp(filename, US"/dev/null")) { if (fstat(fileno(config_file), &statbuf) != 0) - log_write_die(0, LOG_MAIN, "failed to stat configuration file %s", + log_write_die(LOG_MAIN, "failed to stat configuration file %s", big_buffer); if ( statbuf.st_uid != root_uid /* owner not root */ @@ -3431,7 +3431,7 @@ if (f.trusted_config && Ustrcmp(filename, US"/dev/null")) || /* or */ (statbuf.st_mode & 2) != 0 /* world writeable */ ) - log_write_die(0, LOG_MAIN, "Exim configuration file %s has the " + log_write_die(LOG_MAIN, "Exim configuration file %s has the " "wrong owner, group, or mode", big_buffer); /* Do a dummy store-allocation of a size related to the (toplevel) file size. @@ -3459,7 +3459,7 @@ while ((s = get_config_line())) uschar * t; if (config_lineno == 1 && Ustrstr(s, "\xef\xbb\xbf") == s) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "found unexpected BOM (Byte Order Mark)"); if (isupper(*s)) @@ -3495,7 +3495,7 @@ while ((s = get_config_line())) /* If local_sender_retain is set, local_from_check must be unset. */ if (local_sender_retain && local_from_check) - log_write_die(0, LOG_MAIN, "both local_from_check and " + log_write_die(LOG_MAIN, "both local_from_check and " "local_sender_retain are set; this combination is not allowed"); /* If the timezone string is empty, set it to NULL, implying no TZ variable @@ -3528,7 +3528,7 @@ if (!primary_hostname) struct utsname uts; if (uname(&uts) < 0) - log_write_die(0, LOG_MAIN, "uname() failed to yield host name"); + log_write_die(LOG_MAIN, "uname() failed to yield host name"); hostname = US uts.nodename; if (Ustrchr(hostname, '.') == NULL) @@ -3577,7 +3577,7 @@ got set above. Of course, writing to the log may not work if log_file_path is not set, but it will at least get to syslog or somewhere, with any luck. */ if (!*spool_directory) - log_write_die(0, LOG_MAIN, "spool_directory undefined: cannot " + log_write_die(LOG_MAIN, "spool_directory undefined: cannot " "proceed"); /* Expand the spool directory name; it may, for example, contain the primary @@ -3587,7 +3587,7 @@ DEBUG(any) if (Ustrchr(spool_directory, '$')) debug_printf("Expanding spool_directory option\n"); if (!(s = expand_string(spool_directory))) - log_write_die(0, LOG_MAIN, "failed to expand spool_directory " + log_write_die(LOG_MAIN, "failed to expand spool_directory " "%q: %s", spool_directory, expand_string_message); spool_directory = s; @@ -3600,7 +3600,7 @@ if (*log_file_path) const uschar *ss, *sss; int sep = ':'; /* Fixed for log file path */ if (!(s = expand_string(log_file_path))) - log_write_die(0, LOG_MAIN, "failed to expand log_file_path " + log_write_die(LOG_MAIN, "failed to expand log_file_path " "%q: %s", log_file_path, expand_string_message); ss = s; @@ -3610,12 +3610,12 @@ if (*log_file_path) uschar *t; if (sss[0] == 0 || Ustrcmp(sss, "syslog") == 0) continue; if (!(t = Ustrstr(sss, "%s"))) - log_write_die(0, LOG_MAIN, "log_file_path %q does not " + log_write_die(LOG_MAIN, "log_file_path %q does not " "contain \"%%s\"", sss); *t = 'X'; if ((t = Ustrchr(sss, '%'))) if ((t[1] != 'D' && t[1] != 'M') || Ustrchr(t+2, '%') != NULL) - log_write_die(0, LOG_MAIN, "log_file_path %q contains " + log_write_die(LOG_MAIN, "log_file_path %q contains " "unexpected \"%%\" character", s); } @@ -3643,7 +3643,7 @@ if (syslog_facility_str) } if (i >= syslog_list_size) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "failed to interpret syslog_facility %q", syslog_facility_str); } @@ -3653,7 +3653,7 @@ if (*pid_file_path) { const uschar * t = expand_string(pid_file_path); if (!t) - log_write_die(0, LOG_MAIN, "failed to expand pid_file_path " + log_write_die(LOG_MAIN, "failed to expand pid_file_path " "%q: %s", pid_file_path, expand_string_message); pid_file_path = t; } @@ -3692,7 +3692,7 @@ if (system_filter_uid_set && !system_filter_gid_set) { struct passwd *pw = getpwuid(system_filter_uid); if (!pw) - log_write_die(0, LOG_MAIN, "Failed to look up uid %ld", + log_write_die(LOG_MAIN, "Failed to look up uid %ld", (long int)system_filter_uid); system_filter_gid = pw->pw_gid; system_filter_gid_set = TRUE; @@ -3709,11 +3709,11 @@ if (errors_reply_to) &start, &end, &domain, FALSE); if (!recipient) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "error in errors_reply_to (%s): %s", errors_reply_to, errmess); if (!domain) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "errors_reply_to (%s) does not contain a domain", errors_reply_to); } @@ -3721,7 +3721,7 @@ if (errors_reply_to) smtp_accept_max must also be set. */ if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host)) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "smtp_accept_max must be set if smtp_accept_queue or " "smtp_accept_max_per_host is set"); @@ -3736,15 +3736,15 @@ if (host_number_string) uschar *s = expand_string(host_number_string); if (!s) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "failed to expand localhost_number %q: %s", host_number_string, expand_string_message); n = Ustrtol(s, &end, 0); if (Uskip_whitespace(&end)) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "localhost_number value is not a number: %s", s); if (n > LOCALHOST_MAX) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "localhost_number is greater than the maximum allowed value (%d)", LOCALHOST_MAX); host_number = n; @@ -3754,7 +3754,7 @@ if (host_number_string) /* If tls_verify_hosts is set, tls_verify_certificates must also be set */ if ((tls_verify_hosts || tls_try_verify_hosts) && !tls_verify_certificates) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "tls_%sverify_hosts is set, but tls_verify_certificates is not set", tls_verify_hosts ? "" : "try_"); @@ -3762,26 +3762,26 @@ if ((tls_verify_hosts || tls_try_verify_hosts) && !tls_verify_certificates) used by so many clients, and what Exim used to use always, that it makes sense to just min-clamp this max-clamp at that. */ if (tls_dh_max_bits < 1024) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "tls_dh_max_bits is too small, must be at least 1024 for interop"); /* If openssl_options is set, validate it */ if (openssl_options) { # ifdef USE_GNUTLS - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "openssl_options is set but we're using GnuTLS"); # else long dummy; if (!tls_openssl_options_parse(openssl_options, &dummy)) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "openssl_options parse error: %s", openssl_options); # endif } #endif /*DISABLE_TLS*/ if (!nowarn && !keep_environment && environ && *environ) - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "Warning: purging the environment.\n" " Suggested action: use keep_environment."); } @@ -3826,7 +3826,7 @@ for (di = *info_anchor; di; di = di->next) /* Potentially a loadable module. Look for a file with the right name. */ if (!(dd = open_module_dir())) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR); else { @@ -3849,7 +3849,7 @@ else if (!dl) { errormsg = dlerror(); - log_write(0, LOG_MAIN|LOG_PANIC, "Error loading %s %s driver: %s\n", + log_write(LOG_MAIN|LOG_PANIC, "Error loading %s %s driver: %s\n", d->driver_name, class, errormsg); break; } @@ -3858,7 +3858,7 @@ else di = (driver_info *) dlsym(dl, CS string_sprintf("_%s_info", class)); if ((errormsg = dlerror())) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s does not appear to be a %s module (%s)\n", fname, class, errormsg); dlclose(dl); break; @@ -3875,7 +3875,7 @@ else goto found; } - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s module %s is not compatible with this version of Exim\n", class, d->driver_name); dlclose(dl); @@ -3884,7 +3884,7 @@ else } #endif /* LOOKUP_MODULE_DIR */ -log_write_die(0, LOG_CONFIG_IN, +log_write_die(LOG_CONFIG_IN, "%s %s: cannot find %s driver %q", class, d->name, class, d->driver_name); found: @@ -3907,7 +3907,7 @@ driver_init_fini(driver_instance * d, const uschar * class) driver_info * di = d->info; if (!d->driver_name) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "no driver defined for %s %q", class, d->name); (di->init)(d); } @@ -3997,7 +3997,7 @@ while ((buffer = get_config_line())) for (d = *anchor; d; d = d->next) if (Ustrcmp(name, d->name) == 0) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "there are two %ss called %q", class, name); /* Set up a new driver instance data block on the chain, with @@ -4027,7 +4027,7 @@ while ((buffer = get_config_line())) current driver yet. */ if (!d) - log_write_die(0, LOG_CONFIG_IN, "%s name missing", class); + log_write_die(LOG_CONFIG_IN, "%s name missing", class); /* First look to see if this is a generic option; if it is "driver", initialize the driver. If is it not a generic option, we can look for a @@ -4053,7 +4053,7 @@ while ((buffer = get_config_line())) /* The option is not generic and the driver name has not yet been given. */ - else log_write_die(0, LOG_CONFIG_IN, "option %q unknown " + else log_write_die(LOG_CONFIG_IN, "option %q unknown " "(\"driver\" must be specified before any private options)", name); } @@ -4177,7 +4177,7 @@ else if (len == 7 && strncmpic(pp, US"timeout", len) == 0) if (i >= nelem(extras)) if (strncmpic(x, US"DNS", xlen) == 0) - log_write(0, LOG_MAIN|LOG_PANIC, "\"timeout_dns\" is no longer " + log_write(LOG_MAIN|LOG_PANIC, "\"timeout_dns\" is no longer " "available in retry rules (it has never worked) - treated as " "\"timeout\""); else @@ -4267,14 +4267,14 @@ retry_arg(const uschar ** paddr, int type) { const uschar * p = *paddr, * pp; -if (*p++ != ',') log_write_die(0, LOG_CONFIG_IN, "comma expected"); +if (*p++ != ',') log_write_die(LOG_CONFIG_IN, "comma expected"); Uskip_whitespace(&p); pp = p; while (isalnum(*p) || (type == 1 && *p == '.')) p++; if (*p && !isspace(*p) && *p != ',' && *p != ';') - log_write_die(0, LOG_CONFIG_IN, "comma or semicolon expected"); + log_write_die(LOG_CONFIG_IN, "comma or semicolon expected"); *paddr = p; switch (type) @@ -4315,14 +4315,14 @@ while ((p = get_config_line())) Uskip_whitespace(&p); pp = p; while (mac_isgraph(*p)) p++; - if (p - pp <= 0) log_write_die(0, LOG_CONFIG_IN, + if (p - pp <= 0) log_write_die(LOG_CONFIG_IN, "missing error type in retry rule"); /* Test error names for things we understand. */ if ((error = readconf_retry_error(pp, p, &next->basic_errno, &next->more_errno))) - log_write_die(0, LOG_CONFIG_IN, "%s", error); + log_write_die(LOG_CONFIG_IN, "%s", error); /* There may be an optional address list of senders to be used as another constraint on the rule. This was added later, so the syntax is a bit of a @@ -4334,7 +4334,7 @@ while ((p = get_config_line())) { p += 7; Uskip_whitespace(&p); - if (*p++ != '=') log_write_die(0, LOG_CONFIG_IN, + if (*p++ != '=') log_write_die(LOG_CONFIG_IN, "\"=\" expected after \"senders\" in retry rule"); Uskip_whitespace(&p); next->senders = string_dequote(&p); @@ -4368,13 +4368,13 @@ while ((p = get_config_line())) break; default: - log_write_die(0, LOG_CONFIG_IN, "unknown retry rule letter"); + log_write_die(LOG_CONFIG_IN, "unknown retry rule letter"); break; } if (rule->timeout <= 0 || rule->p1 <= 0 || (rule->rule != 'F' && rule->p2 < 1000)) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "bad parameters for retry rule"); if (Uskip_whitespace(&p) == ';') @@ -4383,7 +4383,7 @@ while ((p = get_config_line())) Uskip_whitespace(&p); } else if (*p) - log_write_die(0, LOG_CONFIG_IN, "semicolon expected"); + log_write_die(LOG_CONFIG_IN, "semicolon expected"); } } } @@ -4432,14 +4432,14 @@ readconf_driver_init((driver_instance **)&auths, /* chain anchor */ for (auth_instance * au = auths; au; au = au->drinst.next) { if (!au->public_name) - log_write_die(0, LOG_CONFIG, "no public name specified for " + log_write_die(LOG_CONFIG, "no public name specified for " "the %s authenticator", au->drinst.name); for (auth_instance * bu = au->drinst.next; bu; bu = bu->drinst.next) if (strcmpic(au->public_name, bu->public_name) == 0) if ( au->client && bu->client || au->server && bu->server) - log_write_die(0, LOG_CONFIG, "two %s authenticators " + log_write_die(LOG_CONFIG, "two %s authenticators " "(%s and %s) have the same public name (%s)", au->client && bu->client ? US"client" : US"server", au->drinst.name, bu->drinst.name, au->public_name); @@ -4517,18 +4517,18 @@ while(acl_line) } if (*p != ':' || name[0] == 0) - log_write_die(0, LOG_CONFIG_IN, "missing or malformed ACL name"); + log_write_die(LOG_CONFIG_IN, "missing or malformed ACL name"); node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name); Ustrcpy(node->name, name); if (!tree_insertnode(&acl_anchor, node)) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "there are two ACLs called %q", name); node->data.ptr = acl_read(acl_callback, &error); if (node->data.ptr == NULL && error != NULL) - log_write_die(0, LOG_CONFIG_IN, "error in ACL: %s", error); + log_write_die(LOG_CONFIG_IN, "error in ACL: %s", error); } } @@ -4550,7 +4550,7 @@ static void local_scan_init(void) { #ifndef LOCAL_SCAN_HAS_OPTIONS -log_write_die(0, LOG_CONFIG_IN, "local_scan() options not supported: " +log_write_die(LOG_CONFIG_IN, "local_scan() options not supported: " "(LOCAL_SCAN_HAS_OPTIONS not defined in Local/Makefile)"); #else @@ -4615,14 +4615,14 @@ while(*next_section) if (c == 0) break; if (c > 0) first = mid + 1; else last = mid; if (first >= last) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "\"%.*s\" is not a known configuration section name", n, next_section); mid = (last + first)/2; } bit = 1 << mid; if (((had ^= bit) & bit) == 0) - log_write_die(0, LOG_CONFIG_IN, + log_write_die(LOG_CONFIG_IN, "\"%.*s\" section is repeated in the configuration file", n, next_section); diff --git a/src/src/receive.c b/src/src/receive.c index 90760f621..c8dd5a326 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -58,8 +58,8 @@ if (rc == 0) if (had_data_timeout) { fprintf(stderr, "exim: timed out while reading - message abandoned\n"); - log_write(L_lost_incoming_connection, - LOG_MAIN, "timed out while reading local message"); + if (LOGGING(lost_incoming_connection)) + log_write(LOG_MAIN, "timed out while reading local message"); receive_bomb_out(US"data-timeout", NULL); /* Does not return */ } if (had_data_sigint) @@ -68,7 +68,7 @@ if (rc == 0) { fprintf(stderr, "\nexim: %s received - message abandoned\n", had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); - log_write(0, LOG_MAIN, "%s received while reading local message", + log_write(LOG_MAIN, "%s received while reading local message", had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); } receive_bomb_out(US"signal-exit", NULL); /* Does not return */ @@ -100,7 +100,7 @@ int stdin_ungetc(int c) { if (stdin_inptr <= stdin_buf) - log_write_die(0, LOG_MAIN, "buffer underflow in stdin_ungetc"); + log_write_die(LOG_MAIN, "buffer underflow in stdin_ungetc"); *--stdin_inptr = c; return c; @@ -245,7 +245,7 @@ if (STATVFS(CS path, &statbuf) != 0) } else { - log_write(0, LOG_MAIN|LOG_PANIC, "cannot accept message: failed to stat " + log_write(LOG_MAIN|LOG_PANIC, "cannot accept message: failed to stat " "%s directory %s: %s", name, path, strerror(errno)); smtp_closedown(US"spool or log directory problem"); exim_exit(EXIT_FAILURE); @@ -304,7 +304,7 @@ if (check_spool_space > 0 || msg_size > 0 || check_spool_inodes > 0) if ( space >= 0 && space + msg_size / 1024 < check_spool_space || inodes >= 0 && inodes < check_spool_inodes) { - log_write(0, LOG_MAIN, "spool directory space check failed: space=" + log_write(LOG_MAIN, "spool directory space check failed: space=" PR_EXIM_ARITH " inodes=%d", space, inodes); return FALSE; } @@ -322,7 +322,7 @@ if (check_log_space > 0 || check_log_inodes > 0) if ( space >= 0 && space < check_log_space || inodes >= 0 && inodes < check_log_inodes) { - log_write(0, LOG_MAIN, "log directory space check failed: space=" PR_EXIM_ARITH + log_write(LOG_MAIN, "log directory space check failed: space=" PR_EXIM_ARITH " inodes=%d", space, inodes); return FALSE; } @@ -523,7 +523,7 @@ if (recipients_count >= recipients_list_max) const int safe_recipients_limit = INT_MAX / 2 / sizeof(recipient_item); if (recipients_list_max < 0 || recipients_list_max >= safe_recipients_limit) - log_write_die(0, LOG_MAIN, "Too many recipients: %d", recipients_list_max); + log_write_die(LOG_MAIN, "Too many recipients: %d", recipients_list_max); recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50; recipients_list = store_get(recipients_list_max * sizeof(recipient_item), GET_UNTAINTED); @@ -1165,8 +1165,9 @@ Returns: the SMTP response static uschar * handle_lost_connection(uschar * s) { -log_write(L_lost_incoming_connection | L_smtp_connection, LOG_MAIN, - "%s lost while reading message data%s", smtp_get_connection_info(), s); +if (LOGGING(lost_incoming_connection) || LOGGING(smtp_connection)) + log_write(LOG_MAIN, + "%s lost while reading message data%s", smtp_get_connection_info(), s); smtp_notquit_exit(US"connection-lost", NULL, NULL); return US"421 Lost incoming connection"; } @@ -1251,7 +1252,7 @@ switch(where) if ( cutthrough.cctx.sock >= 0 && cutthrough.delivery && (acl_removed_headers || acl_added_headers)) { - log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs" + log_write(LOG_MAIN|LOG_PANIC, "Header modification in data ACLs" " will not take effect on cutthrough deliveries"); return; } @@ -1494,7 +1495,7 @@ DO_MIME_ACL: /* make sure the eml mbox file is spooled up */ if (!(mbox_file = spool_mbox(&mbox_size, NULL, &mbox_filename))) { /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected."); Uunlink(spool_name); unspool_mbox(); @@ -1520,7 +1521,7 @@ if (rfc822_file_path) if (unlink(CS rfc822_file_path) == -1) { - log_write(0, LOG_PANIC, + log_write(LOG_PANIC, "acl_smtp_mime: can't unlink RFC822 spool file, skipping."); goto END_MIME_ACL; } @@ -1555,7 +1556,7 @@ if (rc == OK) mime_part_count_buffer = mime_part_count; goto MIME_ACL_CHECK; } - log_write(0, LOG_PANIC, + log_write(LOG_PANIC, "acl_smtp_mime: can't open RFC822 spool file, skipping."); unlink(CS rfc822_file_path); } @@ -1610,7 +1611,7 @@ if (!received) { if(spool_name[0] != 0) Uunlink(spool_name); /* Lose the data file */ - log_write_die(0, LOG_MAIN, "Expansion of %q " + log_write_die(LOG_MAIN, "Expansion of %q " "(received_header_text) failed: %s", string_printing(received_header_text), expand_string_message); } @@ -2085,7 +2086,7 @@ OVERSIZE: header_last->next = next; header_last = next; - log_write(0, LOG_MAIN, "ridiculously long message header received from " + log_write(LOG_MAIN, "ridiculously long message header received from " "%s (more than %d characters): message abandoned", f.sender_host_unknown ? sender_ident : sender_fullhost, header_maxsize); @@ -2218,7 +2219,7 @@ OVERSIZE: const uschar * uucp_sender; GET_OPTION("uucp_from_sender"); if (!(uucp_sender = expand_string(uucp_from_sender))) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "expansion of %q failed after matching " "\"From \" line: %s", uucp_from_sender, expand_string_message); else @@ -2323,7 +2324,7 @@ OVERSIZE: if (header_line_maxsize > 0 && next->slen > header_line_maxsize) { - log_write(0, LOG_MAIN, "overlong message header line received from " + log_write(LOG_MAIN, "overlong message header line received from " "%s (more than %d characters): message abandoned", f.sender_host_unknown ? sender_ident : sender_fullhost, header_line_maxsize); @@ -2356,11 +2357,12 @@ OVERSIZE: if (!first_line_ended_crlf && chunking_state > CHUNKING_OFFERED) { - log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " - "Non-CRLF-terminated header, under CHUNKING: message abandoned", - sender_address, - sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"", - sender_ident ? " U=" : "", sender_ident ? sender_ident : US""); + if (LOGGING(size_reject)) + log_write(LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " + "Non-CRLF-terminated header, under CHUNKING: message abandoned", + sender_address, + sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"", + sender_ident ? " U=" : "", sender_ident ? sender_ident : US""); smtp_printf("552 Message header not CRLF terminated\r\n", SP_NO_MORE); bdat_flush_data(); smtp_reply = US""; @@ -2857,7 +2859,7 @@ if ( !msgid_header if (!new_id_domain) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "expansion of %q (message_id_header_domain) " "failed: %s", message_id_domain, expand_string_message); } @@ -2881,7 +2883,7 @@ if ( !msgid_header if (!new_id_text) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "expansion of %q (message_id_header_text) " "failed: %s", message_id_text, expand_string_message); } @@ -3095,8 +3097,9 @@ if ( from_header if (!sender_address_unrewritten) sender_address_unrewritten = sender_address; sender_address = generated_sender_address; - if (Ustrcmp(sender_address_unrewritten, generated_sender_address) != 0) - log_write(L_address_rewrite, LOG_MAIN, + if ( LOGGING(address_rewrite) + && (Ustrcmp(sender_address_unrewritten, generated_sender_address) != 0)) + log_write(LOG_MAIN, "%q from env-from rewritten as %q by submission mode", sender_address_unrewritten, generated_sender_address); } @@ -3208,7 +3211,7 @@ if (cutthrough.cctx.sock >= 0 && cutthrough.delivery) { cancel_cutthrough_connection(TRUE, US"too many headers"); if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */ - log_write(0, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " + log_write(LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " "Too many \"Received\" headers", sender_address, sender_fullhost ? "H=" : "", sender_fullhost ? sender_fullhost : US"", @@ -3239,7 +3242,7 @@ if ((data_fd = Uopen(spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE)) < 0) data_fd = Uopen(spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE); } if (data_fd < 0) - log_write_die(0, LOG_MAIN, "Failed to create spool file %s: %s", + log_write_die(LOG_MAIN, "Failed to create spool file %s: %s", spool_name, strerror(errno)); } @@ -3247,7 +3250,7 @@ if ((data_fd = Uopen(spool_name, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE)) < 0) because the group setting doesn't always get set automatically. */ if (0 != exim_fchown(data_fd, exim_uid, exim_gid, spool_name)) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "Failed setting ownership on spool file %s: %s", spool_name, strerror(errno)); (void)fchmod(data_fd, SPOOL_MODE); @@ -3264,7 +3267,7 @@ lock_data.l_start = 0; lock_data.l_len = spool_data_start_offset(message_id); if (fcntl(data_fd, F_SETLK, &lock_data) < 0) - log_write_die(0, LOG_MAIN, "Cannot lock %s (%d): %s", spool_name, + log_write_die(LOG_MAIN, "Cannot lock %s (%d): %s", spool_name, errno, strerror(errno)); /* We have an open, locked data file. Write the message id to it to make it @@ -3327,15 +3330,16 @@ if (!ferror(spool_data_file) && !(receive_feof)() && message_ended != END_DOT) cancel_cutthrough_connection(TRUE, US"mail too big"); if (smtp_input) receive_swallow_smtp(); /* Swallow incoming SMTP */ - log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " - "message too big: read=%d max=%d", - sender_address, - sender_fullhost ? " H=" : "", - sender_fullhost ? sender_fullhost : US"", - sender_ident ? " U=" : "", - sender_ident ? sender_ident : US"", - message_size, - thismessage_size_limit); + if (LOGGING(size_reject)) + log_write(LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: " + "message too big: read=%d max=%d", + sender_address, + sender_fullhost ? " H=" : "", + sender_fullhost ? sender_fullhost : US"", + sender_ident ? " U=" : "", + sender_ident ? sender_ident : US"", + message_size, + thismessage_size_limit); if (smtp_input) { @@ -3386,7 +3390,7 @@ if (fflush(spool_data_file) == EOF || ferror(spool_data_file) || msg_errno, sender_fullhost ? sender_fullhost : sender_ident); - log_write(0, LOG_MAIN, "Message abandoned: %s", msg); + log_write(LOG_MAIN, "Message abandoned: %s", msg); Uunlink(spool_name); /* Lose the data file */ cancel_cutthrough_connection(TRUE, US"error writing spoolfile"); @@ -3442,7 +3446,7 @@ if (extract_recip && (bad_addresses || recipients_count == 0)) } } - log_write(0, LOG_MAIN|LOG_PANIC, "%s found in headers", + log_write(LOG_MAIN|LOG_PANIC, "%s found in headers", bad_addresses ? "bad addresses" : "no recipients"); fseek(spool_data_file, (long int)spool_data_start_offset(message_id), SEEK_SET); @@ -3651,9 +3655,9 @@ else } smtp_user_msg(code, msg); } - if (log_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, log_msg); - else if (user_msg) log_write(0, LOG_MAIN, "PRDR %s %s", addr, user_msg); - else log_write(0, LOG_MAIN, "%s", CS msg); + if (log_msg) log_write(LOG_MAIN, "PRDR %s %s", addr, log_msg); + else if (user_msg) log_write(LOG_MAIN, "PRDR %s %s", addr, user_msg); + else log_write(LOG_MAIN, "%s", CS msg); if (rc != OK) { receive_remove_recipient(addr); c--; } } @@ -3751,7 +3755,7 @@ else nowhere. The default is main and reject logs. */ if (log_reject_target) - log_write(0, log_reject_target, "F=<%s> rejected by non-SMTP ACL: %s", + log_write(log_reject_target, "F=<%s> rejected by non-SMTP ACL: %s", sender_address, log_msg); if (!user_msg) user_msg = US"local configuration problem"; @@ -3831,7 +3835,7 @@ else { if (had_local_scan_crash) { - log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() function crashed with " + log_write(LOG_MAIN|LOG_REJECT, "local_scan() function crashed with " "signal %d - message temporarily rejected (size %d)", had_local_scan_crash, message_size); receive_bomb_out(US"local-scan-error", US"local verification problem"); @@ -3839,7 +3843,7 @@ else } if (had_local_scan_timeout) { - log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() function timed out - " + log_write(LOG_MAIN|LOG_REJECT, "local_scan() function timed out - " "message temporarily rejected (size %d)", message_size); receive_bomb_out(US"local-scan-timeout", US"local verification problem"); /* Does not return */ @@ -3908,7 +3912,7 @@ else switch(rc) { default: - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "invalid return %d from local_scan(). Temporary rejection given", rc); goto TEMPREJECT; @@ -3936,7 +3940,7 @@ else g = string_append(NULL, 2, US"F=", *sender_address ? sender_address : US"<>"); g = add_host_info_for_log(g); - log_write(0, LOG_MAIN|LOG_REJECT, "%Y %srejected by local_scan(): %.256s", + log_write(LOG_MAIN|LOG_REJECT, "%Y %srejected by local_scan(): %.256s", g, istemp, string_printing(errmsg)); if (smtp_input) @@ -4020,7 +4024,7 @@ if (host_checking || blackholed_by) else if ((msg_size = spool_write_header(message_id, SW_RECEIVING, &errmsg)) < 0) { - log_write(0, LOG_MAIN, "Message abandoned: %s", errmsg); + log_write(LOG_MAIN, "Message abandoned: %s", errmsg); Uunlink(spool_name); /* Lose the data file */ if (smtp_input) @@ -4053,7 +4057,7 @@ if ( fflush(spool_data_file) ) { errmsg = string_sprintf("Spool write error: %s", strerror(errno)); - log_write(0, LOG_MAIN, "%s\n", errmsg); + log_write(LOG_MAIN, "%s\n", errmsg); Uunlink(spool_name); /* Lose the data file */ if (smtp_input) @@ -4235,14 +4239,14 @@ if (message_logs && !blackholed_by) } if (fd < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't open message log %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Couldn't open message log %s: %s", m_name, strerror(errno)); else { FILE *message_log = fdopen(fd, "a"); if (!message_log) { - log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s", + log_write(LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s", m_name, strerror(errno)); (void)close(fd); } @@ -4302,7 +4306,7 @@ if ( smtp_input && sender_host_address && !f.sender_host_notsocket gstring_reset(g); g = string_cat(g, US"SMTP connection lost after final dot"); g = add_host_info_for_log(g); - log_write(0, LOG_MAIN, "%Y", g); + log_write(LOG_MAIN, "%Y", g); /* Delete the files for this aborted message. */ @@ -4366,18 +4370,18 @@ if(!smtp_reply || prdr_requested) if(!smtp_reply) #endif { - log_write(0, LOG_MAIN | + log_write(LOG_MAIN | (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | (LOGGING(received_sender) ? LOG_SENDER : 0), "%Y", g); /* Log any control actions taken by an ACL or local_scan(). */ - if (f.deliver_freeze) log_write(0, LOG_MAIN, "frozen by %s", frozen_by); - if (f.queue_only_policy) log_write(L_delay_delivery, LOG_MAIN, - "no immediate delivery: queued%s%s by %s", - *queue_name ? " in " : "", *queue_name ? CS queue_name : "", - queued_by); + if (f.deliver_freeze) log_write(LOG_MAIN, "frozen by %s", frozen_by); + if (f.queue_only_policy && LOGGING(delay_delivery)) + log_write(LOG_MAIN, "no immediate delivery: queued%s%s by %s", + *queue_name ? " in " : "", *queue_name ? CS queue_name : "", + queued_by); } f.receive_call_bombout = FALSE; @@ -4438,11 +4442,11 @@ if (spool_data_file && cutthrough_done == NOT_TRIED) if (fclose(spool_data_file)) /* Frees the lock */ { log_msg = string_sprintf("spoolfile error on close: %s", strerror(errno)); - log_write(0, LOG_MAIN|LOG_PANIC | + log_write(LOG_MAIN|LOG_PANIC | (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | (LOGGING(received_sender) ? LOG_SENDER : 0), "%s", log_msg); - log_write(0, LOG_MAIN | + log_write(LOG_MAIN | (LOGGING(received_recipients) ? LOG_RECIPIENTS : 0) | (LOGGING(received_sender) ? LOG_SENDER : 0), "rescind the above message-accept"); @@ -4530,7 +4534,7 @@ if (smtp_input) switch (cutthrough_done) { case ACCEPTED: - log_write(0, LOG_MAIN, "Completed");/* Delivery was done */ + log_write(LOG_MAIN, "Completed");/* Delivery was done */ case PERM_REJ: /* Delete spool files */ Uunlink(spool_name); @@ -4582,8 +4586,8 @@ if (blackholed_by) local_scan_data ? string_printing(local_scan_data) : #endif string_sprintf("(%s discarded recipients)", blackholed_by); - log_write(0, LOG_MAIN, "=> blackhole %s%s", detail, blackhole_log_msg); - log_write(0, LOG_MAIN, "Completed"); + log_write(LOG_MAIN, "=> blackhole %s%s", detail, blackhole_log_msg); + log_write(LOG_MAIN, "Completed"); message_id[0] = 0; } diff --git a/src/src/regex.c b/src/src/regex.c index 43f7a9403..b88430d06 100644 --- a/src/src/regex.c +++ b/src/src/regex.c @@ -46,7 +46,7 @@ while ((regex_string = string_nextinlist(&list, &sep, NULL, 0))) if (!re) { - log_write(0, LOG_MAIN, "regex acl condition warning - %s, skipped", errstr); + log_write(LOG_MAIN, "regex acl condition warning - %s, skipped", errstr); continue; } @@ -127,7 +127,7 @@ if (!mime_stream) /* We are in the DATA ACL */ { if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL))) { /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "regex acl condition: error while creating mbox spool file"); return DEFER; } @@ -136,7 +136,7 @@ else { if ((f_pos = ftell(mime_stream)) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "regex acl condition: mime_stream: %s", strerror(errno)); return DEFER; } @@ -177,7 +177,7 @@ else clearerr(mime_stream); if (fseek(mime_stream, f_pos, SEEK_SET) == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "regex acl condition: mime_stream: %s", strerror(errno)); clearerr(mime_stream); } @@ -205,7 +205,7 @@ if (!mime_decoded_filename) mime_decode(&empty); if (!mime_decoded_filename) { /* decoding failed */ - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "mime_regex acl condition warning - could not decode MIME part to file"); return DEFER; } @@ -214,7 +214,7 @@ if (!mime_decoded_filename) /* open file */ if (!(f = fopen(CS mime_decoded_filename, "rb"))) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "mime_regex acl condition warning - can't open '%s' for reading", mime_decoded_filename); return DEFER; diff --git a/src/src/regex_cache.c b/src/src/regex_cache.c index f0981a313..669a90bca 100644 --- a/src/src/regex_cache.c +++ b/src/src/regex_cache.c @@ -156,7 +156,7 @@ if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, { uschar errbuf[128]; pcre2_get_error_message(err, errbuf, sizeof(errbuf)); - log_write_die(0, LOG_MAIN, "regular expression error: " + log_write_die(LOG_MAIN, "regular expression error: " "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern); } diff --git a/src/src/retry.c b/src/src/retry.c index 720f849ae..55522f7ff 100644 --- a/src/src/retry.c +++ b/src/src/retry.c @@ -982,7 +982,7 @@ for (int i = 0; i < 3; i++) addr->user_message = addr->user_message ? string_sprintf("%s: retry timeout exceeded", addr->user_message) : US"retry timeout exceeded"; - log_write(0, LOG_MAIN, "** %s%s%s%s: retry timeout exceeded", + log_write(LOG_MAIN, "** %s%s%s%s: retry timeout exceeded", addr->address, addr->parent ? US" <" : US"", addr->parent ? addr->parent->address : US"", diff --git a/src/src/rewrite.c b/src/src/rewrite.c index 0affaaae8..734418b1f 100644 --- a/src/src/rewrite.c +++ b/src/src/rewrite.c @@ -135,7 +135,7 @@ for (rewrite_rule * rule = rewrite_rules; if (!key) { if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand %q while " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand %q while " "checking for SMTP rewriting: %s", rule->key, expand_string_message); continue; } @@ -199,7 +199,7 @@ for (rewrite_rule * rule = rewrite_rules; expand_string_message = expand_hide_passwords(expand_string_message); - log_write(0, LOG_MAIN|LOG_PANIC, "Expansion of %s failed while rewriting: " + log_write(LOG_MAIN|LOG_PANIC, "Expansion of %s failed while rewriting: " "%s", rule->replacement, expand_string_message); break; } @@ -212,7 +212,7 @@ for (rewrite_rule * rule = rewrite_rules; if (!newparsed) { - log_write(0, LOG_MAIN|LOG_PANIC, "Rewrite of %s yielded unparseable " + log_write(LOG_MAIN|LOG_PANIC, "Rewrite of %s yielded unparseable " "address: %s in address %s", subject, error, new); break; /* Give up on this address */ } @@ -233,7 +233,7 @@ for (rewrite_rule * rule = rewrite_rules; } else { - log_write(0, LOG_MAIN|LOG_PANIC, "Rewrite of %s yielded unqualified " + log_write(LOG_MAIN|LOG_PANIC, "Rewrite of %s yielded unqualified " "address %q", subject, new); break; /* Give up on this address */ } @@ -249,8 +249,8 @@ for (rewrite_rule * rule = rewrite_rules; if (flag == where_list[i].bit) { where = where_list[i].string; break; } - log_write(L_address_rewrite, - LOG_MAIN, "\"%s\" from %s rewritten %s \"%s\" by rule %d", + if (LOGGING(address_rewrite)) + log_write(LOG_MAIN, "\"%s\" from %s rewritten %s \"%s\" by rule %d", yield, where, rule->flags & rewrite_whole || !Ustrchr(new, '<') ? "as" : "with (address part of)", @@ -347,7 +347,7 @@ for (rewrite_rule * rule = rewrite_rules; if (rule->flags & rewrite_repeat) { if (count++ < 10) goto REPEAT_RULE; - log_write(0, LOG_MAIN|LOG_PANIC, "rewrite rule repeat ignored after 10 " + log_write(LOG_MAIN|LOG_PANIC, "rewrite rule repeat ignored after 10 " "times"); } } @@ -502,7 +502,7 @@ while (*s) this one and carry on. */ if (Ustrcmp(errmess, "empty address") != 0) - log_write(0, LOG_MAIN, "qualify/rewrite: %s", errmess); + log_write(LOG_MAIN, "qualify/rewrite: %s", errmess); loop_reset_point = store_reset(loop_reset_point); continue; diff --git a/src/src/route.c b/src/src/route.c index 07be01c65..c2de39228 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -237,11 +237,11 @@ for (rr = routers; rr; rr = rr->drinst.next) } if (!rr) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "new_router %q not found for %q router", name, r->drinst.name); if (after && !afterthis) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "new_router %q does not follow %q router", name, r->drinst.name); } @@ -298,11 +298,11 @@ for (router_instance * r = routers; r; r = r->drinst.next) /* Check for transport or no transport on certain routers */ if (ri->ri_flags & ri_yestransport && !r->transport_name && !r->verify_only) - log_write_die(0, LOG_CONFIG, "%s router:\n " + log_write_die(LOG_CONFIG, "%s router:\n " "a transport is required for this router", r->drinst.name); if (ri->ri_flags & ri_notransport && r->transport_name) - log_write_die(0, LOG_CONFIG, "%s router:\n " + log_write_die(LOG_CONFIG, "%s router:\n " "a transport must not be defined for this router", r->drinst.name); /* The "self" option needs to be decoded into a code value and possibly a @@ -327,7 +327,7 @@ for (router_instance * r = routers; r; r = r->drinst.next) r->self_code = self_reroute; } - else log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + else log_write_die(LOG_CONFIG_FOR, "%s router:\n " "%s is not valid for the self option", r->drinst.name, s); /* If any router has check_local_user set, default retry_use_local_part @@ -1274,7 +1274,7 @@ if (!user) { *errmsg = string_sprintf("Failed to expand user string %q for the " "%s %s: %s", string, driver_name, driver_type, expand_string_message); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", *errmsg); + log_write(LOG_MAIN|LOG_PANIC, "%s", *errmsg); return FALSE; } @@ -1282,7 +1282,7 @@ if (route_finduser(user, pw, uid)) return TRUE; *errmsg = string_sprintf("Failed to find user %q from expanded string " "%q for the %s %s", user, string, driver_name, driver_type); -log_write(0, LOG_MAIN|LOG_PANIC, "%s", *errmsg); +log_write(LOG_MAIN|LOG_PANIC, "%s", *errmsg); return FALSE; } @@ -1316,7 +1316,7 @@ if (!group) { *errmsg = string_sprintf("Failed to expand group string %q for the " "%s %s: %s", string, driver_name, driver_type, expand_string_message); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", *errmsg); + log_write(LOG_MAIN|LOG_PANIC, "%s", *errmsg); return FALSE; } @@ -1324,7 +1324,7 @@ if (!route_findgroup(group, gid)) { *errmsg = string_sprintf("Failed to find group %q from expanded string " "%q for the %s %s", group, string, driver_name, driver_type); - log_write(0, LOG_MAIN|LOG_PANIC, "%s", *errmsg); + log_write(LOG_MAIN|LOG_PANIC, "%s", *errmsg); yield = FALSE; } @@ -1465,7 +1465,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); ) if (!name || name[0] != 'r' || name[1] != '_' || !name[2]) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "bad router variable name '%s' in router '%s'\n", name, drname); return FAIL; } @@ -1643,7 +1643,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr) if (loopcount++ > 100) { - log_write(0, LOG_MAIN|LOG_PANIC, "routing loop for %s", addr->address); + log_write(LOG_MAIN|LOG_PANIC, "routing loop for %s", addr->address); yield = DEFER; goto ROUTERS_LOOP_EXIT; } @@ -1922,7 +1922,7 @@ if (!r) message = s; else if (!f.expand_string_forcedfail) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand " "cannot_route_message in %s router: %s", addr->router->drinst.name, expand_string_message); @@ -1947,7 +1947,7 @@ if (yield == DISCARD) goto ROUTE_EXIT; /* The yield must be either OK or REROUTED. */ if (yield != OK && yield != REROUTED) - log_write_die(0, LOG_MAIN, "%s router returned unknown value %d", + log_write_die(LOG_MAIN, "%s router returned unknown value %d", rname_l, yield); /* If the yield was REROUTED, the router put a child address on the new chain diff --git a/src/src/routers/iplookup.c b/src/src/routers/iplookup.c index fd8880b4a..6e91d3b7d 100644 --- a/src/src/routers/iplookup.c +++ b/src/src/routers/iplookup.c @@ -96,11 +96,11 @@ iplookup_router_options_block * ob = /* A port and a host list must be given */ if (ob->port < 0) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "a port must be specified", r->name); if (!ob->hosts) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "a host list must be specified", r->name); /* Translate protocol name into value */ @@ -109,7 +109,7 @@ if (ob->protocol_name) { if (Ustrcmp(ob->protocol_name, "udp") == 0) ob->protocol = ip_udp; else if (Ustrcmp(ob->protocol_name, "tcp") == 0) ob->protocol = ip_tcp; - else log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + else log_write_die(LOG_CONFIG_FOR, "%s router:\n " "protocol not specified as udp or tcp", r->name); } @@ -382,7 +382,7 @@ else if (!(domain = Ustrchr(reroute, '@'))) { - log_write(0, LOG_MAIN, "%s router: reroute string %s is not of the form " + log_write(LOG_MAIN, "%s router: reroute string %s is not of the form " "user@domain", rblock->drinst.name, reroute); addr->message = string_sprintf("%s router: reroute string %s is not of the " "form user@domain", rblock->drinst.name, reroute); @@ -398,7 +398,7 @@ new_addr->parent = addr; new_addr->prop = addr->prop; if (addr->child_count == USHRT_MAX) - log_write_die(0, LOG_MAIN, "%s router generated more than %d " + log_write_die(LOG_MAIN, "%s router generated more than %d " "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address); addr->child_count++; new_addr->next = *addr_new; diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c index 4191b8384..4e335c8e4 100644 --- a/src/src/routers/manualroute.c +++ b/src/src/routers/manualroute.c @@ -106,7 +106,7 @@ for (int i = 0; i < hff_count; i++) break; } if (ob->hff_code < 0) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "unrecognized setting for host_find_failed option", rblock->name); for (int i = 1; i < hff_count; i++) /* NB starts at 1 to skip "ignore" */ @@ -116,14 +116,14 @@ for (int i = 1; i < hff_count; i++) /* NB starts at 1 to skip "ignore" */ break; } if (ob->hai_code < 0) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "unrecognized setting for host_all_ignored option", rblock->name); /* One of route_list or route_data must be specified */ if ( !ob->route_list && !ob->route_data || ob->route_list && ob->route_data) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "route_list or route_data (but not both) must be specified", rblock->name); } @@ -361,7 +361,7 @@ while (*options) if (!t) { s = string_sprintf("unknown routing option or transport name %q", s); - log_write(0, LOG_MAIN, "Error in %s router: %s", rblock->drinst.name, s); + log_write(LOG_MAIN, "Error in %s router: %s", rblock->drinst.name, s); addr->message = string_sprintf("error in router: %s", s); return DEFER; } @@ -438,7 +438,7 @@ if (!hostlist[0]) if (verify != v_none) goto ROUTED; addr->message = string_sprintf("error in %s router: no host(s) specified " "for domain %s", rblock->drinst.name, addr->domain); - log_write(0, LOG_MAIN, "%s", addr->message); + log_write(LOG_MAIN, "%s", addr->message); return DEFER; } @@ -481,7 +481,7 @@ dealt with above. However, we don't need one if verifying only. */ if (!transport && verify == v_none) { - log_write(0, LOG_MAIN, "Error in %s router: no transport defined", + log_write(LOG_MAIN, "Error in %s router: no transport defined", rblock->drinst.name); addr->message = US"error in router: transport missing"; return DEFER; diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index 6cfaf0ab5..e13abaa45 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -90,13 +90,13 @@ queryprogram_router_options_block *ob = /* A command must be given */ if (!ob->command) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "a command specification is required", rblock->name); /* A uid/gid must be supplied */ if (!ob->cmd_uid_set && !ob->expand_cmd_uid) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "command_user must be specified", rblock->name); } @@ -141,7 +141,7 @@ while (generated != NULL) *addr_new = next; if (addr->child_count == USHRT_MAX) - log_write_die(0, LOG_MAIN, "%s router generated more than %d " + log_write_die(LOG_MAIN, "%s router generated more than %d " "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address); addr->child_count++; @@ -456,7 +456,7 @@ if (strcmpic(rword, US"accept") != 0) else if (strcmpic(rword, US"defer") != 0) { addr->message = string_sprintf("bad command yield: %s %s", rword, rdata); - log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); + log_write(LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); } return DEFER; } @@ -479,7 +479,7 @@ if ((s = expand_getkeyed(US"transport", rdata)) && *s) { addr->message = string_sprintf("unknown transport name %s yielded by " "command", s); - log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); + log_write(LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); return DEFER; } addr->transport = transport; @@ -511,7 +511,7 @@ if ((s = expand_getkeyed(US"hosts", rdata)) && *s) else { addr->message = string_sprintf("bad lookup type %q yielded by command", ss); - log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); + log_write(LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message); return DEFER; } } diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index f8068916a..05ec1bab2 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -151,7 +151,7 @@ redirect_router_options_block * ob = /* Either file or data must be set, but not both */ if ((ob->file == NULL) == (ob->data == NULL)) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "%sone of \"file\" or \"data\" must be specified", r->name, ob->file ? "only " : ""); @@ -164,11 +164,11 @@ if (ob->one_time) { ob->forbid_pipe = ob->forbid_file = ob->forbid_filter_reply = TRUE; if (rblock->extra_headers || rblock->remove_headers) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "\"headers_add\" and \"headers_remove\" are not permitted with " "\"one_time\"", r->name); if (rblock->unseen || rblock->expand_unseen) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "\"unseen\" may not be used with \"one_time\"", r->name); } @@ -188,7 +188,7 @@ if (ob->check_group == TRUE_UNSET) /* If explicit qualify domain set, the preserve option is locked out */ if (ob->qualify_domain && ob->qualify_preserve_domain) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "only one of \"qualify_domain\" or \"qualify_preserve_domain\" must be set", r->name); @@ -198,7 +198,7 @@ if (!rblock->check_local_user && !rblock->uid_set && rblock->expand_uid == NULL && (ob->bit_options & RDO_FILTER) != 0) - log_write_die(0, LOG_CONFIG_FOR, "%s router:\n " + log_write_die(LOG_CONFIG_FOR, "%s router:\n " "\"user\" or \"check_local_user\" must be set with \"allow_filter\"", r->name); } @@ -289,7 +289,7 @@ while (generated) next->parent = addr; next->start_router = rblock->redirect_router; if (addr->child_count == USHRT_MAX) - log_write_die(0, LOG_MAIN, "%s router generated more than %d " + log_write_die(LOG_MAIN, "%s router generated more than %d " "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address); addr->child_count++; @@ -739,7 +739,7 @@ if (frc == FF_DELIVERED) { if (generated == NULL && verify == v_none && !f.address_test_mode) { - log_write(0, LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address, + log_write(LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address, rblock->drinst.name); yield = DISCARD; } diff --git a/src/src/routers/rf_get_transport.c b/src/src/routers/rf_get_transport.c index c8519eaf8..9d28ca765 100644 --- a/src/src/routers/rf_get_transport.c +++ b/src/src/routers/rf_get_transport.c @@ -71,7 +71,7 @@ if (expandable) } if (is_tainted(ss)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to use tainted value '%s' from '%s' for transport", ss, tpname); addr->basic_errno = ERRNO_BADTRANSPORT; /* Avoid leaking info to an attacker */ diff --git a/src/src/routers/rf_self_action.c b/src/src/routers/rf_self_action.c index b5f372d96..cbc711cbd 100644 --- a/src/src/routers/rf_self_action.c +++ b/src/src/routers/rf_self_action.c @@ -77,13 +77,13 @@ switch (code) if (!message_id[0]) if (sender_fullhost) - log_write(0, LOG_MAIN, "%s: %s (while verifying <%s> from host %s)", + log_write(LOG_MAIN, "%s: %s (while verifying <%s> from host %s)", msg, addr->domain, addr->address, sender_fullhost); else - log_write(0, LOG_MAIN, "%s: %s (while routing <%s>)", msg, + log_write(LOG_MAIN, "%s: %s (while routing <%s>)", msg, addr->domain, addr->address); else - log_write(0, LOG_MAIN, "%s: %s", msg, addr->domain); + log_write(LOG_MAIN, "%s: %s", msg, addr->domain); addr->message = msg; addr->special_action = SPECIAL_FREEZE; diff --git a/src/src/search.c b/src/src/search.c index def6b4c7a..8217aea0b 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -406,7 +406,7 @@ int old_pool = store_pool; if (filename && is_tainted(filename)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Tainted filename for search: '%s'", filename); return NULL; } @@ -447,7 +447,7 @@ recently used one. */ if (li->type == lookup_absfile && open_filecount >= lookup_open_max) if (!open_bot) - log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find " + log_write(LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find " "one to close"); else { @@ -635,8 +635,7 @@ else /* If we're called from a transport, no privs to open the paniclog; the logging punts to using stderr - and that seems to stop the debug stream. */ - log_write(0, - transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC, + log_write(transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC, "tainted search query is not properly quoted%s: %s", loc, ks); DEBUG(lookup) diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index e2f23263c..8952e82e8 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -388,8 +388,9 @@ if (recipients_count > 0) raw_recipients_count = recipients_count; } -log_write(L_smtp_incomplete_transaction, LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS, - "%s incomplete transaction (%s)", host_and_ident(TRUE), what); +if (LOGGING(smtp_incomplete_transaction)) + log_write(LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS, + "%s incomplete transaction (%s)", host_and_ident(TRUE), what); } @@ -397,16 +398,18 @@ log_write(L_smtp_incomplete_transaction, LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS, static void log_close_event(const uschar * reason) { -log_write(L_smtp_connection, LOG_MAIN, "%s D=%s closed %s", - smtp_get_connection_info(), string_timesince(&smtp_connection_start), reason); +if (LOGGING(smtp_connection)) + log_write(LOG_MAIN, "%s D=%s closed %s", + smtp_get_connection_info(), string_timesince(&smtp_connection_start), + reason); } void smtp_command_timeout_exit(void) { -log_write(L_lost_incoming_connection, - LOG_MAIN, "SMTP command timeout on%s connection from %s D=%s", +if (LOGGING(lost_incoming_connection)) + log_write(LOG_MAIN, "SMTP command timeout on%s connection from %s D=%s", tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE), string_timesince(&smtp_connection_start)); if (smtp_batched_input) @@ -431,10 +434,11 @@ exim_exit(EXIT_FAILURE); void smtp_data_timeout_exit(void) { -log_write(L_lost_incoming_connection, LOG_MAIN, - "SMTP data timeout (message abandoned) on connection from %s F=<%s> D=%s", - sender_fullhost ? sender_fullhost : US"local process", sender_address, - string_timesince(&smtp_connection_start)); +if (LOGGING(lost_incoming_connection)) + log_write(LOG_MAIN, + "SMTP data timeout (message abandoned) on connection from %s F=<%s> D=%s", + sender_fullhost ? sender_fullhost : US"local process", sender_address, + string_timesince(&smtp_connection_start)); receive_bomb_out(US"data-timeout", US"SMTP incoming data timeout"); /* Does not return */ } @@ -460,7 +464,7 @@ call the local functions instead of the standard C ones. Place a NUL at the end of the buffer to safety-stop C-string reads from it. */ if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE))) - log_write_die(0, LOG_MAIN, "malloc() failed for SMTP input buffer"); + log_write_die(LOG_MAIN, "malloc() failed for SMTP input buffer"); smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0'; smtp_inptr = smtp_inend = smtp_inbuffer; @@ -607,7 +611,7 @@ int smtp_ungetc(int ch) { if (smtp_inptr <= smtp_inbuffer) /* NB: NOT smtp_hasc() ! */ - log_write_die(0, LOG_MAIN, "buffer underflow in smtp_ungetc"); + log_write_die(LOG_MAIN, "buffer underflow in smtp_ungetc"); *--smtp_inptr = ch; return ch; @@ -780,16 +784,16 @@ for(;;) incomplete_transaction_log(US"sync failure"); if (buf) - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error " + log_write(LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error " "(next input sent too soon: pipelining was not advertised): " "rejected %q %s next input=%q%s", smtp_cmd_buffer, host_and_ident(TRUE), string_printing(string_copyn(buf, nchars)), smtp_inend - smtp_inptr > 0 ? "..." : ""); else - log_write(0, LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", + log_write(LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", host_and_ident(TRUE)); - (void) synprot_error(L_smtp_protocol_error, 554, NULL, + (void) synprot_error(TRUE, 554, NULL, US"SMTP synchronization error"); goto repeat_until_rset; } @@ -817,7 +821,7 @@ next_cmd: switch(smtp_read_command(TRUE, 1)) { default: - (void) synprot_error(L_smtp_protocol_error, 503, NULL, + (void) synprot_error(TRUE, 503, NULL, US"only BDAT permissible after non-LAST BDAT"); repeat_until_rset: @@ -826,7 +830,7 @@ next_cmd: case QUIT_CMD: smtp_quit_handler(&user_msg, &log_msg); /*FALLTHROUGH */ case EOF_CMD: return EOF; case RSET_CMD: smtp_rset_handler(); return ERR; - default: if (synprot_error(L_smtp_protocol_error, 503, NULL, + default: if (synprot_error(TRUE, 503, NULL, US"only RSET accepted now") > 0) return ERR; goto repeat_until_rset; @@ -853,7 +857,7 @@ next_cmd: if (sscanf(CS smtp_cmd_data, "%u %n", &chunking_datasize, &n) < 1) { - (void) synprot_error(L_smtp_protocol_error, 501, NULL, + (void) synprot_error(TRUE, 501, NULL, US"missing size for BDAT command"); return ERR; } @@ -868,7 +872,7 @@ next_cmd: return EOD; else { - (void) synprot_error(L_smtp_protocol_error, 504, NULL, + (void) synprot_error(TRUE, 504, NULL, US"zero size for BDAT command"); goto repeat_until_rset; } @@ -1035,7 +1039,7 @@ DEBUG(receive) for (const uschar * t, * s = gs.s; if (!yield) { - log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_printf()"); + log_write(LOG_MAIN|LOG_PANIC, "string too large in smtp_printf()"); smtp_closedown(US"Unexpected error"); exim_exit(EXIT_FAILURE); } @@ -1425,7 +1429,7 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED)) break; case BADARG_CMD: - if (synprot_error(L_smtp_syntax_error, 501, NULL, + if (synprot_error(FALSE, 501, NULL, US"unexpected argument data") > 0) return; break; @@ -1603,7 +1607,7 @@ if (sender_host_authenticated) g = add_tls_info_for_log(g); g = s_connhad_log(g); -log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%#Y", +log_write(LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%#Y", f.tcp_in_fastopen ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " : US"", host_and_ident(FALSE), string_timesince(&smtp_connection_start), g); } @@ -2131,7 +2135,7 @@ const uschar * conn_info = smtp_get_connection_info(); if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5; /* I'd like to get separated H= here, but too hard for now */ -log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr); +log_write(LOG_MAIN, "TLS error on %s %s", conn_info, errstr); return FALSE; } #endif @@ -2211,9 +2215,8 @@ else DEBUG(receive) static void log_connect_tls_drop(const uschar * what, const uschar * log_msg) { -if (log_reject_target) - log_write(L_connection_reject, - log_reject_target, "%s%s%#Y dropped by %s%s%s", +if (log_reject_target && LOGGING(connection_reject)) + log_write(log_reject_target, "%s%s%#Y dropped by %s%s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), add_tls_info_for_log(NULL), @@ -2339,11 +2342,11 @@ bad_srr: break; } *p = '\0'; -log_write(0, LOG_MAIN, "%s", big_buffer); +log_write(LOG_MAIN, "%s", big_buffer); /* Refuse any call with IP options. This is what tcpwrappers 7.5 does. */ -log_write(0, LOG_MAIN|LOG_REJECT, +log_write(LOG_MAIN|LOG_REJECT, "connection from %s refused (IP options)", host_and_ident(FALSE)); smtp_printf("554 SMTP service not available\r\n", SP_NO_MORE); @@ -2479,10 +2482,10 @@ thismessage_size_limit = expand_string_integer(message_size_limit, TRUE); if (expand_string_message) { if (thismessage_size_limit == -1) - log_write(0, LOG_MAIN|LOG_PANIC, "unable to expand message_size_limit: " + log_write(LOG_MAIN|LOG_PANIC, "unable to expand message_size_limit: " "%s", expand_string_message); else - log_write(0, LOG_MAIN|LOG_PANIC, "invalid message_size_limit: " + log_write(LOG_MAIN|LOG_PANIC, "invalid message_size_limit: " "%s", expand_string_message); smtp_closedown(US"Temporary local problem - please try later"); return FALSE; @@ -2556,7 +2559,7 @@ if (!f.sender_host_unknown) { if (errno != ENOPROTOOPT) { - log_write(0, LOG_MAIN, "getsockopt() failed from %s: %s", + log_write(LOG_MAIN, "getsockopt() failed from %s: %s", host_and_ident(FALSE), strerror(errno)); smtp_printf("451 SMTP service not available\r\n", SP_NO_MORE); return FALSE; @@ -2609,7 +2612,7 @@ if (!f.sender_host_unknown) || !(*exp) || (smtp_receive_timeout = readconf_readtime(exp, 0, FALSE)) < 0 ) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "bad value for smtp_receive_timeout: '%s'", exp ? exp : US""); } @@ -2617,8 +2620,9 @@ if (!f.sender_host_unknown) if (verify_check_host(&host_reject_connection) == OK) { - log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "refused connection " - "from %s (host_reject_connection)", host_and_ident(FALSE)); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN|LOG_REJECT, "refused connection " + "from %s (host_reject_connection)", host_and_ident(FALSE)); #ifndef DISABLE_TLS if (!tls_in.on_connect) #endif @@ -2634,11 +2638,12 @@ if (!f.sender_host_unknown) { if ((rc = verify_check_host(&smtp_reserve_hosts)) != OK) { - log_write(L_connection_reject, - LOG_MAIN, "temporarily refused connection from %s: not in " - "reserve list: connected=%d max=%d reserve=%d%s", - host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max, - smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : ""); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN, + "temporarily refused connection from %s: not in " + "reserve list: connected=%d max=%d reserve=%d%s", + host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max, + smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : ""); smtp_printf("421 %s: Too many concurrent SMTP connections; " "please try again later\r\n", SP_NO_MORE, smtp_active_hostname); return FALSE; @@ -2657,10 +2662,11 @@ if (!f.sender_host_unknown) !reserved_host && verify_check_host(&smtp_reserve_hosts) != OK) { - log_write(L_connection_reject, - LOG_MAIN, "temporarily refused connection from %s: not in " - "reserve list and load average = %.2f", host_and_ident(FALSE), - (double)load_average/1000.0); + if (LOGGING(connection_reject)) + log_write(LOG_MAIN, + "temporarily refused connection from %s: not in " + "reserve list and load average = %.2f", host_and_ident(FALSE), + (double)load_average/1000.0); smtp_printf("421 %s: Too much load; please try again later\r\n", SP_NO_MORE, smtp_active_hostname); return FALSE; @@ -2767,7 +2773,7 @@ else GET_OPTION("smtp_banner"); if (!(s = expand_string(smtp_banner))) { - log_write(0, f.expand_string_forcedfail ? LOG_MAIN : LOG_MAIN|LOG_PANIC_DIE, + log_write(f.expand_string_forcedfail ? LOG_MAIN : LOG_MAIN|LOG_PANIC_DIE, "Expansion of %q (smtp_banner) failed: %s", smtp_banner, expand_string_message); /* for force-fail */ @@ -2843,7 +2849,7 @@ if (gstring_length(ss) == 0) /* banner already sent */ if (f.running_in_test_harness) /* make visible to testsuite */ { for (int i = 20; i && check_sync(WBR_DATA_OR_EOF); i--) millisleep(5); - log_write(0, LOG_MAIN, "Ci=%s SMTP peer appears to have %s our banner", + log_write(LOG_MAIN, "Ci=%s SMTP peer appears to have %s our banner", connection_id, check_sync(WBR_DATA_OR_EOF) ? "NOT SEEN" : "seen"); } } @@ -2865,12 +2871,12 @@ else /* not already sent */ uschar * buf = receive_getbuf(&nchars); /* destructive read */ if (buf) - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol " + log_write(LOG_MAIN|LOG_REJECT, "SMTP protocol " "synchronization error (input sent without waiting for greeting): " "rejected connection from %s input=%q", host_and_ident(TRUE), string_printing(string_copyn(buf, nchars))); else - log_write(0, LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", + log_write(LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", host_and_ident(TRUE)); smtp_printf("554 SMTP synchronization error\r\n", SP_NO_MORE); return FALSE; @@ -2911,7 +2917,7 @@ to do so. Then transmit the error response. The return value depends on the number of syntax and protocol errors in this SMTP session. Arguments: - type error type, given as a log flag bit + type error type: TRUE for protocol, FALSE for syntax code response code; <= 0 means don't send a response data data to reflect in the response (can be NULL) errmess the error message @@ -2923,10 +2929,10 @@ These values fit in with the values of the "done" variable in the main processing loop in smtp_setup_msg(). */ int -synprot_error(int type, int code, uschar *data, uschar *errmess) +synprot_error(BOOL type, int code, uschar *data, uschar *errmess) { int yield = -1; -BOOL syntax_error = type == L_smtp_syntax_error; +BOOL syntax_error = !type; #ifndef DISABLE_EVENT event_raise(event_action, @@ -2934,15 +2940,16 @@ event_raise(event_action, errmess, NULL); #endif -log_write(type, LOG_MAIN, "SMTP %s error in %q %s %s", - syntax_error ? "syntax" : "protocol", - string_printing(smtp_cmd_buffer), host_and_ident(TRUE), errmess); +if (syntax_error ? LOGGING(smtp_syntax_error) : LOGGING(smtp_protocol_error)) + log_write(LOG_MAIN, "SMTP %s error in %q %s %s", + syntax_error ? "syntax" : "protocol", + string_printing(smtp_cmd_buffer), host_and_ident(TRUE), errmess); GET_OPTION("smtp_max_synprot_errors"); if (++synprot_error_count > smtp_max_synprot_errors) { yield = 1; - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " + log_write(LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " "syntax or protocol errors (last command was %q, %Y)", host_and_ident(FALSE), string_printing(smtp_cmd_buffer), s_connhad_log(NULL) @@ -3088,7 +3095,7 @@ if (!msg || !*msg || !regex_match(regex_smtp_code, *msg, -1, &match)) len = Ustrlen(match); if (check_valid && (*msg)[0] != (*code)[0]) { - log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with " + log_write(LOG_MAIN|LOG_PANIC, "configured error code starts with " "incorrect digit (expected %c) in %q", (*code)[0], *msg); if (log_msg && *log_msg == *msg) *log_msg = string_sprintf("%s %s", *code, *log_msg + len); @@ -3218,7 +3225,7 @@ if (sender_verified_failed && setflag(sender_verified_failed, af_sverify_told); if (rc != FAIL || LOGGING(sender_verify_fail)) - log_write(0, LOG_MAIN|LOG_REJECT, "%s sender verify %s for <%s>%s", + log_write(LOG_MAIN|LOG_REJECT, "%s sender verify %s for <%s>%s", host_and_ident(TRUE), ((sender_verified_failed->special_action & 255) == DEFER)? "defer":"fail", sender_verified_failed->address, @@ -3291,9 +3298,9 @@ smtp_fflush(SFF_UNCORK); the connection is not forcibly to be dropped, return 0. Otherwise, log why it is closing if required and return 2. */ -if (log_reject_target) - log_write(where == ACL_WHERE_CONNECT ? L_connection_reject : 0, - log_reject_target, "%s%s%#Y%s%#Y%#Y%#Y %srejected %s%s", +if ( log_reject_target + && (where != ACL_WHERE_CONNECT || LOGGING(connection_reject))) + log_write(log_reject_target, "%s%s%#Y%s%#Y%#Y%#Y %srejected %s%s", LOGGING(dnssec) && sender_host_dnssec ? US" DS" : US"", host_and_ident(TRUE), add_tls_info_for_log(NULL), @@ -3371,7 +3378,7 @@ we get when the line goes on to drop when CHUNKING. */ if (smtp_notquit_reason) { #ifdef notdef - log_write(0, LOG_PANIC, + log_write(LOG_PANIC, "smtp_notquit_exit() called more than once (%s, prev: %s)", reason, smtp_notquit_reason); #endif @@ -3385,7 +3392,7 @@ GET_OPTION("acl_smtp_notquit"); if (acl_smtp_notquit && reason) if (acl_check(ACL_WHERE_NOTQUIT, NULL, acl_smtp_notquit, &user_msg, &log_msg) == ERROR) - log_write(0, LOG_MAIN|LOG_PANIC, "ACL for not-QUIT returned ERROR: %s", + log_write(LOG_MAIN|LOG_PANIC, "ACL for not-QUIT returned ERROR: %s", log_msg); /* Write an SMTP response if we are expected to give one. As the default @@ -3703,9 +3710,9 @@ if (f.allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0) } smtp_printf("501 %s: recipient address must contain a domain\r\n", SP_NO_MORE, smtp_cmd_data); -log_write(L_smtp_syntax_error, - LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s", - tag, *recipient, host_and_ident(TRUE), host_lookup_msg); +if (LOGGING(smtp_syntax_error)) + log_write(LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s", + tag, *recipient, host_and_ident(TRUE), host_lookup_msg); return 0; } @@ -3722,7 +3729,7 @@ GET_OPTION("acl_smtp_quit"); if ( acl_smtp_quit && acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp) == ERROR) - log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s", + log_write(LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s", *log_msgp); #ifdef EXIM_TCP_CORK @@ -3808,7 +3815,7 @@ if (verify_check_host(&wellknown_advertise_hosts) != FAIL) } smtp_printf("554 not permitted\r\n", SP_NO_MORE); -log_write(0, LOG_MAIN|LOG_REJECT, "rejected %q from %s", +log_write(LOG_MAIN|LOG_REJECT, "rejected %q from %s", smtp_cmd_buffer, sender_helo_name, host_and_ident(FALSE)); return 0; } @@ -3819,7 +3826,7 @@ static int expand_mailmax(const uschar * s) { if (!(s = expand_string(s))) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand smtp_accept_max_per_connection"); + log_write(LOG_MAIN|LOG_PANIC, "failed to expand smtp_accept_max_per_connection"); return *s ? Uatoi(s) : 0; } @@ -3835,11 +3842,12 @@ void (*oldsignal)(int); pid_t pid; if (sender_address) - return synprot_error(L_smtp_protocol_error, 503, NULL, + return synprot_error(TRUE, 503, NULL, US"ETRN is not permitted inside a transaction"); -log_write(L_etrn, LOG_MAIN, "ETRN %s received from %s", smtp_cmd_argument, - host_and_ident(FALSE)); +if (LOGGING(etrn)) + log_write(LOG_MAIN, "ETRN %s received from %s", smtp_cmd_argument, + host_and_ident(FALSE)); GET_OPTION("acl_smtp_etrn"); if ((rc = acl_check(ACL_WHERE_ETRN, NULL, acl_smtp_etrn, @@ -3880,7 +3888,7 @@ if (smtp_etrn_command) deliver_domain = NULL; if (!rc) { - log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s", error); smtp_printf("458 Internal failure\r\n", SP_NO_MORE); return 0; @@ -3892,7 +3900,7 @@ if (smtp_etrn_command) else { if (*smtp_cmd_data++ != '#') - return synprot_error(L_smtp_syntax_error, 501, NULL, + return synprot_error(FALSE, 501, NULL, US"argument must begin with #"); etrn_command = US"exim -R"; @@ -3954,7 +3962,7 @@ if ((pid = exim_fork(US"etrn-command")) == 0) exim_nullstd(); /* Ensure std{in,out,err} exist */ /* argv[0] should be untainted, from child_exec_exim() */ execv(CS argv[0], (char *const *)argv); - log_write_die(0, LOG_MAIN, "exec of %q (ETRN) failed: %s", + log_write_die(LOG_MAIN, "exec of %q (ETRN) failed: %s", etrn_command, strerror(errno)); _exit(EXIT_FAILURE); /* paranoia */ } @@ -3965,7 +3973,7 @@ if ((pid = exim_fork(US"etrn-command")) == 0) complete, before removing the serialization. */ if (pid < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "2nd fork for serialized ETRN " + log_write(LOG_MAIN|LOG_PANIC, "2nd fork for serialized ETRN " "failed: %s", strerror(errno)); else { @@ -3986,7 +3994,7 @@ and restore the signal state. */ if (pid < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s", strerror(errno)); smtp_printf("458 Unable to fork process\r\n", SP_NO_MORE); if (smtp_etrn_serialize) enq_end(etrn_serialize_key); @@ -4128,7 +4136,7 @@ while (done <= 0) uschar * save_name = sender_host_authenticated, * logmsg; sender_host_authenticated = au->drinst.name; if ((logmsg = event_raise(event_action, US"auth:fail", s, NULL))) - log_write(0, LOG_MAIN, "%s", logmsg); + log_write(LOG_MAIN, "%s", logmsg); sender_host_authenticated = save_name; } #endif @@ -4168,19 +4176,19 @@ while (done <= 0) if (!fl.auth_advertised && !f.allow_auth_unadvertised) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"AUTH command used when not advertised"); break; } if (sender_host_authenticated) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"already authenticated"); break; } if (sender_address) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"not permitted in mail transaction"); break; } @@ -4203,7 +4211,7 @@ while (done <= 0) for (; (c = *smtp_cmd_data) && !isspace(c); smtp_cmd_data++) if (!isalnum(c) && c != '-' && c != '_') { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"invalid character in authentication mechanism name"); goto COMMAND_LOOP; } @@ -4246,14 +4254,14 @@ while (done <= 0) } #endif if (logmsg) - log_write(0, LOG_MAIN|LOG_REJECT, "%s", logmsg); + log_write(LOG_MAIN|LOG_REJECT, "%s", logmsg); else - log_write(0, LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s", + log_write(LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s", au->drinst.name, host_and_ident(TRUE), errmsg); } } else - done = synprot_error(L_smtp_protocol_error, 504, NULL, + done = synprot_error(TRUE, 504, NULL, string_sprintf("%s authentication mechanism not supported", s)); } @@ -4297,7 +4305,7 @@ while (done <= 0) { smtp_printf("501 Syntactically invalid %s argument(s)\r\n", SP_NO_MORE, hello); - log_write(0, LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically " + log_write(LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically " "invalid argument(s): %s", hello, host_and_ident(FALSE), *smtp_cmd_argument == 0 ? US"(no argument given)" : string_printing(smtp_cmd_argument)); @@ -4305,7 +4313,7 @@ while (done <= 0) GET_OPTION("smtp_max_synprot_errors"); if (++synprot_error_count > smtp_max_synprot_errors) { - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " + log_write(LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " "syntax or protocol errors (last command was %q, %Y)", host_and_ident(FALSE), string_printing(smtp_cmd_buffer), s_connhad_log(NULL) @@ -4363,7 +4371,7 @@ while (done <= 0) { smtp_printf("%d %s argument does not match calling host\r\n", SP_NO_MORE, tempfail? 451 : 550, hello); - log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s", + log_write(LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s", tempfail? "temporarily " : "", hello, sender_helo_name, host_and_ident(FALSE)); f.helo_verified = old_helo_verified; @@ -4456,7 +4464,7 @@ while (done <= 0) s = string_sprintf("%.*s%s", codelen, smtp_code, user_msg); if ((t= strpbrk(CS s, "\r\n")) != NULL) { - log_write(0, LOG_MAIN|LOG_PANIC, "EHLO/HELO response must not contain " + log_write(LOG_MAIN|LOG_PANIC, "EHLO/HELO response must not contain " "newlines: message truncated: %s", string_printing(s)); *t = '\0'; } @@ -4749,7 +4757,7 @@ while (done <= 0) smtp_mailcmd_count++; if (!xclient_mi) - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"XCLIENT command used when not advertised"); else { @@ -4780,9 +4788,9 @@ while (done <= 0) if ( fl.helo_verify_required || verify_check_host(&hosts_require_helo) == OK) { - log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no " + log_write(LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no " "HELO/EHLO given", host_and_ident(FALSE)); - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"HELO or EHLO required"); break; } @@ -4791,14 +4799,14 @@ while (done <= 0) if (sender_address) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"sender already given"); break; } if (!*smtp_cmd_data) { - done = synprot_error(L_smtp_protocol_error, 501, NULL, + done = synprot_error(TRUE, 501, NULL, US"MAIL must have an address operand"); break; } @@ -4809,7 +4817,7 @@ while (done <= 0) if (smtp_mailcmd_max > 0 && smtp_mailcmd_count > smtp_mailcmd_max) { smtp_printf("421 too many messages in this connection\r\n", SP_NO_MORE); - log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many " + log_write(LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many " "messages in one connection", host_and_ident(TRUE)); break; } @@ -4875,7 +4883,7 @@ while (done <= 0) else { body_8bitmime = 0; - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"invalid data for BODY"); goto COMMAND_LOOP; } @@ -4894,7 +4902,7 @@ while (done <= 0) /* Check if RET has already been set */ if (dsn_ret > 0) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"RET can be specified once only"); goto COMMAND_LOOP; } @@ -4907,7 +4915,7 @@ while (done <= 0) /* Check for invalid invalid value, and exit with error */ if (dsn_ret == 0) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"Value for RET is invalid"); goto COMMAND_LOOP; } @@ -4919,7 +4927,7 @@ while (done <= 0) /* Check if the dsn envid has been already set */ if (dsn_envid) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"ENVID can be specified once only"); goto COMMAND_LOOP; } @@ -4946,7 +4954,7 @@ while (done <= 0) /* Put back terminator overrides for error message */ value[-1] = '='; name[-1] = ' '; - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"invalid data for AUTH"); goto COMMAND_LOOP; } @@ -4981,7 +4989,7 @@ while (done <= 0) case FAIL: authenticated_sender = NULL; - log_write(0, LOG_MAIN, "ignoring AUTH=%s from %s (%s)", + log_write(LOG_MAIN, "ignoring AUTH=%s from %s (%s)", value, host_and_ident(TRUE), ignore_msg); break; @@ -5009,7 +5017,7 @@ while (done <= 0) case ENV_MAIL_OPT_UTF8: if (!fl.smtputf8_advertised) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"SMTPUTF8 used when not advertised"); goto COMMAND_LOOP; } @@ -5072,7 +5080,7 @@ while (done <= 0) if (!raw_sender) { - done = synprot_error(L_smtp_syntax_error, 501, smtp_cmd_data, errmess); + done = synprot_error(FALSE, 501, smtp_cmd_data, errmess); break; } @@ -5085,13 +5093,11 @@ while (done <= 0) if (thismessage_size_limit > 0 && message_size > thismessage_size_limit) { smtp_printf("552 Message size exceeds maximum permitted\r\n", SP_NO_MORE); - log_write(L_size_reject, - LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: " - "message too big: size%s=%d max=%d", - sender_address, - host_and_ident(TRUE), - (message_size == INT_MAX)? ">" : "", - message_size, + if (LOGGING(size_reject)) + log_write(LOG_MAIN|LOG_REJECT, + "rejected MAIL FROM:<%s> %s: message too big: size%s=%d max=%d", + sender_address, host_and_ident(TRUE), + message_size == INT_MAX ? ">" : "", message_size, thismessage_size_limit); sender_address = NULL; break; @@ -5133,12 +5139,10 @@ while (done <= 0) { smtp_printf("501 %s: sender address must contain a domain\r\n", SP_NO_MORE, smtp_cmd_data); - log_write(L_smtp_syntax_error, - LOG_MAIN|LOG_REJECT, - "unqualified sender rejected: <%s> %s%s", - raw_sender, - host_and_ident(TRUE), - host_lookup_msg); + if (LOGGING(smtp_syntax_error)) + log_write(LOG_MAIN|LOG_REJECT, + "unqualified sender rejected: <%s> %s%s", + raw_sender, host_and_ident(TRUE), host_lookup_msg); sender_address = NULL; break; } @@ -5199,7 +5203,7 @@ while (done <= 0) /* We got really to many recipients. A check against configured limits is done later */ if (rcpt_count < 0 || rcpt_count >= INT_MAX/2) - log_write_die(0, LOG_MAIN, "Too many recipients: %d", rcpt_count); + log_write_die(LOG_MAIN, "Too many recipients: %d", rcpt_count); rcpt_count++; was_rcpt = fl.rcpt_in_progress = TRUE; @@ -5217,7 +5221,7 @@ while (done <= 0) } else { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"sender not yet given"); was_rcpt = FALSE; /* Not a valid RCPT */ } @@ -5229,7 +5233,7 @@ while (done <= 0) if (!smtp_cmd_data[0]) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"RCPT must have an address operand"); rcpt_fail_count++; break; @@ -5251,7 +5255,7 @@ while (done <= 0) /* Check whether orcpt has been already set */ if (rcpt_orcpt) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"ORCPT can be specified once only"); goto COMMAND_LOOP; } @@ -5264,7 +5268,7 @@ while (done <= 0) /* Check if the notify flags have been already set */ if (rcpt_dsn_flags > 0) { - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"NOTIFY can be specified once only"); goto COMMAND_LOOP; } @@ -5296,7 +5300,7 @@ while (done <= 0) else { /* Catch any strange values */ - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"Invalid value for NOTIFY parameter"); goto COMMAND_LOOP; } @@ -5330,7 +5334,7 @@ while (done <= 0) if (!(recipient = parse_extract_address(recipient, &errmess, &start, &end, &recipient_domain, FALSE))) { - done = synprot_error(L_smtp_syntax_error, 501, smtp_cmd_data, errmess); + done = synprot_error(FALSE, 501, smtp_cmd_data, errmess); rcpt_fail_count++; break; } @@ -5364,7 +5368,7 @@ while (done <= 0) rcpt_fail_count++; smtp_printf("552 too many recipients\r\n", SP_NO_MORE); if (!toomany) - log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message " + log_write(LOG_MAIN|LOG_REJECT, "too many recipients: message " "rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE)); } else @@ -5372,7 +5376,7 @@ while (done <= 0) rcpt_defer_count++; smtp_printf("452 too many recipients\r\n", SP_NO_MORE); if (!toomany) - log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess " + log_write(LOG_MAIN|LOG_REJECT, "too many recipients: excess " "temporarily rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE)); } @@ -5442,7 +5446,7 @@ while (done <= 0) smtp_printf("250 Accepted\r\n", SP_NO_MORE); rcpt_fail_count++; discarded = TRUE; - log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: " + log_write(LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: " "discarded by %s ACL%s%s", host_and_ident(TRUE), sender_address_unrewritten ? sender_address_unrewritten : sender_address, smtp_cmd_argument, f.recipients_discarded ? "MAIL" : "RCPT", @@ -5486,7 +5490,7 @@ while (done <= 0) HAD(SCH_BDAT); if (chunking_state != CHUNKING_OFFERED) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"BDAT command used when CHUNKING not advertised"); break; } @@ -5495,7 +5499,7 @@ while (done <= 0) if (sscanf(CS smtp_cmd_data, "%u %n", &chunking_datasize, &n) < 1) { - done = synprot_error(L_smtp_protocol_error, 501, NULL, + done = synprot_error(TRUE, 501, NULL, US"missing size for BDAT command"); break; } @@ -5537,7 +5541,7 @@ while (done <= 0) smtp_printf("503 Valid RCPT command must precede %s\r\n", SP_NO_MORE, smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]]); else - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)] == SCH_DATA ? US"valid RCPT command must precede DATA" : US"valid RCPT command must precede BDAT"); @@ -5657,7 +5661,7 @@ while (done <= 0) s = addr->user_message ? string_sprintf("550 <%s> %s", address, addr->user_message) : string_sprintf("550 <%s> is not deliverable", address); - log_write(0, LOG_MAIN, "VRFY failed for %s %s", + log_write(LOG_MAIN, "VRFY failed for %s %s", smtp_cmd_argument, host_and_ident(TRUE)); break; } @@ -5693,7 +5697,7 @@ while (done <= 0) HAD(SCH_STARTTLS); if (!fl.tls_advertised) { - done = synprot_error(L_smtp_protocol_error, 503, NULL, + done = synprot_error(TRUE, 503, NULL, US"STARTTLS command used when not advertised"); break; } @@ -5903,20 +5907,22 @@ while (done <= 0) */ if (sender_address || recipients_count > 0) - log_write(L_lost_incoming_connection, LOG_MAIN, - "unexpected %s while reading SMTP command from %s%s%s D=%s", - f.sender_host_unknown ? "EOF" : "disconnection", - f.tcp_in_fastopen_logged - ? US"" - : f.tcp_in_fastopen - ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " - : US"", - host_and_ident(FALSE), errstr, - string_timesince(&smtp_connection_start) - ); - - else - log_write(L_smtp_connection, LOG_MAIN, "%s %slost%s D=%s", + { + if (LOGGING(lost_incoming_connection)) + log_write(LOG_MAIN, + "unexpected %s while reading SMTP command from %s%s%s D=%s", + f.sender_host_unknown ? "EOF" : "disconnection", + f.tcp_in_fastopen_logged + ? US"" + : f.tcp_in_fastopen + ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " + : US"", + host_and_ident(FALSE), errstr, + string_timesince(&smtp_connection_start) + ); + } + else if (LOGGING(smtp_connection)) + log_write(LOG_MAIN, "%s %slost%s D=%s", smtp_get_connection_info(), f.tcp_in_fastopen && !f.tcp_in_fastopen_logged ? US"TFO " : US"", errstr, @@ -5938,7 +5944,7 @@ while (done <= 0) break; case BADARG_CMD: - done = synprot_error(L_smtp_syntax_error, 501, NULL, + done = synprot_error(FALSE, 501, NULL, US"unexpected argument data"); break; @@ -5946,7 +5952,7 @@ while (done <= 0) /* This currently happens only for NULLs, but could be extended. */ case BADCHAR_CMD: - done = synprot_error(L_smtp_syntax_error, 0, NULL, /* Just logs */ + done = synprot_error(FALSE, 0, NULL, /* Just logs */ US"NUL character(s) present (shown as '?')"); smtp_printf("501 NUL characters are not allowed in SMTP commands\r\n", SP_NO_MORE); @@ -5963,7 +5969,7 @@ while (done <= 0) if (buf) { buf[nchars] = '\0'; - log_write(0, LOG_MAIN|LOG_REJECT, + log_write(LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error " "(next input sent too soon: pipelining was%s advertised): " "rejected %q %s next input=%q (%u bytes)", @@ -5972,7 +5978,7 @@ while (done <= 0) string_printing(buf), nchars); } else - log_write(0, LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", + log_write(LOG_MAIN|LOG_REJECT, "Error or EOF on input from %s", host_and_ident(TRUE)); smtp_notquit_exit(US"synchronization-error", US"554", US"SMTP synchronization error"); @@ -5985,7 +5991,7 @@ while (done <= 0) s = smtp_cmd_buffer; Uskip_nonwhite(&s); incomplete_transaction_log(US"too many non-mail commands"); - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " + log_write(LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " "nonmail commands (last was \"%.*s\")", host_and_ident(FALSE), (int)(s - smtp_cmd_buffer), smtp_cmd_buffer); smtp_notquit_exit(US"bad-commands", US"554", US"Too many nonmail commands"); @@ -6002,20 +6008,21 @@ while (done <= 0) GET_OPTION("smtp_max_unknown_commands"); if (unknown_command_count++ >= smtp_max_unknown_commands) { - log_write(L_smtp_syntax_error, LOG_MAIN, - "SMTP syntax error in %q %s %s", - string_printing(smtp_cmd_buffer), host_and_ident(TRUE), - US"unrecognized command"); + if (LOGGING(smtp_syntax_error)) + log_write(LOG_MAIN, + "SMTP syntax error in %q %s %s", + string_printing(smtp_cmd_buffer), host_and_ident(TRUE), + US"unrecognized command"); incomplete_transaction_log(US"unrecognized command"); smtp_notquit_exit(US"bad-commands", US"500", US"Too many unrecognized commands"); done = 2; - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " + log_write(LOG_MAIN|LOG_REJECT, "SMTP call from %s dropped: too many " "unrecognized commands (last was %q)", host_and_ident(FALSE), string_printing(smtp_cmd_buffer)); } else - done = synprot_error(L_smtp_syntax_error, 500, NULL, + done = synprot_error(FALSE, 500, NULL, US"unrecognized command"); break; } diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 146b97e3e..78f20e705 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -57,7 +57,7 @@ if (!(expint = expand_string(istring))) if (is_tainted(expint)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to use tainted value '%s' from '%s' for interface", expint, istring); addr->transport_return = PANIC; @@ -425,7 +425,7 @@ if (!save_errno) sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port); else { - log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), + log_write(LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), "getsockname() failed: %s", strerror(errno)); close(sock); return -1; @@ -514,7 +514,7 @@ if (ob->socks_proxy) { if (!(ob->socks_proxy = expand_string(ob->socks_proxy))) { - log_write(0, LOG_MAIN|LOG_PANIC, "Bad expansion for socks_proxy in %s", + log_write(LOG_MAIN|LOG_PANIC, "Bad expansion for socks_proxy in %s", sc->tblock->drinst.name); return -1; } @@ -559,7 +559,7 @@ HDEBUG(transport|acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, if (!(cctx = outblock->cctx)) { - log_write(0, LOG_MAIN|LOG_PANIC, "null conn-context pointer"); + log_write(LOG_MAIN|LOG_PANIC, "null conn-context pointer"); errno = 0; return FALSE; } @@ -665,12 +665,12 @@ if (format) va_start(ap, format); if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, CS format, ap)) - log_write_die(0, LOG_MAIN, "overlong write_command in outgoing " + log_write_die(LOG_MAIN, "overlong write_command in outgoing " "SMTP"); va_end(ap); if (gs.ptr > outblock->buffersize) - log_write_die(0, LOG_MAIN, "overlong write_command in outgoing " + log_write_die(LOG_MAIN, "overlong write_command in outgoing " "SMTP"); if (gs.ptr > outblock->buffersize - (outblock->ptr - outblock->buffer)) diff --git a/src/src/spam.c b/src/src/spam.c index 7f5f0ba42..df2365945 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -123,12 +123,12 @@ if (Ustrncmp(param, "retry=", 6) == 0) return 0; } -log_write(0, LOG_MAIN, "%s warning - invalid spamd parameter: '%s'", +log_write(LOG_MAIN, "%s warning - invalid spamd parameter: '%s'", loglabel, param); return -1; /* syntax error */ badval: - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s warning - invalid spamd %s value: '%s'", loglabel, name, s); return -1; /* syntax error */ } @@ -168,7 +168,7 @@ for (long rnd = random_number(weights), i = 0; i < num_servers; i++) return i; } -log_write(0, LOG_MAIN|LOG_PANIC, +log_write(LOG_MAIN|LOG_PANIC, "%s unknown error (memory/cpu corruption?)", loglabel); return -1; } @@ -216,7 +216,7 @@ if (*spamd_address != '$') spamd_address_work = spamd_address; else if (!(spamd_address_work = expand_string(spamd_address))) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s spamd_address starts with $, but expansion failed: %s", loglabel, expand_string_message); return DEFER; @@ -239,7 +239,7 @@ if (spam_ok && Ustrcmp(cached_user_name, user_name) == 0) if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL))) { /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s error while creating mbox spool file", loglabel); return DEFER; } @@ -285,7 +285,7 @@ start = time(NULL); } if (args < 2) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s warning - invalid spamd address: '%s'", loglabel, address); continue; } @@ -298,7 +298,7 @@ start = time(NULL); /* check if we have at least one server */ if (!num_servers) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s no useable spamd server addresses in spamd_address configuration option.", loglabel); goto defer; @@ -325,13 +325,13 @@ start = time(NULL); if (spamd_cctx.sock >= 0) break; - log_write(0, LOG_MAIN, "%s spamd: %s", loglabel, errstr); + log_write(LOG_MAIN, "%s spamd: %s", loglabel, errstr); sd->is_failed = TRUE; current_server = spamd_get_server(spamd_address_vector, num_servers); if (current_server < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "%s all spamd servers failed", loglabel); + log_write(LOG_MAIN|LOG_PANIC, "%s all spamd servers failed", loglabel); goto defer; } sd = spamd_address_vector[current_server]; @@ -378,7 +378,7 @@ else if (wrote == -1) { (void)close(spamd_cctx.sock); - log_write(0, LOG_MAIN|LOG_PANIC, "%s spamd %s send failed: %s", + log_write(LOG_MAIN|LOG_PANIC, "%s spamd %s send failed: %s", loglabel, callout_address, strerror(errno)); goto defer; } @@ -413,13 +413,13 @@ again: else if (result < 1) { if (result == -1) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s %s on spamd %s socket", loglabel, callout_address, strerror(errno)); else { if (time(NULL) - start < sd->timeout) goto again; - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s timed out writing spamd %s, socket", loglabel, callout_address); } (void)close(spamd_cctx.sock); @@ -429,7 +429,7 @@ again: wrote = send(spamd_cctx.sock,spamd_buffer + offset,read - offset,0); if (wrote == -1) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s %s on spamd %s socket", loglabel, callout_address, strerror(errno)); (void)close(spamd_cctx.sock); goto defer; @@ -445,7 +445,7 @@ while (!feof(mbox_file) && !ferror(mbox_file)); if (ferror(mbox_file)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s error reading spool file: %s", loglabel, strerror(errno)); (void)close(spamd_cctx.sock); goto defer; @@ -468,7 +468,7 @@ spamd_buffer[offset] = '\0'; /* guard byte */ /* error handling */ if (errno != 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s error reading from spamd %s, socket: %s", loglabel, callout_address, strerror(errno)); (void)close(spamd_cctx.sock); return DEFER; @@ -487,7 +487,7 @@ if (sd->is_rspamd) || spamd_report_offset >= offset /* verify within buffer */ ) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s cannot parse spamd %s, output: %d", loglabel, callout_address, r); return DEFER; } @@ -516,7 +516,7 @@ else "SPAMD/%7s 0 EX_OK\r\nSpam: %*s ; %lf / %lf\r\n\r\n%n", spamd_version,&spamd_score,&spamd_threshold,&spamd_report_offset) != 3) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s cannot parse spamd %s output", loglabel, callout_address); return DEFER; } diff --git a/src/src/spool_in.c b/src/src/spool_in.c index fca9e129b..d340ebbb1 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -71,7 +71,7 @@ for (int i = 0; i < 2; i++) { if (i == 0) continue; if (!f.queue_running) - log_write(0, LOG_MAIN, "Spool%s%s file %s-D not found", + log_write(LOG_MAIN, "Spool%s%s file %s-D not found", *queue_name ? US" Q=" : US"", *queue_name ? queue_name : US"", id); @@ -82,7 +82,7 @@ for (int i = 0; i < 2; i++) id); } else - log_write(0, LOG_MAIN, "Spool error for %s: %s", fname, strerror(errno)); + log_write(LOG_MAIN, "Spool error for %s: %s", fname, strerror(errno)); errno = save_errno; return -1; } @@ -106,7 +106,8 @@ lock_data.l_len = spool_data_start_offset(id); if (fcntl(fd, F_SETLK, &lock_data) < 0) { - log_write(L_skip_delivery, LOG_MAIN, + if (LOGGING(skip_delivery)) + log_write(LOG_MAIN, "Spool file for %s is locked (another process is handling this message)", id); (void)close(fd); diff --git a/src/src/spool_mbox.c b/src/src/spool_mbox.c index 425f36e9f..bc4fe0a8d 100644 --- a/src/src/spool_mbox.c +++ b/src/src/spool_mbox.c @@ -54,7 +54,7 @@ if (!spool_mbox_ok) s = string_sprintf("scan/%s", message_id); if (!directory_make(spool_directory, s, 0750, FALSE)) { - log_write(0, LOG_MAIN|LOG_PANIC, "%s", + log_write(LOG_MAIN|LOG_PANIC, "%s", string_open_failed("scan directory %s/scan/%s", spool_directory, s)); goto OUT; } @@ -63,7 +63,7 @@ if (!spool_mbox_ok) if (!(mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE))) { - log_write(0, LOG_MAIN|LOG_PANIC, "%s", + log_write(LOG_MAIN|LOG_PANIC, "%s", string_open_failed("scan file %s", mbox_path)); goto OUT; } @@ -81,7 +81,7 @@ if (!spool_mbox_ok) if (s) if (fwrite(s, Ustrlen(s), 1, mbox_file) != 1) { - log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \ + log_write(LOG_MAIN|LOG_PANIC, "Error/short write while writing \ mailbox headers to %s", mbox_path); goto OUT; } @@ -93,7 +93,7 @@ if (!spool_mbox_ok) if (my_headerlist->type != '*') if (fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file) != 1) { - log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \ + log_write(LOG_MAIN|LOG_PANIC, "Error/short write while writing \ message headers to %s", mbox_path); goto OUT; } @@ -102,7 +102,7 @@ if (!spool_mbox_ok) if (fwrite("\n", 1, 1, mbox_file) != 1) { - log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \ + log_write(LOG_MAIN|LOG_PANIC, "Error/short write while writing \ message headers to %s", mbox_path); goto OUT; } @@ -125,7 +125,7 @@ if (!spool_mbox_ok) if (!l_data_file) { - log_write(0, LOG_MAIN|LOG_PANIC, "Could not open datafile for message %s", + log_write(LOG_MAIN|LOG_PANIC, "Could not open datafile for message %s", message_id); goto OUT; } @@ -166,7 +166,7 @@ if (!spool_mbox_ok) if (j > 0) if (fwrite(buffer, j, 1, mbox_file) != 1) { - log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \ + log_write(LOG_MAIN|LOG_PANIC, "Error/short write while writing \ message body to %s", mbox_path); goto OUT; } @@ -185,7 +185,7 @@ if (!spool_mbox_ok) if ( !(yield = Ufopen(mbox_path,"rb")) || fstat(fileno(yield), &statbuf) != 0 ) - log_write(0, LOG_MAIN|LOG_PANIC, "%s", + log_write(LOG_MAIN|LOG_PANIC, "%s", string_open_failed( "scan file %s", mbox_path)); else *mbox_file_size = statbuf.st_size; @@ -231,14 +231,14 @@ if (spool_mbox_ok && !f.no_mbox_unspool) file_path = string_sprintf("%s/%s", mbox_path, name); debug_printf("unspool_mbox(): unlinking '%s'\n", file_path); if (unlink(CS file_path) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, "unlink(%s): %s", file_path, strerror(errno)); + log_write(LOG_MAIN|LOG_PANIC, "unlink(%s): %s", file_path, strerror(errno)); } closedir(tempdir); /* remove directory */ if (rmdir(CS mbox_path) != 0) - log_write(0, LOG_MAIN|LOG_PANIC, "rmdir(%s): %s", mbox_path, strerror(errno)); + log_write(LOG_MAIN|LOG_PANIC, "rmdir(%s): %s", mbox_path, strerror(errno)); store_reset(reset_point); } spool_mbox_ok = 0; diff --git a/src/src/spool_out.c b/src/src/spool_out.c index 124c6fb1d..81be7198b 100644 --- a/src/src/spool_out.c +++ b/src/src/spool_out.c @@ -52,7 +52,7 @@ if (f) (void)fclose(f); if (errmsg) *errmsg = msg; else - log_write_die(0, LOG_MAIN, "%s", msg); + log_write_die(LOG_MAIN, "%s", msg); return -1; } @@ -465,7 +465,7 @@ uschar * fname = spool_fname(string_sprintf("%s%s", from, dir), subdir, id, suff uschar * tname = spool_q_fname(string_sprintf("%s%s", to, dir), dq, subdir, id, suffix); if (Ulink(fname, tname) < 0 && (!noentok || errno != ENOENT)) { - log_write(0, LOG_MAIN|LOG_PANIC, "link(%q, %q) failed while moving " + log_write(LOG_MAIN|LOG_PANIC, "link(%q, %q) failed while moving " "message: %s", fname, tname, strerror(errno)); return FALSE; } @@ -501,7 +501,7 @@ break_link(const uschar * dir, const uschar * subdir, const uschar * id, uschar * fname = spool_fname(string_sprintf("%s%s", from, dir), subdir, id, suffix); if (Uunlink(fname) < 0 && (!noentok || errno != ENOENT)) { - log_write(0, LOG_MAIN|LOG_PANIC, "unlink(%q) failed while moving " + log_write(LOG_MAIN|LOG_PANIC, "unlink(%q) failed while moving " "message: %s", fname, strerror(errno)); return FALSE; } @@ -565,7 +565,7 @@ if (!break_link(US"input", subdir, id, US"-H", from, FALSE) || !break_link(US"msglog", subdir, id, US"", from, TRUE)) return FALSE; -log_write(0, LOG_MAIN, "moved from %s%s%s%sinput, %smsglog to %s%s%s%sinput, %smsglog", +log_write(LOG_MAIN, "moved from %s%s%s%sinput, %smsglog to %s%s%s%sinput, %smsglog", *queue_name?"(":"", *queue_name?queue_name:US"", *queue_name?") ":"", from, from, *dest_qname?"(":"", *dest_qname?dest_qname:US"", *dest_qname?") ":"", diff --git a/src/src/std-crypto.c b/src/src/std-crypto.c index 29efa6997..127f7ab34 100644 --- a/src/src/std-crypto.c +++ b/src/src/std-crypto.c @@ -1017,7 +1017,7 @@ for (int first = 0, last = dh_constants_count; last > first; ) if (c == 0) { if (dp->logging) - log_write(0, dp->logging, + log_write(dp->logging, "WARNING: deprecated Diffie-Hellman parameter '%s' used", dp->label); return dp->pem; } diff --git a/src/src/store.c b/src/src/store.c index 2268acbf9..3735f8d76 100644 --- a/src/src/store.c +++ b/src/src/store.c @@ -285,7 +285,7 @@ for (pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++) #ifndef COMPILE_UTILITY stackdump(); #endif -log_write_die(0, LOG_MAIN, +log_write_die(LOG_MAIN, "bad memory reference; pool not found, at %s %d", func, linenumber); return NULL; } @@ -344,7 +344,7 @@ return is_tainted_dnsa(p); void die_tainted(const uschar * msg, const uschar * func, int line) { -log_write_die(0, LOG_MAIN, "Taint mismatch, %s: %s %d\n", +log_write_die(LOG_MAIN, "Taint mismatch, %s: %s %d\n", msg, func, line); } @@ -404,7 +404,7 @@ does this to return a current watermark value for a later release of allocated store. */ if (size < 0 || size >= INT_MAX/2) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "bad memory allocation requested (%d bytes) from %s %d", size, func, linenumber); @@ -460,7 +460,7 @@ if (size > pp->yield_length) int err = posix_memalign((void **)&newblock, pgsize, (mlength + pgsize - 1) & ~(pgsize - 1)); if (err) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "failed to alloc (using posix_memalign) %d bytes of memory: '%s'" "called from line %d in %s", size, strerror(err), linenumber, func); @@ -767,7 +767,7 @@ int inc = newsize - oldsize; int rounded_oldsize = oldsize; if (oldsize < 0 || newsize < oldsize || newsize >= INT_MAX/2) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "bad memory extension requested (%d -> %d bytes) at %s %d", oldsize, newsize, func, linenumber); @@ -867,7 +867,7 @@ if (CS ptr < bc || CS ptr > bc + b->length) if (CS ptr >= bc && CS ptr <= bc + b->length) break; } if (!b) - log_write_die(0, LOG_MAIN, "internal error: store_reset(%p) " + log_write_die(LOG_MAIN, "internal error: store_reset(%p) " "failed: pool=%d %-14s %4d", ptr, pool, func, linenumber); } @@ -958,10 +958,10 @@ store_reset_3(rmark r, const char * func, int linenumber) void ** ptr = r; if (store_pool >= POOL_TAINT_BASE) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "store_reset called for pool %d: %s %d\n", store_pool, func, linenumber); if (!r) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "store_reset called with bad mark: %s %d\n", func, linenumber); internal_store_reset(*ptr, store_pool + POOL_TAINT_BASE, func, linenumber); @@ -1059,7 +1059,7 @@ DEBUG(memory) #endif /* COMPILE_UTILITY */ if (store_pool >= POOL_TAINT_BASE) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "store_mark called for pool %d: %s %d\n", store_pool, func, linenumber); /* Stash a mark for the tainted-twin release, in the untainted twin. Return @@ -1159,7 +1159,7 @@ BOOL release_ok = !is_tainted(oldblock) && pp->store_last_get == oldblock; /*XX uschar * newblock; if (len < 0 || len > newsize) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "bad memory extension requested (%d -> %d bytes) at %s %d", len, newsize, func, linenumber); @@ -1197,7 +1197,7 @@ void * yield; a negative int, to the (unsigned, wider) size_t */ if (size >= INT_MAX/2) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "bad internal_store_malloc request (" SIZE_T_FMT " bytes) from %s %d", size, func, line); @@ -1205,7 +1205,7 @@ size += sizeof(size_t); /* space to store the size, used under debug */ if (size < 16) size = 16; if (!(yield = malloc(size))) - log_write_die(0, LOG_MAIN, "failed to malloc " SIZE_T_FMT " bytes of memory: " + log_write_die(LOG_MAIN, "failed to malloc " SIZE_T_FMT " bytes of memory: " "called from line %d in %s", size, line, func); #ifndef COMPILE_UTILITY diff --git a/src/src/string.c b/src/src/string.c index bb1bc6c02..7bbbf094b 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -746,7 +746,7 @@ g = string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE, va_end(ap); if (!g) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "string_sprintf expansion was longer than %d; format string was (%s)\n" " called from %s %d\n", STRING_SPRINTF_BUFFER_SIZE, format, func, line); @@ -1209,13 +1209,13 @@ existing length of the string. */ unsigned inc = oldsize < 4096 ? 127 : 1023; if (g->ptr < 0 || g->ptr > g->size || g->size >= INT_MAX/2) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "internal error in gstring_grow (ptr %d size %d)", g->ptr, g->size); if (count <= 0) return; if (count >= INT_MAX/2 - g->ptr) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "internal error in gstring_grow (ptr %d count %d)", g->ptr, count); g->size = (p + count + inc + 1) & ~inc; /* one for a NUL */ @@ -1267,7 +1267,7 @@ string_catn(gstring * g, const uschar * s, int count) int p; if (count < 0) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "internal error in string_catn (count %d)", count); if (count == 0) return g; @@ -1292,7 +1292,7 @@ else if (is_incompatible(g->s, s)) } if (g->ptr < 0 || g->ptr > g->size) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "internal error in string_catn (ptr %d size %d)", g->ptr, g->size); p = g->ptr; @@ -1911,14 +1911,14 @@ while (*fp) default: strncpy(newformat, item_start, fp - item_start); newformat[fp-item_start] = '\0'; - log_write_die(0, LOG_MAIN, "string_format: unsupported type " + log_write_die(LOG_MAIN, "string_format: unsupported type " "in %q in %q", newformat, format); break; } } if (g->ptr > g->size) - log_write_die(0, LOG_MAIN, + log_write_die(LOG_MAIN, "string_format internal error: caller %s %d", func, line); return g; } diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 825ddb04f..5c840edc5 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -497,7 +497,7 @@ DEBUG(tls) #ifndef DISABLE_OCSP if (tls_ocsp_file && (gnutls_buggy_ocsp = tls_is_buggy_ocsp())) - log_write(0, LOG_MAIN, "OCSP unusable with this GnuTLS library version"); + log_write(LOG_MAIN, "OCSP unusable with this GnuTLS library version"); #endif exim_gnutls_base_init_done = TRUE; @@ -591,14 +591,14 @@ if (!state->host) uschar * conn_info = smtp_get_connection_info(); if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5; /* I'd like to get separated H= here, but too hard for now */ - log_write(0, LOG_MAIN, "TLS error on %s %s", conn_info, errstr); + log_write(LOG_MAIN, "TLS error on %s %s", conn_info, errstr); } else if ( !tls_out.smtp_quit #ifdef GNUTLS_E_PREMATURE_TERMINATION || rc != GNUTLS_E_PREMATURE_TERMINATION #endif ) - log_write(0, LOG_MAIN, "H=%s [%s] TLS error on connection %s", + log_write(LOG_MAIN, "H=%s [%s] TLS error on connection %s", state->host->name, state->host->address, errstr); else DEBUG(tls) debug_printf("H=%s [%s] TLS error on connection %s\n", @@ -1231,7 +1231,7 @@ switch (tls_id) DEBUG(tls) debug_printf("\n"); if (server_seen_alpn > 1) { - log_write(0, LOG_MAIN, "TLS ALPN (%Y) rejected", g); + log_write(LOG_MAIN, "TLS ALPN (%Y) rejected", g); DEBUG(tls) debug_printf("TLS: too many ALPNs presented in handshake\n"); return GNUTLS_E_NO_APPLICATION_PROTOCOL; } @@ -1510,7 +1510,7 @@ else { if (Ustat(bundle, &statbuf) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, "could not stat '%s' " + log_write(LOG_MAIN|LOG_PANIC, "could not stat '%s' " "(tls_verify_certificates): %s", bundle, strerror(errno)); return DEFER; } @@ -1523,7 +1523,7 @@ else So s/!S_ISREG/S_ISDIR/ and change some messaging ... */ if (S_ISDIR(statbuf.st_mode)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "tls_verify_certificates %q is a directory", bundle); return DEFER; } @@ -2909,7 +2909,7 @@ if ((cert_list = gnutls_certificate_get_peers(session, &cert_list_size))) if ((yield = event_raise(state->event_action, US"tls:cert", string_sprintf("%d", cert_list_size), &errno))) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "SSL verify denied by event-action: depth=%d: %s", cert_list_size, yield); return 1; /* reject */ @@ -3690,7 +3690,7 @@ if (ob->tls_alpn) DEBUG(tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); } #else - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "ALPN unusable with this GnuTLS library version; ignoring %q\n", ob->tls_alpn); #endif @@ -4194,7 +4194,7 @@ while (left > 0) ) { /* Outlook, dammit */ if (LOGGING(protocol_detail)) - log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before" + log_write(LOG_MAIN, "[%s] after QUIT, client reset TCP before" " SMTP response and TLS close\n", sender_host_address); else DEBUG(tls) debug_printf("[%s] SSL_write: after QUIT," @@ -4348,7 +4348,7 @@ uschar * dummy_errstr; #endif if (exim_gnutls_base_init_done) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "already initialised GnuTLS, Exim developer bug"); #if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL) diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index 0556a071c..c61d64342 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -672,7 +672,7 @@ if (dh_bitsize <= tls_dh_max_bits) == 0) { ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); - log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (D-H param setting '%s'): %s", + log_write(LOG_MAIN|LOG_PANIC, "TLS error (D-H param setting '%s'): %s", dhexpanded ? dhexpanded : US"default", ssl_errstring); #if OPENSSL_VERSION_NUMBER >= 0x30000000L /* EVP_PKEY_free(pkey); crashes */ @@ -879,7 +879,7 @@ if ( !BN_set_word(bn, (unsigned long)RSA_F4) { ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); - log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s", + log_write(LOG_MAIN|LOG_PANIC, "TLS error (RSA_generate_key): %s", ssl_errstring); return NULL; } @@ -1053,7 +1053,7 @@ if (ev) /* NB we do not bother setting peerdn */ if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth), &errno))) { - log_write(0, LOG_MAIN, "[%s] %s verify denied by event-action: " + log_write(LOG_MAIN, "[%s] %s verify denied by event-action: " "depth=%d cert=%s: %s", tlsp == &tls_out ? deliver_host_address : sender_host_address, what, depth, dn, yield); @@ -1119,7 +1119,7 @@ uschar dn[256]; if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn))) { DEBUG(tls) debug_printf("X509_NAME_oneline() error\n"); - log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", + log_write(LOG_MAIN, "[%s] SSL verify error: internal error", tlsp == &tls_out ? deliver_host_address : sender_host_address); return 0; } @@ -1131,7 +1131,7 @@ if (preverify_ok == 0) uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])", *verify_mode, sender_host_address) : US""; - log_write(0, LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s", + log_write(LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s", tlsp == &tls_out ? deliver_host_address : sender_host_address, extra, depth, X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), dn); @@ -1185,7 +1185,7 @@ else { if (rc < 0) { - log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", + log_write(LOG_MAIN, "[%s] SSL verify error: internal error", tlsp == &tls_out ? deliver_host_address : sender_host_address); name = NULL; } @@ -1203,7 +1203,7 @@ else ? string_sprintf(" (during %c-verify for [%s])", *verify_mode, sender_host_address) : US""; - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "[%s] SSL verify error%s: certificate name mismatch: DN=%q H=%q", tlsp == &tls_out ? deliver_host_address : sender_host_address, extra, dn, verify_cert_hostnames); @@ -1266,7 +1266,7 @@ BOOL dummy_called, optional = FALSE; if (!X509_NAME_oneline(X509_get_subject_name(cert), CS dn, sizeof(dn))) { DEBUG(tls) debug_printf("X509_NAME_oneline() error\n"); - log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error", + log_write(LOG_MAIN, "[%s] SSL verify error: internal error", deliver_host_address); return 0; } @@ -1341,7 +1341,7 @@ if (!filename || !*filename) return; ERR_clear_error(); if (!(bio = BIO_new_file(CS filename, "rb"))) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "Failed to open OCSP response file %q: %.100s", filename, ERR_reason_error_string(ERR_get_error())); return; @@ -1354,7 +1354,7 @@ if (is_pem) long len; if (!PEM_read_bio(bio, &dummy, &dummy, &data, &len)) { - log_write(0, LOG_MAIN|LOG_PANIC, "Failed to read PEM file %q: %.100s", + log_write(LOG_MAIN|LOG_PANIC, "Failed to read PEM file %q: %.100s", filename, ERR_reason_error_string(ERR_get_error())); return; } @@ -1368,7 +1368,7 @@ BIO_free(bio); if (!resp) { - log_write(0, LOG_MAIN|LOG_PANIC, "Error reading OCSP response from %q: %s", + log_write(LOG_MAIN|LOG_PANIC, "Error reading OCSP response from %q: %s", filename, ERR_reason_error_string(ERR_get_error())); return; } @@ -2309,7 +2309,7 @@ SSL_set_SSL_CTX(s, server_sni); return SSL_TLSEXT_ERR_OK; bad: - log_write(0, LOG_MAIN|LOG_PANIC, "%s", errstr); + log_write(LOG_MAIN|LOG_PANIC, "%s", errstr); return SSL_TLSEXT_ERR_ALERT_FATAL; } @@ -2518,7 +2518,7 @@ if(!p) } if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher)) - log_write(0, LOG_MAIN, "Required TLS certificate status not received"); + log_write(LOG_MAIN, "Required TLS certificate status not received"); else DEBUG(tls) debug_printf(" null\n"); @@ -2533,7 +2533,7 @@ if (!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len))) { tls_out.ocsp = OCSP_FAILED; /*XXX should use tlsp-> to permit concurrent outbound */ if (LOGGING(tls_cipher)) - log_write(0, LOG_MAIN, "Received TLS cert status response, parse error"); + log_write(LOG_MAIN, "Received TLS cert status response, parse error"); else DEBUG(tls) debug_printf(" parse error\n"); return 0; @@ -2543,7 +2543,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) { tls_out.ocsp = OCSP_FAILED; if (LOGGING(tls_cipher)) - log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response"); + log_write(LOG_MAIN, "Received TLS cert status response, error parsing response"); else DEBUG(tls) debug_printf(" error parsing response\n"); OCSP_RESPONSE_free(rsp); @@ -2689,7 +2689,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(ssl)), CS peerdn, sizeof(peerdn)); - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "[%s] %s Received TLS cert (DN: '%.*s') status response, " "itself unverifiable: %s", deliver_host_address, deliver_host, @@ -2756,7 +2756,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) DEBUG(tls) ERR_print_errors(bp); cbinfo->u_ocsp.client.verify_errstr = US"(SSL_connect) Server certificate status is out-of-date"; - log_write(0, LOG_MAIN, "OCSP dates invalid"); + log_write(LOG_MAIN, "OCSP dates invalid"); goto failed; } @@ -2769,7 +2769,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) case V_OCSP_CERTSTATUS_REVOKED: cbinfo->u_ocsp.client.verify_errstr = US"(SSL_connect) Server certificate revoked"; - log_write(0, LOG_MAIN, "Server certificate revoked%s%s", + log_write(LOG_MAIN, "Server certificate revoked%s%s", reason != -1 ? "; reason: " : "", reason != -1 ? OCSP_crl_reason_str(reason) : ""); DEBUG(tls) time_print(bp, "Revocation Time", rev); @@ -2777,7 +2777,7 @@ if (!(bs = OCSP_response_get1_basic(rsp))) default: cbinfo->u_ocsp.client.verify_errstr = US"(SSL_connect) Server certificate has unknown status"; - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "Server certificate status unknown, in OCSP stapling"); break; } @@ -3250,7 +3250,7 @@ if (expcerts && *expcerts) if (Ustat(expcerts, &statbuf) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to stat %s for certificates", expcerts); return DEFER; } @@ -3283,7 +3283,7 @@ This is inconsistent with the need to verify the OCSP proof of the server cert. && !chain_from_pem_file(file, vp) ) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to load cert chain from %s", file); return DEFER; } @@ -3343,7 +3343,7 @@ This is inconsistent with the need to verify the OCSP proof of the server cert. struct stat statbufcrl; if (Ustat(expcrl, &statbufcrl) < 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "failed to stat %s for certificates revocation lists", expcrl); return DEFER; } @@ -3986,7 +3986,7 @@ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; if (found) return OK; -log_write(0, LOG_MAIN, "DANE error: No usable TLSA records"); +log_write(LOG_MAIN, "DANE error: No usable TLSA records"); return DEFER; } #endif /*SUPPORT_DANE*/ @@ -4390,7 +4390,7 @@ if (ob->tls_alpn) DEBUG(tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn); } #else - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "ALPN unusable with this OpenSSL library version; ignoring %q\n", ob->tls_alpn); #endif @@ -4595,7 +4595,7 @@ switch(error) if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5; /* I'd like to get separated H= here, but too hard for now */ ERR_error_string_n(ERR_peek_error(), ssl_errstring, sizeof(ssl_errstring)); - log_write(0, LOG_MAIN, "TLS error (SSL_read): on %s %s", conn_info, ssl_errstring); + log_write(LOG_MAIN, "TLS error (SSL_read): on %s %s", conn_info, ssl_errstring); DEBUG(tls) tls_debug_err(ssl, US"SSL_read", inbytes); ssl_xfer_error = TRUE; return FALSE; @@ -4828,22 +4828,22 @@ for (int left = len; left > 0;) case SSL_ERROR_SSL: ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); - log_write(0, LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring); + log_write(LOG_MAIN, "TLS error (SSL_write): %s", ssl_errstring); return -1; case SSL_ERROR_ZERO_RETURN: - log_write(0, LOG_MAIN, "SSL channel closed on write"); + log_write(LOG_MAIN, "SSL channel closed on write"); return -1; case SSL_ERROR_SYSCALL: if (errno == 0) { DEBUG(tls) debug_printf("- SSL_ERROR_SYSCALL with zero errno\n"); } else if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit) - log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s", + log_write(LOG_MAIN, "SSL_write: (from %s) syscall: %s", sender_fullhost ? sender_fullhost : US"", strerror(errno)); else if (LOGGING(protocol_detail)) - log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before" + log_write(LOG_MAIN, "[%s] after QUIT, client reset TCP before" " SMTP response and TLS close\n", sender_host_address); else DEBUG(tls) debug_printf("[%s] SSL_write: after QUIT," @@ -4851,7 +4851,7 @@ for (int left = len; left > 0;) return -1; default: - log_write(0, LOG_MAIN, "SSL_write error %d", error); + log_write(LOG_MAIN, "SSL_write error %d", error); return -1; } } diff --git a/src/src/tls.c b/src/src/tls.c index e280a1f3e..159e3f888 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -117,7 +117,7 @@ else if ( !(*result = expand_string(US s)) /* need to clean up const more */ ) { *errstr = US"Internal error"; - log_write(0, LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name, + log_write(LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name, expand_string_message); return FALSE; } @@ -505,7 +505,7 @@ int tls_ungetc(int ch) { if (ssl_xfer_buffer_lwm <= 0) - log_write_die(0, LOG_MAIN, "buffer underflow in tls_ungetc"); + log_write_die(LOG_MAIN, "buffer underflow in tls_ungetc"); ssl_xfer_buffer[--ssl_xfer_buffer_lwm] = ch; return ch; @@ -791,7 +791,7 @@ if ( !tls_advertise_hosts ) return TRUE; else if (!nowarn && !tls_certificate) - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "Warning: No server certificate defined; will use a selfsigned one.\n" " Suggested action: either install a certificate or change tls_advertise_hosts option"); @@ -799,7 +799,7 @@ oldsignal = signal(SIGCHLD, SIG_DFL); fflush(NULL); if ((pid = exim_fork(US"cipher-validate")) < 0) - log_write_die(0, LOG_MAIN, "fork failed for TLS check"); + log_write_die(LOG_MAIN, "fork failed for TLS check"); if (pid == 0) { @@ -809,8 +809,7 @@ if (pid == 0) US"calling tls_validate_require_cipher"); if ((errmsg = tls_validate_require_cipher())) - log_write_die(0, LOG_CONFIG, - "tls_require_ciphers invalid: %s", errmsg); + log_write_die(LOG_CONFIG, "tls_require_ciphers invalid: %s", errmsg); fflush(NULL); exim_underbar_exit(EXIT_SUCCESS); } diff --git a/src/src/tlscert-gnu.c b/src/src/tlscert-gnu.c index 43d362904..159905f41 100644 --- a/src/src/tlscert-gnu.c +++ b/src/src/tlscert-gnu.c @@ -37,7 +37,7 @@ const uschar * cp; if ((fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert, GNUTLS_X509_FMT_PEM, buf, &sz))) { - log_write(0, LOG_MAIN, "TLS error in certificate export: %s", + log_write(LOG_MAIN, "TLS error in certificate export: %s", gnutls_strerror(fail)); return FALSE; } @@ -71,7 +71,7 @@ datum.data = string_unprinting(US buf); datum.size = Ustrlen(datum.data); if ((rc = gnutls_x509_crt_import(crt, &datum, GNUTLS_X509_FMT_PEM))) { - log_write(0, LOG_MAIN, "TLS error in certificate import: %s", + log_write(LOG_MAIN, "TLS error in certificate import: %s", gnutls_strerror(rc)); crt = NULL; } @@ -435,7 +435,7 @@ if ( (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert, GNUTLS_X509_FMT_DER, cp, &len)) ) { - log_write(0, LOG_MAIN, "TLS error in certificate export: %s", + log_write(LOG_MAIN, "TLS error in certificate export: %s", gnutls_strerror(fail)); return NULL; } diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c index 5e3ce22a4..ce4951c5e 100644 --- a/src/src/tlscert-openssl.c +++ b/src/src/tlscert-openssl.c @@ -45,7 +45,7 @@ BIO * bp = BIO_new(BIO_s_mem()); BOOL fail; if ((fail = PEM_write_bio_X509(bp, (X509 *)cert) ? 0 : 1)) - log_write(0, LOG_MAIN, "TLS error in certificate export: %s", + log_write(LOG_MAIN, "TLS error in certificate export: %s", ERR_error_string(ERR_get_error(), NULL)); else { @@ -79,7 +79,7 @@ if (x) X509_free(x); bp = BIO_new_mem_buf(US cp, -1); if (!(x = PEM_read_bio_X509(bp, NULL, 0, NULL))) - log_write(0, LOG_MAIN, "TLS error in certificate import: %s", + log_write(LOG_MAIN, "TLS error in certificate import: %s", ERR_error_string(ERR_get_error(), NULL)); *cert = (void *)x; @@ -494,7 +494,7 @@ BIO * bp = BIO_new(BIO_s_mem()); uschar * cp = NULL; if (!i2d_X509_bio(bp, (X509 *)cert)) - log_write(0, LOG_MAIN, "TLS error in certificate export: %s", + log_write(LOG_MAIN, "TLS error in certificate export: %s", ERR_error_string(ERR_get_error(), NULL)); else { diff --git a/src/src/transport.c b/src/src/transport.c index 371ce2cd9..04be9e286 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -215,11 +215,11 @@ for (transport_instance * t = transports; t; t = t->drinst.next) { const transport_info * ti = t->drinst.info; if (!ti->local && t->shadow) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "shadow transport not allowed on non-local transport %s", t->drinst.name); if (t->body_only && t->headers_only) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "%s transport: body_only and headers_only are mutually exclusive", t->drinst.name); } @@ -455,7 +455,7 @@ that the result will never be expanded. */ va_start(ap, format); if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap)) - log_write_die(0, LOG_MAIN, "overlong formatted string in transport"); + log_write_die(LOG_MAIN, "overlong formatted string in transport"); va_end(ap); tctx.u.fd = fd; return transport_write_block(&tctx, gs.s, gs.ptr, FALSE); @@ -1823,7 +1823,7 @@ don't try to use it. */ if (host_record->count > WAIT_NAME_MAX) { - log_write(0, LOG_MAIN|LOG_PANIC, "smtp-wait database entry for %s has bad " + log_write(LOG_MAIN|LOG_PANIC, "smtp-wait database entry for %s has bad " "count=%d (max=%d)", hostname, host_record->count, WAIT_NAME_MAX); goto dbclose_false; } diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 68ea552f3..16519726a 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -343,7 +343,7 @@ if (ob->lock_retries == 0) ob->lock_retries = 1; /* Only one of a file name or directory name must be given. */ if (ob->filename && ob->dirname) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "only one of \"file\" or \"directory\" can be specified", trname); /* If a file name was specified, neither quota_filecount nor quota_directory @@ -352,10 +352,10 @@ must be given. */ if (ob->filename) { if (ob->quota_filecount) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "quota_filecount must not be set without \"directory\"", trname); if (ob->quota_directory) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "quota_directory must not be set without \"directory\"", trname); } @@ -370,7 +370,7 @@ requested, the default for fcntl is FALSE. */ if (ob->use_flock) { #ifdef NO_FLOCK - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "flock() support was not available in the operating system when this " "binary was built", trname); #endif /* NO_FLOCK */ @@ -395,7 +395,7 @@ if (ob->mbx_format) #endif /* SUPPORT_MBX */ if (!ob->use_fcntl && !ob->use_flock && !ob->use_lockfile && !ob->use_mbx_lock) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "no locking configured", trname); /* Unset timeouts for non-used locking types */ @@ -410,20 +410,20 @@ be set. */ if (ob->dirname) { if (ob->maildir_format && ob->mailstore_format) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "only one of maildir and mailstore may be specified", trname); if (ob->quota_filecount != NULL && !ob->quota) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "quota must be set if quota_filecount is set", trname); if (ob->quota_directory != NULL && !ob->quota) - log_write_die(0, LOG_CONFIG_FOR, "%s transport:\n " + log_write_die(LOG_CONFIG_FOR, "%s transport:\n " "quota must be set if quota_directory is set", trname); } /* If a fixed uid field is set, then a gid field must also be set. */ if (tblock->uid_set && !tblock->gid_set && !tblock->expand_gid) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "user set without group for the %s transport", trname); /* If "create_file" is set, check that a valid option is given, and set the @@ -436,7 +436,7 @@ if ((s = ob->create_file_string ) && *s) else if (*s == '/' || Ustrcmp(s, "belowhome") == 0) val = create_belowhome; else if (Ustrcmp(s, "inhome") == 0) val = create_inhome; else - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "invalid value given for \"create_file\" for the %s transport: '%s'", trname, s); ob->create_file = val; diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index 9937505e8..da1c2f6bc 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -95,7 +95,7 @@ autoreply_transport_options_block *ob = /* If a fixed uid field is set, then a gid field must also be set. */ if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "user set without group for the %s transport", t->name); } diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index 8fa29dff6..9f8e73110 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -84,14 +84,14 @@ lmtp_transport_options_block * ob = t->options_block; /* Either the command field or the socket field must be set */ if ((ob->cmd == NULL) == (ob->skt == NULL)) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "one (and only one) of command or socket must be set for the %s transport", tblock->drinst.name); /* If a fixed uid field is set, then a gid field must also be set. */ if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "user set without group for the %s transport", tblock->drinst.name); /* Set up the bitwise options for transport_write_message from the various diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index ada39f723..6a5175438 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -155,7 +155,7 @@ if (ob->permit_coredump) #ifdef SETRLIMIT_NOT_SUPPORTED if (errno != ENOSYS && errno != ENOTSUP) #endif - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "delivery setrlimit(RLIMIT_CORE, RLIM_INFINITY) failed: %s", strerror(errno)); } @@ -190,14 +190,14 @@ tblock->setup = pipe_transport_setup; if (tblock->deliver_as_creator && (tblock->uid_set || tblock->gid_set || tblock->expand_uid != NULL || tblock->expand_gid != NULL)) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "both pipe_as_creator and an explicit uid/gid are set for the %s " "transport", trname); /* If a fixed uid field is set, then a gid field must also be set. */ if (tblock->uid_set && !tblock->gid_set && tblock->expand_gid == NULL) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "user set without group for the %s transport", trname); /* Temp_errors must consist only of digits and colons, but there can be @@ -207,7 +207,7 @@ if (ob->temp_errors != NULL && Ustrcmp(ob->temp_errors, "*") != 0) { size_t p = Ustrspn(ob->temp_errors, "0123456789: "); if (ob->temp_errors[p] != 0) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "temp_errors must be a list of numbers or an asterisk for the %s " "transport", trname); } @@ -216,12 +216,12 @@ if (ob->temp_errors != NULL && Ustrcmp(ob->temp_errors, "*") != 0) should be set. */ if (tblock->return_output && tblock->return_fail_output) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "both return_output and return_fail_output set for %s transport", trname); if (tblock->log_output && tblock->log_fail_output) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "both log_output and log_fail_output set for the %s transport", trname); @@ -248,14 +248,14 @@ else /* The restrict_to_path and use_shell options are incompatible */ if (ob->restrict_to_path && ob->use_shell) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "both restrict_to_path and use_shell set for %s transport", trname); /* The allow_commands and use_shell options are incompatible */ if (ob->allow_commands && ob->use_shell) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "both allow_commands and use_shell set for %s transport", trname); diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index ca106b2cb..0ea5e6c45 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -63,7 +63,7 @@ void queuefile_transport_init(driver_instance * t) queuefile_transport_options_block * ob = t->options_block; if (!ob->dirname) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "directory must be set for the %s transport", t->name); } diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index da89808d3..5fb07bd7f 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -417,7 +417,7 @@ tblock->setup = smtp_transport_setup; if (ob->command_timeout <= 0 || ob->data_timeout <= 0 || ob->final_timeout <= 0) - log_write_die(0, LOG_CONFIG, + log_write_die(LOG_CONFIG, "command, data, or final timeout value is zero for %s transport", t->name); @@ -675,7 +675,7 @@ if (suffix) else message = string_fmt_append(message, " %s", exim_errstr(basic_errno)); -log_write(0, LOG_MAIN, "%Y", message); +log_write(LOG_MAIN, "%Y", message); deliver_msglog("%s %.*s\n", tod_stamp(tod_log), message->ptr, message->s); } @@ -1470,7 +1470,7 @@ while (count-- > 0) if (LOGGING(outgoing_port)) g = log_portnum(g, sx->port == PORT_NONE ? 25 : sx->port); g = string_fmt_append(g, " %s", addr->message); - log_write(0, LOG_MAIN, "%Y", g); + log_write(LOG_MAIN, "%Y", g); gstring_reset(g); gstring_release_unused(g); } @@ -1616,12 +1616,12 @@ switch(rc) sender_host_authenticated = au->drinst.name; if ((logmsg = event_raise(sx->conn_args.tblock->event_action, US"auth:fail", sx->buffer, NULL))) - log_write(0, LOG_MAIN, "%s", logmsg); + log_write(LOG_MAIN, "%s", logmsg); sender_host_authenticated = save_name; } #endif if (!logmsg) - log_write(0, LOG_MAIN, "%s authenticator failed H=%s [%s] %s", + log_write(LOG_MAIN, "%s authenticator failed H=%s [%s] %s", au->drinst.name, host->name, host->address, sx->buffer); break; } @@ -1634,7 +1634,7 @@ switch(rc) case CANCELLED: if (*sx->buffer != 0) - log_write(0, LOG_MAIN, "%s authenticator cancelled " + log_write(LOG_MAIN, "%s authenticator cancelled " "authentication H=%s [%s] %s", au->drinst.name, host->name, host->address, sx->buffer); break; @@ -2252,7 +2252,7 @@ else } else if (strcmpic(ob->protocol, US"smtp") != 0) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "bad protocol option in transport: '%s'\n", ob->protocol); return ERROR; } @@ -2354,7 +2354,7 @@ if (continue_hostname && continue_proxy_cipher) existing conn drop the connection to force a new one. */ if (ob->tls_sni && !(sni = expand_string(ob->tls_sni))) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's tls_sni value: %s", sx->addrlist->address, expand_string_message); @@ -2570,7 +2570,7 @@ is the non-TFO-C case for smtps, where the Client Hello will go on the 3rd-ack. if (sx->helo_data) if (!(sx->helo_data = expand_string(sx->helo_data))) if (sx->verify) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's helo_data value for callout: %s", sx->addrlist->address, expand_string_message); @@ -2582,7 +2582,7 @@ is the non-TFO-C case for smtps, where the Client Hello will go on the 3rd-ack. &expand_string_message)), expand_string_message) if (sx->verify) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "<%s>: failed to expand transport's helo_data value for callout: %s", sx->addrlist->address, expand_string_message); else @@ -2845,7 +2845,7 @@ goto SEND_QUIT; # ifdef EXPERIMENTAL_SRV_SMTPS else if (sx->conn_args.host->tls_needs == SRV_STARTTLS_MUST) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "Connection aborted; STARTTLS support by %s [%s] required by DNS SRV" " but STARTTLS not offered", sx->conn_args.host->name, sx->conn_args.host->address); @@ -3022,7 +3022,7 @@ if ( smtp_peer_options & OPTION_TLS # ifdef SUPPORT_DANE if (sx->conn_args.dane) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "DANE attempt failed; TLS connection to %s [%s]: %s", sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr); # ifndef DISABLE_EVENT @@ -4696,7 +4696,7 @@ else DEBUG(deliver) debug_printf("S:journalling %s", sx->buffer); len = Ustrlen(CS sx->buffer); if (write(journal_fd, sx->buffer, len) != len) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for " + log_write(LOG_MAIN|LOG_PANIC, "failed to write journal for " "%s: %s", sx->buffer, strerror(errno)); } } @@ -4743,7 +4743,7 @@ else DEBUG(deliver) debug_printf("journalling(PRDR) %s\n", sx->buffer); len = Ustrlen(CS sx->buffer); if (write(journal_fd, sx->buffer, len) != len) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for " + log_write(LOG_MAIN|LOG_PANIC, "failed to write journal for " "%s: %s", sx->buffer, strerror(errno)); } else if (addr->transport_return == DEFER) @@ -4755,7 +4755,7 @@ else /* Ensure the journal file is pushed out to disk. */ if (EXIMfsync(journal_fd) < 0) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to fsync journal: %s", + log_write(LOG_MAIN|LOG_PANIC, "failed to fsync journal: %s", strerror(errno)); } } @@ -4836,7 +4836,7 @@ if (!sx->ok) break; if (!addr) /* all rcpts fates determined */ { - log_write(0, LOG_MAIN, "peer close after all rcpt responses;" + log_write(LOG_MAIN, "peer close after all rcpt responses;" " converting i/o-error to no-error"); sx->ok = TRUE; goto happy; @@ -5122,7 +5122,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit) } if (pid < 0) - log_write_die(0, LOG_PANIC_DIE, "fork failed"); + log_write_die(LOG_PANIC_DIE, "fork failed"); close(pfd[0]); continue_fd = pfd[1]; @@ -5584,7 +5584,7 @@ if (!hostlist || (ob->hosts_override && ob->hosts)) if (is_tainted(s)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "attempt to use tainted host list '%s' from '%s' in transport %s", s, ob->hosts, trname); /* Avoid leaking info to an attacker */ @@ -6204,7 +6204,7 @@ retry_non_continued: && verify_check_given_host(CUSS &ob->hosts_require_tls, host) != OK ) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s: delivering unencrypted to H=%s [%s] (not in hosts_require_tls)", first_addr->message, host->name, host->address); first_addr = prepare_addresses(addrlist, host); diff --git a/src/src/verify.c b/src/src/verify.c index 910da5104..3e355e350 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -372,7 +372,7 @@ if (addr->transport == cutthrough.addr.transport) US"callout") || (port = smtp_get_port(tf->port, addr, US"callout")) < 0 ) - log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, + log_write(LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, addr->message); smtp_port_for_connect(host, port); @@ -591,7 +591,7 @@ if (!addr->transport) } else if (Ustrcmp(addr->transport->drinst.driver_name, "smtp") != 0) - log_write(0, LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp", + log_write(LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp", addr->transport->drinst.name, addr->transport->drinst.driver_name); else { @@ -609,7 +609,7 @@ else GET_OPTION("callout_random_local_part"); if ( callout_random_local_part && !(random_local_part = expand_string(callout_random_local_part))) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand " "callout_random_local_part: %s", expand_string_message); } @@ -700,7 +700,7 @@ coding means skipping this whole loop and doing the append separately. */ US"callout") || (port = smtp_get_port(tf->port, addr, US"callout")) < 0 ) - log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, + log_write(LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address, addr->message); /* Large (12k, 66k if DANE supported. Tainted, for the receive buffers */ @@ -736,7 +736,7 @@ tls_retry_connection: && verify_check_given_host(CUSS &ob->hosts_require_tls, host) != OK ) { - log_write(0, LOG_MAIN, + log_write(LOG_MAIN, "%s: callout unencrypted to %s [%s] (not in hosts_require_tls)", addr->message, host->name, host->address); addr->transport_return = PENDING_DEFER; @@ -766,7 +766,7 @@ tls_retry_connection: case ENETDOWN: case ENETUNREACH: case EINVAL: /* OpenBSD gives this for netunreach */ - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "%s verify %s (making callout connection): T=%s %s", options & vopt_is_recipient ? "sender" : "recipient", yield == FAIL ? "fail" : "defer", @@ -1968,7 +1968,7 @@ while (addr_new) if (!ti->local) { if ((tp->setup)(tp, addr, &tf, 0, 0, NULL) != OK) - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(LOG_MAIN|LOG_PANIC, "setup fail for %s transport for callout (%s)", tp->drinst.name, expand_string_message); @@ -1983,7 +1983,7 @@ while (addr_new) host_list = NULL; /* Ignore the router's hosts */ if (!(s = expand_string(tf.hosts))) - log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts " + log_write(LOG_MAIN|LOG_PANIC, "failed to expand list of hosts " "%q in %s transport for callout: %s", tf.hosts, tp->drinst.name, expand_string_message); else @@ -2847,7 +2847,7 @@ if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port, rfc1413_query_timeout, &early_data) < 0) { if (errno == ETIMEDOUT && LOGGING(ident_timeout)) - log_write(0, LOG_MAIN, "ident connection to %s timed out", + log_write(LOG_MAIN, "ident connection to %s timed out", sender_host_address); else DEBUG(ident) debug_printf("ident connection to %s failed: %s\n", @@ -3102,7 +3102,7 @@ if (iplookup) /* Find the search type */ if (!(li = search_findtype(t, endname - t))) - log_write_die(0, LOG_MAIN, "%s", search_error_message); + log_write_die(LOG_MAIN, "%s", search_error_message); /* Adjust parameters for the type of lookup. For a query-style lookup, there is no file name, and the "key" is just the query. For query-style with a file @@ -3145,7 +3145,7 @@ if (iplookup) of the caching arrangements. */ if (!(handle = search_open(filename, li, 0, NULL, NULL))) - log_write_die(0, LOG_MAIN, "%s", search_error_message); + log_write_die(LOG_MAIN, "%s", search_error_message); result = search_find(handle, filename, key, -1, NULL, 0, 0, NULL, opts); if (valueptr) *valueptr = result; @@ -3228,7 +3228,7 @@ if ((semicolon = Ustrchr(ss, ';'))) if (!li) /* Unknown lookup type */ { - log_write(0, LOG_MAIN|LOG_PANIC, "%s in host list item %q", + log_write(LOG_MAIN|LOG_PANIC, "%s in host list item %q", search_error_message, ss); return DEFER; } commit e742c93d787657340ebb994c45fc8a05c0027d89 Author: Jeremy Harris Date: Tue Feb 24 19:42:05 2026 +0000 Force a 4xx reposponse to end-of-data when close fails. Bug 3204 diff --git a/src/src/receive.c b/src/src/receive.c index c8dd5a326..fd0f9c138 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -4455,8 +4455,10 @@ if (spool_data_file && cutthrough_done == NOT_TRIED) Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H")); Uunlink(spool_fname(US"msglog", message_subdir, message_id, US"")); - /* Claim a data ACL temp-reject, just to get reject logging and response */ - if (smtp_input) smtp_handle_acl_fail(ACL_WHERE_DATA, rc, NULL, log_msg); + /* Claim a data ACL temp-reject, to get reject logging and SMTP response */ + + if (smtp_input) + smtp_handle_acl_fail(ACL_WHERE_DATA, DEFER, NULL, log_msg); smtp_reply = US""; /* Indicate reply already sent */ message_id[0] = 0; /* no message accepted */ commit a245b7d8b659e6b6be19bd8f25895cd5d2d33bfe Author: Jeremy Harris Date: Wed Feb 25 09:00:38 2026 +0000 Log: avoid numeric error codes in log lines diff --git a/src/src/deliver.c b/src/src/deliver.c index 93d79af08..0cfe587eb 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1098,7 +1098,7 @@ return g; static gstring * -delivery_log_dsn(gstring * g, const address_item * addr) +d_dsnlog(gstring * g, const address_item * addr) { return LOGGING(dsn) ? dsn_ret || dsn_envid || addr->dsn_flags & rf_dsnflags || addr->dsn_orcpt @@ -1251,7 +1251,7 @@ else g = string_catn(g, US" K", 2); } -g = delivery_log_dsn(g, addr); +g = d_dsnlog(g, addr); #ifndef DISABLE_DKIM if (addr->dkim_used && LOGGING(dkim_verbose)) @@ -1292,15 +1292,14 @@ if (LOGGING(queue_time)) if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); -/* string_cat() always leaves room for the terminator. Release the -store we used to build the line after writing it. */ - log_write(flags, "%Y", g); #ifndef DISABLE_EVENT if (!msg) msg_event_raise(US"msg:delivery", addr); #endif +/* Release the store we used to build the line after writing it. */ + store_reset(reset_point); return; } @@ -1312,7 +1311,7 @@ deferral_log(address_item * addr, uschar * now, int logflags, uschar * driver_name, uschar * driver_kind) { rmark reset_point = store_mark(); -gstring * g = string_get(256); +gstring * g = string_get_tainted(256, GET_TAINTED); /* Build up the line that is used for both the message log and the main log. */ @@ -1340,15 +1339,15 @@ if (driver_name) else if (driver_kind) g = string_append(g, 2, US" ", driver_kind); -g = string_fmt_append(g, " defer (%d)", addr->basic_errno); +g = string_catn(g, US" defer", 6); -if (addr->basic_errno > 0) - g = string_append(g, 2, US": ", US strerror(addr->basic_errno)); +if (addr->basic_errno != 0 && !addr->message) + g = string_fmt_append(g, " (%s)", exim_errstr(addr->basic_errno)); if (addr->host_used) g = d_hostlog(g, addr); -g = delivery_log_dsn(g, addr); +g = d_dsnlog(g, addr); if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); @@ -1382,7 +1381,7 @@ static void failure_log(address_item * addr, uschar * driver_kind, uschar * now) { rmark reset_point = store_mark(); -gstring * g = string_get(256); +gstring * g = string_get_tainted(256, GET_TAINTED); #ifndef DISABLE_EVENT /* Message failures for which we will send a DSN get their event raised @@ -1427,13 +1426,13 @@ if (LOGGING(protocol_detail) && addr->protocol_sequence) g = d_tlslog(g, addr); #endif -g = delivery_log_dsn(g, addr); - -if (addr->basic_errno > 0) - g = string_append(g, 2, US" : ", US strerror(addr->basic_errno)); +g = d_dsnlog(g, addr); if (addr->message) g = string_append(g, 2, US" : ", addr->message); +else if (addr->basic_errno != 0) + g = string_fmt_append(g, " (%s)", exim_errstr(addr->basic_errno)); + if (LOGGING(deliver_time)) g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time)); @@ -1517,9 +1516,12 @@ malformed, it won't ever have gone near LDAP.) */ if (addr->message) { const uschar * s = string_printing(addr->message); + uschar * t; - /* deconst cast ok as string_printing known to have alloc'n'copied */ - addr->message = expand_hide_passwords(US s); + /* deconst cast ok IF string_printing known to have alloc'n'copied */ + + t = s == addr->message ? string_copy(s) : US s; + addr->message = expand_hide_passwords(t); } /* If we used a transport that has one of the "return_output" options set, and @@ -1538,7 +1540,8 @@ if (addr->return_file >= 0 && addr->return_filename) { BOOL return_output = FALSE; struct stat statbuf; - (void)EXIMfsync(addr->return_file); + + (void) EXIMfsync(addr->return_file); /* If there is no output, do nothing. */ @@ -2019,9 +2022,9 @@ if (expand_string_message) else if (size_limit > 0 && message_size > size_limit) { rc = FAIL; + addr->basic_errno = ERRNO_TPTLIMIT; addr->message = - string_sprintf("message is too big (transport limit = %d)", - size_limit); + string_sprintf("message is too big (transport limit = %d)", size_limit); } return rc; @@ -4624,8 +4627,10 @@ Does that also apply to address_data? return_path = new_return_path; else if (!f.expand_string_forcedfail) { - panicmsg = string_sprintf("Failed to expand return path %q: %s", - tp->return_path, expand_string_message); + common_error(FALSE, addr, ERRNO_EXPANDFAIL, + US "Failed to expand return path %q: %s", + tp->return_path, expand_string_message); + panicmsg = addr->message; goto enq_continue; } } @@ -5348,6 +5353,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe (void)close(pfd[pipe_read]); panicmsg = string_sprintf("fork failed for remote delivery to %s: %s", addr->domain, strerror(errno)); + addr->basic_errno = errno; goto enq_continue; } diff --git a/src/src/expand.c b/src/src/expand.c index 0c6366bac..aab3b76a7 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -8956,6 +8956,7 @@ return OK; /* Avoid potentially exposing a password in a string about to be logged */ +/*XXX potential constify? */ uschar * expand_hide_passwords(uschar * s) diff --git a/src/src/globals.c b/src/src/globals.c index cf121c6f0..337842770 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -960,8 +960,7 @@ uschar *log_file_path = US LOG_FILE_PATH const uschar * const log_notall_names[] = { NULL }; /* List of names for logging channels. Must be in alphabetical order. -Must match enum logging_test_bit (macros.h). -This is a superset of logwrite_options[]. */ +Must match enum logging_test_bit (macros.h). */ #define LOG_CHAN(chan) {.name = US #chan, .logchan_bit = Lt_##chan} diff --git a/src/src/log.c b/src/src/log.c index 959b2b5e5..490b965dd 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -55,7 +55,7 @@ number definitions in macros.h */ static const uschar * exim_errstrings[] = { [0] = US"", - [- ERRNO_UNKNOWNERROR] = US"unknown error", + [- ERRNO_UNKNOWNERROR] = US"error-code not set", [- ERRNO_USERSLASH] = US"user slash", [- ERRNO_EXISTRACE] = US"exist race", [- ERRNO_NOTREGULAR] = US"not regular", @@ -81,7 +81,7 @@ static const uschar * exim_errstrings[] = { [- 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_EXPANDFAIL] = US"string expansion failed", [- ERRNO_GIDFAIL] = US"Failed to get gid", [- ERRNO_UIDFAIL] = US"Failed to get uid", [- ERRNO_BADTRANSPORT] = US"Unset or non-existent transport", @@ -105,6 +105,12 @@ static const uschar * exim_errstrings[] = { [- ERRNO_AUTHPROB] = US"Authenticator 'other' failure", [- ERRNO_UTF8_FWD] = US"target not supporting SMTPUTF8", [- ERRNO_HOST_IS_LOCAL] = US"host is local", + [- ERRNO_PASSONE] = US"pass1", + [- ERRNO_NOROUTER] = US"no handling router", + [- ERRNO_ROUTERDEFER] = US"rt-defer", + [- ERRNO_ROUTERFAIL] = US"rt-fail", + [- ERRNO_MXDEFER] = US"mxdefer", + [- ERRNO_TPTLIMIT] = US"tpt-lim", [- ERRNO_TAINT] = US"tainted filename", [- ERRNO_RRETRY] = US"Not time for routing", diff --git a/src/src/macros.h b/src/src/macros.h index 574082c0a..d7e5576f7 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -572,20 +572,26 @@ table exim_errstrings[] in log.c */ #define ERRNO_AUTHPROB (-48) /* Authenticator "other" failure */ #define ERRNO_UTF8_FWD (-49) /* target not supporting SMTPUTF8 */ #define ERRNO_HOST_IS_LOCAL (-50) /* Transport refuses to talk to localhost */ -#define ERRNO_TAINT (-51) /* Transport refuses to talk use tainted filename */ +#define ERRNO_PASSONE (-51) /* first-pass-only routing */ +#define ERRNO_NOROUTER (-52) /* ran out of routers */ +#define ERRNO_ROUTERDEFER (-53) /* redirect router :defer: */ +#define ERRNO_ROUTERFAIL (-54) /* redirect router :fail: */ +#define ERRNO_MXDEFER (-55) /* missing MX, defer requested */ +#define ERRNO_TPTLIMIT (-57) /* transport limit */ +#define ERRNO_TAINT (-58) /* Transport refuses to use tainted filename */ /* These must be last, so all retry deferments can easily be identified */ -#define ERRNO_RETRY_BASE (-52) /* Base to test against */ -#define ERRNO_RRETRY (-52) /* Not time for routing */ +#define ERRNO_RETRY_BASE (-59) /* Base to test against */ +#define ERRNO_RRETRY (-59) /* Not time for routing */ -#define ERRNO_WARN_BASE (-53) /* Base to test against */ -#define ERRNO_LRETRY (-53) /* Not time for local delivery */ -#define ERRNO_HRETRY (-54) /* Not time for any remote host */ -#define ERRNO_LOCAL_ONLY (-55) /* Local-only delivery */ -#define ERRNO_QUEUE_DOMAIN (-56) /* Domain in queue_domains */ -#define ERRNO_TRETRY (-57) /* Transport concurrency limit */ -#define ERRNO_EVENT (-58) /* Event processing request alternate response */ +#define ERRNO_WARN_BASE (-60) /* Base to test against */ +#define ERRNO_LRETRY (-60) /* Not time for local delivery */ +#define ERRNO_HRETRY (-61) /* Not time for any remote host */ +#define ERRNO_LOCAL_ONLY (-62) /* Local-only delivery */ +#define ERRNO_QUEUE_DOMAIN (-63) /* Domain in queue_domains */ +#define ERRNO_TRETRY (-64) /* Transport concurrency limit */ +#define ERRNO_EVENT (-65) /* Event processing request alternate response */ diff --git a/src/src/route.c b/src/src/route.c index c2de39228..c3f4ecaa0 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -1909,6 +1909,7 @@ running a router go direct to ROUTE_EXIT from code above. */ if (!r) { HDEBUG(route) debug_printf_indent("no more routers\n"); + addr->basic_errno = ERRNO_NOROUTER; if (!addr->message) { uschar * message = US"Unrouteable address"; diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c index 8e1adc0ed..b9d531528 100644 --- a/src/src/routers/dnslookup.c +++ b/src/src/routers/dnslookup.c @@ -301,13 +301,14 @@ for (;;) &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) { case DEFER: - addr->message = US"lookup defer for mx_domains"; - return DEFER; + addr->basic_errno = ERRNO_DNSDEFER; + addr->message = US"lookup defer for mx_domains"; + return DEFER; case OK: - DEBUG(route) debug_printf("%s router rejected %s: no MX record(s)\n", - rblock->drinst.name, fully_qualified_name); - continue; + DEBUG(route) debug_printf("%s router rejected %s: no MX record(s)\n", + rblock->drinst.name, fully_qualified_name); + continue; } /* Deferral returns forthwith, and anything other than failure breaks the @@ -315,6 +316,7 @@ for (;;) if (rc == HOST_FIND_SECURITY) { + addr->basic_errno = ERRNO_DNSDEFER; addr->message = US"host lookup done insecurely"; return DEFER; } @@ -326,6 +328,7 @@ for (;;) rblock->drinst.name); return PASS; } + addr->basic_errno = ERRNO_DNSDEFER; addr->message = US"host lookup did not complete"; return DEFER; } @@ -338,12 +341,14 @@ for (;;) &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL)) { case DEFER: + addr->basic_errno = ERRNO_DNSDEFER; addr->message = US"lookup defer for fail_defer_domains option"; return DEFER; case OK: DEBUG(route) debug_printf("%s router: matched fail_defer_domains\n", rblock->drinst.name); + addr->basic_errno = ERRNO_MXDEFER; addr->message = US"missing MX, or all MXs point to missing A records," " and defer requested"; return DEFER; diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 05ec1bab2..614f9e0e0 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -604,10 +604,12 @@ switch (frc) verifying. Remove any SMTP code if it is not allowed. */ case FF_DEFER: + addr->basic_errno = ERRNO_ROUTERDEFER; yield = DEFER; goto SORT_MESSAGE; case FF_FAIL: + addr->basic_errno = ERRNO_ROUTERFAIL; if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK) return xrc; add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw); diff --git a/src/src/routers/rf_self_action.c b/src/src/routers/rf_self_action.c index cbc711cbd..5912d933e 100644 --- a/src/src/routers/rf_self_action.c +++ b/src/src/routers/rf_self_action.c @@ -90,6 +90,7 @@ switch (code) return DEFER; case self_defer: + addr->basic_errno = ERRNO_ROUTERDEFER; addr->message = msg; return DEFER; @@ -115,6 +116,7 @@ switch (code) DEBUG(route) debug_printf_indent("%s: %s: address failed (self = fail)\n", msg, addr->domain); addr->message = msg; + addr->basic_errno = ERRNO_HOST_IS_LOCAL; setflag(addr, af_pass_message); return FAIL; } diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 16519726a..989afc620 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -1580,9 +1580,9 @@ if (!isdirectory) { addr->basic_errno = errno; addr->message = - string_sprintf("creating lock file hitching post %s " - "(euid=%ld egid=%ld)", hitchname, (long int)geteuid(), - (long int)getegid()); + string_sprintf("creating lock file hitching post %s %s " + "(euid=%ld egid=%ld)", hitchname, + strerror(errno), (long int)geteuid(), (long int)getegid()); return FALSE; } @@ -1854,8 +1854,8 @@ if (!isdirectory) } addr->basic_errno = errno; if (isfifo) - addr->message = string_sprintf("while opening named pipe %s " - "(could mean no process is reading it)", filename); + addr->message = string_sprintf("while opening named pipe %s %s " + "(could mean no process is reading it)", filename, strerror(errno)); else if (errno != EWOULDBLOCK) addr->message = string_sprintf("while opening mailbox %s", filename); goto RETURN; diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 5fb07bd7f..645a7fcaf 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -5909,8 +5909,11 @@ retry_non_continued: expired = FALSE; for (address_item * addr = addrlist; addr; addr = addr->next) if (addr->transport_return == DEFER) + { + addr->basic_errno = ERRNO_PASSONE; addr->message = US"first-pass only routing due to -odqs, " "queue_smtp_domains or control=queue"; + } continue; /* With next host */ } commit 695adf7af4c7ce611371076aee62ccfdfc730974 Author: Jeremy Harris Date: Wed Feb 25 10:51:22 2026 +0000 Testsuite: munge for pipe-open eror diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 989afc620..acbcd73d6 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -1854,7 +1854,7 @@ if (!isdirectory) } addr->basic_errno = errno; if (isfifo) - addr->message = string_sprintf("while opening named pipe %s %s " + addr->message = string_sprintf("while opening named pipe %q: %s " "(could mean no process is reading it)", filename, strerror(errno)); else if (errno != EWOULDBLOCK) addr->message = string_sprintf("while opening mailbox %s", filename); commit 5dbf408be98caa1c7af21854288ba33c49ef0766 Author: Jeremy Harris Date: Sat Feb 28 16:14:56 2026 +0000 Event: proc:deliver diff --git a/src/src/deliver.c b/src/src/deliver.c index 0cfe587eb..778869482 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -6784,6 +6784,10 @@ open_db dbblock, * dbm_file = NULL; BOOL has_privs = TRUE; rmark reset_point; +#ifndef DISABLE_EVENT +(void) event_raise(event_action, US"proc:deliver", id, NULL); +#endif + CONTINUED_ID: reset_point = store_mark(); commit f90ab861cf2faa7fb8efa62636cebd80b71ed383 Author: Jeremy Harris Date: Sat Feb 28 19:43:09 2026 +0000 DKIM: Add List-Unsubscribe-Post: to signing list sample macros. Bug 3153 diff --git a/src/src/miscmods/pdkim/pdkim.h b/src/src/miscmods/pdkim/pdkim.h index 454343b1b..ec9bbcd7b 100644 --- a/src/src/miscmods/pdkim/pdkim.h +++ b/src/src/miscmods/pdkim/pdkim.h @@ -39,6 +39,7 @@ "Resent-Sender:Resent-To:Resent-Cc:"\ "Resent-Message-ID:In-Reply-To:References:"\ "List-Id:List-Help:List-Unsubscribe:"\ + "List-Unsubscribe-Post:"\ "List-Subscribe:List-Post:List-Owner:List-Archive" #define PDKIM_OVERSIGN_HEADERS "+From:+Sender:+Reply-To:+Subject:+Date:"\ @@ -48,6 +49,7 @@ "+Resent-Sender:+Resent-To:+Resent-Cc:"\ "+Resent-Message-ID:+In-Reply-To:+References:"\ "+List-Id:+List-Help:+List-Unsubscribe:"\ + "+List-Unsubscribe-Post:"\ "+List-Subscribe:+List-Post:+List-Owner:+List-Archive" /* -------------------------------------------------------------------------- */ commit 313cb880f46d5adbe6a39430439d12b6510573ac Author: Jeremy Harris Date: Tue Mar 3 17:11:23 2026 +0000 tidying diff --git a/src/src/deliver.c b/src/src/deliver.c index 778869482..eae9616fc 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -5736,9 +5736,8 @@ while (*s) a bounce or a warning message. It tries to format the message reasonably as required by RFC 3461 by adding a space after each newline -it uses the same logic as print_address_error() above. if af_pass_message is true -and addr->message is set it uses the remote host answer. if not addr->user_message -is used instead if available. +If af_pass_message and addr->message are set, we assume the latter contains, +as a trailing component, the error information. Arguments: addr the address @@ -5748,7 +5747,7 @@ Returns: nothing */ static void -print_dsn_diagnostic_code(const address_item *addr, FILE *f) +print_dsn_diagnostic_code(const address_item * addr, FILE * f) { uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL; unsigned cnt; @@ -5761,6 +5760,11 @@ DEBUG(deliver) debug_printf("DSN Diagnostic-Code: addr->message = %s\n", addr->message); /* search first ": ". we assume to find the remote-MTA answer there */ + +/*XXX Fragile. Very easy for what is in addr->message to be changed +in maintenance, eg. adding an earlier ": ". But, also, a remote reponse +could include one. Do we need a separate copy of the response? */ + if (!(s = Ustrstr(addr->message, ": "))) return; /* not found, bail out */ diff --git a/src/src/rda.c b/src/src/rda.c index 66f4d1239..c23f34c89 100644 --- a/src/src/rda.c +++ b/src/src/rda.c @@ -562,8 +562,8 @@ Returns: values from extraction function, or FF_NONEXIST: int rda_interpret(redirect_block * rdata, int options, const uschar * include_directory, const sieve_block * sieve, - const ugid_block * ugid, address_item ** generated, - uschar ** error, error_block ** eblockp, int * filtertype, const uschar * rname) + const ugid_block * ugid, address_item ** generated, uschar ** error, + error_block ** eblockp, int * filtertype, const uschar * rname) { int fd, rc, pfd[2]; int yield, status; diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c index 614f9e0e0..6a8fee9ec 100644 --- a/src/src/routers/redirect.c +++ b/src/src/routers/redirect.c @@ -482,19 +482,16 @@ int redirect_router_entry( { redirect_router_options_block * ob = (redirect_router_options_block *)(rblock->drinst.options_block); -address_item *generated = NULL; -const uschar *save_qualify_domain_recipient = qualify_domain_recipient; -uschar *discarded = US"discarded"; +address_item * generated = NULL; +const uschar * save_qualify_domain_recipient = qualify_domain_recipient; +uschar * discarded = US"discarded"; address_item_propagated addr_prop; -error_block *eblock = NULL; +error_block * eblock = NULL; ugid_block ugid; redirect_block redirect; sieve_block sieve; -int filtertype = FILTER_UNSET; -int yield = OK; -int options = ob->bit_options; -int frc = 0; -int xrc = 0; +int filtertype = FILTER_UNSET, yield = OK, options = ob->bit_options; +int frc = 0, xrc = 0; /* Initialize the data to be propagated to the children */ commit 221f20507effe34c8cafa105b8a3986fc56691f5 Author: Jeremy Harris Date: Wed Mar 4 13:02:03 2026 +0000 DSN: commandline options. Bug 2560 diff --git a/src/src/daemon.c b/src/src/daemon.c index c10924426..96421e820 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -576,7 +576,7 @@ if (pid == 0) } { - BOOL ok = receive_msg(FALSE); + BOOL ok = receive_msg(FALSE, rf_notify_unset); search_tidyup(); /* Close cached databases */ if (!ok) /* Connection was dropped */ { diff --git a/src/src/deliver.c b/src/src/deliver.c index eae9616fc..488f87317 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -8840,7 +8840,8 @@ else if (addr_defer != (address_item *)(+1)) { DEBUG(deliver) debug_printf("one_time: adding %s in place of %s\n", otaddr->address, otaddr->parent->address); - receive_add_recipient(otaddr->address, t); + /*XXX should we copy the parent dsn_flags,orcpt ? */ + receive_add_recipient(otaddr->address, t, rf_notify_unset, NULL); recipients_list[recipients_count-1].errors_to = otaddr->prop.errors_address; tree_add_nonrecipient(otaddr->parent->address); update_spool = TRUE; diff --git a/src/src/exim.c b/src/src/exim.c index d06e3eda8..782941457 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1844,70 +1844,37 @@ int main(int argc, char ** cargv) { const uschar ** argv = CUSS cargv; -int arg_receive_timeout = -1; -int arg_smtp_receive_timeout = -1; -int arg_error_handling = error_handling; -int filter_sfd = -1; -int filter_ufd = -1; -int group_count; -int i, rv; -int list_queue_option = QL_BASIC; -int msg_action = 0; -int msg_action_arg = -1; -int namelen = argv[0] ? Ustrlen(argv[0]) : 0; -int queue_only_reason = 0; +int arg_receive_timeout = -1, arg_smtp_receive_timeout = -1, + arg_error_handling = error_handling, filter_sfd = -1, filter_ufd = -1, + group_count, i, rv, list_queue_option = QL_BASIC, msg_action = 0, + msg_action_arg = -1, namelen = argv[0] ? Ustrlen(argv[0]) : 0, + queue_only_reason = 0, rcpt_dsn_flags = 0, recipients_arg = argc, + sender_address_domain = 0, test_retry_arg = -1, test_rewrite_arg = -1; #ifdef EXIM_PERL int perl_start_option = 0; #endif -int recipients_arg = argc; -int sender_address_domain = 0; -int test_retry_arg = -1; -int test_rewrite_arg = -1; gid_t original_egid; -BOOL arg_queue_only = FALSE; -BOOL bi_option = FALSE; -BOOL checking = FALSE; -BOOL count_queue = FALSE; -BOOL extract_recipients = FALSE; -BOOL flag_G = FALSE; -BOOL flag_n = FALSE; -BOOL forced_delivery = FALSE; -BOOL f_end_dot = FALSE; -BOOL deliver_give_up = FALSE; -BOOL list_queue = FALSE; -BOOL list_options = FALSE; -BOOL list_config = FALSE; -BOOL local_queue_only; -BOOL one_msg_action = FALSE; -BOOL opt_D_used = FALSE; -BOOL queue_only_set = FALSE; -BOOL receiving_message = TRUE; -BOOL sender_ident_set = FALSE; -BOOL session_local_queue_only; -BOOL unprivileged; -BOOL removed_privilege = FALSE; -BOOL usage_wanted = FALSE; -BOOL verify_address_mode = FALSE; -BOOL verify_as_sender = FALSE; -BOOL rcpt_verify_quota = FALSE; -BOOL version_printed = FALSE; -const uschar * alias_arg = NULL; -const uschar * called_as = US""; -const uschar * cmdline_syslog_name = NULL; -const uschar * start_queue_run_id = NULL; -const uschar * stop_queue_run_id = NULL; -const uschar * expansion_test_message = NULL; -const uschar * ftest_domain = NULL; -const uschar * ftest_localpart = NULL; -const uschar * ftest_prefix = NULL; -const uschar * ftest_suffix = NULL; +BOOL arg_queue_only = FALSE, bi_option = FALSE, checking = FALSE, + count_queue = FALSE, extract_recipients = FALSE, flag_G = FALSE, + flag_n = FALSE, forced_delivery = FALSE, f_end_dot = FALSE, + deliver_give_up = FALSE, list_queue = FALSE, list_options = FALSE, + list_config = FALSE, local_queue_only, one_msg_action = FALSE, + opt_D_used = FALSE, queue_only_set = FALSE, receiving_message = TRUE, + sender_ident_set = FALSE, session_local_queue_only, unprivileged, + removed_privilege = FALSE, usage_wanted = FALSE, + verify_address_mode = FALSE, verify_as_sender = FALSE, + rcpt_verify_quota = FALSE, version_printed = FALSE; +const uschar * alias_arg = NULL, * called_as = US"", + * cmdline_syslog_name = NULL, * start_queue_run_id = NULL, + * stop_queue_run_id = NULL, * expansion_test_message = NULL, + * ftest_domain = NULL, * ftest_localpart = NULL, + * ftest_prefix = NULL, * ftest_suffix = NULL, + * malware_test_file = NULL, * real_sender_address; uschar * log_oneline = NULL; -const uschar * malware_test_file = NULL; -const uschar * real_sender_address; uschar * originator_home = US"/"; size_t sz; -struct passwd *pw; +struct passwd * pw; struct stat statbuf; pid_t passed_qr_pid = (pid_t)0; int passed_qr_pipe = -1; @@ -1919,13 +1886,13 @@ BOOL info_stdout = FALSE; /* Possible options for -R and -S */ -static uschar *rsopts[] = { US"f", US"ff", US"r", US"rf", US"rff" }; +static uschar * rsopts[] = { US"f", US"ff", US"r", US"rf", US"rff" }; /* Need to define this in case we need to change the environment in order to get rid of a bogus time zone. We have to make it char rather than uschar -because some OS define it in /usr/include/unistd.h. */ +because some OS' define it in /usr/include/unistd.h. */ -extern char **environ; +extern char ** environ; #ifdef MEASURE_TIMING (void)gettimeofday(×tamp_startup, NULL); @@ -3410,6 +3377,77 @@ on the second character (the one after '-'), to save some effort. */ } break; + /* -oDSN: RFC 3461 DSN options: + -oDSN N=[never,success,failure,delay] + -oDSN R=[full,hdrs] + -oDSN V= + */ + case 'D': + { + const uschar * s; + uschar c; + + if (Ustrcmp(argrest, "SN") != 0) + { + badarg = TRUE; + break; + } + if (i+1 >= argc) exim_fail("string expected after -oDSN"); + switch (c = *(s = argv[++i])) + { + default: exim_fail("only subcases N,R,V expected for -oDSN"); + case 'N': case 'R': case 'V': + if (*++s == '=') break; + exim_fail("equals expected after -oDSN subcase letter"); + } + s++; + switch (c) + { + case 'N': + while (*s) + { + if (Ustrncmp(s, "never", 5) == 0) + if (*(s += 5) || rcpt_dsn_flags) + exim_fail("DSN NOTIFY=never may not be combined"); + else + rcpt_dsn_flags = rf_notify_never; + else if (Ustrncmp(s, "success", 7) == 0) + { rcpt_dsn_flags |= rf_notify_success; s += 7; } + else if (Ustrncmp(s, "failure", 7) == 0) + { rcpt_dsn_flags |= rf_notify_failure; s += 7; } + else if (Ustrncmp(s, "delay", 5) == 0) + { rcpt_dsn_flags |= rf_notify_delay; s += 5; } + else + exim_fail("DSN NOTIFY bad value"); + + if (!s) break; + if (*s == ',') s++; + } + break; + + case 'R': + if (Ustrcmp(s, "full") == 0) + dsn_ret = dsn_ret_full; + else if (Ustrcmp(s, "hdrs") == 0) + dsn_ret = dsn_ret_hdrs; + else + exim_fail("bad value for DSN RET"); + break; + + case 'V': /* per rfc 3461 4.4 - 100 char max, after xtext-enc + and the "ENVID=" prefix */ + { + unsigned n = 0; + for (const uschar * t = s; *t; t++, n++) + if (!isprint(*t)) exim_fail("DSN ENVID has bad character"); + dsn_envid = xtextencode(s, n); + if (Ustrlen(dsn_envid) > 100-6) exim_fail("DSN ENVID is oversize"); + break; + } + } + } + break; + /* -odb: background delivery */ case 'd': @@ -5439,7 +5477,7 @@ if (f.expansion_test) filter_test = FTEST_USER; /* Fudge to make it look like filter test */ message_ended = END_NOTENDED; recipients_max_expanded = atoi(CCS rme); - read_message_body(receive_msg(extract_recipients)); + read_message_body(receive_msg(extract_recipients, rf_notify_unset)); message_linecount += body_linecount; (void)dup2(save_stdin, 0); (void)close(save_stdin); @@ -5581,7 +5619,7 @@ if (host_checking) for (; (reset_point = store_mark()); store_reset(reset_point)) { if (smtp_setup_msg() <= 0) break; - if (!receive_msg(FALSE)) break; + if (!receive_msg(FALSE, rf_notify_unset)) break; return_path = sender_address = NULL; dnslist_domain = dnslist_matched = NULL; @@ -5880,7 +5918,7 @@ for (BOOL more = TRUE; more; ) /* Now get the data for the message */ - more = receive_msg(extract_recipients); + more = receive_msg(extract_recipients, rcpt_dsn_flags); if (!message_id[0]) { cancel_cutthrough_connection(TRUE, US"receive dropped"); @@ -6006,7 +6044,10 @@ for (BOOL more = TRUE; more; ) } } - receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1); + /*XXX no way to set orcpt from cmdline, yet */ + receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1, + rcpt_dsn_flags, NULL); + s = ss; if (!finished) while (*++s && (*s == ',' || isspace(*s))); @@ -6054,7 +6095,7 @@ for (BOOL more = TRUE; more; ) spool. */ message_ended = END_NOTENDED; - more = receive_msg(extract_recipients); + more = receive_msg(extract_recipients, rcpt_dsn_flags); /* more is always FALSE here (not SMTP message) when reading a message for real; when reading the headers of a message for filter testing, @@ -6094,7 +6135,8 @@ for (BOOL more = TRUE; more; ) ftest_prefix ? ftest_prefix : US"", deliver_localpart, ftest_suffix ? ftest_suffix : US"", - deliver_domain), -1); + deliver_domain), + -1, rcpt_dsn_flags, NULL); printf("Recipient = %s\n", recipients_list[0].address); if (ftest_prefix) printf("Prefix = %s\n", ftest_prefix); diff --git a/src/src/functions.h b/src/src/functions.h index 062891e72..f6c21b8c4 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -453,7 +453,7 @@ extern void read_message_body(BOOL); extern void receive_bomb_out(const uschar *, uschar *) NORETURN; extern BOOL receive_check_fs(int); extern BOOL receive_check_set_sender(const uschar *); -extern BOOL receive_msg(BOOL); +extern BOOL receive_msg(BOOL, int); extern int_eximarith_t receive_statvfs(BOOL, int *); extern void receive_swallow_smtp(void); extern int recv_fd_from_sock(int); diff --git a/src/src/local_scan.h b/src/src/local_scan.h index f3ed1addb..102b3ed53 100644 --- a/src/src/local_scan.h +++ b/src/src/local_scan.h @@ -159,7 +159,7 @@ typedef struct recipient_item { const uschar *address; /* the recipient address */ int pno; /* parent number for "one_time" alias, or -1 */ const uschar *errors_to; /* the errors_to address or NULL */ - uschar *orcpt; /* DSN orcpt */ + const uschar *orcpt; /* DSN orcpt */ int dsn_flags; /* DSN flags */ } recipient_item; @@ -219,7 +219,7 @@ extern int lss_match_domain(uschar *, uschar *); extern int lss_match_local_part(uschar *, uschar *, BOOL); extern int lss_match_address(uschar *, uschar *, BOOL); extern int lss_match_host(uschar *, uschar *, uschar *); -extern void receive_add_recipient(const uschar *, int); +extern void receive_add_recipient(const uschar *, int, int, const uschar *); extern BOOL receive_remove_recipient(const uschar *); extern uschar *rfc2047_decode(uschar *, BOOL, const uschar *, int, int *, uschar **); diff --git a/src/src/macros.h b/src/src/macros.h index d7e5576f7..76f2c5619 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -923,6 +923,7 @@ enum { /* Flags for recipient_block, used in DSN support */ +#define rf_notify_unset 0x00 #define rf_dsnlasthop 0x01 /* Do not propagate DSN any further */ #define rf_notify_never 0x02 /* NOTIFY= settings */ #define rf_notify_success 0x04 diff --git a/src/src/malware.c b/src/src/malware.c index 1f6e8bcfb..6ba2c5030 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -1861,7 +1861,7 @@ message_id = message_id_buf; sender_address = US"malware-sender@example.net"; return_path = US""; recipients_list = NULL; -receive_add_recipient(US"malware-victim@example.net", -1); +receive_add_recipient(US"malware-victim@example.net", -1, rf_notify_unset,NULL); f.enable_dollar_recipients = TRUE; ret = malware_internal(US"*", TRUE, eml_filename, 0); diff --git a/src/src/queue.c b/src/src/queue.c index 6eeca6eb6..c880412e8 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -1585,7 +1585,7 @@ switch(action) #ifdef SUPPORT_I18N if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE; #endif - receive_add_recipient(recipient, -1); + receive_add_recipient(recipient, -1, rf_notify_unset, NULL); log_write(LOG_MAIN, "recipient <%s> added by %s", recipient, username); } diff --git a/src/src/receive.c b/src/src/receive.c index fd0f9c138..cca230de9 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -509,13 +509,18 @@ format. Arguments: recipient the next address to add to recipients_list pno parent number for fixed aliases; -1 otherwise + dsn_flags classes of notify + dsn_orcpt original recipient Returns: nothing */ void -receive_add_recipient(const uschar * recipient, int pno) +receive_add_recipient(const uschar * recipient, int pno, int dsn_flags, + const uschar * dsn_orcpt) { +recipient_item * rp; + if (recipients_count >= recipients_list_max) { const recipient_item * oldlist = recipients_list; @@ -531,11 +536,15 @@ if (recipients_count >= recipients_list_max) memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item)); } -recipients_list[recipients_count].address = recipient; -recipients_list[recipients_count].pno = pno; -recipients_list[recipients_count].orcpt = NULL; -recipients_list[recipients_count].dsn_flags = 0; -recipients_list[recipients_count++].errors_to = NULL; +rp = recipients_list + recipients_count++; +rp->address = recipient; +rp->pno = pno; +rp->orcpt = dsn_orcpt; +rp->dsn_flags = dsn_flags; +rp->errors_to = NULL; + +/* DEBUG(receive) debug_printf("DSN: orcpt: %s flags: %d\n", + rp->orcpt, rp->dsn_flags); */ } @@ -1721,6 +1730,7 @@ terminated by CRLF is treated in the same way as a bare CR. Arguments: extract_recip TRUE if recipients are to be extracted from the message's headers + rcpt_dsn_flags notify classes, used only if extract_recip Returns: TRUE there are more messages to be read (SMTP input) FALSE there are no more messages to be read (non-SMTP input @@ -1731,7 +1741,7 @@ whether the headers (which is all that is read) were terminated by '.' or not. */ BOOL -receive_msg(BOOL extract_recip) +receive_msg(BOOL extract_recip, int rcpt_dsn_flags) { int rc = FAIL, msg_size = 0, process_info_len = Ustrlen(process_info); int header_size = 256, had_zero = 0, prevlines_length = 0, ptr = 0; @@ -2726,12 +2736,10 @@ if (extract_recip) no recipients left. */ else if (recipient) - { if (tree_search(tree_nonrecipients, recipient) == NULL) - receive_add_recipient(recipient, -1); + receive_add_recipient(recipient, -1, rcpt_dsn_flags, NULL); else extracted_ignored = TRUE; - } /* Move on past this address */ diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 8952e82e8..cbce7a121 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1997,6 +1997,8 @@ while (done <= 0) else moan_smtp_batch(smtp_cmd_buffer, "501 sender address must contain " "a domain"); + + /*XXX Note: we do not handle DSN options on MAIL */ break; @@ -2057,7 +2059,8 @@ while (done <= 0) moan_smtp_batch(smtp_cmd_buffer, "501 recipient address must contain a domain"); - receive_add_recipient(recipient, -1); + /*XXX Note: we do not handle DSN options on RCPT */ + receive_add_recipient(recipient, -1, rf_notify_unset, NULL); break; @@ -5425,15 +5428,7 @@ while (done <= 0) smtp_user_msg(US"250", user_msg); else smtp_printf("250 Accepted\r\n", more); - receive_add_recipient(recipient, -1); - - /* Set the dsn flags in the recipients_list */ - recipients_list[recipients_count-1].orcpt = rcpt_orcpt; - recipients_list[recipients_count-1].dsn_flags = rcpt_dsn_flags; - - /* DEBUG(receive) debug_printf("DSN: orcpt: %s flags: %d\n", - recipients_list[recipients_count-1].orcpt, - recipients_list[recipients_count-1].dsn_flags); */ + receive_add_recipient(recipient, -1, rcpt_dsn_flags, rcpt_orcpt); } /* The recipient was discarded */ diff --git a/src/src/spool_in.c b/src/src/spool_in.c index d340ebbb1..9fba36e17 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -839,12 +839,8 @@ the Coverity error on recipients_count */ where = US"recipient"; for (recipients_count = 0; recipients_count < rcount; recipients_count++) { - int nn; - int pno = -1; - int dsn_flags = 0; - uschar *orcpt = NULL; - uschar *errors_to = NULL; - uschar *p; + int nn, pno = -1, dsn_flags = 0; + uschar * orcpt = NULL, * errors_to = NULL, * p; if (fgets_big_buffer(fp) == NULL) goto SPOOL_READ_ERROR; nn = Ustrlen(big_buffer); diff --git a/src/src/structs.h b/src/src/structs.h index 833c16655..e25c69f6a 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -560,7 +560,7 @@ typedef struct address_item { uschar *message; /* error message */ uschar *user_message; /* error message that can be sent over SMTP or quoted in bounce message */ - const uschar *onetime_parent; /* saved original parent for onetime */ + const uschar *onetime_parent; /* saved original parent for onetime */ uschar **pipe_expandn; /* numeric expansions for pipe from filter */ uschar *return_filename; /* name of return file */ uschar *self_hostname; /* after self=pass */ @@ -589,7 +589,7 @@ typedef struct address_item { uschar *auth_id; /* auth "login" name used by transport */ uschar *auth_sndr; /* AUTH arg to SMTP MAIL, used by transport */ - uschar *dsn_orcpt; /* DSN orcpt value */ + const uschar *dsn_orcpt; /* DSN orcpt value */ int dsn_flags; /* DSN flags */ int dsn_aware; /* DSN aware flag */ commit 9d2a8b572f81baea8be95d826ee71c87e01d1f05 Author: Jeremy Harris Date: Thu Mar 5 15:21:23 2026 +0000 check malloc return values diff --git a/src/exim_monitor/em_version.c b/src/exim_monitor/em_version.c index aac3788cd..5b4fa1b92 100644 --- a/src/exim_monitor/em_version.c +++ b/src/exim_monitor/em_version.c @@ -31,14 +31,15 @@ uschar today[20]; #endif version_string = US"2.06"; +version_date = US store_malloc(32); +version_date[0] = 0; #ifdef EXIM_BUILD_DATE_OVERRIDE -/* Reproducible build support; build tooling should have given us something looking like - * "25-Feb-2017 20:15:40" in EXIM_BUILD_DATE_OVERRIDE based on $SOURCE_DATE_EPOCH in environ - * per - */ -version_date = US malloc(32); -version_date[0] = 0; +/* Reproducible build support; build tooling should have given us something +looking like "25-Feb-2017 20:15:40" in EXIM_BUILD_DATE_OVERRIDE based on +$SOURCE_DATE_EPOCH in environ per + */ + Ustrncat(version_date, EXIM_BUILD_DATE_OVERRIDE, 31); #else @@ -46,8 +47,6 @@ Ustrcpy(today, US __DATE__); if (today[4] == ' ') i = 1; today[3] = today[6] = '-'; -version_date = US malloc(32); -version_date[0] = 0; Ustrncat(version_date, today+4+i, 3-i); Ustrncat(version_date, today, 4); Ustrncat(version_date, today+7, 4); diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index 3ef61735f..fab0dd97a 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -97,7 +97,7 @@ if (!OK) printf("\n*** \"%s\" (%s) must contain precisely one occurrence of\n" "*** \"%%s\". Please review your build-time configuration.\n\n/", value, name); - exit(1); + exit(EXIT_FAILURE); } } @@ -115,14 +115,14 @@ char buffer[1024]; if (argc != 1) { printf("*** Buildconfig: called with incorrect arguments\n"); - exit(1); + exit(EXIT_FAILURE); } new = fopen("config.h", "wb"); if (new == NULL) { printf("*** Buildconfig: failed to open config.h for output\n"); - exit(1); + exit(EXIT_FAILURE); } printf("Building configuration file config.h\n"); @@ -216,7 +216,7 @@ if (!(base = fopen("Makefile", "rb"))) { printf("*** Buildconfig: failed to open Makefile\n"); (void)fclose(new); - exit(1); + exit(EXIT_FAILURE); } errno_quota[0] = 0; /* no over-riding value set */ @@ -257,7 +257,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) { printf("*** Only one of USE_DB, USE_GDBM, USE_SQLITE or USE_TDB should be " "defined in Local/Makefile\n"); - exit(1); + exit(EXIT_FAILURE); } use_which_db_in_local_makefile = 1; } @@ -279,7 +279,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) if (*p++ != '=') { printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount); - exit(1); + exit(EXIT_FAILURE); } while (isspace((unsigned char)*p)) p++; if (strcmp(p, "YES") == 0 || strcmp(p, "yes") == 0) *(h->flag) = 1; @@ -302,7 +302,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) if (*p++ != '=') { printf("*** Buildconfig: syntax error in Makefile line %d\n", linecount); - exit(1); + exit(EXIT_FAILURE); } while (isspace((unsigned char)*p)) p++; strcpy(s->data, p); @@ -338,7 +338,7 @@ if (base == NULL) { printf("*** Buildconfig: failed to open ../src/config.h.defaults\n"); (void)fclose(new); - exit(1); + exit(EXIT_FAILURE); } while (fgets(buffer, sizeof(buffer), base) != NULL) @@ -411,7 +411,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** EXIM_USER has not been defined in any of the Makefiles in " "the\n \"Local\" directory. Please review your build-time " "configuration.\n\n"); - return 1; + return EXIT_FAILURE; } while (isspace((unsigned char)(*user))) user++; @@ -420,7 +420,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** EXIM_USER is defined as an empty string in one of the " "files\n in the \"Local\" directory. Please review your build-time" "\n configuration.\n\n"); - return 1; + return EXIT_FAILURE; } for (s = user; *s; s++) @@ -429,7 +429,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** EXIM_USER contains the control character 0x%02X in one " "of the files\n in the \"Local\" directory. Please review your " "build-time\n configuration.\n\n", *s); - return 1; + return EXIT_FAILURE; } /* Numeric uid given */ @@ -458,7 +458,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** User \"%s\" (specified in one of the Makefiles) does not " "exist.\n Please review your build-time configuration.\n\n", user); - return 1; + return EXIT_FAILURE; } uid = pw->pw_uid; @@ -484,7 +484,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) else printf("EXIM_USER is defined numerically, so there is no" "\n default for EXIM_GROUP and you must set it explicitly.\n P"); printf("lease review your build-time configuration.\n\n"); - return 1; + return EXIT_FAILURE; } for (s = group; *s; s++) @@ -493,7 +493,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** EXIM_GROUP contains the control character 0x%02X in one " "of the files\n in the \"Local\" directory. Please review your " "build-time\n configuration.\n\n", *s); - return 1; + return EXIT_FAILURE; } /* Group name given. This may be by reference or to be looked up now, @@ -520,7 +520,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** Group \"%s\" (specified in one of the Makefiles) does " "not exist.\n Please review your build-time configuration.\n\n", group); - return 1; + return EXIT_FAILURE; } gid = gr->gr_gid; } @@ -532,7 +532,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) { printf("\n*** No group set for Exim. Please review your build-time " "configuration.\n\n"); - return 1; + return EXIT_FAILURE; } /* security sanity checks @@ -545,7 +545,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) (strcmp(username, "toor") == 0) ))) { printf("\n*** Exim's internal user must not be root.\n\n"); - return 1; + return EXIT_FAILURE; } /* Output user and group names or uid/gid. When names are set, uid/gid @@ -590,7 +590,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** %s contains the control character 0x%02X in " "one of the files\n in the \"Local\" directory. Please review " "your build-time\n configuration.\n\n", name, *s); - return 1; + return EXIT_FAILURE; } /* Numeric uid given */ @@ -620,7 +620,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** Group \"%s\" (specified in one of the Makefiles) does not " "exist.\n Please review your build-time configuration.\n\n", user); - return 1; + return EXIT_FAILURE; } gid = gr->gr_gid; } @@ -633,7 +633,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** User \"%s\" (specified in one of the Makefiles) does not " "exist.\n Please review your build-time configuration.\n\n", user); - return 1; + return EXIT_FAILURE; } uid = pw->pw_uid; } @@ -668,7 +668,11 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) char *p = list; while (*p != 0) if (*p++ == ':') count++; - vector = malloc((count+1) * sizeof(uid_t)); + if (!(vector = malloc((count+1) * sizeof(uid_t)))) + { + perror("malloc"); + exit(EXIT_FAILURE); + } vector[0] = (uid_t)count; for (int i = 1; i <= count; list++, i++) @@ -693,7 +697,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) " in one of the Makefiles) does not exist.\n" " Please review your build-time configuration.\n\n", name); - return 1; + return EXIT_FAILURE; } vector[j++] = pw->pw_uid; } @@ -750,7 +754,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) { printf("\n*** LDAP_LIB_TYPE=%s is not a recognized LDAP library type." "\n*** Please review your build-time configuration.\n\n", value); - return 1; + return EXIT_FAILURE; } } @@ -766,7 +770,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) { printf("\n*** RADIUS_LIB_TYPE=%s is not a recognized RADIUS library type." "\n*** Please review your build-time configuration.\n\n", value); - return 1; + return EXIT_FAILURE; } } @@ -832,7 +836,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) else { printf("Value of %s should be -1..9\n", name); - return 1; + return EXIT_FAILURE; } } @@ -854,7 +858,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) else { printf("Unreasonable value (%s) of \"%s\".\n", value, name); - return 1; + return EXIT_FAILURE; } } @@ -883,7 +887,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) printf("\n*** %s has not been defined in any of the Makefiles in the\n" " \"Local\" directory. " "Please review your build-time configuration.\n\n", name); - return 1; + return EXIT_FAILURE; } if (strcmp(name, "TIMEZONE_DEFAULT") == 0) @@ -930,7 +934,7 @@ Some OS' have released with it broken. */ fprintf(new, "\n/* End of config.h */\n"); (void)fclose(new); -return 0; +return EXIT_SUCCESS; } /* End of buildconfig.c */ diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 7a0354b06..1bf59b83d 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -687,7 +687,11 @@ spool_directory = argv[1]; debug_modify_channel(US""); debug_modify_channel(US"+all-memory"); debug_file = stderr; -big_buffer = malloc(big_buffer_size); +if (!(big_buffer = malloc(big_buffer_size))) + { + perror("malloc"); + return 1; + } for (i = 0; i < max_db; i++) dbblock[i].dbptr = NULL; diff --git a/src/src/exim_dbmbuild.c b/src/src/exim_dbmbuild.c index 07350b25f..13a1a948d 100644 --- a/src/src/exim_dbmbuild.c +++ b/src/src/exim_dbmbuild.c @@ -213,6 +213,9 @@ uschar dirname[512]; uschar *buffer = malloc(max_outsize); uschar *line = malloc(max_insize); +if (!buffer || !line) + { perror("malloc"); exit(EXIT_FAILURE); } + while (argc > 1) { if (Ustrcmp(argv[arg], "-nolc") == 0) lowercase = FALSE; diff --git a/src/src/exim_lock.c b/src/src/exim_lock.c index 1797fa98b..47c87bafb 100644 --- a/src/src/exim_lock.c +++ b/src/src/exim_lock.c @@ -299,9 +299,11 @@ if (use_lockfile) primary_hostname = s.nodename; len = (int)strlen(filename); - lockname = malloc(len + 8); + if ( !(lockname = malloc(len + 8)) + || !(hitchname = malloc(len + 32 + (int)strlen(primary_hostname)))) + { perror("malloc"); exit(EXIT_FAILURE); } + sprintf(lockname, "%s.lock", filename); - hitchname = malloc(len + 32 + (int)strlen(primary_hostname)); /* Presumably, this must match appendfile.c */ sprintf(hitchname, "%s.%s.%08x.%08x", lockname, primary_hostname, diff --git a/src/src/expand.c b/src/src/expand.c index aab3b76a7..c02af288c 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -9124,7 +9124,10 @@ uschar buffer[1024]; debug_modify_channel(US"+v"); debug_file = stderr; debug_fd = fileno(debug_file); -big_buffer = malloc(big_buffer_size); + +if (!(big_buffer = malloc(big_buffer_size))) + { perror("malloc"); exit(EXIT_FAILURE); } + store_init(); for (int i = 1; i < argc; i++) diff --git a/src/src/hash.c b/src/src/hash.c index e5abada37..b8a804be2 100644 --- a/src/src/hash.c +++ b/src/src/hash.c @@ -836,7 +836,9 @@ for (i = 0; i < sizeof(tests)/sizeof(uschar *); i ++) /* 1 000 000 repetitions of "a" */ -ctest = malloc(1000000); +if (!(ctest = malloc(1000000))) + { perror("malloc"); exit(EXIT_FAILURE); } + memset(ctest, 'a', 1000000); printf("1 000 000 repetitions of 'a'\n"); diff --git a/src/src/hintsdb/hints_tdb.h b/src/src/hintsdb/hints_tdb.h index ac6f62395..322466973 100644 --- a/src/src/hintsdb/hints_tdb.h +++ b/src/src/hintsdb/hints_tdb.h @@ -126,6 +126,7 @@ exim_dbcreate_cursor(EXIM_DB * dbp) { # ifdef COMPILE_UTILITY EXIM_CURSOR * c = malloc(sizeof(TDB_DATA)); +if (!c) return c; # else EXIM_CURSOR * c = store_malloc(sizeof(TDB_DATA)); # endif diff --git a/src/src/readconf.c b/src/src/readconf.c index 972c8eb53..b4062fdf8 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -416,6 +416,7 @@ add_driver_info(driver_info ** drlist_p, const driver_info * newent, { #ifdef MACRO_PREDEF driver_info * listent = malloc(size); +if (!listent) return; #else driver_info * listent = store_get(size, newent); #endif diff --git a/src/src/string.c b/src/src/string.c index 7bbbf094b..4cddbc343 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -2110,7 +2110,8 @@ while (fgets(CS buffer, sizeof(buffer), stdin) != NULL) else { - uschar *sss = malloc(s - ss + 1); + uschar * sss = malloc(s - ss + 1); + if (!sss) { perror("malloc"); return EXIT_FAILURE; } Ustrncpy(sss, ss, s-ss); args[n++] = sss; } @@ -2133,7 +2134,7 @@ while (fgets(CS buffer, sizeof(buffer), stdin) != NULL) if (countset) printf("count=%d\n", count); } -return 0; +return EXIT_SUCCESS; } #endif diff --git a/src/src/xtextencode.c b/src/src/xtextencode.c index 09d5cd7f8..56cc723b4 100644 --- a/src/src/xtextencode.c +++ b/src/src/xtextencode.c @@ -92,6 +92,7 @@ xtextdecode(const uschar * code, uschar ** ptr) int x; #ifdef COMPILE_UTILITY uschar * result = malloc(Ustrlen(code) + 1); +if (!result) return -1' #else uschar * result = store_get(Ustrlen(code) + 1, code); #endif commit af8bea97c267514d085af5b845f0ad7803ac4a67 Author: Jeremy Harris Date: Fri Mar 6 11:55:14 2026 +0000 tidying diff --git a/src/src/functions.h b/src/src/functions.h index f6c21b8c4..59f089080 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -640,8 +640,12 @@ extern uschar *string_nextinlist_trc(const uschar **listptr, int *separator, usc extern int strcmpic(const uschar *, const uschar *); extern int strncmpic(const uschar *, const uschar *, int); -extern uschar *strstric(const uschar *, const uschar *, BOOL); -extern const uschar *strstric_c(const uschar *, const uschar *, BOOL); +extern uschar * strstric_nc(const uschar *, const uschar *, BOOL); +extern const uschar * strstric_c(const uschar *, const uschar *, BOOL); +#define strstric(X, Y, B) _Generic((X), \ + uschar *: strstric_nc, \ + const uschar *: strstric_c \ + )(X, Y, B) extern int synprot_error(BOOL, int, uschar *, uschar *); diff --git a/src/src/miscmods/exim_filter.c b/src/src/miscmods/exim_filter.c index e86bf9b04..04681aa4a 100644 --- a/src/src/miscmods/exim_filter.c +++ b/src/src/miscmods/exim_filter.c @@ -1719,7 +1719,7 @@ switch (c->type) break; case cond_contains: - yield = strstric_c(exp[0], exp[1], FALSE) != NULL; + yield = strstric(exp[0], exp[1], FALSE) != NULL; break; case cond_CONTAINS: diff --git a/src/src/queue.c b/src/src/queue.c index c880412e8..6f6de72cf 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -603,7 +603,7 @@ for (int i = queue_run_in_order ? -1 : 0; else if ( deliver_selectstring_sender && !(f.deliver_selectstring_sender_regex ? regex_match(selectstring_regex_sender, sender_address, -1, NULL) - : (strstric_c(sender_address, deliver_selectstring_sender, FALSE) + : (strstric(sender_address, deliver_selectstring_sender, FALSE) != NULL) ) ) { @@ -622,7 +622,7 @@ for (int i = queue_run_in_order ? -1 : 0; const uschar * address = recipients_list[i].address; if ( (f.deliver_selectstring_regex ? regex_match(selectstring_regex, address, -1, NULL) - : (strstric_c(address, deliver_selectstring, FALSE) != NULL) + : (strstric(address, deliver_selectstring, FALSE) != NULL) ) && tree_search(tree_nonrecipients, address) == NULL ) diff --git a/src/src/string.c b/src/src/string.c index 4cddbc343..c5e3aab1c 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -860,12 +860,8 @@ while (*s) return NULL; } -/*XXX C11 apparently has "generic functions", which allow the tracking -of a parameter's type through to the return type. Thit would neatly -permit a single function name to be used, with better dev-safety, for this. */ - uschar * -strstric(const uschar * s, const uschar * t, BOOL space_follows) +strstric_nc(const uschar * s, const uschar * t, BOOL space_follows) { return US strstric_c(s, t, space_follows); } diff --git a/src/src/xtextencode.c b/src/src/xtextencode.c index 56cc723b4..02f762145 100644 --- a/src/src/xtextencode.c +++ b/src/src/xtextencode.c @@ -92,7 +92,7 @@ xtextdecode(const uschar * code, uschar ** ptr) int x; #ifdef COMPILE_UTILITY uschar * result = malloc(Ustrlen(code) + 1); -if (!result) return -1' +if (!result) return -1; #else uschar * result = store_get(Ustrlen(code) + 1, code); #endif commit 8f0d8de19c538395da75f338ab26db9a3b761034 Author: Jeremy Harris Date: Fri Mar 6 21:06:05 2026 +0000 Nongreedy affix wildcards for local_parts. Bug 126 diff --git a/src/src/route.c b/src/src/route.c index c3f4ecaa0..ea87c2618 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -391,8 +391,9 @@ for (router_instance * r = routers; r; r = r->drinst.next) *************************************************/ /* This function is handed a local part and a list of possible prefixes; if any -one matches, return the prefix length. A prefix beginning with '*' is a -wildcard. +one matches, return the prefix length. +A prefix beginning with '*' is a greedy wildcard (longest match), one beginning +with '~' is a nongreedy wildcard. Arguments: local_part the local part to check @@ -407,16 +408,13 @@ route_check_prefix(const uschar * local_part, const uschar * prefixes, unsigned * vp) { int sep = 0; -uschar *prefix; -const uschar *listptr = prefixes; - -while ((prefix = string_nextinlist(&listptr, &sep, NULL, 0))) +for (const uschar * prefix; prefix = string_nextinlist(&prefixes,&sep,NULL,0); ) { - int plen = Ustrlen(prefix); - if (prefix[0] == '*') + unsigned plen = Ustrlen(prefix); + if (*prefix == '*') { - prefix++; - for (const uschar * p = local_part + Ustrlen(local_part) - (--plen); + prefix++; plen--; + for (const uschar * p = local_part + Ustrlen(local_part) - plen; p >= local_part; p--) if (strncmpic(prefix, p, plen) == 0) { @@ -425,6 +423,16 @@ while ((prefix = string_nextinlist(&listptr, &sep, NULL, 0))) return plen + vlen; } } + else if (*prefix == '~') + { + const uschar * p = strstric(local_part, ++prefix, FALSE); + if (p) + { + unsigned vlen = p - local_part; + if (vp) *vp = vlen; + return plen-1 + vlen; + } + } else if (strncmpic(prefix, local_part, plen) == 0) { @@ -443,8 +451,9 @@ return 0; *************************************************/ /* This function is handed a local part and a list of possible suffixes; -if any one matches, return the suffix length. A suffix ending with '*' -is a wildcard. +if any one matches, return the suffix length. +A suffix ending with '*' is a greedy wildcard (longest match), one ending +with '~' is a nongreedy wildcard. Arguments: local_part the local part to check @@ -459,31 +468,47 @@ route_check_suffix(const uschar * local_part, const uschar * suffixes, unsigned * vp) { int sep = 0, alen = Ustrlen(local_part); -const uschar * listptr = suffixes, * suffix; +unsigned suffix_len, vlen; -while ((suffix = string_nextinlist(&listptr, &sep, NULL, 0))) +for (uschar * suffix; suffix = string_nextinlist(&suffixes, &sep, NULL, 0); ) { int slen = Ustrlen(suffix); - if (suffix[slen-1] == '*') + uschar c = suffix[slen-1]; + if (c == '*') + { + for (const uschar * p = local_part, * pend = p + alen - (--slen) + 1; + p < pend; p++) + if (strncmpic(suffix, p, slen) == 0) + { + suffix_len = alen - (p - local_part); + vlen = suffix_len - slen; + goto out; + } + } + else if (c == '~') { - const uschar * pend = local_part + alen - (--slen) + 1; - for (const uschar * p = local_part; p < pend; p++) + for (const uschar * p = local_part + alen - (--slen) + 1; + p >= local_part; p--) if (strncmpic(suffix, p, slen) == 0) { - int tlen = alen - (p - local_part); - if (vp) *vp = tlen - slen; - return tlen; + suffix_len = alen - (p - local_part); + vlen = suffix_len - slen; + goto out; } } else if (alen > slen && strncmpic(suffix, local_part + alen - slen, slen) == 0) { - if (vp) *vp = 0; - return slen; + suffix_len = slen; vlen = 0; + goto out; } } return 0; + +out: + if (vp) *vp = vlen; + return suffix_len; } diff --git a/src/src/string.c b/src/src/string.c index c5e3aab1c..7220c41ac 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -828,10 +828,8 @@ Returns: pointer to substring in string, or NULL if not found const uschar * strstric_c(const uschar * s, const uschar * t, BOOL space_follows) { -const uschar * p = t; -const uschar * yield = NULL; -int cl = tolower(*p); -int cu = toupper(*p); +const uschar * p = t, * yield = NULL; +int cl = tolower(*p), cu = toupper(*p); while (*s) { commit 5830c8ed96c44fea5dc8ba0a1bcf05bc779356d3 Author: Jeremy Harris Date: Sat Mar 7 18:32:40 2026 +0000 Queue runs: newest-first option. Bug 127 diff --git a/src/src/globals.c b/src/src/globals.c index 337842770..ae7798a3e 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -369,6 +369,7 @@ BOOL queue_only = FALSE; BOOL queue_only_load_latch = TRUE; BOOL queue_only_override = TRUE; BOOL queue_run_in_order = FALSE; +const uschar * queue_run_order = NULL; BOOL recipients_max_reject = FALSE; BOOL return_path_remove = TRUE; diff --git a/src/src/globals.h b/src/src/globals.h index 9d581ae67..a09d9ef74 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -830,7 +830,8 @@ extern int queue_only_load; /* Max load before auto-queue */ extern BOOL queue_only_load_latch; /* Latch queue_only_load TRUE */ extern uschar *queue_only_file; /* Queue if file exists/not-exists */ extern BOOL queue_only_override; /* Allow override from command line */ -extern BOOL queue_run_in_order; /* As opposed to random */ +extern BOOL queue_run_in_order; /* (obsolete) As opposed to random */ +extern const uschar * queue_run_order; /* undef/old/random/new-first */ extern uschar *queue_run_max; /* Max queue runners */ extern unsigned queue_size; /* items in queue */ extern time_t queue_size_next; /* next time to evaluate queue_size */ diff --git a/src/src/queue.c b/src/src/queue.c index 6f6de72cf..949c232f7 100644 --- a/src/src/queue.c +++ b/src/src/queue.c @@ -39,14 +39,15 @@ static BOOL queue_tls_init = FALSE; queue_get_spool_list() below. Arguments: - a points to an ordered list of queue_filename items - b points to another ordered list + a points to an ordered list of queue_filename items + b points to another ordered list + order older/newer first -Returns: a pointer to a merged ordered list +Returns: a pointer to a merged ordered list */ static queue_filename * -merge_queue_lists(queue_filename * a, queue_filename * b) +merge_queue_lists(queue_filename * a, queue_filename * b, s_order_t order) { queue_filename * first = NULL, ** append = &first; @@ -60,7 +61,7 @@ while (a && b) d = Ustrcmp(a->text + (a_old ? 6+1+6+1 : MESSAGE_ID_TIME_LEN + 1 + MESSAGE_ID_PID_LEN + 1), b->text + (b_old ? 6+1+6+1 : MESSAGE_ID_TIME_LEN + 1 + MESSAGE_ID_PID_LEN + 1)); } - if (d < 0) + if ((d < 0) == (order == SLIST_OLDER_FIRST)) { *append = a; append= &a->next; @@ -100,7 +101,7 @@ therein. Single-character sub-directories are handled as follows: identifying character of the subdirectory, if any. The subdirs vector is still required as an argument. -If the randomize argument is TRUE, messages are returned in "randomized" order. +If random order requested messages are returned in "randomized" order. Actually, the order is anything but random, but the algorithm is cheap, and the point is simply to ensure that the same order doesn't occur every time, in case a particular message is causing a remote MTA to barf - we would like to try @@ -110,7 +111,7 @@ If the randomize argument is FALSE, sort the list according to the file name. This should give the order in which the messages arrived. It is normally used only for presentation to humans, in which case the (possibly expensive) sort that it does is not part of the normal operational code. However, if -queue_run_in_order is set, sorting has to take place for queue runs as well. +running ordered, sorting has to take place for queue runs as well. When randomize is FALSE, the first argument is normally -1, so all messages are included. @@ -118,7 +119,7 @@ Arguments: subdiroffset sub-directory character offset, or 0 or -1 (see above) subdirs vector to store list of subdirchars subcount pointer to int in which to store count of subdirs - randomize TRUE if the order of the list is to be unpredictable + order dontcare/oldest/random/newest-first pcount If not NULL, fill in with count of files and do not return list Returns: pointer to a chain of queue name items @@ -126,7 +127,7 @@ Returns: pointer to a chain of queue name items static queue_filename * queue_get_spool_list(int subdiroffset, uschar * subdirs, int * subcount, - BOOL randomize, unsigned * pcount) + s_order_t order, unsigned * pcount) { int i, flags = 0, resetflags = -1, subptr; queue_filename * yield = NULL, * last = NULL; @@ -140,7 +141,7 @@ not randomizing, initialize the sublists for the bottom-up merge sort. */ if (pcount) *pcount = 0; -else if (randomize) +else if (order == SLIST_RANDOM) resetflags = time(NULL) & 0xFFFF; else for (i = 0; i < LOG2_MAXNODES; i++) @@ -174,7 +175,7 @@ for (; i <= *subcount; i++) { int count = 0; int subdirchar = subdirs[i]; /* 0 for main directory */ - DIR *dd; + DIR * dd; if (subdirchar != 0) { @@ -221,13 +222,14 @@ for (; i <= *subcount; i++) Ustrcpy(next->text, name); next->dir_uschar = subdirchar; - /* Handle the creation of a randomized list. The first item becomes both - the top and bottom of the list. Subsequent items are inserted either at - the top or the bottom, randomly. This is, I argue, faster than doing a - sort by allocating a random number to each item, and it also saves having - to store the number with each item. */ + if (order == SLIST_RANDOM) + { + /* Handle the creation of a randomized list. The first item becomes + both the top and bottom of the list. Subsequent items are inserted + either at the top or the bottom, randomly. This is, I argue, faster + than doing a sort by allocating a random number to each item, and it + also saves having to store the number with each item. */ - if (randomize) if (!yield) { next->next = NULL; @@ -237,7 +239,7 @@ for (; i <= *subcount; i++) { if (flags == 0) flags = resetflags; - if ((flags & 1) == 0) + if (!(flags & 1)) { next->next = yield; yield = next; @@ -250,16 +252,16 @@ for (; i <= *subcount; i++) } flags = flags >> 1; } - - /* Otherwise do a bottom-up merge sort based on the name. */ - + } else { + /* Do a bottom-up merge sort based on the name. */ + next->next = NULL; for (int j = 0; j < LOG2_MAXNODES; j++) if (root[j]) { - next = merge_queue_lists(next, root[j]); + next = merge_queue_lists(next, root[j], order); root[j] = j == LOG2_MAXNODES - 1 ? next : NULL; } else @@ -305,9 +307,9 @@ for (; i <= *subcount; i++) /* When using a bottom-up merge sort, do the final merging of the sublists. Then pass back the final list of file items. */ -if (!pcount && !randomize) +if (!pcount && order != SLIST_RANDOM) for (i = 0; i < LOG2_MAXNODES; ++i) - yield = merge_queue_lists(yield, root[i]); + yield = merge_queue_lists(yield, root[i], order); return yield; } @@ -363,6 +365,7 @@ int subcount = 0; uschar subdirs[64]; pid_t qpid[4] = {0}; /* Parallelism factor for q2stage 1st phase */ BOOL single_id = FALSE, msg_handled = FALSE; +s_order_t order; #ifdef MEASURE_TIMING report_time_since(×tamp_startup, US"queue_run start"); @@ -388,6 +391,21 @@ f.queue_smtp = q->queue_2stage; queue_run_pid = getpid(); f.queue_running = TRUE; +GET_OPTION("queue_run_order"); +order = SLIST_RANDOM; /* default */ +if (queue_run_order) + { + if (Ustrcmp(queue_run_order, "oldest") == 0) + order = SLIST_OLDER_FIRST; + else if (Ustrcmp(queue_run_order, "newest") == 0) + order = SLIST_NEWER_FIRST; + } +else + { + GET_OPTION("queue_run_in_order"); /* Obsolete option, 4.100 onwards */ + if (queue_run_in_order) order = SLIST_OLDER_FIRST; + } + /* Log the true start of a queue run, and fancy options */ if (!recurse) @@ -451,7 +469,7 @@ if (!queue_tls_init) /* If the spool is split into subdirectories, we want to process it one directory at a time, so as to spread out the directory scanning and the delivering when there are lots of messages involved, except when -queue_run_in_order is set. +running the queue in (some) order. In the random order case, this loop runs once for the main directory (handling any messages therein), and then repeats for any subdirectories that were found. @@ -460,11 +478,11 @@ directory, fills in subdirs, and sets subcount. The order of the directories is then randomized after the first time through, before they are scanned in subsequent iterations. -When the first argument of queue_get_spool_list() is -1 (for queue_run_in_ -order), it scans all directories and makes a single message list. */ +When the first argument of queue_get_spool_list() is -1 (for ordered queue runs) +it scans all directories and makes a single message list. */ -for (int i = queue_run_in_order ? -1 : 0; - i <= (queue_run_in_order ? -1 : subcount); +for (int i = order == SLIST_RANDOM ? 0 : -1; + i <= (order == SLIST_RANDOM ? subcount : -1); i++) { rmark reset_point1 = store_mark(); @@ -480,7 +498,7 @@ for (int i = queue_run_in_order ? -1 : 0; } for (queue_filename * fq = queue_get_spool_list(i, subdirs, &subcount, - !queue_run_in_order, NULL); + order, NULL); fq; fq = fq->next) { pid_t pid; @@ -511,7 +529,7 @@ for (int i = queue_run_in_order ? -1 : 0; /* If initial of a 2-phase run (and not under the test-harness) maintain a set of child procs to get disk parallelism */ - if (q->queue_2stage && !queue_run_in_order) + if (q->queue_2stage && order == SLIST_RANDOM) { int j; if (qpid[ @@ -758,7 +776,7 @@ single_item_retry: /* If initial of a 2-phase run, we are a child - so just exit */ - if (q->queue_2stage && !queue_run_in_order) + if (q->queue_2stage && order == SLIST_RANDOM) exim_exit(EXIT_SUCCESS); /* If we are in the test harness, and this is not the first of a 2-stage @@ -775,7 +793,7 @@ single_item_retry: go_around: /* If initial of a 2-phase run, we are a child - so just exit */ - if (q->queue_2stage && !queue_run_in_order) + if (q->queue_2stage && order == SLIST_RANDOM) exim_exit(EXIT_SUCCESS); } /* End loop for list of messages */ @@ -785,7 +803,7 @@ single_item_retry: /* If this was the first time through for random order processing, and sub-directories have been found, randomize their order if necessary. */ - if (i == 0 && subcount > 1 && !queue_run_in_order) + if (i == 0 && subcount > 1 && order == SLIST_RANDOM) for (int j = 1; j <= subcount; j++) { int r; @@ -893,7 +911,7 @@ tls_support orig_tls_in = tls_in; for (queue_filename * fq = queue_get_spool_list(-1, /* entire queue */ subdirs, /* for holding sublist*/ &subcount, /* for subcount */ - FALSE, /* not random */ + SLIST_OLDER_FIRST, /* not random */ NULL); fq && yield != OK; fq = fq->next) { @@ -954,7 +972,7 @@ uschar subdirs[64]; (void) queue_get_spool_list(-1, /* entire queue */ subdirs, /* for holding sub list */ &subcount, /* for subcount */ - FALSE, /* not random */ + SLIST_ORDER_UNDEFINED, &count); /* just get the count */ return count; } @@ -1054,7 +1072,7 @@ else -1, /* entire queue */ subdirs, /* for holding sub list */ &subcount, /* for subcount */ - option >= QL_UNSORTED, /* randomize if required */ + option >= QL_UNSORTED ? SLIST_RANDOM : SLIST_OLDER_FIRST, NULL); /* don't just count */ option &= ~QL_UNSORTED; diff --git a/src/src/readconf.c b/src/src/readconf.c index b4062fdf8..ba4131d2b 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -284,6 +284,7 @@ static optionlist optionlist_config[] = { { "queue_only_override", opt_bool, {&queue_only_override} }, { "queue_run_in_order", opt_bool, {&queue_run_in_order} }, { "queue_run_max", opt_stringptr, {&queue_run_max} }, + { "queue_run_order", opt_stringptr, {&queue_run_order} }, { "queue_smtp_domains", opt_stringptr, {&queue_smtp_domains} }, { "receive_timeout", opt_time, {&receive_timeout} }, { "received_header_text", opt_stringptr, {&received_header_text} }, diff --git a/src/src/structs.h b/src/src/structs.h index e25c69f6a..6b231c97a 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -1048,5 +1048,11 @@ typedef struct misc_module_info { #define MISC_MODULE_MAGIC 0x4d4d4d31 /* MMM1 */ + +/* Spool list ordering */ +typedef enum { + SLIST_ORDER_UNDEFINED, SLIST_OLDER_FIRST, SLIST_RANDOM, SLIST_NEWER_FIRST +} s_order_t; + #endif /* whole file */ /* End of structs.h */ commit 4f09add48b47e098b11e3dc5ee55afac6c9260d7 Author: Jeremy Harris Date: Sat Mar 14 16:32:46 2026 +0000 ACL seen: fix refresh timestamp diff --git a/src/src/acl.c b/src/src/acl.c index 87bc06ee8..b7a5277d5 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -2452,22 +2452,18 @@ Returns: OK - Sender's rate is above limit */ static int -acl_ratelimit(const uschar *arg, int where, uschar **log_msgptr) +acl_ratelimit(const uschar * arg, int where, uschar ** log_msgptr) { double limit, period, count; -uschar *ss; -uschar *key = NULL; -uschar *unique = NULL; -int sep = '/'; +uschar * ss, * key = NULL, * unique = NULL; +int sep = '/', mode = RATE_PER_WHAT, old_pool, rc; BOOL leaky = FALSE, strict = FALSE, readonly = FALSE; BOOL noupdate = FALSE, badacl = FALSE; -int mode = RATE_PER_WHAT; -int old_pool, rc; tree_node ** anchor = NULL, * t; -open_db dbblock, *dbm; +open_db dbblock, * dbm; int dbdb_size; -dbdata_ratelimit *dbd; -dbdata_ratelimit_unique *dbdb; +dbdata_ratelimit * dbd; +dbdata_ratelimit_unique * dbdb; struct timeval tv; /* Parse the first two options and record their values in expansion @@ -3057,14 +3053,12 @@ if (dbd) /* an existing record */ { HDEBUG(acl) debug_printf_indent("seen db not written (readonly)\n"); } else if (mode == SEEN_WRITE || !before) { - dbd->gen.time_stamp = now; - dbfn_write(dbm, key, dbd, sizeof(*dbd)); + dbfn_write_ts(dbm, key, dbd, sizeof(*dbd), now); HDEBUG(acl) debug_printf_indent("seen db written (update)\n"); } else if (diff >= refresh) { - dbd->gen.time_stamp = now - interval; - dbfn_write(dbm, key, dbd, sizeof(*dbd)); + dbfn_write_ts(dbm, key, dbd, sizeof(*dbd), now - interval); HDEBUG(acl) debug_printf_indent("seen db written (refresh)\n"); } } @@ -3072,8 +3066,8 @@ else { /* No record found, yield always FAIL */ if (mode != SEEN_READONLY) { - dbdata_seen d = {.gen = {.time_stamp = now}}; - dbfn_write(dbm, key, &d, sizeof(*dbd)); + dbdata_seen d = {0}; + dbfn_write_ts(dbm, key, &d, sizeof(d), now); HDEBUG(acl) debug_printf_indent("seen db written (create)\n"); } else diff --git a/src/src/dbfn.c b/src/src/dbfn.c index 1bf59b83d..0c50c03a6 100644 --- a/src/src/dbfn.c +++ b/src/src/dbfn.c @@ -545,7 +545,8 @@ Returns: the yield of the underlying dbm or db "write" function. If this */ int -dbfn_write(open_db * dbblock, const uschar * key, void * ptr, int length) +dbfn_write_ts(open_db * dbblock, const uschar * key, void * ptr, int length, + time_t ts) { EXIM_DATUM key_datum, value_datum; dbdata_generic * gptr = (dbdata_generic *)ptr; @@ -555,7 +556,7 @@ uschar * key_copy = store_get(klen, key); memcpy(key_copy, key, klen); gptr->version = HINTS_VERSION; gptr->tainted = is_tainted(ptr); -gptr->time_stamp = time(NULL); +gptr->time_stamp = ts; DEBUG(hints_lookup) debug_printf_indent("dbfn_write: key=%s datalen %d\n", key, length); @@ -569,6 +570,12 @@ exim_datum_size_set(&value_datum, length); return exim_dbput(dbblock->dbptr, &key_datum, &value_datum); } +int +dbfn_write(open_db * dbblock, const uschar * key, void * ptr, int length) +{ +return dbfn_write_ts(dbblock, key, ptr, length, time(NULL)); +} + /************************************************* @@ -795,6 +802,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) Uskip_whitespace(&data); dbwait = (dbdata_wait *)(&structbuffer); + memset(dbwait, 0, sizeof(dbdata_generic)); Ustrcpy(dbwait->text, data); start = clock(); diff --git a/src/src/dbfunctions.h b/src/src/dbfunctions.h index a6fb2b51e..c9622881a 100644 --- a/src/src/dbfunctions.h +++ b/src/src/dbfunctions.h @@ -23,6 +23,7 @@ void *dbfn_read_with_length(open_db *, const uschar *, int *); void *dbfn_read_enforce_length(open_db *, const uschar *, size_t); uschar *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **); int dbfn_write(open_db *, const uschar *, void *, int); +int dbfn_write_ts(open_db *, const uschar *, void *, int, time_t); BOOL dbfn_transaction_start(open_db *); void dbfn_transaction_commit(open_db *); commit 90e7f8cfe01235c80cd9951a462c8452b5e878db Author: Jeremy Harris Date: Tue Mar 17 20:20:20 2026 +0000 Content Scan: fix $spam_score_int for negative values. Bug 2987 diff --git a/src/src/spam.c b/src/src/spam.c index df2365945..cfa924739 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -3,7 +3,7 @@ *************************************************/ /* - * Copyright (c) The Exim Maintainers 2016 - 2025 + * Copyright (c) The Exim Maintainers 2016 - 2026 * Copyright (c) Tom Kistner 2003 - 2015 * License: GPL * SPDX-License-Identifier: GPL-2.0-or-later @@ -576,9 +576,8 @@ spam_bar = spam_bar_buffer; spam_score = spam_score_buffer; /* create "int" spam score */ -j = (int)((spamd_score + 0.001)*10); (void)string_format(spam_score_int_buffer, sizeof(spam_score_int_buffer), - "%d", j); + "%.0f", spamd_score*10); spam_score_int = spam_score_int_buffer; /* compare threshold against score */ commit 8dc59b5636252a110644c9a759e987e861e37824 Author: Jeremy Harris Date: Tue Mar 17 21:06:06 2026 +0000 Content Scan: use allocated report buffers diff --git a/src/src/exim.c b/src/src/exim.c index 782941457..b3e0c9afe 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -6308,6 +6308,7 @@ MORELOOP: #ifdef WITH_CONTENT_SCAN malware_name = NULL; regex_vars_clear(); + spam_action = spam_report = spam_bar = spam_score = spam_score_int = NULL; #endif callout_address = NULL; sending_ip_address = NULL; diff --git a/src/src/spam.c b/src/src/spam.c index cfa924739..5b185fb98 100644 --- a/src/src/spam.c +++ b/src/src/spam.c @@ -15,11 +15,6 @@ #ifdef WITH_CONTENT_SCAN #include "spam.h" -uschar spam_score_buffer[16]; -uschar spam_score_int_buffer[16]; -uschar spam_bar_buffer[128]; -uschar spam_action_buffer[32]; -uschar spam_report_buffer[32600]; const uschar * cached_user_name = NULL; BOOL spam_ok = FALSE; int spam_rc = 0; @@ -185,7 +180,6 @@ client_conn_ctx spamd_cctx = {.sock = -1}; uschar spamd_buffer[32600]; int i, j, offset; uschar spamd_version[8], spamd_short_result[8]; -uschar spamd_score_char; double spamd_threshold, spamd_score, spamd_reject_score; int spamd_report_offset; uschar *p,*q; @@ -497,10 +491,8 @@ if (sd->is_rspamd) if (Ustrncmp(p, "Action: ", sizeof("Action: ") - 1) == 0) { p += sizeof("Action: ") - 1; - q = &spam_action_buffer[0]; - while (*p && *p != '\r' && (q - spam_action_buffer) < sizeof(spam_action_buffer) - 1) - *q++ = *p++; - *q = '\0'; + for (q = p; *q != '\r' && q - p < 32; ) q++; + spam_action = string_copyn(p, q - p); } } else @@ -522,63 +514,47 @@ else } } - Ustrcpy(spam_action_buffer, - spamd_score >= spamd_threshold ? US"reject" : US"no action"); + spam_action = spamd_score >= spamd_threshold ? US"reject" : US"no action"; } /* Create report. Since this is a multiline string, we must hack it into shape first */ -p = &spamd_buffer[spamd_report_offset]; -q = spam_report_buffer; -while (*p != '\0') { - /* skip \r */ - if (*p == '\r') - { - p++; - continue; - } - *q++ = *p; - if (*p++ == '\n') - { - /* add an extra space after the newline to ensure - that it is treated as a header continuation line */ - *q++ = ' '; - } - } -/* NULL-terminate */ -*q-- = '\0'; -/* cut off trailing leftovers */ -while (*q <= ' ') - *q-- = '\0'; + gstring * g = NULL; -spam_report = spam_report_buffer; -spam_action = spam_action_buffer; + for (const uschar * p = &spamd_buffer[spamd_report_offset]; *p; p++) + if (*p != '\r') + { + g = string_catn(g, p, 1); + + /* add an extra space after the newline to ensure + that it is treated as a header continuation line */ + if (*p == '\n') g = string_catn(g, US" ", 1); + } + + for (uschar c; (c = gstring_last_char(g)) && c <= ' '; ) + gstring_trim(g, 1); + + spam_report = string_from_gstring(g); + } /* create spam bar */ -spamd_score_char = spamd_score > 0 ? '+' : '-'; -j = abs((int)(spamd_score)); -i = 0; -if (j != 0) - while ((i < j) && (i <= MAX_SPAM_BAR_CHARS)) - spam_bar_buffer[i++] = spamd_score_char; +j = abs((int)spamd_score); +j = MIN(j, MAX_SPAM_BAR_CHARS); +if (j == 0) + spam_bar = string_copyn(US"/", 1); else { - spam_bar_buffer[0] = '/'; - i = 1; + gstring * g = string_get(j+1); + while(j--) g = string_catn(g, spamd_score > 0 ? US"+" : US"-", 1); + spam_bar = string_from_gstring(g); } -spam_bar_buffer[i] = '\0'; -spam_bar = spam_bar_buffer; /* create "float" spam score */ -(void)string_format(spam_score_buffer, sizeof(spam_score_buffer), - "%.1f", spamd_score); -spam_score = spam_score_buffer; +spam_score = string_sprintf("%.1f", spamd_score); /* create "int" spam score */ -(void)string_format(spam_score_int_buffer, sizeof(spam_score_int_buffer), - "%.0f", spamd_score*10); -spam_score_int = spam_score_int_buffer; +spam_score_int = string_sprintf("%.0f", spamd_score*10); /* compare threshold against score */ spam_rc = spamd_score >= spamd_threshold diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 9fba36e17..8aafd95db 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -291,10 +291,8 @@ tls_in.sni = NULL; tls_in.ocsp = OCSP_NOT_REQ; #endif -#ifdef WITH_CONTENT_SCAN -spam_bar = NULL; -spam_score = NULL; -spam_score_int = NULL; +#if defined(WITH_CONTENT_SCAN) && !defined(COMPILE_UTILITY) +spam_action = spam_report = spam_bar = spam_score = spam_score_int = NULL; #endif #if defined(SUPPORT_I18N) && !defined(COMPILE_UTILITY) commit 8f7d8b4e9af6f89684e547df14bcf0edd4248d1b Author: Jeremy Harris Date: Fri Mar 20 10:25:58 2026 +0000 tidying diff --git a/src/src/auths/gsasl.c b/src/src/auths/gsasl.c index 2b8e14647..99d0d8890 100644 --- a/src/src/auths/gsasl.c +++ b/src/src/auths/gsasl.c @@ -446,7 +446,7 @@ preload_prop(sctx, GSASL_QOPS, US "qop-auth"); #ifndef DISABLE_TLS if (tls_in.channelbinding) { - /* Some auth mechanisms can ensure that both sides are talking withing the + /* Some auth mechanisms can ensure that both sides are talking within the same security context; for TLS, this means that even if a bad certificate has been accepted, they remain MitM-proof because both sides must be within the same negotiated session; if someone is terminating one session and @@ -472,8 +472,7 @@ if (tls_in.channelbinding) */ if (ob->server_channelbinding) { - HDEBUG(auth) debug_printf("Auth %s: Enabling channel-binding\n", - auname); + HDEBUG(auth) debug_printf("Auth %s: Enabling channel-binding\n", auname); # ifndef CHANNELBIND_HACK preload_prop(sctx, # ifdef EXIM_GSASL_HAVE_EXPORTER diff --git a/src/src/miscmods/dmarc.c b/src/src/miscmods/dmarc.c index a354b475c..dfd229b20 100644 --- a/src/src/miscmods/dmarc.c +++ b/src/src/miscmods/dmarc.c @@ -198,8 +198,8 @@ else if (!dmarc_abort) } } -/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should -instead do this in the ACLs. */ +/* Skip DMARC if connection is SMTP Auth. Preferably this should not be +hardwired; the admin should instead do this in the ACLs. */ if (!dmarc_abort && !sender_host_authenticated) { diff --git a/src/src/miscmods/dmarc_native.c b/src/src/miscmods/dmarc_native.c index a14785802..7270f0228 100644 --- a/src/src/miscmods/dmarc_native.c +++ b/src/src/miscmods/dmarc_native.c @@ -357,8 +357,8 @@ else } } -/* Skip DMARC if connection is SMTP Auth. Temporarily, admin should -instead do this in the ACLs. */ +/* Skip DMARC if connection is SMTP Auth. Preferably this should not be +hardwired; the admin should instead do this in the ACLs. */ if (!dmarc_abort && !sender_host_authenticated) { diff --git a/src/src/miscmods/xclient.c b/src/src/miscmods/xclient.c index 3c6c11984..842c3051d 100644 --- a/src/src/miscmods/xclient.c +++ b/src/src/miscmods/xclient.c @@ -222,10 +222,7 @@ for (state = XCLIENT_SKIP_SPACES; *s; ) authentication_failed = FALSE; } else - { - authenticated_id = NULL; - sender_host_authenticated = NULL; - } + authenticated_id = sender_host_authenticated = NULL; break; # ifdef XCLIENT_V1 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index cbce7a121..b0ed04a89 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -4977,14 +4977,14 @@ while (done <= 0) switch (rc) { case OK: - if (authenticated_by == NULL || - authenticated_by->mail_auth_condition == NULL || - expand_check_condition(authenticated_by->mail_auth_condition, + if (!authenticated_by + || !authenticated_by->mail_auth_condition + || expand_check_condition(authenticated_by->mail_auth_condition, authenticated_by->drinst.name, US"authenticator")) break; /* Accept the AUTH */ ignore_msg = US"server_mail_auth_condition failed"; - if (authenticated_id != NULL) + if (authenticated_id) ignore_msg = string_sprintf("%s: authenticated ID=%q", ignore_msg, authenticated_id); diff --git a/src/src/xclient.c b/src/src/xclient.c deleted file mode 100644 index 33e49b766..000000000 --- a/src/src/xclient.c +++ /dev/null @@ -1,302 +0,0 @@ -/************************************************* -* Exim - an Internet mail transport agent * -*************************************************/ - -/* Copyright (c) The Exim Maintainers 2023 - 2025 */ -/* See the file NOTICE for conditions of use and distribution. */ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "exim.h" - -#ifdef EXPERIMENTAL_XCLIENT - -/* This is a proxy protocol. - -From https://www.postfix.org/XCLIENT_README.html I infer two generations of -protocol. The more recent one obviates the utility of the HELO attribute, since -it mandates the proxy always sending a HELO/EHLO smtp command following (a -successful) XCLIENT command, and that will carry a NELO name (which we assume, -though it isn't specified, will be the actual one presented to the proxy by the -possibly-new client). The same applies to the PROTO attribute. */ - -# define XCLIENT_V2 - -enum xclient_cmd_e { - XCLIENT_CMD_UNKNOWN, - XCLIENT_CMD_ADDR, - XCLIENT_CMD_NAME, - XCLIENT_CMD_PORT, - XCLIENT_CMD_LOGIN, - XCLIENT_CMD_DESTADDR, - XCLIENT_CMD_DESTPORT, -# ifdef XCLIENT_V1 - XCLIENT_CMD_HELO, - XCLIENT_CMD_PROTO, -# endif -}; - -struct xclient_cmd { - const uschar * str; - unsigned len; -} xclient_cmds[] = { - [XCLIENT_CMD_UNKNOWN] = { NULL }, - [XCLIENT_CMD_ADDR] = { US"ADDR", 4 }, - [XCLIENT_CMD_NAME] = { US"NAME", 4 }, - [XCLIENT_CMD_PORT] = { US"PORT", 4 }, - [XCLIENT_CMD_LOGIN] = { US"LOGIN", 5 }, - [XCLIENT_CMD_DESTADDR] = { US"DESTADDR", 8 }, - [XCLIENT_CMD_DESTPORT] = { US"DESTPORT", 8 }, -# ifdef XCLIENT_V1 - [XCLIENT_CMD_HELO] = { US"HELO", 4 }, - [XCLIENT_CMD_PROTO] = { US"PROTO", 5 }, -# endif -}; - -/************************************************* -* XCLIENT proxy implementation * -*************************************************/ - -/* Arguments: - code points to the coded string - end points to the end of coded string - ptr where to put the pointer to the result, which is in - dynamic store -Returns: the number of bytes in the result, excluding the final zero; - -1 if the input is malformed -*/ - -static int -xclient_xtextdecode(const uschar * code, const uschar * end, uschar ** ptr) -{ -return xtextdecode(string_copyn(code, end-code), ptr); -} - -/************************************************* -* Check XCLIENT line and set sender_address * -*************************************************/ - - -/* Check the format of a XCLIENT line. -Arguments: - s the data portion of the line (already past any white space) - resp result: smtp respose code - flagp input: helo seen output: fail is fatal - -Return: NULL on success, or error message -*/ - -# define XCLIENT_UNAVAIL US"[UNAVAILABLE]" -# define XCLIENT_TEMPUNAVAIL US"[TEMPUNAVAIL]" - -uschar * -xclient_smtp_command(uschar * s, int * resp, BOOL * flagp) -{ -uschar * word = s; -enum { - XCLIENT_READ_COMMAND = 0, - XCLIENT_READ_VALUE, - XCLIENT_SKIP_SPACES -} state = XCLIENT_SKIP_SPACES; -enum xclient_cmd_e cmd; - -if ( !*flagp - && verify_check_host(&hosts_require_helo) == OK) - { - *resp = 503; - *flagp= FALSE; - return US"no HELO/EHLO given"; - } - -/* If already in a proxy session, do not re-check permission. -Strictly we should avoid doing this for a Proxy-Protocol -session to avoid mixups. */ - -if(!proxy_session && verify_check_host(&hosts_xclient) == FAIL) - { - *resp = 550; - *flagp= TRUE; - return US"XCLIENT command used when not advertised"; - } - -if (sender_address) - { - *resp = 503; - *flagp= FALSE; - return US"mail transaction in progress"; - } - -if (!*word) - { - s = US"XCLIENT must have at least one operand"; - goto fatal_501; - } - -for (state = XCLIENT_SKIP_SPACES; *s; ) - switch (state) - { - case XCLIENT_READ_COMMAND: - { - int len; - - word = s; - while (*s && *s != '=') s++; - len = s - word; - if (!*s) - { - s = string_sprintf("XCLIENT: missing value for parameter '%.*s'", - len, word); - goto fatal_501; - } - - DEBUG(transport) debug_printf(" XCLIENT: cmd %.*s\n", len, word); - cmd = XCLIENT_CMD_UNKNOWN; - for (struct xclient_cmd * x = xclient_cmds + 1; - x < xclient_cmds + nelem(xclient_cmds); x++) - if (len == x->len && strncmpic(word, x->str, len) == 0) - { - cmd = x - xclient_cmds; - break; - } - if (cmd == XCLIENT_CMD_UNKNOWN) - { - s = string_sprintf("XCLIENT: unrecognised parameter '%.*s'", - len, word); - goto fatal_501; - } - state = XCLIENT_READ_VALUE; - } - break; - - case XCLIENT_READ_VALUE: - { - int old_pool = store_pool; - int len; - uschar * val; - - word = ++s; /* skip the = */ - Uskip_nonwhite(&s); - len = s - word; - - DEBUG(transport) debug_printf(" XCLIENT: \tvalue %.*s\n", len, word); - if (len == 0) - { s = US"XCLIENT: zero-length value for param"; goto fatal_501; } - - if ( len == 13 - && ( strncmpic(word, XCLIENT_UNAVAIL, 13) == 0 - || strncmpic(word, XCLIENT_TEMPUNAVAIL, 13) == 0 - ) ) - val = NULL; - - else if ((len = xclient_xtextdecode(word, s, &val)) == -1) - { - s = string_sprintf("failed xtext decode for XCLIENT: '%.*s'", len, word); - goto fatal_501; - } - - store_pool = POOL_PERM; - switch (cmd) - { - case XCLIENT_CMD_ADDR: - proxy_local_address = sender_host_address; - sender_host_address = val ? string_copyn(val, len) : NULL; - break; - case XCLIENT_CMD_NAME: - sender_host_name = val ? string_copyn(val, len) : NULL; - break; - case XCLIENT_CMD_PORT: - proxy_local_port = sender_host_port; - sender_host_port = val ? Uatoi(val) : 0; - break; - case XCLIENT_CMD_DESTADDR: - proxy_external_address = val ? string_copyn(val, len) : NULL; - break; - case XCLIENT_CMD_DESTPORT: - proxy_external_port = val ? Uatoi(val) : 0; - break; - - case XCLIENT_CMD_LOGIN: - if (val) - { - authenticated_id = string_copyn(val, len); - sender_host_authenticated = US"xclient"; - authentication_failed = FALSE; - } - else - { - authenticated_id = NULL; - sender_host_authenticated = NULL; - } - break; - -# ifdef XCLIENT_V1 - case XCLIENT_CMD_HELO: - sender_helo_name = val ? string_copyn(val, len) : NULL; - break; - case XCLIENT_CMD_PROTO: - if (!val) - { store_pool = old_pool; s = US"missing proto for XCLIENT"; goto fatal_501; } - else if (len == 4 && strncmpic(val, US"SMTP", 4) == 0) - *esmtpflag = FALSE; /* function arg */ - else if (len == 5 && strncmpic(val, US"ESMTP", 5) == 0) - *esmtpflag = TRUE; - else - { store_pool = old_pool; s = US"bad proto for XCLIENT"; goto fatal_501; } - break; -# endif - default: break; /* stupid compiler silencing */ - } - store_pool = old_pool; - state = XCLIENT_SKIP_SPACES; - break; - } - - case XCLIENT_SKIP_SPACES: - Uskip_whitespace(&s); - state = XCLIENT_READ_COMMAND; - break; - - default: - s = US"unhandled XCLIENT parameter type"; - goto fatal_501; - } - -if (!proxy_local_address) - { s = US"missing ADDR for XCLIENT"; goto fatal_501; } -if (!proxy_local_port) - { s = US"missing PORT for XCLIENT"; goto fatal_501; } -if (state != XCLIENT_SKIP_SPACES) - { s = US"bad state parsing XCLIENT parameters"; goto fatal_501; } - -host_build_sender_fullhost(); -proxy_session = TRUE; -*resp = 220; -return NULL; - -fatal_501: - *flagp= TRUE; - *resp = 501; - return s; -} - -# undef XCLIENT_UNAVAIL -# undef XCLIENT_TEMPUNAVAIL - - -gstring * -xclient_smtp_advertise_str(gstring * g) -{ -g = string_catn(g, US"-XCLIENT ", 8); -for (int i = 1; i < nelem(xclient_cmds); i++) - { - g = string_catn(g, US" ", 1); - g = string_cat(g, xclient_cmds[i].str); - } -return string_catn(g, US"\r\n", 2); -} - - -#endif /*EXPERIMENTAL_XCLIENT*/ - -/* vi: aw ai sw=2 -*/ -/* End of xclient.c */ commit aefe2ae93663cfcb3e0e356c79a592c2cfd3a33a Author: Jeremy Harris Date: Fri Mar 20 11:42:27 2026 +0000 Debug: results of expansion conditionals diff --git a/src/src/expand.c b/src/src/expand.c index c02af288c..9dbc12ac8 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2510,7 +2510,8 @@ if (!name[0]) "but found \"%.16s\"", s); return -1; } -DEBUG(expand) debug_printf_indent("cond: %s\n", name); +DEBUG(expand) if (Ustrcmp(name, "def") != 0) + debug_printf_indent("cond: %s\n", name); if (opname) *opname = string_copy(name); @@ -3747,6 +3748,8 @@ goto failout; failout: next = NULL; out: + DEBUG(expand) if (yield && next) + debug_printf_indent("cond %q res: %s\n", opname, *yield ? "T" : "F"); expand_level--; return next; } commit de3d186fd49e0ff10386b8e7bf3d03c888e4f76b Author: Jeremy Harris Date: Mon Mar 23 10:41:01 2026 +0000 Fix logged errno for journal file perms fail. Bug 3209 diff --git a/src/src/deliver.c b/src/src/deliver.c index 488f87317..d02bc0458 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -8401,9 +8401,9 @@ if (addr_local || addr_remote) #endif ) { - int ret = Uunlink(fname); + int fault_errno = errno, ret = Uunlink(fname); log_write(LOG_MAIN|LOG_PANIC, "Couldn't set perms on journal file %s: %s", - fname, strerror(errno)); + fname, strerror(fault_errno)); if(ret && errno != ENOENT) log_write_die(LOG_MAIN, "failed to unlink %s: %s", fname, strerror(errno)); commit c8d81e125e58515384bed22d3a924801645ce4a5 Author: Jeremy Harris Date: Thu Apr 2 11:06:41 2026 +0100 Drop ancient spoolfile format support diff --git a/src/src/spool_in.c b/src/src/spool_in.c index 8aafd95db..b3f807fe1 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2025 */ +/* Copyright (c) The Exim Maintainers 2020 - 2026 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -863,13 +863,10 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) additional data. Otherwise, the possibilities are as follows: Exim 3 type:
,, + - no longer handled - The second set of digits is the parent number for one_time addresses. The - other values were remnants of earlier experiments that were abandoned. - - Exim 4 first type:
- - The digits are the parent number for one_time addresses. + Exim 4 first type (pre 4.50):
+ - no longer handled Exim 4 new type:
# @@ -886,31 +883,15 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) while (isdigit(*p)) p--; - /* Handle Exim 3 spool files */ - - if (*p == ',') - { - int dummy; -#if !defined (COMPILE_UTILITY) - DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - Exim 3 spool file\n"); -#endif - while (isdigit(*(--p)) || *p == ','); - if (*p == ' ') - { - *p++ = 0; - (void)sscanf(CS p, "%d,%d", &dummy, &pno); - } - } - - /* Handle early Exim 4 spool files */ + /* Fail Exim 3 and pre-4.50 spool files */ - else if (*p == ' ') + if (*p == ',' || *p == ' ') { -#if !defined (COMPILE_UTILITY) - DEBUG(deliver) debug_printf_indent("**** SPOOL_IN - early Exim 4 spool file\n"); -#endif - *p++ = 0; - (void)sscanf(CS p, "%d", &pno); + log_write(LOG_MAIN|LOG_PANIC, "Spool%s%s file %s bad format", + *queue_name ? US" Q=" : US"", + *queue_name ? queue_name : US"", + fname); + return spool_read_hdrerror; } /* Handle current format Exim 4 spool files */ commit 9f6219b392555f829170ad005f5a753ec39d1c14 Author: Jeremy Harris Date: Thu Apr 2 12:58:20 2026 +0100 Harden spoolfile reading diff --git a/src/src/spool_in.c b/src/src/spool_in.c index b3f807fe1..60b1ef244 100644 --- a/src/src/spool_in.c +++ b/src/src/spool_in.c @@ -881,7 +881,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) with orcpt len(orcpt),dsn_flags */ - while (isdigit(*p)) p--; + while (p > big_buffer && isdigit(*p)) p--; /* Fail Exim 3 and pre-4.50 spool files */ @@ -909,10 +909,10 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) if (flags & 0x01) /* one_time data exists */ { int len; - while (isdigit(*(--p)) || *p == ',' || *p == '-'); + while (p > big_buffer && (isdigit(*(--p)) || *p == ',' || *p == '-')) ; (void)sscanf(CS p+1, "%d,%d", &len, &pno); *p = 0; - if (len > 0) + if (len > 0 && p > big_buffer + len) { p -= len; errors_to = string_copy_taint(p, GET_TAINTED); @@ -920,13 +920,13 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++) } *--p = 0; /* Terminate address */ - if (flags & 0x02) /* one_time data exists */ + if (flags & 0x02) /* orcpt data exists */ { int len; - while (isdigit(*(--p)) || *p == ',' || *p == '-'); + while (p > big_buffer && (isdigit(*(--p)) || *p == ',' || *p == '-')) ; (void)sscanf(CS p+1, "%d,%d", &len, &dsn_flags); *p = 0; - if (len > 0) + if (len > 0 && p > big_buffer + len) { p -= len; orcpt = string_copy_taint(p, GET_TAINTED); commit dc76912f892e9ed25e3eafe036529107537652a1 Author: Jeremy Harris Date: Thu Apr 2 20:38:30 2026 +0100 DKIM: harden tag parsing. Bug 3056 diff --git a/src/src/miscmods/pdkim/pdkim.c b/src/src/miscmods/pdkim/pdkim.c index 122f3f225..654fac52d 100644 --- a/src/src/miscmods/pdkim/pdkim.c +++ b/src/src/miscmods/pdkim/pdkim.c @@ -473,13 +473,39 @@ for (uschar * p = raw_hdr; ; p++) if (where == PDKIM_HDR_LIMBO) { /* In limbo, just wait for a tag-char to appear */ - if (!(c >= 'a' && c <= 'z')) + if (!c || isspace(c)) goto NEXT_CHAR; + if (!(c >= 'a' && c <= 'z')) + { + DEBUG(acl) debug_printf_indent("bad char %W starting tag name\n", p); + return NULL; + } where = PDKIM_HDR_TAG; } if (where == PDKIM_HDR_TAG) + { + if (c == ' ' || c == '\t') /* Permit FWS after tag name */ + { + while (c = *++p) + if (c != ' ' && c != '\t') switch (c) + { + case '\r': + if (*++p != '\n' || (c = *++p) != ' ' && c != '\t') + { + DEBUG(acl) debug_printf_indent("bad FWS after tag name\n"); + return NULL; + } + break; + case '=': case ';': + goto DONE_FWS; + default: + DEBUG(acl) debug_printf_indent("space in tag name\n"); + return NULL; + } + DONE_FWS: + } if (c == '=') { if (Ustrcmp(string_from_gstring(cur_tag), "b") == 0) @@ -490,8 +516,9 @@ for (uschar * p = raw_hdr; ; p++) where = PDKIM_HDR_VALUE; goto NEXT_CHAR; } - else if (!isspace(c)) + else cur_tag = string_catn(cur_tag, p, 1); + } if (where == PDKIM_HDR_VALUE) { commit c74edb1fa98418191e2b9541d515d4a262b6a378 Author: Jeremy Harris Date: Thu Apr 2 20:45:13 2026 +0100 Compiler quietening Broken-by: dc76912f892e diff --git a/src/src/miscmods/pdkim/pdkim.c b/src/src/miscmods/pdkim/pdkim.c index 654fac52d..d39af02f2 100644 --- a/src/src/miscmods/pdkim/pdkim.c +++ b/src/src/miscmods/pdkim/pdkim.c @@ -504,7 +504,7 @@ for (uschar * p = raw_hdr; ; p++) DEBUG(acl) debug_printf_indent("space in tag name\n"); return NULL; } - DONE_FWS: + DONE_FWS: ; } if (c == '=') { commit 8a4fad6c09d8e4dd29187c0d69b335145b3535ab Author: Jeremy Harris Date: Fri Apr 3 11:16:29 2026 +0100 ARC: fix crash on bad pubkey contruction diff --git a/src/src/base64.c b/src/src/base64.c index 60f653f10..2bafa78e5 100644 --- a/src/src/base64.c +++ b/src/src/base64.c @@ -137,8 +137,8 @@ Returns: the number of bytes in the result, or -1 if the input was malformed Whitespace in the input is ignored. -A zero is added on to the end to make it easy in cases where the result is to -be interpreted as text. This is not included in the count. */ +A zero byte is added on to the end to make it easy in cases where the result is +to be interpreted as text. This is not included in the count. */ static uschar dec64table[] = { 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0-15 */ @@ -156,7 +156,7 @@ b64decode(const uschar * code, uschar ** ptr, const void * proto_mem) { int x, y; -uschar *result; +uschar * result; { int l = Ustrlen(code); diff --git a/src/src/miscmods/arc.c b/src/src/miscmods/arc.c index 846272d7f..8b2dcbfa2 100644 --- a/src/src/miscmods/arc.c +++ b/src/src/miscmods/arc.c @@ -821,27 +821,28 @@ typedef int (*fn_t) /* Get the public key from DNS */ -/*XXX dkim module */ if (!(pubkey = arc_line_to_pubkey(al, &errstr))) + rc = ERROR; +else { - *errstr_p = string_sprintf("%s (%s)", errstr, why); - return ERROR; + rc = (((fn_t *) arc_dkim_mod_info->functions)[DKIM_SIG_VERIFY]) + (sighash, hhash_computed, hm, pubkey, &errstr); + switch (rc) + { + case OK: + break; + case FAIL: + DEBUG(acl) + debug_printf("ARC i=%d %s verify %s\n", as->instance, why, errstr); + break; + case ERROR: + DEBUG(acl) debug_printf("ARC verify %s init: %s\n", why, errstr); + break; + } } -rc = (((fn_t *) arc_dkim_mod_info->functions)[DKIM_SIG_VERIFY]) - (sighash, hhash_computed, hm, pubkey, &errstr); -switch (rc) - { - case OK: - break; - case FAIL: - DEBUG(acl) - debug_printf("ARC i=%d %s verify %s\n", as->instance, why, errstr); - break; - case ERROR: - DEBUG(acl) debug_printf("ARC verify %s init: %s\n", why, errstr); - break; - } +if (rc != OK) + *errstr_p = string_sprintf("%s (%s)", errstr, why); return rc; } diff --git a/src/src/miscmods/pdkim/signing.c b/src/src/miscmods/pdkim/signing.c index 5bd432881..6aba5a56f 100644 --- a/src/src/miscmods/pdkim/signing.c +++ b/src/src/miscmods/pdkim/signing.c @@ -825,7 +825,8 @@ switch(fmt) case KEYFMT_DER: /*XXX hmm, we never free this */ if (!(verify_ctx->key = d2i_PUBKEY(NULL, &s, pubkey->len))) - ret = US ERR_error_string(ERR_get_error(), NULL); + ret = string_sprintf("deccoding pubkey DER:%s", + ERR_reason_error_string(ERR_get_error())); break; #ifdef SIGN_HAVE_ED25519 case KEYFMT_ED25519_BARE: commit 6f5edf501bafdca1f234af6103c1173cc43805da Author: Jeremy Harris Date: Sat Apr 4 22:27:58 2026 +0100 Sieve filters: add more debug output for script errors. Bug 2083 diff --git a/src/src/miscmods/sieve_filter.c b/src/src/miscmods/sieve_filter.c index 4271b8958..1efc41844 100644 --- a/src/src/miscmods/sieve_filter.c +++ b/src/src/miscmods/sieve_filter.c @@ -291,20 +291,17 @@ if (address->ptr > 0) uschar * error; const uschar * ss = parse_extract_address(address->s, &error, &start, &end, &domain, FALSE); - if (!ss) - { - filter->errmsg = string_sprintf("malformed address %q (%s)", - address->s, error); - return -1; - } - else + if (ss) return 1; + + filter->errmsg = string_sprintf("malformed address %q (%s)", + address->s, error); } else - { filter->errmsg = CUS "empty address"; - return -1; - } + +DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); +return -1; } @@ -339,7 +336,11 @@ for (t = s = str->s, e = s + str->ptr; s < e; ) | (isdigit(s[2]) ? s[2]-'0' : tolower(s[2])-'a'+10); s += 3; } - else return FALSE; + else + { + DEBUG(filter) debug_printf_indent("uri decode: bad encoding\n"); + return FALSE; + } } else *t++ = *s++; @@ -403,7 +404,7 @@ if (*uri && *uri != '?') if (!uri_decode(to)) { filter->errmsg = US"Invalid URI encoding"; - return -1; + goto bad; } new = store_get(sizeof(string_item), GET_UNTAINTED); new->text = string_from_gstring(to); @@ -413,7 +414,7 @@ if (*uri && *uri != '?') else { filter->errmsg = US"Missing addr-spec in URI"; - return -1; + goto bad; } if (*uri == '%') uri += 3; else break; @@ -432,14 +433,14 @@ if (*uri == '?') if (!uri_decode(hname)) { filter->errmsg = US"Invalid URI encoding"; - return -1; + goto bad; } } /* match = */ if (*uri++ != '=') { filter->errmsg = US"Missing equal after hname"; - return -1; + goto bad; } /* match hvalue */ @@ -451,7 +452,7 @@ if (*uri == '?') if (!uri_decode(hvalue)) { filter->errmsg = US"Invalid URI encoding"; - return -1; + goto bad; } } if (hname->ptr == 2 && strcmpic(hname->s, US"to") == 0) @@ -492,9 +493,13 @@ if (*uri == '?') if (*uri) { filter->errmsg = US"Syntactically invalid URI"; - return -1; + goto bad; } return 1; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } #endif @@ -649,7 +654,11 @@ while (n < nend) case '\\': { ++npart; - if (npart == nend) return -1; + if (npart == nend) + { + DEBUG(filter) debug_printf_indent("glob pattern error\n"); + return -1; + } /* FALLTHROUGH */ } default: @@ -1076,6 +1085,7 @@ while (*filter->pc) else ++filter->pc; } filter->errmsg = CUS "missing end of comment"; +DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } @@ -1109,6 +1119,7 @@ while (*filter->pc) ++filter->pc; filter->errmsg = CUS "missing end of comment"; +DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } @@ -1202,7 +1213,10 @@ do if (*src == ' ' || *src == '\t' || *src == '\n') while (*src == ' ' || *src == '\t' || *src == '\n') ++src; else + { + DEBUG(filter) debug_printf_indent("hex decode: bad syntax\n"); return -1; + } } while (src < end); return decoded; @@ -1252,8 +1266,16 @@ do for (c = 0, d = 0; d < 7 && src < end && isxdigit(n = tolower(*src)); c = (c<<4)|(n>= '0' && n<= '9' ? n-'0' : 10+(n-'a')), ++d, ++src) ; - if (src == hex_seq) return -1; - if (d == 7 || (!((c >= 0 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0x10ffff)))) return -2; + if (src == hex_seq) + { + DEBUG(filter) debug_printf_indent("unicode decode: bad syntax\n"); + return -1; + } + if (d == 7 || (!((c >= 0 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0x10ffff)))) + { + DEBUG(filter) debug_printf_indent("unicode decode: char not in range\n"); + return -2; + } if (c<128) { if (dst) *dst++ = c; @@ -1454,7 +1476,7 @@ if (*filter->pc == '"') /* quoted string */ } } filter->errmsg = CUS "missing end of string"; - return -1; + goto bad; } else if (Ustrncmp(filter->pc, CUS "text:", 5) == 0) /* multiline string */ { @@ -1481,7 +1503,7 @@ else if (Ustrncmp(filter->pc, CUS "text:", 5) == 0) /* multiline string */ else { filter->errmsg = CUS "syntax error"; - return -1; + goto bad; } while (*filter->pc) { @@ -1536,9 +1558,13 @@ else if (Ustrncmp(filter->pc, CUS "text:", 5) == 0) /* multiline string */ } } filter->errmsg = CUS "missing end of multi line string"; - return -1; + goto bad; } else return 0; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } @@ -1605,7 +1631,7 @@ if (*filter->pc>= '0' && *filter->pc<= '9') if (errno == ERANGE) { filter->errmsg = CUstrerror(ERANGE); - return -1; + goto bad; } filter->pc = e; u = 1; @@ -1615,17 +1641,18 @@ if (*filter->pc>= '0' && *filter->pc<= '9') if (d>(ULONG_MAX/u)) { filter->errmsg = CUstrerror(ERANGE); - return -1; + goto bad; } d *= u; *data = d; return 1; } -else - { - filter->errmsg = CUS "missing number"; + +filter->errmsg = CUS "missing number"; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; - } } @@ -1678,6 +1705,7 @@ if (*filter->pc == '[') /* string list */ else { filter->errmsg = CUS "missing string"; + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); goto error; } } @@ -1698,13 +1726,13 @@ if (*filter->pc == '[') /* string list */ else { filter->errmsg = CUS "missing closing bracket"; + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); goto error; } } else /* single string */ { - if (!(d = store_get(sizeof(gstring)*2, GET_UNTAINTED))) - return -1; + d = store_get(sizeof(gstring)*2, GET_UNTAINTED); m = parse_string(filter, &d[0]); if (m == -1) @@ -1725,6 +1753,7 @@ else /* single string */ } error: filter->errmsg = CUS "missing string list"; +DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } @@ -1756,7 +1785,7 @@ if (parse_identifier(filter, CUS ":user") == 1) if (!filter->require_subaddress) { filter->errmsg = CUS "missing previous require \"subaddress\";"; - return -1; + goto bad; } *a = ADDRPART_USER; return 1; @@ -1766,7 +1795,7 @@ else if (parse_identifier(filter, CUS ":detail") == 1) if (!filter->require_subaddress) { filter->errmsg = CUS "missing previous require \"subaddress\";"; - return -1; + goto bad; } *a = ADDRPART_DETAIL; return 1; @@ -1789,6 +1818,10 @@ else if (parse_identifier(filter, CUS ":all") == 1) return 1; } else return 0; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } @@ -1923,7 +1956,9 @@ if (*filter->pc == '(') switch (parse_test(filter, &cond, exec)) { case -1: return -1; - case 0: filter->errmsg = CUS "missing test"; return -1; + case 0: filter->errmsg = CUS "missing test"; + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; default: ++*n; if (cond) ++*num_true; break; } if (parse_white(filter) == -1) return -1; @@ -1938,6 +1973,7 @@ if (*filter->pc == '(') else { filter->errmsg = CUS "missing closing paren"; + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } } @@ -1963,7 +1999,7 @@ Returns: 1 success static int parse_test(struct Sieve *filter, int *cond, int exec) { -if (parse_white(filter) == -1) return -1; +if (parse_white(filter) == -1) goto bad; if (parse_identifier(filter, CUS "address")) { /* @@ -1982,52 +2018,52 @@ if (parse_identifier(filter, CUS "address")) for (;;) { - if (parse_white(filter) == -1) return -1; + if (parse_white(filter) == -1) goto bad; if ((m = parse_addresspart(filter, &addressPart)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (ap) { filter->errmsg = CUS "address part already specified"; - return -1; + goto bad; } else ap = 1; } else if ((m = parse_comparator(filter, &comparator)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (co) { filter->errmsg = CUS "comparator already specified"; - return -1; + goto bad; } else co = 1; } else if ((m = parse_matchtype(filter, &matchType)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (mt) { filter->errmsg = CUS "match type already specified"; - return -1; + goto bad; } else mt = 1; } else break; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &hdr)) != 1) { if (m == 0) filter->errmsg = CUS "header string list expected"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &key)) != 1) { if (m == 0) filter->errmsg = CUS "key string list expected"; - return -1; + goto bad; } *cond = 0; for (gstring * h = hdr; h->ptr != -1 && !*cond; ++h) @@ -2045,7 +2081,7 @@ if (parse_identifier(filter, CUS "address")) ) { filter->errmsg = CUS "invalid header field"; - return -1; + goto bad; } if (exec) { @@ -2053,7 +2089,7 @@ if (parse_identifier(filter, CUS "address")) if (!(header_value = expand_string(string_sprintf("$rheader_%s", quote(h))))) { filter->errmsg = CUS "header string expansion failed"; - return -1; + goto bad; } f.parse_allow_group = TRUE; while (*header_value && !*cond) @@ -2087,7 +2123,7 @@ if (parse_identifier(filter, CUS "address")) for (gstring * k = key; k->ptr != - 1; ++k) { *cond = compare(filter, k, &partStr, comparator, matchType); - if (*cond == -1) return -1; + if (*cond == -1) goto bad; if (*cond) break; } } @@ -2111,8 +2147,8 @@ else if (parse_identifier(filter, CUS "allof")) switch (parse_testlist(filter, &n, &num_true, exec)) { - case -1: return -1; - case 0: filter->errmsg = CUS "missing test list"; return -1; + case -1: goto bad; + case 0: filter->errmsg = CUS "missing test list"; goto bad; default: *cond = (n == num_true); return 1; } } @@ -2126,8 +2162,8 @@ else if (parse_identifier(filter, CUS "anyof")) switch (parse_testlist(filter, &n, &num_true, exec)) { - case -1: return -1; - case 0: filter->errmsg = CUS "missing test list"; return -1; + case -1: goto bad; + case 0: filter->errmsg = CUS "missing test list"; goto bad; default: *cond = (num_true>0); return 1; } } @@ -2141,11 +2177,11 @@ else if (parse_identifier(filter, CUS "exists")) int m; if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &hdr)) != 1) { if (m == 0) filter->errmsg = CUS "header string list expected"; - return -1; + goto bad; } if (exec) { @@ -2157,7 +2193,7 @@ else if (parse_identifier(filter, CUS "exists")) if (!header_def) { filter->errmsg = CUS "header string expansion failed"; - return -1; + goto bad; } if (Ustrcmp(header_def,"false") == 0) *cond = 0; } @@ -2189,42 +2225,42 @@ else if (parse_identifier(filter, CUS "header")) for (;;) { if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_comparator(filter, &comparator)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (co) { filter->errmsg = CUS "comparator already specified"; - return -1; + goto bad; } else co = 1; } else if ((m = parse_matchtype(filter, &matchType)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (mt) { filter->errmsg = CUS "match type already specified"; - return -1; + goto bad; } else mt = 1; } else break; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &hdr)) != 1) { if (m == 0) filter->errmsg = CUS "header string list expected"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &key)) != 1) { if (m == 0) filter->errmsg = CUS "key string list expected"; - return -1; + goto bad; } *cond = 0; for (gstring * h = hdr; h->ptr != -1 && !*cond; ++h) @@ -2232,7 +2268,7 @@ else if (parse_identifier(filter, CUS "header")) if (!is_header(h)) { filter->errmsg = CUS "invalid header field"; - return -1; + goto bad; } if (exec) { @@ -2245,13 +2281,13 @@ else if (parse_identifier(filter, CUS "header")) if (!header_value.s || !header_def) { filter->errmsg = CUS "header string expansion failed"; - return -1; + goto bad; } for (gstring * k = key; k->ptr != -1; ++k) if (Ustrcmp(header_def,"true") == 0) { *cond = compare(filter, k, &header_value, comparator, matchType); - if (*cond == -1) return -1; + if (*cond == -1) goto bad; if (*cond) break; } } @@ -2260,11 +2296,11 @@ else if (parse_identifier(filter, CUS "header")) } else if (parse_identifier(filter, CUS "not")) { - if (parse_white(filter) == -1) return -1; + if (parse_white(filter) == -1) goto bad; switch (parse_test(filter, cond, exec)) { - case -1: return -1; - case 0: filter->errmsg = CUS "missing test"; return -1; + case -1: goto bad; + case 0: filter->errmsg = CUS "missing test"; goto bad; default: *cond = !*cond; return 1; } } @@ -2278,16 +2314,16 @@ else if (parse_identifier(filter, CUS "size")) unsigned long limit; int overNotUnder; - if (parse_white(filter) == -1) return -1; + if (parse_white(filter) == -1) goto bad; if (parse_identifier(filter, CUS ":over")) overNotUnder = 1; else if (parse_identifier(filter, CUS ":under")) overNotUnder = 0; else { filter->errmsg = CUS "missing :over or :under"; - return -1; + goto bad; } - if (parse_white(filter) == -1) return -1; - if (parse_number(filter, &limit) == -1) return -1; + if (parse_white(filter) == -1) goto bad; + if (parse_number(filter, &limit) == -1) goto bad; *cond = (overNotUnder ? (message_size>limit) : (message_sizerequire_envelope) { filter->errmsg = CUS "missing previous require \"envelope\";"; - return -1; + goto bad; } for (;;) { - if (parse_white(filter) == -1) return -1; + if (parse_white(filter) == -1) goto bad; if ((m = parse_comparator(filter, &comparator)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (co) { filter->errmsg = CUS "comparator already specified"; - return -1; + goto bad; } else co = 1; } else if ((m = parse_addresspart(filter, &addressPart)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (ap) { filter->errmsg = CUS "address part already specified"; - return -1; + goto bad; } else ap = 1; } else if ((m = parse_matchtype(filter, &matchType)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (mt) { filter->errmsg = CUS "match type already specified"; - return -1; + goto bad; } else mt = 1; } else break; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &env)) != 1) { if (m == 0) filter->errmsg = CUS "envelope string list expected"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &key)) != 1) { if (m == 0) filter->errmsg = CUS "key string list expected"; - return -1; + goto bad; } *cond = 0; for (gstring * e = env; e->ptr != -1 && !*cond; ++e) @@ -2423,21 +2459,21 @@ else if (parse_identifier(filter, CUS "envelope")) else { filter->errmsg = CUS "invalid envelope string"; - return -1; + goto bad; } if (exec && envelopeExpr) { if (!(envelope = expand_string(US envelopeExpr))) { filter->errmsg = CUS "header string expansion failed"; - return -1; + goto bad; } for (gstring * k = key; k->ptr != -1; ++k) { gstring envelopeStr = {.s = envelope, .ptr = Ustrlen(envelope), .size = Ustrlen(envelope)+1}; *cond = compare(filter, k, &envelopeStr, comparator, matchType); - if (*cond == -1) return -1; + if (*cond == -1) goto bad; if (*cond) break; } } @@ -2458,14 +2494,14 @@ else if (parse_identifier(filter, CUS "valid_notify_method")) if (!filter->require_enotify) { filter->errmsg = CUS "missing previous require \"enotify\";"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &uris)) != 1) { if (m == 0) filter->errmsg = CUS "URI string list expected"; - return -1; + goto bad; } if (exec) { @@ -2502,28 +2538,28 @@ else if (parse_identifier(filter, CUS "notify_method_capability")) if (!filter->require_enotify) { filter->errmsg = CUS "missing previous require \"enotify\";"; - return -1; + goto bad; } for (;;) { - if (parse_white(filter) == -1) return -1; + if (parse_white(filter) == -1) goto bad; if ((m = parse_comparator(filter, &comparator)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (co) { filter->errmsg = CUS "comparator already specified"; - return -1; + goto bad; } else co = 1; } else if ((m = parse_matchtype(filter, &matchType)) != 0) { - if (m == -1) return -1; + if (m == -1) goto bad; if (mt) { filter->errmsg = CUS "match type already specified"; - return -1; + goto bad; } else mt = 1; } @@ -2532,21 +2568,21 @@ else if (parse_identifier(filter, CUS "notify_method_capability")) if ((m = parse_string(filter, &uri)) != 1) { if (m == 0) filter->errmsg = CUS "missing notification URI string"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_string(filter, &capa)) != 1) { if (m == 0) filter->errmsg = CUS "missing notification capability string"; - return -1; + goto bad; } if (parse_white(filter) == -1) - return -1; + goto bad; if ((m = parse_stringlist(filter, &keys)) != 1) { if (m == 0) filter->errmsg = CUS "missing key string list"; - return -1; + goto bad; } if (exec) { @@ -2561,7 +2597,7 @@ else if (parse_identifier(filter, CUS "notify_method_capability")) for (gstring * k = keys; k->ptr != -1; ++k) { *cond = compare(filter, k, &str_maybe, comparator, matchType); - if (*cond == -1) return -1; + if (*cond == -1) goto bad; if (*cond) break; } } @@ -2569,6 +2605,10 @@ else if (parse_identifier(filter, CUS "notify_method_capability")) } #endif else return 0; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } @@ -2605,6 +2645,7 @@ if (*filter->pc == '{') return 1; } filter->errmsg = CUS "expecting command or closing brace"; + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } return 0; @@ -2634,6 +2675,7 @@ if (*filter->pc == ';') return 1; } filter->errmsg = CUS "missing semicolon"; +DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); return -1; } @@ -2675,7 +2717,7 @@ while (*filter->pc) if (m == 0) { filter->errmsg = CUS "missing test"; - return -1; + goto bad; } if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { @@ -2687,7 +2729,7 @@ while (*filter->pc) if (m == 0) { filter->errmsg = CUS "missing block"; - return -1; + goto bad; } unsuccessful = !cond; for (;;) /* elsif test block */ @@ -2704,7 +2746,7 @@ while (*filter->pc) if (m == 0) { filter->errmsg = CUS "missing test"; - return -1; + goto bad; } if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { @@ -2716,7 +2758,7 @@ while (*filter->pc) if (m == 0) { filter->errmsg = CUS "missing block"; - return -1; + goto bad; } if (exec && unsuccessful && cond) unsuccessful = 0; @@ -2734,7 +2776,7 @@ while (*filter->pc) if (m == 0) { filter->errmsg = CUS "missing block"; - return -1; + goto bad; } } } @@ -2800,7 +2842,7 @@ while (*filter->pc) if (!filter->require_copy) { filter->errmsg = CUS "missing previous require \"copy\";"; - return -1; + goto bad; } copy = 1; } @@ -2812,12 +2854,12 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "missing redirect recipient string"; - return -1; + goto bad; } if (strchr(CCS recipient.s, '@') == NULL) { filter->errmsg = CUS "unqualified recipient address"; - return -1; + goto bad; } if (exec) { @@ -2844,7 +2886,7 @@ while (*filter->pc) if (!filter->require_fileinto) { filter->errmsg = CUS "missing previous require \"fileinto\";"; - return -1; + goto bad; } for (;;) { @@ -2855,7 +2897,7 @@ while (*filter->pc) if (!filter->require_copy) { filter->errmsg = CUS "missing previous require \"copy\";"; - return -1; + goto bad; } copy = 1; } @@ -2866,7 +2908,7 @@ while (*filter->pc) if ((m = parse_string(filter, &folder)) != 1) { if (m == 0) filter->errmsg = CUS "missing fileinto folder string"; - return -1; + goto bad; } m = 0; s = folder.s; if (folder.ptr == 0) @@ -2881,7 +2923,7 @@ while (*filter->pc) if (m) { filter->errmsg = CUS "invalid folder"; - return -1; + goto bad; } if (exec) { @@ -2919,14 +2961,14 @@ while (*filter->pc) if (!filter->require_enotify) { filter->errmsg = CUS "missing previous require \"enotify\";"; - return -1; + goto bad; } envelope_from = sender_address && sender_address[0] ? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain") : US ""; if (!envelope_from) { filter->errmsg = CUS "expansion failure for envelope from"; - return -1; + goto bad; } for (;;) { @@ -2939,7 +2981,7 @@ while (*filter->pc) if ((m = parse_string(filter, &from)) != 1) { if (m == 0) filter->errmsg = CUS "from string expected"; - return -1; + goto bad; } } else if (parse_identifier(filter, CUS ":importance") == 1) @@ -2950,12 +2992,12 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "importance string expected"; - return -1; + goto bad; } if (importance.ptr != 1 || importance.s[0] < '1' || importance.s[0] > '3') { filter->errmsg = CUS "invalid importance"; - return -1; + goto bad; } } else if (parse_identifier(filter, CUS ":options") == 1) @@ -2971,7 +3013,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "message string expected"; - return -1; + goto bad; } } else break; @@ -2982,7 +3024,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "missing method string"; - return -1; + goto bad; } if (parse_semicolon(filter) == -1) return -1; @@ -2999,7 +3041,7 @@ while (*filter->pc) if (!auto_submitted_value.s || !auto_submitted_def) { filter->errmsg = CUS "header string expansion failed"; - return -1; + goto bad; } if (Ustrcmp(auto_submitted_def,"true") != 0 || Ustrcmp(auto_submitted_value.s,"no") == 0) { @@ -3095,14 +3137,14 @@ while (*filter->pc) if (!filter->require_vacation) { filter->errmsg = CUS "missing previous require \"vacation\";"; - return -1; + goto bad; } if (exec) { if (filter->vacation_ran) { filter->errmsg = CUS "trying to execute vacation more than once"; - return -1; + goto bad; } filter->vacation_ran = TRUE; } @@ -3139,7 +3181,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "subject string expected"; - return -1; + goto bad; } } else if (parse_identifier(filter, CUS ":from") == 1) @@ -3150,7 +3192,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "from string expected"; - return -1; + goto bad; } if (check_mail_address(filter, &from) != 1) return -1; @@ -3163,7 +3205,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "addresses string list expected"; - return -1; + goto bad; } for (gstring * a = addresses; a->ptr != -1; ++a) { @@ -3186,7 +3228,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "handle string expected"; - return -1; + goto bad; } } else break; @@ -3197,7 +3239,7 @@ while (*filter->pc) { if (m == 0) filter->errmsg = CUS "missing reason string"; - return -1; + goto bad; } if (reason_is_mime) { @@ -3208,7 +3250,7 @@ while (*filter->pc) if (serrmsg = CUS "MIME reason string contains 8bit text"; - return -1; + goto bad; } } if (parse_semicolon(filter) == -1) return -1; @@ -3224,7 +3266,7 @@ while (*filter->pc) if (!(mi = misc_mod_find(US"exim_filter", NULL))) { filter->errmsg = CUS "test for 'personal': module not available"; - return -1; + goto bad; } if ((((fn_t *) mi->functions)[EXIM_FILTER_PERSONAL])(aliases, TRUE)) { @@ -3344,6 +3386,10 @@ while (*filter->pc) #endif } return 1; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } @@ -3404,7 +3450,7 @@ if (exec && filter->vacation_directory && filter_test == FTEST_NONE) && errno != ENOENT) { filter->errmsg = CUS "unable to open vacation directory"; - return -1; + goto bad; } if (oncelogdir) @@ -3435,7 +3481,7 @@ while (parse_identifier(filter, CUS "require")) if ((m = parse_stringlist(filter, &cap)) != 1) { if (m == 0) filter->errmsg = CUS "capability string list expected"; - return -1; + goto bad; } for (gstring * check = cap; check->s; ++check) { @@ -3453,7 +3499,7 @@ while (parse_identifier(filter, CUS "require")) if (!filter->enotify_mailto_owner) { filter->errmsg = CUS "enotify disabled"; - return -1; + goto bad; } filter->require_enotify = 1; } @@ -3467,7 +3513,7 @@ while (parse_identifier(filter, CUS "require")) if (filter_test == FTEST_NONE && !filter->vacation_directory) { filter->errmsg = CUS "vacation disabled"; - return -1; + goto bad; } filter->require_vacation = TRUE; } @@ -3480,7 +3526,7 @@ while (parse_identifier(filter, CUS "require")) else { filter->errmsg = CUS "unknown capability"; - return -1; + goto bad; } } if (parse_semicolon(filter) == -1) return -1; @@ -3489,9 +3535,13 @@ while (parse_identifier(filter, CUS "require")) if (*filter->pc) { filter->errmsg = CUS "syntax error"; - return -1; + goto bad; } return 1; + +bad: + DEBUG(filter) debug_printf_indent("%s\n", filter->errmsg); + return -1; } commit 284cae4e9b5308477438ac26bd5c783d10c879c1 Author: Bernard Quatermass Date: Sun Apr 5 14:12:15 2026 +0100 Removal of obsolete AV scanners for #3210 (#3212) Removal of obsolete AV scanners for #3210 Reviewed-on: https://code.exim.org/exim/exim/pulls/3212 Reviewed-by: Jeremy Harris diff --git a/src/src/EDITME b/src/src/EDITME index a74e64228..67c9e74e9 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -592,11 +592,7 @@ SUPPORT_DANE=yes # If you have content scanning you may wish to only include some of the scanner # interfaces. Uncomment any of these lines to remove that code. -# DISABLE_MAL_FFROTD=yes -# DISABLE_MAL_FFROT6D=yes -# DISABLE_MAL_DRWEB=yes # DISABLE_MAL_FSECURE=yes -# DISABLE_MAL_SOPHIE=yes # DISABLE_MAL_CLAM=yes # DISABLE_MAL_AVAST=yes # DISABLE_MAL_SOCK=yes diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index b9080f1a2..cbc840eb3 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -202,11 +202,7 @@ Do not put spaces between # and the 'define'. #define WHITELIST_D_MACROS #define WITH_CONTENT_SCAN -#define DISABLE_MAL_FFROTD -#define DISABLE_MAL_FFROT6D -#define DISABLE_MAL_DRWEB #define DISABLE_MAL_FSECURE -#define DISABLE_MAL_SOPHIE #define DISABLE_MAL_CLAM #define DISABLE_MAL_AVAST #define DISABLE_MAL_SOCK diff --git a/src/src/malware.c b/src/src/malware.c index 6ba2c5030..60ca0448f 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -3,7 +3,7 @@ *************************************************/ /* - * Copyright (c) The Exim Maintainers 2015 - 2025 + * Copyright (c) The Exim Maintainers 2015 - 2026 * Copyright (c) Tom Kistner 2003 - 2015 * License: GPL * SPDX-License-Identifier: GPL-2.0-or-later @@ -15,21 +15,6 @@ #ifdef WITH_CONTENT_SCAN /* entire file */ typedef enum { -#ifndef DISABLE_MAL_FFROTD - M_FPROTD, -#endif -#ifndef DISABLE_MAL_FFROT6D - M_FPROT6D, -#endif -#ifndef DISABLE_MAL_DRWEB - M_DRWEB, -#endif -#ifndef DISABLE_MAL_FSECURE - M_FSEC, -#endif -#ifndef DISABLE_MAL_SOPHIE - M_SOPHIE, -#endif #ifndef DISABLE_MAL_CLAM M_CLAMD, #endif @@ -53,21 +38,6 @@ static struct scan contype_t conn; } m_scans[] = { -#ifndef DISABLE_MAL_FFROTD - { M_FPROTD, US"f-protd", US"localhost 10200-10204", MC_TCP }, -#endif -#ifndef DISABLE_MAL_FFROT6D - { M_FPROT6D, US"f-prot6d", US"localhost 10200", MC_TCP }, -#endif -#ifndef DISABLE_MAL_DRWEB - { M_DRWEB, US"drweb", US"/usr/local/drweb/run/drwebd.sock", MC_STRM }, -#endif -#ifndef DISABLE_MAL_FSECURE - { M_FSEC, US"fsecure", US"/var/run/.fsav", MC_UNIX }, -#endif -#ifndef DISABLE_MAL_SOPHIE - { M_SOPHIE, US"sophie", US"/var/run/sophie", MC_UNIX }, -#endif #ifndef DISABLE_MAL_CLAM { M_CLAMD, US"clamd", US"/tmp/clamd", MC_NONE }, #endif @@ -129,25 +99,6 @@ typedef struct clamd_address { #endif -#ifndef DISABLE_MAL_DRWEB -# define DRWEBD_SCAN_CMD (1) /* scan file, buffer or diskfile */ -# define DRWEBD_RETURN_VIRUSES (1<<0) /* ask daemon return to us viruses names from report */ -# define DRWEBD_IS_MAIL (1<<19) /* say to daemon that format is "archive MAIL" */ - -# define DERR_READ_ERR (1<<0) /* read error */ -# define DERR_NOMEMORY (1<<2) /* no memory */ -# define DERR_TIMEOUT (1<<9) /* scan timeout has run out */ -# define DERR_BAD_CALL (1<<15) /* wrong command */ - -static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$"; -static const pcre2_code * drweb_re = NULL; -#endif - -#ifndef DISABLE_MAL_FSECURE -static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$"; -static const pcre2_code * fsec_re = NULL; -#endif - #ifndef DISABLE_MAL_AVAST static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]"; static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)"; @@ -157,13 +108,6 @@ static const pcre2_code * ava_re_virus = NULL; static const pcre2_code * ava_re_error = NULL; #endif -#ifndef DISABLE_MAL_FFROT6D -static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$"; -static const uschar * fprot6d_re_virus_str = US "^\\d+\\s\\s+.+$"; -static const pcre2_code * fprot6d_re_error = NULL; -static const pcre2_code * fprot6d_re_virus = NULL; -#endif - /******************************************************************************/ @@ -317,6 +261,8 @@ uschar * p = buffer; ssize_t rcv; BOOL ok = FALSE; +*buffer = '\0'; + if (!fd_ready(fd, tmo)) return -2; @@ -346,17 +292,6 @@ DEBUG(acl) debug_printf_indent("Malware scan: read '%s'\n", buffer); return p - buffer; } -/* return TRUE iff size as requested */ -#ifndef DISABLE_MAL_DRWEB -static BOOL -recv_len(int sock, void * buf, int size, time_t tmo) -{ -return fd_ready(sock, tmo) - ? recv(sock, buf, size, 0) == size - : FALSE; -} -#endif - #ifndef DISABLE_MAL_CLAM static int clamd_option(clamd_address * cd, const uschar * optstr, int * subsep) @@ -510,391 +445,6 @@ if (!malware_ok) switch (scanent->scancode) { -#ifndef DISABLE_MAL_FFROTD - case M_FPROTD: /* "f-protd" scanner type -------------------------------- */ - { - uschar *fp_scan_option; - unsigned int detected=0, par_count=0; - uschar * scanrequest; - uschar buf[32768], *strhelper, *strhelper2; - uschar * malware_name_internal = NULL; - int len; - - scanrequest = string_sprintf("GET %s", eml_filename); - - while ((fp_scan_option = string_nextinlist(&av_scanner_work, &sep, - NULL, 0))) - { - scanrequest = string_sprintf("%s%s%s", scanrequest, - par_count ? "%20" : "?", fp_scan_option); - par_count++; - } - scanrequest = string_sprintf("%s HTTP/1.0\r\n\r\n", scanrequest); - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s: %s\n", - scanner_name, scanrequest); - - /* send scan request */ - if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest)+1, &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - while ((len = recv_line(malware_daemon_ctx.sock, buf, sizeof(buf), tmo)) >= 0) - if (len > 0) - { - if (Ustrstr(buf, US""))) - { - if ((strhelper2 = Ustrstr(buf, US"")) != NULL) - { - *strhelper2 = '\0'; - malware_name_internal = string_copy(strhelper+6); - } - } - else if (Ustrstr(buf, US"") - ? malware_name_internal : NULL; - break; - } - } - if (len < -1) - { - (void)close(malware_daemon_ctx.sock); - return DEFER; - } - break; - } /* f-protd */ -#endif - -#ifndef DISABLE_MAL_FFROT6D - case M_FPROT6D: /* "f-prot6d" scanner type ----------------------------------- */ - { - int bread; - uschar * e, * linebuffer, * scanrequest; - uschar av_buffer[1024]; - - if ((!fprot6d_re_virus && !(fprot6d_re_virus = m_pcre_compile(fprot6d_re_virus_str, FALSE, &errstr))) - || (!fprot6d_re_error && !(fprot6d_re_error = m_pcre_compile(fprot6d_re_error_str, FALSE, &errstr)))) - return malware_panic_defer(errstr); - - scanrequest = string_sprintf("SCAN FILE %s\n", eml_filename); - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s: %s\n", - scanner_name, scanrequest); - - if (m_sock_send(malware_daemon_ctx.sock, scanrequest, Ustrlen(scanrequest), &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo); - - if (bread <= 0) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to read from socket (%s)", strerror(errno)), - malware_daemon_ctx.sock); - - if (bread == sizeof(av_buffer)) - return m_panic_defer_3(scanent, CUS callout_address, - US"buffer too small", malware_daemon_ctx.sock); - - av_buffer[bread] = '\0'; - linebuffer = string_copy(av_buffer); - - m_sock_send(malware_daemon_ctx.sock, US"QUIT\n", 5, 0); - - if ((e = m_pcre_exec(fprot6d_re_error, linebuffer))) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("scanner reported error (%s)", e), malware_daemon_ctx.sock); - - if (!(malware_name = m_pcre_exec(fprot6d_re_virus, linebuffer))) - malware_name = NULL; - - break; - } /* f-prot6d */ -#endif - -#ifndef DISABLE_MAL_DRWEB - case M_DRWEB: /* "drweb" scanner type ----------------------------------- */ - /* v0.1 - added support for tcp sockets */ - /* v0.0 - initial release -- support for unix sockets */ - { - int result; - off_t fsize; - unsigned int fsize_uint; - uschar * tmpbuf, *drweb_fbuf; - int drweb_rc, drweb_cmd, drweb_flags = 0x0000, drweb_fd, - drweb_vnum, drweb_slen, drweb_fin = 0x0000; - - /* prepare variables */ - drweb_cmd = htonl(DRWEBD_SCAN_CMD); - drweb_flags = htonl(DRWEBD_RETURN_VIRUSES | DRWEBD_IS_MAIL); - - if (*scanner_options != '/') - { - /* calc file size */ - if ((drweb_fd = exim_open2(CCS eml_filename, O_RDONLY)) == -1) - return m_panic_defer_3(scanent, NULL, - string_sprintf("can't open spool file %s: %s", - eml_filename, strerror(errno)), - malware_daemon_ctx.sock); - - if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1) - { - int err; -badseek: err = errno; - (void)close(drweb_fd); - return m_panic_defer_3(scanent, NULL, - string_sprintf("can't seek spool file %s: %s", - eml_filename, strerror(err)), - malware_daemon_ctx.sock); - } - fsize_uint = (unsigned int) fsize; - if ((off_t)fsize_uint != fsize) - { - (void)close(drweb_fd); - return m_panic_defer_3(scanent, NULL, - string_sprintf("seeking spool file %s, size overflow", - eml_filename), - malware_daemon_ctx.sock); - } - drweb_slen = htonl(fsize); - if (lseek(drweb_fd, 0, SEEK_SET) < 0) - goto badseek; - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n", - scanner_name, scanner_options); - - /* send scan request */ - if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0)) - { - (void)close(drweb_fd); - return m_panic_defer_3(scanent, CUS callout_address, string_sprintf( - "unable to send commands to socket (%s)", scanner_options), - malware_daemon_ctx.sock); - } - - if (!(drweb_fbuf = store_malloc(fsize_uint))) - { - (void)close(drweb_fd); - return m_panic_defer_3(scanent, NULL, - string_sprintf("unable to allocate memory %u for file (%s)", - fsize_uint, eml_filename), - malware_daemon_ctx.sock); - } - - if ((result = read (drweb_fd, drweb_fbuf, fsize)) == -1) - { - int err = errno; - (void)close(drweb_fd); - store_free(drweb_fbuf); - return m_panic_defer_3(scanent, NULL, - string_sprintf("can't read spool file %s: %s", - eml_filename, strerror(err)), - malware_daemon_ctx.sock); - } - (void)close(drweb_fd); - - /* send file body to socket */ - if (send(malware_daemon_ctx.sock, drweb_fbuf, fsize, 0) < 0) - { - store_free(drweb_fbuf); - return m_panic_defer_3(scanent, CUS callout_address, string_sprintf( - "unable to send file body to socket (%s)", scanner_options), - malware_daemon_ctx.sock); - } - store_free(drweb_fbuf); - } - else - { - drweb_slen = htonl(Ustrlen(eml_filename)); - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s local scan [%s]\n", - scanner_name, scanner_options); - - /* send scan request */ - if ((send(malware_daemon_ctx.sock, &drweb_cmd, sizeof(drweb_cmd), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_flags, sizeof(drweb_flags), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), 0) < 0) || - (send(malware_daemon_ctx.sock, eml_filename, Ustrlen(eml_filename), 0) < 0) || - (send(malware_daemon_ctx.sock, &drweb_fin, sizeof(drweb_fin), 0) < 0)) - return m_panic_defer_3(scanent, CUS callout_address, string_sprintf( - "unable to send commands to socket (%s)", scanner_options), - malware_daemon_ctx.sock); - } - - /* wait for result */ - if (!recv_len(malware_daemon_ctx.sock, &drweb_rc, sizeof(drweb_rc), tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"unable to read return code", malware_daemon_ctx.sock); - drweb_rc = ntohl(drweb_rc); - - if (!recv_len(malware_daemon_ctx.sock, &drweb_vnum, sizeof(drweb_vnum), tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"unable to read the number of viruses", malware_daemon_ctx.sock); - drweb_vnum = ntohl(drweb_vnum); - - /* "virus(es) found" if virus number is > 0 */ - if (drweb_vnum) - { - gstring * g = NULL; - - /* setup default virus name */ - malware_name = US"unknown"; - - /* set up match regex */ - if (!drweb_re) - drweb_re = m_pcre_compile(drweb_re_str, FALSE, &errstr); - - /* read and concatenate virus names into one string */ - for (int i = 0; i < drweb_vnum; i++) - { - pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx); - - /* read the size of report */ - if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"cannot read report size", malware_daemon_ctx.sock); - drweb_slen = ntohl(drweb_slen); - - /* assume tainted, since it is external input */ - tmpbuf = store_get(drweb_slen, GET_TAINTED); - - /* read report body */ - if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo)) - return m_panic_defer_3(scanent, CUS callout_address, - US"cannot read report string", malware_daemon_ctx.sock); - tmpbuf[drweb_slen] = '\0'; - - /* try matcher on the line, grab substring */ - result = pcre2_match(drweb_re, (PCRE2_SPTR)tmpbuf, PCRE2_ZERO_TERMINATED, - 0, 0, md, pcre_gen_mtc_ctx); - if (result >= 2) - { - PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); - - if (i==0) /* the first name we just copy to malware_name */ - g = string_catn(NULL, US ovec[2], ovec[3] - ovec[2]); - - else /* concatenate each new virus name to previous */ - { - g = string_catn(g, US"/", 1); - g = string_catn(g, US ovec[2], ovec[3] - ovec[2]); - } - } - /* pcre2_match_data_free(md); gen ctx needs no free */ - } - malware_name = string_from_gstring(g); - } - else - { - const char *drweb_s = NULL; - - if (drweb_rc & DERR_READ_ERR) drweb_s = "read error"; - if (drweb_rc & DERR_NOMEMORY) drweb_s = "no memory"; - if (drweb_rc & DERR_TIMEOUT) drweb_s = "timeout"; - if (drweb_rc & DERR_BAD_CALL) drweb_s = "wrong command"; - /* retcodes DERR_SYMLINK, DERR_NO_REGFILE, DERR_SKIPPED. - * DERR_TOO_BIG, DERR_TOO_COMPRESSED, DERR_SPAM, - * DERR_CRC_ERROR, DERR_READSOCKET, DERR_WRITE_ERR - * and others are ignored */ - if (drweb_s) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("drweb daemon retcode 0x%x (%s)", drweb_rc, drweb_s), - malware_daemon_ctx.sock); - - /* no virus found */ - malware_name = NULL; - } - break; - } /* drweb */ -#endif - -#ifndef DISABLE_MAL_FSECURE - case M_FSEC: /* "fsecure" scanner type ---------------------------------- */ - { - int i, bread = 0; - uschar * file_name; - uschar av_buffer[1024]; - static uschar *cmdopt[] = { US"CONFIGURE\tARCHIVE\t1\n", - US"CONFIGURE\tTIMEOUT\t0\n", - US"CONFIGURE\tMAXARCH\t5\n", - US"CONFIGURE\tMIME\t1\n" }; - - malware_name = NULL; - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", - scanner_name, scanner_options); - /* pass options */ - memset(av_buffer, 0, sizeof(av_buffer)); - for (i = 0; i != nelem(cmdopt); i++) - { - - if (m_sock_send(malware_daemon_ctx.sock, cmdopt[i], Ustrlen(cmdopt[i]), &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo); - if (bread > 0) av_buffer[bread]='\0'; - if (bread < 0) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to read answer %d (%s)", i, strerror(errno)), - malware_daemon_ctx.sock); - for (int j = 0; j < bread; j++) - if (av_buffer[j] == '\r' || av_buffer[j] == '\n') - av_buffer[j] ='@'; - } - - /* pass the mailfile to fsecure */ - file_name = string_sprintf("SCAN\t%s\n", eml_filename); - - if (m_sock_send(malware_daemon_ctx.sock, file_name, Ustrlen(file_name), &errstr) < 0) - return m_panic_defer(scanent, CUS callout_address, errstr); - - /* set up match */ - /* todo also SUSPICION\t */ - if (!fsec_re) - fsec_re = m_pcre_compile(fsec_re_str, FALSE, &errstr); - - /* read report, linewise. Apply a timeout as the Fsecure daemon - sometimes wants an answer to "PING" but they won't tell us what */ - { - uschar * p = av_buffer; - uschar * q; - - for (;;) - { - errno = ETIMEDOUT; - i = av_buffer+sizeof(av_buffer)-p; - if ((bread= ip_recv(&malware_daemon_ctx, p, i-1, tmo)) < 0) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to read result (%s)", strerror(errno)), - malware_daemon_ctx.sock); - - for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1) - { - *q = '\0'; - - /* Really search for virus again? */ - if (!malware_name) - /* try matcher on the line, grab substring */ - malware_name = m_pcre_exec(fsec_re, p); - - if (Ustrstr(p, "OK\tScan ok.")) - goto fsec_found; - } - - /* copy down the trailing partial line then read another chunk */ - i = av_buffer+sizeof(av_buffer)-p; - memmove(av_buffer, p, i); - p = av_buffer+i; - } - } - - fsec_found: - break; - } /* fsecure */ -#endif - #ifndef DISABLE_MAL_CMDLINE case M_CMDL: /* "cmdline" scanner type ---------------------------------- */ { @@ -1028,53 +578,6 @@ badseek: err = errno; } /* cmdline */ #endif -#ifndef DISABLE_MAL_SOPHIE - case M_SOPHIE: /* "sophie" scanner type --------------------------------- */ - { - int bread = 0; - uschar *p; - uschar * file_name; - uschar av_buffer[1024]; - - /* pass the scan directory to sophie */ - file_name = string_copy(eml_filename); - if ((p = Ustrrchr(file_name, '/'))) - *p = '\0'; - - DEBUG(acl) debug_printf_indent("Malware scan: issuing %s scan [%s]\n", - scanner_name, scanner_options); - - if ( write(malware_daemon_ctx.sock, file_name, Ustrlen(file_name)) < 0 - || write(malware_daemon_ctx.sock, "\n", 1) != 1 - ) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to write to UNIX socket (%s)", scanner_options), - malware_daemon_ctx.sock); - - /* wait for result */ - memset(av_buffer, 0, sizeof(av_buffer)); - if ((bread = ip_recv(&malware_daemon_ctx, av_buffer, sizeof(av_buffer), tmo)) <= 0) - return m_panic_defer_3(scanent, CUS callout_address, - string_sprintf("unable to read from UNIX socket (%s)", scanner_options), - malware_daemon_ctx.sock); - - /* infected ? */ - if (av_buffer[0] == '1') { - uschar * s = Ustrchr(av_buffer, '\n'); - if (s) - *s = '\0'; - malware_name = string_copy(&av_buffer[2]); - } - else if (!strncmp(CS av_buffer, "-1", 2)) - return m_panic_defer_3(scanent, CUS callout_address, - US"scanner reported error", malware_daemon_ctx.sock); - else /* all ok, no virus */ - malware_name = NULL; - - break; - } -#endif - #ifndef DISABLE_MAL_CLAM case M_CLAMD: /* "clamd" scanner type ----------------------------------- */ { @@ -1887,14 +1390,6 @@ malware_init(void) if (!malware_default_re) malware_default_re = regex_must_compile(malware_regex_default, MCS_NOFLAGS, TRUE); -#ifndef DISABLE_MAL_DRWEB -if (!drweb_re) - drweb_re = regex_must_compile(drweb_re_str, MCS_NOFLAGS, TRUE); -#endif -#ifndef DISABLE_MAL_FSECURE -if (!fsec_re) - fsec_re = regex_must_compile(fsec_re_str, MCS_NOFLAGS, TRUE); -#endif #ifndef DISABLE_MAL_AVAST if (!ava_re_clean) ava_re_clean = regex_must_compile(ava_re_clean_str, MCS_NOFLAGS, TRUE); @@ -1903,12 +1398,6 @@ if (!ava_re_virus) if (!ava_re_error) ava_re_error = regex_must_compile(ava_re_error_str, MCS_NOFLAGS, TRUE); #endif -#ifndef DISABLE_MAL_FFROT6D -if (!fprot6d_re_error) - fprot6d_re_error = regex_must_compile(fprot6d_re_error_str, MCS_NOFLAGS, TRUE); -if (!fprot6d_re_virus) - fprot6d_re_virus = regex_must_compile(fprot6d_re_virus_str, MCS_NOFLAGS, TRUE); -#endif } commit fd8d862e9249274a28e7bc21bcab5141199618f9 Author: Jeremy Harris Date: Sun Apr 5 21:36:18 2026 +0100 Exim filter: move testprint to debug stream, when debug enabled. Bug 424 diff --git a/src/src/miscmods/exim_filter.c b/src/src/miscmods/exim_filter.c index 04681aa4a..93fbd3bd3 100644 --- a/src/src/miscmods/exim_filter.c +++ b/src/src/miscmods/exim_filter.c @@ -2500,7 +2500,7 @@ while (commands) if (filter_test != FTEST_NONE || IS_DEBUG(filter)) { const uschar * t = string_printing(expargs[0]); - if (filter_test == FTEST_NONE) + DEBUG(filter) debug_printf_indent("Filter: testprint: %s\n", t); else printf("Testprint: %s\n", t); commit 320482241e766498f8afd1c0b19f209820cd1831 Author: Jeremy Harris Date: Sun Apr 5 21:55:13 2026 +0100 Debug: use standard indent mech for exim-filter diff --git a/src/src/miscmods/exim_filter.c b/src/src/miscmods/exim_filter.c index 93fbd3bd3..53e2cc366 100644 --- a/src/src/miscmods/exim_filter.c +++ b/src/src/miscmods/exim_filter.c @@ -59,7 +59,6 @@ static int expect_endif; static int had_else_endif; static int log_fd; static int log_mode; -static int output_indent; static BOOL filter_delivered; static BOOL finish_obeyed; static BOOL seen_force; @@ -787,17 +786,6 @@ return nextsigchar(ptr, TRUE); -/************************************************* -* Output the current indent * -*************************************************/ - -static void -indent(void) -{ -DEBUG(filter) for (int i = 0; i < output_indent; i++) debug_printf(" "); -} - - /************************************************* * Condition printer: for debugging * @@ -1674,10 +1662,7 @@ switch (c->type) if (filter_thisaddress) { if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) - { - indent(); debug_printf_indent("Extracted address %s\n", filter_thisaddress); - } yield = test_condition(c->right.c, FALSE); } @@ -1788,7 +1773,6 @@ switch (c->type) if ((filter_test != FTEST_NONE && ANY_DEBUG) || IS_DEBUG(filter)) { - indent(); debug_printf_indent("%sondition is %s: ", toplevel ? "C" : "Sub-c", yield == c->testfor ? "true" : "false"); @@ -1937,7 +1921,6 @@ while (commands) if (filter_test != FTEST_NONE) { - indent(); printf("%seliver message to: %s%s%s%s\n", commands->seen ? "D" : "Unseen d", expargs[0], @@ -1950,12 +1933,13 @@ while (commands) else { - DEBUG(filter) debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n", - commands->seen ? "" : "unseen ", - expargs[0], - commands->noerror ? " (noerror)" : "", - s ? " errors_to " : "", - s ? s : US""); + DEBUG(filter) + debug_printf_indent("Filter: %sdeliver message to: %s%s%s%s\n", + commands->seen ? "" : "unseen ", + expargs[0], + commands->noerror ? " (noerror)" : "", + s ? " errors_to " : "", + s ? s : US""); /* Create the new address and add it to the chain, setting the af_ignore_error flag if necessary, and the errors address, which can be @@ -1977,7 +1961,6 @@ while (commands) if (filter_test != FTEST_NONE) { - indent(); if (mode < 0) printf("%save message to: %s%s\n", commands->seen ? "S" : "Unseen s", @@ -2018,7 +2001,6 @@ while (commands) s = string_copy(commands->args[0].u); if (filter_test != FTEST_NONE) { - indent(); printf("%sipe message to: %s%s\n", commands->seen ? "P" : "Unseen p", s, commands->noerror? " (noerror)" : ""); @@ -2076,7 +2058,6 @@ while (commands) log_filename = expargs[0]; if (filter_test != FTEST_NONE) { - indent(); printf("%sogfile %s\n", commands->seen ? "Seen l" : "L", log_filename); } break; @@ -2086,7 +2067,6 @@ while (commands) if (filter_test != FTEST_NONE) { - indent(); printf("%sogwrite \"%s\"\n", commands->seen ? "Seen l" : "L", string_printing(s)); } @@ -2098,7 +2078,7 @@ while (commands) { DEBUG(filter) debug_printf_indent("filter log command aborted: euid=%ld\n", - (long int)geteuid()); + (long int)geteuid()); *error_pointer = US"logwrite command forbidden"; return FF_ERROR; } @@ -2106,7 +2086,7 @@ while (commands) { int len; DEBUG(filter) debug_printf_indent("writing filter log as euid %ld\n", - (long int)geteuid()); + (long int)geteuid()); if (log_fd < 0) { if (!log_filename) @@ -2207,7 +2187,6 @@ while (commands) if (filter_test != FTEST_NONE) { - indent(); printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg); } else @@ -2217,7 +2196,6 @@ while (commands) case FINISH_COMMAND: if (filter_test != FTEST_NONE) { - indent(); printf("%sinish\n", commands->seen ? "Seen f" : "F"); } else @@ -2235,10 +2213,10 @@ while (commands) ok = FF_ERROR; else { - output_indent += 2; + expand_level += 2; ok = interpret_commands(commands->args[condition_value ? 1:2].f, generated); - output_indent -= 2; + expand_level -= 2; } filter_thisaddress = save_address; if (finish_obeyed || ok != FF_DELIVERED && ok != FF_NOTDELIVERED) @@ -2346,7 +2324,6 @@ while (commands) if (filter_test != FTEST_NONE) { const uschar *to = commands->args[mailarg_index_to].u; - indent(); printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M", to ? to : US"", commands->command == VACATION_COMMAND ? " (vacation)" : "", @@ -2357,7 +2334,7 @@ while (commands) if (arg) { int len = Ustrlen(mailargs[i]); - int indent = ANY_DEBUG ? output_indent : 0; + int indent = ANY_DEBUG ? expand_level : 0; while (len++ < 7 + indent) printf(" "); printf("%s: %s%s\n", mailargs[i], string_printing(arg), ( commands->args[mailarg_index_expand].u @@ -2399,10 +2376,13 @@ while (commands) if (arg) { int len = Ustrlen(mailargs[i]); - while (len++ < 15) debug_printf_indent(" "); - debug_printf_indent("%s: %s%s\n", mailargs[i], string_printing(arg), + if (len > 14) len = 14; + expand_level += len; + debug_printf_indent("%s: %s%s\n", mailargs[i], + string_printing(arg), (commands->args[mailarg_index_expand].u != NULL && Ustrcmp(mailargs[i], "file") == 0)? " (expanded)" : ""); + expand_level -= len; } } } @@ -2546,14 +2526,13 @@ const uschar *save_headers_charset = headers_charset; filter_cmd *commands = NULL; filter_cmd **lastcmdptr = &commands; -DEBUG(route) debug_printf("Filter: start of processing\n"); +DEBUG(route) debug_printf_indent("Filter: start of processing\n"); acl_level++; /* Initialize "not in an if command", set the global flag that is always TRUE while filtering, and zero the variables. */ expect_endif = 0; -output_indent = 0; f.filter_running = TRUE; for (i = 0; i < FILTER_VARIABLE_COUNT; i++) filter_n[i] = 0; @@ -2627,7 +2606,7 @@ f.filter_running = FALSE; headers_charset = save_headers_charset; acl_level--; -DEBUG(route) debug_printf("Filter: end of processing\n"); +DEBUG(route) debug_printf_indent("Filter: end of processing\n"); return yield; } commit a8c046b7000dd0654ac93571166f706d8a1df186 Author: Jeremy Harris Date: Wed Apr 15 09:42:48 2026 +0100 debug_store: fix bad-ptr on freezing messsage diff --git a/src/src/deliver.c b/src/src/deliver.c index d02bc0458..d6db7006d 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -9199,7 +9199,8 @@ while (a) void check_deliver_addrs_not_freed(void (*f)(const uschar*, const uschar*, void*), void * ctx) { -check_addr_list(US"(addr_defer)", addr_defer, f, ctx); +if (addr_defer != (address_item *)(+1)) + check_addr_list(US"(addr_defer)", addr_defer, f, ctx); check_addr_list(US"(addr_failed)", addr_failed, f, ctx); check_addr_list(US"(addr_fallback)", addr_fallback, f, ctx); check_addr_list(US"(addr_local)", addr_local, f, ctx); commit da96127de22cde0e60da77a92eb1859fa506b115 Author: Jeremy Harris Date: Sun Apr 12 13:23:27 2026 +0100 Docs: minor clarification diff --git a/src/src/receive.c b/src/src/receive.c index cca230de9..826273ea1 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -825,7 +825,7 @@ SMTP, in which case the CRs are optional, but... FUDGE: It seems that sites on the net send out messages with just LF terminators, despite the warnings in the RFCs, and other MTAs handle this. So -we make the CRs optional in all cases. +we make the CRs optional in all cases [no longer; see below]. July 2003: Bare CRs cause trouble. We now treat them as line terminators as well, so that there are no CRs in spooled messages. However, the message diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index b0ed04a89..1bdf47e17 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -5203,7 +5203,7 @@ while (done <= 0) case RCPT_CMD: HAD(SCH_RCPT); - /* We got really to many recipients. A check against configured + /* We got badly too many recipients. A check against configured limits is done later */ if (rcpt_count < 0 || rcpt_count >= INT_MAX/2) log_write_die(LOG_MAIN, "Too many recipients: %d", rcpt_count); commit ebc783075de6eb6d3cc6ffe57335a1ec936481f2 Author: Jeremy Harris Date: Sun Apr 19 11:34:48 2026 +0100 Debug: add channel "start" diff --git a/src/src/drtables.c b/src/src/drtables.c index 8ba2d62af..66b4e0a1d 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -304,7 +304,7 @@ misc_module_list = mi; if (mi->init) { - EARLY_DEBUG(any, "Module init: %q\n", mi->name); + EARLY_DEBUG(start, "Module init: %q\n", mi->name); expand_level++; if (!mi->init(mi)) EARLY_DEBUG(any, "module init call failed for %q\n", mi->name); @@ -312,7 +312,7 @@ if (mi->init) } if (mi->lib_vers_report) - DEBUG(any) debug_printf_indent("%Y", mi->lib_vers_report(NULL)); + DEBUG(start) debug_printf_indent("%Y", mi->lib_vers_report(NULL)); /* EARLY_DEBUG(any, "added %q\n", mi->name); */ } diff --git a/src/src/exim.c b/src/src/exim.c index b3e0c9afe..4bec03e13 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1268,7 +1268,8 @@ g = transport_show_supported(g); #ifdef WITH_CONTENT_SCAN g = malware_show_supported(g); #endif -show_string(is_stdout, g); g = NULL; +show_string(is_stdout, g); +gstring_reset(g); if (fixed_never_users[0] > 0) { @@ -1326,7 +1327,7 @@ DEBUG(any) Currently they are output in misc_mod_add() */ show_string(is_stdout, g); - g = NULL; + gstring_reset(g); for (auth_info * ai = auths_available; ai; ai = (auth_info *)ai->drinfo.next) if (ai->version_report) @@ -1349,7 +1350,7 @@ Currently they are output in misc_mod_add() */ } show_string(is_stdout, g); - g = NULL; + gstring_reset(g); /* Has to be before the lookups as the spf lookup calls into the spf module */ init_misc_mod_list(); @@ -1357,7 +1358,7 @@ Currently they are output in misc_mod_add() */ init_lookup_list(); tree_walk(lookups_tree, lookup_version_report_cb, &g); show_string(is_stdout, g); - g = NULL; + gstring_reset(g); #ifdef WHITELIST_D_MACROS g = string_fmt_append(g, "WHITELIST_D_MACROS: %q\n", WHITELIST_D_MACROS); @@ -1735,7 +1736,8 @@ for (macro_item * m = macros_user; m; m = m->next) if (m->command_line) if (!regex_match(regex_whitelisted_macro, m->replacement, len, NULL)) return FALSE; } -DEBUG(any) debug_printf("macros_trusted overridden to true by whitelisting\n"); +DEBUG(start) + debug_printf("macros_trusted overridden to true by whitelisting\n"); return TRUE; #endif } @@ -4044,7 +4046,7 @@ if (ANY_DEBUG) debug_printf("Exim version %s uid=%ld gid=%ld pid=" PID_T_FMT " %Y\n", version_string, (long int)real_uid, (long int)real_gid, getpid(), debug_selector_dump(NULL)); - if (!version_printed) + DEBUG(start) if (!version_printed) show_whats_supported(FALSE); } } @@ -4343,7 +4345,7 @@ if (checking && commandline_checks_require_admin && !f.admin_user) decode_bits(log_selector, log_selector_size, log_notall_names, log_selector_string, log_channels, log_chan_count, DCB_LOG); -DEBUG(any) +DEBUG(start) { debug_printf("configuration file is %s\n", config_main_filename); debug_printf("log selectors ="); @@ -4619,8 +4621,11 @@ if (bi_option) configuration file. We leave these prints here to ensure that syslog setup, logfile setup, and so on has already happened. */ -if (f.trusted_caller) DEBUG(any) debug_printf("trusted user\n"); -if (f.admin_user) DEBUG(any) debug_printf("admin user\n"); +DEBUG(any) + { + if (f.trusted_caller) debug_printf("trusted user\n"); + if (f.admin_user) debug_printf("admin user\n"); + } /* Only an admin user may start the daemon or force a queue run in the default configuration, but the queue run restriction can be relaxed. Only an admin @@ -4787,7 +4792,7 @@ if ( !unprivileged /* originally had root AND */ else { int rv; - DEBUG(any) debug_printf("dropping to exim gid; retaining priv uid\n"); + DEBUG(start) debug_printf("dropping to exim gid; retaining priv uid\n"); rv = setgid(exim_gid); /* Impact of failure is that some stuff might end up with an incorrect group. We track this for failures from root, since any attempt to change privilege diff --git a/src/src/globals.c b/src/src/globals.c index ae7798a3e..09e88f7aa 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -691,7 +691,8 @@ bit_table debug_channels[] = { DEBUG_CHAN(retry), DEBUG_CHAN(rewrite), DEBUG_CHAN(route), - DEBUG_CHAN(timestamp), /* 32 */ + DEBUG_CHAN(start), /* 32 */ + DEBUG_CHAN(timestamp), DEBUG_CHAN(tls), DEBUG_CHAN(transport), DEBUG_CHAN(uid), diff --git a/src/src/readconf.c b/src/src/readconf.c index ba4131d2b..ea47000d4 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -4607,7 +4607,7 @@ while(*next_section) int mid = last/2; int n = Ustrlen(next_section); - EARLY_DEBUG(any, "%s: %s\n", __FUNCTION__, next_section); + EARLY_DEBUG(start, "%s: %s\n", __FUNCTION__, next_section); expand_level++; if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, US"s"); commit 371e5210218746e876fd71c888fdb666c85ceb56 Author: Jeremy Harris Date: Sun Apr 19 15:14:14 2026 +0100 GnuTLS: fix hostname verify of server cert for empty Subject. Bug 3215 diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 5c840edc5..557a07dae 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2372,7 +2372,6 @@ gnutls_kx_algorithm_t kx; gnutls_mac_algorithm_t mac; gnutls_certificate_type_t ct; gnutls_x509_crt_t crt; -uschar * dn_buf; size_t sz; if (state->have_set_peerdn) @@ -2516,18 +2515,26 @@ exim_gnutls_peer_err(US"cert 0"); state->tlsp->peercert = state->peercert = crt; +state->peerdn = US""; sz = 0; -rc = gnutls_x509_crt_get_dn(crt, NULL, &sz); -if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER) +if (!(rc = gnutls_x509_crt_get_dn(crt, NULL, &sz))) + { DEBUG(tls) debug_printf_indent("TLS: zero-length DN\n"); } +else if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + { DEBUG(tls) debug_printf_indent("TLS: no DN\n"); } +else { - exim_gnutls_peer_err(US"getting size for cert DN failed"); - return FAIL; /* should not happen */ - } -dn_buf = store_get_perm(sz, GET_TAINTED); -rc = gnutls_x509_crt_get_dn(crt, CS dn_buf, &sz); -exim_gnutls_peer_err(US"failed to extract certificate DN [gnutls_x509_crt_get_dn(cert 0)]"); + uschar * dn_buf; + if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER) + { + exim_gnutls_peer_err(US"getting size for cert DN failed"); + return FAIL; /* should not happen */ + } + dn_buf = store_get_perm(sz, GET_TAINTED); + rc = gnutls_x509_crt_get_dn(crt, CS dn_buf, &sz); + exim_gnutls_peer_err(US"failed to extract certificate DN [gnutls_x509_crt_get_dn(cert 0)]"); -state->peerdn = dn_buf; + state->peerdn = dn_buf; + } return OK; #undef exim_gnutls_peer_err commit 628bbaca7672748d941a12e7cd5f0122a4e18c81 Author: Jeremy Harris Date: Tue Apr 28 14:47:32 2026 +0100 Support musl libc dn_expand oddity CVE-2026-40684 diff --git a/src/src/string.c b/src/src/string.c index 7220c41ac..15ff62f51 100644 --- a/src/src/string.c +++ b/src/src/string.c @@ -626,17 +626,17 @@ uschar * yield; uschar * ss = yield = store_get(Ustrlen(s) + 1, GET_TAINTED); /* always treat as tainted */ while (*s) - { if (*s != '\\') *ss++ = *s++; - else if (isdigit(s[1])) - { - *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0'; - s += 4; + else if (isdigit(*++s)) /* Apparently, musl libc dn_expand seen doing \DD */ + { /* and \D also. We can only hope not when a real digit follows. */ + uschar c = *s++ - '0'; + if (isdigit(*s)) c = c * 10 + *s++ - '0'; + if (isdigit(*s)) c = c * 10 + *s++ - '0'; + *ss++ = c; } else if (*++s) *ss++ = *s++; - } *ss = 0; return yield; commit 9fdc057e71b87c87a0d3d2288b2810a0efaaba57 Author: Bernard Quatermass Date: Mon Mar 23 16:43:51 2026 +0000 when dewrap, only skip \ if associated char CVE2026-40685 diff --git a/src/src/expand.c b/src/src/expand.c index 9dbc12ac8..f61766049 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -2408,7 +2408,7 @@ if (Uskip_whitespace(&p) == *wrap) wrap++; while (*p) { - if (*p == '\\') p++; + if (*p == '\\' && *(p+1)) p++; else if (!quotesmode && *p == wrap[-1]) depth++; else if (*p == *wrap) if (depth == 0) commit f2570bde16fb4d4a1242ff363a4c4eecf6372efc Author: Jeremy Harris Date: Mon Mar 23 15:10:28 2026 +0000 Expansions: harden for malformed UTF-8 CVE2026-40686 diff --git a/src/src/expand.c b/src/src/expand.c index f61766049..eb933ada1 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -931,7 +931,7 @@ static int utf8_table2[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01}; int a = utf8_table1[c & 0x3f]; /* Number of additional bytes */ \ int s = 6*a; \ c = (c & utf8_table2[a]) << s; \ - while (a-- > 0) \ + while (a-- > 0 && *ptr) \ { \ s -= 6; \ c |= (*ptr++ & 0x3f) << s; \ commit 68b963b9f75ca27b38e1c0f8c87037990199f505 Author: Jeremy Harris Date: Tue Mar 10 21:29:52 2026 +0000 SPA authenticator: harden buffer usage CVE-2026-40687 diff --git a/src/src/auths/auth-spa.c b/src/src/auths/auth-spa.c index db62c6859..70c20ee3d 100644 --- a/src/src/auths/auth-spa.c +++ b/src/src/auths/auth-spa.c @@ -161,7 +161,6 @@ extern int DEBUGLEVEL; #include "../exim.h" #include "auth-spa.h" -#include #ifndef _BYTEORDER_H @@ -409,6 +408,8 @@ spa_base64_to_bits(char *out, int outlength, const char *in) int len = 0; uschar digit1, digit2, digit3, digit4; +memset(out, 0, outlength); + if (in[0] == '+' && in[1] == ' ') in += 2; if (*in == '\r') @@ -1233,14 +1234,10 @@ spa_bytes_add(buffer, off, header, string, len); } static uschar * -strToUnicode(const uschar * p) +strToUnicode(const uschar * p, int len) { -static uschar buf[1024]; -size_t l = Ustrlen(p); - -assert(l * 2 < sizeof buf); - -for (int i = 0; l--; ) { buf[i++] = *p++; buf[i++] = 0; } +uschar * buf = store_get(len * 2, p); +for (int i = 0; len--; ) { buf[i++] = *p++; buf[i++] = 0; } return buf; } @@ -1253,38 +1250,18 @@ int len = 0; if (p) { len = Ustrlen(p); - b = US strToUnicode(p); + b = strToUnicode(p, len); } spa_bytes_add(buffer, off, header, b, len*2); } -#ifdef notdef - -#define DumpBuffer(fp, structPtr, header) \ - dumpRaw(fp,(US structPtr)+IVAL(&structPtr->header.offset,0),SVAL(&structPtr->header.len,0)) - - -static void -dumpRaw(FILE * fp, uschar *buf, size_t len) -{ -int i; - -for (i = 0; i < len; ++i) - fprintf(fp, "%02x ", buf[i]); - -fprintf(fp, "\n"); -} -#endif - -char * -unicodeToString(char *p, size_t len) +uschar * +unicodeToString(char * p, size_t len) { int i; -static char buf[1024]; - -assert(len + 1 < sizeof buf); +uschar * buf = store_get((int)len + 1, p); for (i = 0; i < len; ++i) { @@ -1299,83 +1276,31 @@ return buf; static uschar * toString(const char * p, size_t len) { -static uschar buf[1024]; - -assert(len + 1 < sizeof buf); +uschar * buf = store_get((int)len + 1, p); memcpy(buf, p, len); -buf[len] = 0; +buf[len] = '\0'; return buf; } static inline uschar * get_challenge_unistr(SPAAuthChallenge * challenge, SPAStrHeader * hdr) { -int offset= IVAL(&hdr->offset, 0); -int len = SVAL(&hdr->len, 0); -return offset+ len < sizeof(SPAAuthChallenge) - ? US unicodeToString(CS challenge + offset, len/2) : US""; -} +int offset = IVAL(&hdr->offset, 0), len = SVAL(&hdr->len, 0); -static inline uschar * -get_challenge_str(SPAAuthChallenge * challenge, SPAStrHeader * hdr) -{ -int offset= IVAL(&hdr->offset, 0); -int len = SVAL(&hdr->len, 0); -return offset+ len < sizeof(SPAAuthChallenge) - ? US toString(CS challenge + offset, len) : US""; +return offset + len < sizeof(SPAAuthChallenge) + ? unicodeToString(CS challenge + offset, len/2) : US""; } -#ifdef notdef - -#define GetUnicodeString(structPtr, header) \ - unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2) - -#define GetString(structPtr, header) \ - toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0)) - - -void -dumpSmbNtlmAuthRequest(FILE * fp, SPAAuthRequest * request) +static uschar * +get_challenge_str(SPAAuthChallenge * challenge, SPAStrHeader * hdr) { -fprintf(fp, "NTLM Request:\n"); -fprintf(fp, " Ident = %s\n", request->ident); -fprintf(fp, " mType = %d\n", IVAL(&request->msgType, 0)); -fprintf(fp, " Flags = %08x\n", IVAL(&request->flags, 0)); -fprintf(fp, " User = %s\n", GetString(request, user)); -fprintf(fp, " Domain = %s\n", GetString(request, domain)); -} +int offset = IVAL(&hdr->offset, 0), len = SVAL(&hdr->len, 0); -void -dumpSmbNtlmAuthChallenge(FILE * fp, SPAAuthChallenge * challenge) -{ -fprintf(fp, "NTLM Challenge:\n"); -fprintf(fp, " Ident = %s\n", challenge->ident); -fprintf(fp, " mType = %d\n", IVAL(&challenge->msgType, 0)); -fprintf(fp, " Domain = %s\n", GetUnicodeString(challenge, uDomain)); -fprintf(fp, " Flags = %08x\n", IVAL(&challenge->flags, 0)); -fprintf(fp, " Challenge = "); -dumpRaw(fp, challenge->challengeData, 8); +return offset + len < sizeof(SPAAuthChallenge) + ? toString(CS challenge + offset, len) : US""; } -void -dumpSmbNtlmAuthResponse(FILE * fp, SPAAuthResponse * response) -{ -fprintf(fp, "NTLM Response:\n"); -fprintf(fp, " Ident = %s\n", response->ident); -fprintf(fp, " mType = %d\n", IVAL(&response->msgType, 0)); -fprintf(fp, " LmResp = "); -DumpBuffer(fp, response, lmResponse); -fprintf(fp, " NTResp = "); -DumpBuffer(fp, response, ntResponse); -fprintf(fp, " Domain = %s\n", GetUnicodeString(response, uDomain)); -fprintf(fp, " User = %s\n", GetUnicodeString(response, uUser)); -fprintf(fp, " Wks = %s\n", GetUnicodeString(response, uWks)); -fprintf(fp, " sKey = "); -DumpBuffer(fp, response, sessionKey); -fprintf(fp, " Flags = %08x\n", IVAL(&response->flags, 0)); -} -#endif void spa_build_auth_request(SPAAuthRequest * request, diff --git a/src/src/auths/auth-spa.h b/src/src/auths/auth-spa.h index 19882d6aa..081e938ee 100644 --- a/src/src/auths/auth-spa.h +++ b/src/src/auths/auth-spa.h @@ -92,6 +92,5 @@ extern void spa_smb_encrypt (unsigned char * passwd, unsigned char * c8, unsigned char * p24); extern void spa_smb_nt_encrypt (unsigned char * passwd, unsigned char * c8, unsigned char * p24); -extern char *unicodeToString(char *p, size_t len); extern void spa_build_auth_challenge(SPAAuthRequest *, SPAAuthChallenge *);