From 74e0617f5ad5aa05f6e19f7b7cf6ecfe039749f6 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 09:49:49 +0000 Subject: [PATCH 01/16] Add examples of virus and spam scanning to the default configuration. --- doc/doc-txt/ChangeLog | 7 ++++- src/src/configure.default | 60 +++++++++++++++++++++++++++++++++++---- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index a732ae6ef..ed449756f 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.99 2005/03/22 16:52:06 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.100 2005/03/29 09:49:49 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -77,6 +77,11 @@ PH/13 If "headers_add" in a transport didn't end in a newline, Exim printed TF/01 Added $received_time. +PH/14 Modified the default configuration to add an acl_smtp_data ACL, with + commented out examples of how to interface to a virus scanner and to + SpamAssassin. Also added commented examples of av_scanner and + spamd_address settings. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/configure.default b/src/src/configure.default index 6a29ec50d..5671746d6 100644 --- a/src/src/configure.default +++ b/src/src/configure.default @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/configure.default,v 1.1 2004/10/07 10:39:01 ph10 Exp $ +# $Cambridge: exim/src/src/configure.default,v 1.2 2005/03/29 09:49:49 ph10 Exp $ ###################################################################### # Runtime configuration file for Exim # @@ -100,15 +100,34 @@ hostlist relay_from_hosts = 127.0.0.1 # SMTP mail by using the loopback address. A number of MUAs use this method of # sending mail. - # All three of these lists may contain many different kinds of item, including # wildcarded names, regular expressions, and file lookups. See the reference -# manual for details. The lists above are used in the access control list for -# incoming messages. The name of this ACL is defined here: +# manual for details. The lists above are used in the access control lists for +# checking incoming messages. The names of these ACLs are defined here: acl_smtp_rcpt = acl_check_rcpt +acl_smtp_data = acl_check_data + +# You should not change those settings until you understand how ACLs work. + + +# If you are running a version of Exim that was compiled with the content- +# scanning extension, you can cause incoming messages to be automatically +# scanned for viruses. You have to modify the configuration in two places to +# set this up. The first of them is here, where you define the interface to +# your scanner. This example is typical for ClamAV; see the manual for details +# of what to set for other virus scanners. The second modification is in the +# acl_check_data access control list (see below). -# You should not change that setting until you understand how ACLs work. +# av_scanner = clamd:/tmp/clamd + + +# For spam scanning, there is a similar option that defines the interface to +# SpamAssassin. You do not need to set this if you are using the default, which +# is shown in this commented example. As for virus scanning, you must also +# modify the acl_check_data access control list to enable spam scanning. + +# spamd_address = 127.0.0.1 783 # Specify the domain you want to be added to all unqualified addresses @@ -344,6 +363,37 @@ acl_check_rcpt: deny message = relay not permitted +# This ACL is used after the contents of a message have been received. This +# is the ACL in which you can test a message's headers or body, and in +# particular, this is where you can invoke external virus or spam scanners. +# Some suggested ways of configuring these tests are shown below, commented +# out. Without any tests, this ACL accepts all messages. If you want to use +# such tests, you must ensure that Exim is compiled with the content-scanning +# extension (WITH_CONTENT_SCAN=yes in Local/Makefile). + +acl_check_data: + + # Deny if the message contains a virus. Before enabling this check, you + # must install a virus scanner and set the av_scanner option above. + # + # deny malware = * + # message = This message contains a virus ($malware_name). + + # Add headers to a message if it is judged to be spam. Before enabling this, + # you must install SpamAssassin. You may also need to set the spamd_address + # option above. + # + # warn spam = nobody + # message = X-Spam_score: $spam_score\n\ + # X-Spam_score_int: $spam_score_int\n\ + # X-Spam_bar: $spam_bar\n\ + # X-Spam_report: $spam_report + + # Accept the message. + + accept + + ###################################################################### # ROUTERS CONFIGURATION # -- 2.30.2 From 2f079f46bc72c815552f0572500d151a19fd27da Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 10:56:48 +0000 Subject: [PATCH 02/16] Further tidies and minor fixes to the tables that control which ACL condition is allowed when. --- doc/doc-txt/ChangeLog | 10 ++++- src/src/acl.c | 101 ++++++++++++------------------------------ 2 files changed, 37 insertions(+), 74 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index ed449756f..4a1d45045 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.100 2005/03/29 09:49:49 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.101 2005/03/29 10:56:48 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -10,7 +10,7 @@ Exim version 4.51 TK/01 Added Yahoo DomainKeys support via libdomainkeys. See doc/experimental-spec.txt for details. (http://domainkeys.sf.net) -TK/02 Fix ACL "control" statment not being available in MIME ACL. +TK/02 Fix ACL "control" statement not being available in MIME ACL. TK/03 Fix ACL "regex" condition not being available in MIME ACL. @@ -82,6 +82,12 @@ PH/14 Modified the default configuration to add an acl_smtp_data ACL, with SpamAssassin. Also added commented examples of av_scanner and spamd_address settings. +PH/15 Further to TK/02 and TK/03 above, tidied up the tables of what conditions + and controls are allowed in which ACLs. There were a couple of minor + errors. Some of the entries in the conditions table (which is a table of + where they are NOT allowed) were getting very unwieldy; rewrote them as a + negation of where the condition IS allowed. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/acl.c b/src/src/acl.c index 8fb6a7eef..704e9cb5e 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/acl.c,v 1.25 2005/03/15 15:36:41 ph10 Exp $ */ +/* $Cambridge: exim/src/src/acl.c,v 1.26 2005/03/29 10:56:48 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -244,7 +244,8 @@ static uschar cond_modifiers[] = { }; /* Bit map vector of which conditions are not allowed at certain times. For -each condition, there's a bitmap of dis-allowed times. */ +each condition, there's a bitmap of dis-allowed times. For some, it is easier +to specify the negation of a small number of allowed times. */ static unsigned int cond_forbids[] = { 0, /* acl */ @@ -265,34 +266,24 @@ static unsigned int cond_forbids[] = { 0, /* condition */ /* Certain types of control are always allowed, so we let it through - always and check in the control processing itself */ + always and check in the control processing itself. */ 0, /* control */ #ifdef WITH_CONTENT_SCAN - (1< Date: Tue, 29 Mar 2005 11:01:32 +0000 Subject: [PATCH 03/16] New OS/os.c-cygwin from the maintainer. --- doc/doc-txt/ChangeLog | 4 +- src/OS/os.c-cygwin | 505 +++++++++++++++++++++++++++++------------- 2 files changed, 360 insertions(+), 149 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 4a1d45045..496ba5943 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.101 2005/03/29 10:56:48 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.102 2005/03/29 11:01:32 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -88,6 +88,8 @@ PH/15 Further to TK/02 and TK/03 above, tidied up the tables of what conditions where they are NOT allowed) were getting very unwieldy; rewrote them as a negation of where the condition IS allowed. +PH/16 Installed updated OS/os.c-cygwin from the Cygwin maintainer. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/OS/os.c-cygwin b/src/OS/os.c-cygwin index 739605590..5459044e5 100644 --- a/src/OS/os.c-cygwin +++ b/src/OS/os.c-cygwin @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/OS/os.c-cygwin,v 1.1 2004/10/06 15:07:39 ph10 Exp $ */ +/* $Cambridge: exim/src/OS/os.c-cygwin,v 1.2 2005/03/29 11:01:32 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -78,7 +78,7 @@ int cygwin_setgid(gid_t gid ) res = setgid(gid); if (cygwin_debug) fprintf(stderr, "setgid %lu %lu %d pid: %d\n", - gid, getgid(), res, getpid()); + gid, getgid(), res, getpid()); } return res; } @@ -124,19 +124,19 @@ static DWORD get_privileges () && LookupPrivilegeValue (NULL, SE_CREATE_TOKEN_NAME, &cluid) && LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &rluid) && (GetTokenInformation( hToken, TokenPrivileges, - privs, sizeof (buffer), &length) - || (GetLastError () == ERROR_INSUFFICIENT_BUFFER - && (privs = (PTOKEN_PRIVILEGES) alloca (length)) - && GetTokenInformation(hToken, TokenPrivileges, - privs, length, &length)))) { + privs, sizeof (buffer), &length) + || (GetLastError () == ERROR_INSUFFICIENT_BUFFER + && (privs = (PTOKEN_PRIVILEGES) alloca (length)) + && GetTokenInformation(hToken, TokenPrivileges, + privs, length, &length)))) { for (i = 0; i < privs->PrivilegeCount; i++) { if (privs->Privileges[i].Luid.QuadPart == cluid.QuadPart) - ret |= CREATE_BIT; + ret |= CREATE_BIT; else if (privs->Privileges[i].Luid.QuadPart == rluid.QuadPart) - ret |= RESTORE_BIT; + ret |= RESTORE_BIT; else continue; if (ret == (CREATE_BIT | RESTORE_BIT)) - break; + break; } } else @@ -227,7 +227,7 @@ void cygwin_init(int argc, char ** argv, void * rup, if (privileged) { /* Can setuid */ if (cygwin_setgid(* (gid_t *) egp) /* Setuid to exim */ || cygwin_setuid(* (uid_t *) eup)) - privileged = -1; /* Problem... Perhaps not in 544 */ + privileged = -1; /* Problem... Perhaps not in 544 */ } /* Pretend we are root to avoid useless execs. @@ -241,31 +241,74 @@ void cygwin_init(int argc, char ** argv, void * rup, if (cygwin_debug) { fprintf(stderr, "Starting uid %ld, gid %ld, ntsec %lu, privileged %d.\n", - myuid, mygid, cygwin_internal(CW_CHECK_NTSEC, NULL), privileged); + myuid, mygid, cygwin_internal(CW_CHECK_NTSEC, NULL), privileged); fprintf(stderr, "root_uid %ld, exim_uid %ld, exim_gid %ld, config_uid %ld.\n", - * (uid_t *) rup, * (uid_t *) eup, * (gid_t *) egp, * (uid_t *) cup); + * (uid_t *) rup, * (uid_t *) eup, * (gid_t *) egp, * (uid_t *) cup); } return; } +#ifndef OS_LOAD_AVERAGE /* Can be set on command line */ +#define OS_LOAD_AVERAGE /* src/os.c need not provide it */ + /***************************************************************** * Functions for average load measurements + There are two methods, which work only on NT. + + The first one uses the HKEY_PERFORMANCE_DATA registry to + get performance data. It is complex but well documented + and works on all NT versions. + + The second one uses NtQuerySystemInformation. + Its use is discouraged starting with WinXP. + + Until 4.43, the Cygwin port of exim was using the first + method. + +*****************************************************************/ +#define PERF_METHOD2 + +/* Structure to compute the load average efficiently */ +typedef struct { + DWORD Lock; + unsigned long long Time100ns; /* Last measurement time */ + unsigned long long IdleCount; /* Latest cumulative idle time */ + unsigned long long LastCounter; /* Last measurement counter */ + unsigned long long PerfFreq; /* Perf counter frequency */ + int LastLoad; /* Last reported load, or -1 */ +#ifdef PERF_METHOD1 + PPERF_DATA_BLOCK PerfData; /* Pointer to a buffer to get the data */ + DWORD BufferSize; /* Size of PerfData */ + LPSTR * NamesArray; /* Temporary (malloc) buffer for index */ +#endif +} cygwin_perf_t; + +static struct { + HANDLE handle; + pid_t pid; + cygwin_perf_t *perf; +} cygwin_load = {NULL, 0, NULL}; + +#ifdef PERF_METHOD1 +/************************************************************* + METHOD 1 + Obtaining statistics in Windows is done at a low level by calling registry functions, in particular the key HKEY_PERFORMANCE_DATA on NT and successors. Something equivalent exists on Win95, see Microsoft article - HOWTO: Access the Performance Registry Under Windows 95 (Q174631) + HOWTO: Access the Performance Registry Under Windows 95 (KB 174631) but it is not implemented here. The list of objects to be polled is specified in the string passed to RegQueryValueEx in ReadStat() below. On NT, all objects are polled even if info about only one is required. This is fixed in Windows 2000. See articles - INFO: Perflib Calling Close Procedure in Windows 2000 (Q270127) + INFO: Perflib Calling Close Procedure in Windows 2000 (KB 270127) INFO: Performance Data Changes Between Windows NT 4.0 and Windows - 2000 (Q296523) + 2000 (KB 296523) It is unclear to me how the counters are primarily identified. Whether it's by name strings or by the offset of their strings @@ -280,8 +323,6 @@ void cygwin_init(int argc, char ** argv, void * rup, as expected. *****************************************************************/ -#ifndef OS_LOAD_AVERAGE /* Can be set on command line */ -#define OS_LOAD_AVERAGE /* src/os.c need not provide it */ /* Object and counter indices and names */ #define PROCESSOR_OBJECT_INDEX 238 @@ -290,19 +331,6 @@ void cygwin_init(int argc, char ** argv, void * rup, #define PROCESSOR_TIME_COUNTER 6 #define PROCESSOR_TIME_NAME "% Processor Time" -/* Structure to compute the load average efficiently */ -static struct { - long long Time100ns; /* Last measurement time */ - long long IdleCount; /* Latest cumulative idle time */ - long long LastCounter; /* Last measurement counter */ - long long PerfFreq; /* Perf counter frequency */ - PPERF_DATA_BLOCK PerfData; /* Pointer to a buffer to get the data */ - DWORD BufferSize; /* Size of PerfData */ - int LastLoad; /* Last reported load, or -1 */ - LPSTR * NamesArray; /* Temporary (malloc) buffer for index */ - BOOL Init; /* True if initialized */ -} cygwin_load = { 0, 0, 0, 0, NULL, 0, 0, NULL, FALSE}; - #define BYTEINCREMENT 800 /* Block to add to PerfData */ /***************************************************************** @@ -331,8 +359,8 @@ static struct { /***************************************************************** * Load the counter and object names from the registry - to cygwin_load.NameStrings - and index them in cygwin_load.NamesArray + to cygwin_load.perf->NameStrings + and index them in cygwin_load.perf->NamesArray NameStrings seems to be taken from the file X:\Winnt\system32\perfc009.dat @@ -352,21 +380,21 @@ static BOOL GetNameStrings( ) /* Get the number of Counter items into dwArraySize. */ if ((res = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", - 0, - KEY_QUERY_VALUE, /* KEY_READ, */ - &hKeyPerflib)) + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib", + 0, + KEY_QUERY_VALUE, /* KEY_READ, */ + &hKeyPerflib)) != ERROR_SUCCESS) { DEBUG(D_load) debug_printf("RegOpenKeyEx (1): error %ld (Windows)\n", res); return FALSE; } dwNamesSize = sizeof(dwArraySize); /* Temporary reuse */ if ((res = RegQueryValueEx( hKeyPerflib, - "Last Counter", - NULL, - NULL, - (LPBYTE) &dwArraySize, - &dwNamesSize )) + "Last Counter", + NULL, + NULL, + (LPBYTE) &dwArraySize, + &dwNamesSize )) != ERROR_SUCCESS) { DEBUG(D_load) debug_printf("RegQueryValueEx (1): error %ld (Windows)\n", res); return FALSE; @@ -374,10 +402,10 @@ static BOOL GetNameStrings( ) RegCloseKey( hKeyPerflib ); /* Open the key containing the counter and object names. */ if ((res = RegOpenKeyEx( HKEY_LOCAL_MACHINE, - "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009", - 0, - KEY_READ, - &hKeyPerflib)) + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009", + 0, + KEY_READ, + &hKeyPerflib)) != ERROR_SUCCESS) { DEBUG(D_load) debug_printf("RegOpenKeyEx (2): error %ld (Windows)\n", res); return FALSE; @@ -388,21 +416,21 @@ static BOOL GetNameStrings( ) lpCurrentString = NULL; while (1) { res = RegQueryValueEx( hKeyPerflib, - "Counter", - NULL, - NULL, - (unsigned char *) lpCurrentString, - &dwNamesSize); + "Counter", + NULL, + NULL, + (unsigned char *) lpCurrentString, + &dwNamesSize); if ((res == ERROR_SUCCESS) && /* Bug (NT 4.0): SUCCESS was returned on first call */ - (cygwin_load.NamesArray != NULL)) break; - if ((res == ERROR_SUCCESS) || /* but cygwin_load.NamesArrays == NULL */ + (cygwin_load.perf->NamesArray != NULL)) break; + if ((res == ERROR_SUCCESS) || /* but cygwin_load.perf->NamesArrays == NULL */ (res == ERROR_MORE_DATA)) { /* Allocate memory BOTH for the names array and for the counter and object names */ - if ((cygwin_load.NamesArray = - (LPSTR *) malloc( (dwArraySize + 1) * sizeof(LPSTR) + dwNamesSize * sizeof(CHAR))) - != NULL) { + if ((cygwin_load.perf->NamesArray = + (LPSTR *) malloc( (dwArraySize + 1) * sizeof(LPSTR) + dwNamesSize * sizeof(CHAR))) + != NULL) { /* Point to area for the counter and object names */ - lpCurrentString = (LPSTR) & cygwin_load.NamesArray[dwArraySize + 1]; + lpCurrentString = (LPSTR) & cygwin_load.perf->NamesArray[dwArraySize + 1]; continue; } DEBUG(D_load) debug_printf("Malloc: errno %d (%s)\n", errno, strerror(errno)); @@ -417,7 +445,7 @@ static BOOL GetNameStrings( ) while (*lpCurrentString) { dwCounter = atol( lpCurrentString ); lpCurrentString += (lstrlen(lpCurrentString)+1); - cygwin_load.NamesArray[dwCounter] = lpCurrentString; + cygwin_load.perf->NamesArray[dwCounter] = lpCurrentString; lpCurrentString += (strlen(lpCurrentString)+1); } return TRUE; @@ -429,23 +457,23 @@ static BOOL GetNameStrings( ) *****************************************************************/ static BOOL ReadTimeCtr(PPERF_OBJECT_TYPE PerfObj, - PPERF_COUNTER_DEFINITION CurCntr, - PPERF_COUNTER_BLOCK PtrToCntr, - unsigned long long * TimePtr){ + PPERF_COUNTER_DEFINITION CurCntr, + PPERF_COUNTER_BLOCK PtrToCntr, + unsigned long long * TimePtr){ int j; /* Scan all counters. */ for( j = 0; j < PerfObj->NumCounters; j++ ) { if (CurCntr->CounterNameTitleIndex == PROCESSOR_TIME_COUNTER) { /* Verify it is really the proc time counter */ if ((CurCntr->CounterType != PERF_100NSEC_TIMER_INV) || /* Wrong type */ - ((cygwin_load.NamesArray != NULL) && /* Verify name */ - (strcmp(cygwin_load.NamesArray[CurCntr->CounterNameTitleIndex], - PROCESSOR_TIME_NAME)))) { - log_write(0, LOG_MAIN|LOG_PANIC, + ((cygwin_load.perf->NamesArray != NULL) && /* Verify name */ + (strcmp(cygwin_load.perf->NamesArray[CurCntr->CounterNameTitleIndex], + PROCESSOR_TIME_NAME)))) { + log_write(0, LOG_MAIN|LOG_PANIC, "Incorrect Perf counter type or name %x %s", - (unsigned) CurCntr->CounterType, - cygwin_load.NamesArray[CurCntr->CounterNameTitleIndex]); - return FALSE; + (unsigned) CurCntr->CounterType, + cygwin_load.perf->NamesArray[CurCntr->CounterNameTitleIndex]); + return FALSE; } *TimePtr += *(unsigned long long int *) ((PBYTE) PtrToCntr + CurCntr->CounterOffset); return TRUE; /* return TRUE as soon as we found the counter */ @@ -455,6 +483,7 @@ static BOOL ReadTimeCtr(PPERF_OBJECT_TYPE PerfObj, } return FALSE; } + /***************************************************************** * ReadStat() @@ -462,8 +491,8 @@ static BOOL ReadTimeCtr(PPERF_OBJECT_TYPE PerfObj, Return TRUE if success. *****************************************************************/ -static BOOL ReadStat(long long int *Time100nsPtr, - long long int * IdleCountPtr) +static BOOL ReadStat(unsigned long long int *Time100nsPtr, + unsigned long long int * IdleCountPtr) { PPERF_OBJECT_TYPE PerfObj; PPERF_INSTANCE_DEFINITION PerfInst; @@ -476,20 +505,20 @@ static BOOL ReadStat(long long int *Time100nsPtr, We may need to blindly increase the buffer size. BufferSize does not return info but may be changed */ while (1) { - DWORD BufferSize = cygwin_load.BufferSize; + DWORD BufferSize = cygwin_load.perf->BufferSize; res = RegQueryValueEx( HKEY_PERFORMANCE_DATA, - PROCESSOR_OBJECT_STRING, - NULL, - NULL, - (LPBYTE) cygwin_load.PerfData, - &BufferSize ); + PROCESSOR_OBJECT_STRING, + NULL, + NULL, + (LPBYTE) cygwin_load.perf->PerfData, + &BufferSize ); if (res == ERROR_SUCCESS) break; if (res == ERROR_MORE_DATA ) { /* Increment if necessary to get a buffer that is big enough. */ - cygwin_load.BufferSize += BYTEINCREMENT; - if ((cygwin_load.PerfData = - (PPERF_DATA_BLOCK) realloc( cygwin_load.PerfData, cygwin_load.BufferSize )) - != NULL) continue; + cygwin_load.perf->BufferSize += BYTEINCREMENT; + if ((cygwin_load.perf->PerfData = + (PPERF_DATA_BLOCK) realloc( cygwin_load.perf->PerfData, cygwin_load.perf->BufferSize )) + != NULL) continue; DEBUG(D_load) debug_printf("Malloc: errno %d (%s)\n", errno, strerror(errno)); } else { /* Serious error */ @@ -501,62 +530,62 @@ static BOOL ReadStat(long long int *Time100nsPtr, *Time100nsPtr = 0; *IdleCountPtr = 0; /* We should only have one object, but write general code just in case. */ - PerfObj = FirstObject( cygwin_load.PerfData ); - for( i = 0; i < cygwin_load.PerfData->NumObjectTypes; i++ ) { + PerfObj = FirstObject( cygwin_load.perf->PerfData ); + for( i = 0; i < cygwin_load.perf->PerfData->NumObjectTypes; i++ ) { /* We are only interested in the processor object */ if ( PerfObj->ObjectNameTitleIndex == PROCESSOR_OBJECT_INDEX) { /* Possibly verify it is really the Processor object. */ - if ((cygwin_load.NamesArray != NULL) && - (strcmp(cygwin_load.NamesArray[PerfObj->ObjectNameTitleIndex], - PROCESSOR_OBJECT_NAME))) { - log_write(0, LOG_MAIN|LOG_PANIC, - "Incorrect Perf object name %s", - cygwin_load.NamesArray[PerfObj->ObjectNameTitleIndex]); - return FALSE; + if ((cygwin_load.perf->NamesArray != NULL) && + (strcmp(cygwin_load.perf->NamesArray[PerfObj->ObjectNameTitleIndex], + PROCESSOR_OBJECT_NAME))) { + log_write(0, LOG_MAIN|LOG_PANIC, + "Incorrect Perf object name %s", + cygwin_load.perf->NamesArray[PerfObj->ObjectNameTitleIndex]); + return FALSE; } /* Get the first counter */ PerfCntr = FirstCounter( PerfObj ); /* See if the object has instances. - It should, but write general code. */ + It should, but write general code. */ if( PerfObj->NumInstances != PERF_NO_INSTANCES ) { - PerfInst = FirstInstance( PerfObj ); - for( k = 0; k < PerfObj->NumInstances; k++ ) { - /* There can be several processors. + PerfInst = FirstInstance( PerfObj ); + for( k = 0; k < PerfObj->NumInstances; k++ ) { + /* There can be several processors. Accumulate both the Time100ns and the idle counter. - On Win 2000 I have seen an instance named "_Total". - Do not use it. We only use instances with a single + Starting with Win2000 there is an instance named "_Total". + Do not use it. We only use instances with a single character in the name. If we examine the object names, we also look at the instance names and their lengths and issue reports */ - if ( cygwin_load.NamesArray != NULL) { + if ( cygwin_load.perf->NamesArray != NULL) { CHAR ascii[30]; /* The name is in unicode */ - wsprintf(ascii,"%.29lS", - (char *)((PBYTE)PerfInst + PerfInst->NameOffset)); - log_write(0, LOG_MAIN, + wsprintf(ascii,"%.29lS", + (char *)((PBYTE)PerfInst + PerfInst->NameOffset)); + log_write(0, LOG_MAIN, "Perf: Found processor instance \"%s\", length %d", ascii, PerfInst->NameLength); - if ((PerfInst->NameLength != 4) && + if ((PerfInst->NameLength != 4) && (strcmp(ascii, "_Total") != 0)) { - log_write(0, LOG_MAIN|LOG_PANIC, + log_write(0, LOG_MAIN|LOG_PANIC, "Perf: WARNING: Unexpected processor instance name"); - return FALSE; + return FALSE; } } - if (PerfInst->NameLength == 4) { - *Time100nsPtr += cygwin_load.PerfData->PerfTime100nSec.QuadPart; - PtrToCntr = InstanceCounterBlock(PerfInst); - if (! ReadTimeCtr(PerfObj, PerfCntr, PtrToCntr, IdleCountPtr)) { - return FALSE; - } + if (PerfInst->NameLength == 4) { + *Time100nsPtr += cygwin_load.perf->PerfData->PerfTime100nSec.QuadPart; + PtrToCntr = InstanceCounterBlock(PerfInst); + if (! ReadTimeCtr(PerfObj, PerfCntr, PtrToCntr, IdleCountPtr)) { + return FALSE; + } } - PerfInst = NextInstance( PerfInst ); - } + PerfInst = NextInstance( PerfInst ); + } return (*Time100nsPtr != 0); /* Something was read */ } else { /* No instance, just the counter data */ - *Time100nsPtr = cygwin_load.PerfData->PerfTime100nSec.QuadPart; - PtrToCntr = ObjectCounterBlock(PerfObj); - return ReadTimeCtr(PerfObj, PerfCntr, PtrToCntr, IdleCountPtr); + *Time100nsPtr = cygwin_load.perf->PerfData->PerfTime100nSec.QuadPart; + PtrToCntr = ObjectCounterBlock(PerfObj); + return ReadTimeCtr(PerfObj, PerfCntr, PtrToCntr, IdleCountPtr); } } PerfObj = NextObject( PerfObj ); @@ -564,43 +593,176 @@ static BOOL ReadStat(long long int *Time100nsPtr, return FALSE; /* Did not find the Processor object */ } +#elif defined(PERF_METHOD2) + +/************************************************************* + METHOD 2 + + Uses NtQuerySystemInformation. + This requires definitions that are not part of + standard include files. +*************************************************************/ +#include + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation = 0, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, + SystemProcessesAndThreadsInformation = 5, + SystemProcessorTimes = 8, + SystemPagefileInformation = 18, + /* There are a lot more of these... */ +} SYSTEM_INFORMATION_CLASS; + +typedef struct _SYSTEM_BASIC_INFORMATION +{ + ULONG Unknown; + ULONG MaximumIncrement; + ULONG PhysicalPageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPage; + ULONG HighestPhysicalPage; + ULONG AllocationGranularity; + ULONG LowestUserAddress; + ULONG HighestUserAddress; + ULONG ActiveProcessors; + UCHAR NumberProcessors; +} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + +typedef struct __attribute__ ((aligned (8))) _SYSTEM_PROCESSOR_TIMES +{ + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_TIMES, *PSYSTEM_PROCESSOR_TIMES; + +typedef NTSTATUS NTAPI (*NtQuerySystemInformation_t) (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); +typedef ULONG NTAPI (*RtlNtStatusToDosError_t) (NTSTATUS); + +static NtQuerySystemInformation_t NtQuerySystemInformation; +static RtlNtStatusToDosError_t RtlNtStatusToDosError; + +/***************************************************************** + * + LoadNtdll() + Load special functions from the NTDLL + Return TRUE if success. + + *****************************************************************/ + +static BOOL LoadNtdll() +{ + HINSTANCE hinstLib; + + if ((hinstLib = LoadLibrary("NTDLL.DLL")) + && (NtQuerySystemInformation = + (NtQuerySystemInformation_t) GetProcAddress(hinstLib, + "NtQuerySystemInformation")) + && (RtlNtStatusToDosError = + (RtlNtStatusToDosError_t) GetProcAddress(hinstLib, + "RtlNtStatusToDosError"))) + return TRUE; + + DEBUG(D_load) + debug_printf("perf: load: %ld (Windows)\n", GetLastError()); + return FALSE; +} + +/***************************************************************** + * + ReadStat() + Measures current Time100ns and IdleCount + Return TRUE if success. + + *****************************************************************/ + +static BOOL ReadStat(unsigned long long int *Time100nsPtr, + unsigned long long int *IdleCountPtr) +{ + NTSTATUS ret; + SYSTEM_BASIC_INFORMATION sbi; + PSYSTEM_PROCESSOR_TIMES spt; + + *Time100nsPtr = *IdleCountPtr = 0; + + if ((ret = NtQuerySystemInformation(SystemBasicInformation, + (PVOID) &sbi, sizeof sbi, NULL)) + != STATUS_SUCCESS) { + DEBUG(D_load) + debug_printf("Perf: NtQuerySystemInformation: %lu (Windows)\n", + RtlNtStatusToDosError(ret)); + } + else if (!(spt = (PSYSTEM_PROCESSOR_TIMES) alloca(sizeof(spt[0]) * sbi.NumberProcessors))) { + DEBUG(D_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_printf("Perf: NtQuerySystemInformation: %lu (Windows)\n", + RtlNtStatusToDosError(ret)); + } + else { + int i; + for (i = 0; i < sbi.NumberProcessors; i++) { + *Time100nsPtr += spt[i].KernelTime.QuadPart;; + *Time100nsPtr += spt[i].UserTime.QuadPart; + *IdleCountPtr += spt[i].IdleTime.QuadPart; + } + return TRUE; + } + return FALSE; +} +#endif /* PERF_METHODX */ + /***************************************************************** * InitLoadAvg() - Initialize the cygwin_load structure. - and set cygwin_load.Flag to TRUE if successful. + Initialize the cygwin_load.perf structure. + and set cygwin_load.perf->Flag to TRUE if successful. This is called the first time os_getloadavg is called *****************************************************************/ -static void InitLoadAvg() +static void InitLoadAvg(cygwin_perf_t *this) { BOOL success = TRUE; - cygwin_load.Init = TRUE; /* We have run */ + /* Get perf frequency and counter */ - QueryPerformanceFrequency((LARGE_INTEGER *)& cygwin_load.PerfFreq); - QueryPerformanceCounter((LARGE_INTEGER *)& cygwin_load.LastCounter); + QueryPerformanceFrequency((LARGE_INTEGER *)& this->PerfFreq); + QueryPerformanceCounter((LARGE_INTEGER *)& this->LastCounter); + +#ifdef PERF_METHOD1 DEBUG(D_load) { /* Get the name strings through the registry to verify that the object and counter numbers have the names we expect */ success = GetNameStrings(); } - /* Get initial values for Time100ns and IdleCount - and possibly verify the names */ - // success = success && - success = ReadStat( & cygwin_load.Time100ns, - & cygwin_load.IdleCount); +#endif + /* Get initial values for Time100ns and IdleCount */ + success = success + && ReadStat( & this->Time100ns, + & this->IdleCount); /* If success, set the Load to 0, else to -1 */ - if (success) cygwin_load.LastLoad = 0; + if (success) this->LastLoad = 0; else { log_write(0, LOG_MAIN, "Cannot obtain Load Average"); - cygwin_load.LastLoad = -1; + this->LastLoad = -1; } +#ifdef PERF_METHOD1 /* Free the buffer created for debug name verification */ - if (cygwin_load.NamesArray != NULL) { - free(cygwin_load.NamesArray); - cygwin_load.NamesArray = NULL; + if (this->NamesArray != NULL) { + free(this->NamesArray); + this->NamesArray = NULL; } +#endif } + + /***************************************************************** * os_getloadavg() @@ -611,42 +773,89 @@ static void InitLoadAvg() The first time we are called we initialize the counts and return 0 or -1. - The load cannot be measured because we use the processor 100% + The initial load cannot be measured as we use the processor 100% *****************************************************************/ +static SECURITY_ATTRIBUTES sa = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE}; #define AVERAGING 10 + int os_getloadavg() { - long long Time100ns, IdleCount, CurrCounter; + unsigned long long Time100ns, IdleCount, CurrCounter; int value; + pid_t newpid; + + /* New process. + Reload the dlls and the file mapping */ + if ((newpid = getpid()) != cygwin_load.pid) { + BOOL new; + cygwin_load.pid = newpid; + +#ifdef PERF_METHOD2 + if (!LoadNtdll()) { + log_write(0, LOG_MAIN, "Cannot obtain Load Average"); + cygwin_load.perf = NULL; + return -1; + } +#endif + + 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_printf("Perf: CreateFileMapping: handle %x\n", (unsigned) 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_printf("Perf: MapViewOfFile: addr %x\n", (unsigned) cygwin_load.perf); + if (new && cygwin_load.perf) + InitLoadAvg(cygwin_load.perf); + } + + /* Check if initialized OK */ + if (!cygwin_load.perf || cygwin_load.perf->LastLoad < 0) + return -1; + + /* If we cannot get the lock, we return 0. + This is to prevent any lock-up possibility. + Finding a lock busy is unlikely, and giving up only + results in an immediate delivery .*/ + + if (InterlockedCompareExchange(&cygwin_load.perf->Lock, 1, 0)) { + DEBUG(D_load) + debug_printf("Perf: Lock busy\n"); + return 0; + } - if (! cygwin_load.Init) InitLoadAvg(); - else if (cygwin_load.LastLoad >= 0) { /* Initialized OK */ /* Get the current time (PerfCounter) */ QueryPerformanceCounter((LARGE_INTEGER *)& CurrCounter); /* Calls closer than AVERAGING sec apart use the previous value */ - if (CurrCounter - cygwin_load.LastCounter > - AVERAGING * cygwin_load.PerfFreq) { + if (CurrCounter - cygwin_load.perf->LastCounter > + AVERAGING * cygwin_load.perf->PerfFreq) { /* Get Time100ns and IdleCount */ if (ReadStat( & Time100ns, & IdleCount)) { /* Success */ - /* Return processor load on 1000 scale */ - value = 1000 - ((1000 * (IdleCount - cygwin_load.IdleCount)) / - (Time100ns - cygwin_load.Time100ns)); - cygwin_load.Time100ns = Time100ns; - cygwin_load.IdleCount = IdleCount; - cygwin_load.LastCounter = CurrCounter; - cygwin_load.LastLoad = value; + /* Return processor load on 1000 scale */ + value = 1000 - ((1000 * (IdleCount - cygwin_load.perf->IdleCount)) / + (Time100ns - cygwin_load.perf->Time100ns)); + cygwin_load.perf->Time100ns = Time100ns; + cygwin_load.perf->IdleCount = IdleCount; + cygwin_load.perf->LastCounter = CurrCounter; + cygwin_load.perf->LastLoad = value; + DEBUG(D_load) + debug_printf("Perf: New load average %d\n", value); } else { /* Something bad happened. - Refuse to measure the load anymore - but don't bother releasing the buffer */ + Refuse to measure the load anymore + but don't bother releasing the buffer */ log_write(0, LOG_MAIN, "Cannot obtain Load Average"); - cygwin_load.LastLoad = -1; - } + cygwin_load.perf->LastLoad = -1; } } + else DEBUG(D_load) - debug_printf("Perf: load average = %d\n", cygwin_load.LastLoad); - return cygwin_load.LastLoad; + debug_printf("Perf: Old load average %d\n", cygwin_load.perf->LastLoad); + cygwin_load.perf->Lock = 0; + return cygwin_load.perf->LastLoad; } #endif /* OS_LOAD_AVERAGE */ #endif /* COMPILE_UTILITY */ -- 2.30.2 From 7766a4f0bde58b3456f26dc584aa869cd1340f3c Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 14:19:21 +0000 Subject: [PATCH 04/16] Add support for libradiusclient version 0.4.0 onwards, where they have changed the API. --- doc/doc-txt/ChangeLog | 8 +++++- doc/doc-txt/NewStuff | 8 +++++- src/ACKNOWLEDGMENTS | 5 ++-- src/src/EDITME | 23 +++++++++++------ src/src/auths/call_radius.c | 49 +++++++++++++++++++++++++++++-------- src/src/buildconfig.c | 3 ++- 6 files changed, 73 insertions(+), 23 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 496ba5943..0e14c76c3 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.102 2005/03/29 11:01:32 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.103 2005/03/29 14:19:21 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -90,6 +90,12 @@ PH/15 Further to TK/02 and TK/03 above, tidied up the tables of what conditions PH/16 Installed updated OS/os.c-cygwin from the Cygwin maintainer. +PH/17 The API for radiusclient changed at release 0.4.0. Unfortunately, the + header file does not have a version number, so I've had to invent a new + value for RADIUS_LIB_TYPE, namely "RADIUSCLIENTNEW" to request the new + API. The code is untested by me (my Linux distribution still has 0.3.2 of + radiusclient), but it was contributed by a Radius user. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 053bdabab..51ac28c37 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.30 2005/03/22 16:52:06 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.31 2005/03/29 14:19:21 ph10 Exp $ New Features in Exim -------------------- @@ -91,6 +91,12 @@ TF/01 $received_time is a new expansion variable containing the time and date as a number of seconds since the start of the Unix epoch when the current message was received. +PH/03 There is a new value for RADIUS_LIB_TYPE that can be set in + Local/Makefile. It is RADIUSCLIENTNEW, and it requests that the new API, + in use from radiusclient 0.4.0 onwards, be used. It does not appear to be + possible to detect the different versions automatically. + + Version 4.50 ------------ diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index 0982973d2..faaedb639 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.16 2005/03/22 14:11:54 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.17 2005/03/29 14:19:21 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 22 March 2005 +Last updated: 29 March 2005 THE OLD LIST @@ -83,6 +83,7 @@ Steve Campbell eximstats extensions and continued maintenance Brian Candler Use h_errno for gethostbyname() Suggested patch for .ifdef etc Several minor fixes and suggestions +Pete Carah Patch for change to radiusclient API Oliver Cook Suggested patch for exigrep & rejected messages Patch to add sender/host info to local_scan() rejects Suggested patch to add queue time to "Completed" diff --git a/src/src/EDITME b/src/src/EDITME index 72f797bb3..901fd4366 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/EDITME,v 1.9 2005/03/22 14:11:54 ph10 Exp $ +# $Cambridge: exim/src/src/EDITME,v 1.10 2005/03/29 14:19:21 ph10 Exp $ ################################################## # The Exim mail transport agent # @@ -722,17 +722,24 @@ ZCAT_COMMAND=/usr/bin/zcat # If you have set RADIUS_CONFIG_FILE, you should also set one of these to # indicate which RADIUS library is used: -# -# RADIUSCLIENT is the radiusclient library; you probably need to add -# -libradiusclient to EXTRALIBS -# -# RADLIB is the Radius library that comes with FreeBSD (the header file is -# called radlib.h); you probably need to add -lradius to EXTRALIBS # RADIUS_LIB_TYPE=RADIUSCLIENT +# RADIUS_LIB_TYPE=RADIUSCLIENTNEW # RADIUS_LIB_TYPE=RADLIB -# If you don't set one of these, Exim assumes the radiusclient library. +# RADIUSCLIENT is the radiusclient library; you probably need to add +# -lradiusclient to EXTRALIBS. +# +# The API for the radiusclient library was changed at release 0.4.0. +# Unfortunately, the header file does not define a version number that clients +# can use to support both the old and new APIs. If you are using version 0.4.0 +# or later of the radiusclient library, you should use RADIUSCLIENTNEW. +# +# RADLIB is the Radius library that comes with FreeBSD (the header file is +# called radlib.h); you probably need to add -lradius to EXTRALIBS. +# +# If you do not set RADIUS_LIB_TYPE, Exim assumes the radiusclient library, +# using the original API. #------------------------------------------------------------------------------ diff --git a/src/src/auths/call_radius.c b/src/src/auths/call_radius.c index 133de74dd..a20237689 100644 --- a/src/src/auths/call_radius.c +++ b/src/src/auths/call_radius.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/auths/call_radius.c,v 1.2 2005/01/04 10:00:43 ph10 Exp $ */ +/* $Cambridge: exim/src/src/auths/call_radius.c,v 1.3 2005/03/29 14:19:21 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -29,12 +29,13 @@ static void dummy(int x) { dummy(x-1); } #else /* RADIUS_CONFIG_FILE */ -/* Two different Radius libraries are supported. The default is radiusclient. */ +/* Two different Radius libraries are supported. The default is radiusclient, +using its original API. At release 0.4.0 the API changed. */ #ifdef RADIUS_LIB_RADLIB #include #else - #ifndef RADIUS_LIB_RADIUSCLIENT + #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW) #define RADIUS_LIB_RADIUSCLIENT #endif #include @@ -67,12 +68,15 @@ int result; int sep = 0; #ifdef RADIUS_LIB_RADLIB -struct rad_handle *h; + struct rad_handle *h; #else -VALUE_PAIR *send = NULL; -VALUE_PAIR *received; -unsigned int service = PW_AUTHENTICATE_ONLY; -char msg[4096]; + #ifdef RADIUS_LIB_RADIUSCLIENTNEW + rc_handle *h; + #endif + VALUE_PAIR *send = NULL; + VALUE_PAIR *received; + unsigned int service = PW_AUTHENTICATE_ONLY; + char msg[4096]; #endif @@ -87,10 +91,11 @@ DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" " /* Authenticate using the radiusclient library */ -#ifdef RADIUS_LIB_RADIUSCLIENT +#ifndef RADIUS_LIB_RADLIB rc_openlog("exim"); +#ifdef RADIUS_LIB_RADIUSCLIENT if (rc_read_config(RADIUS_CONFIG_FILE) != 0) *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE); @@ -106,13 +111,37 @@ else if (rc_avpair_add(&send, PW_USER_PASSWORD, CS radius_args, 0) == NULL) else if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0) == NULL) *errptr = string_sprintf("RADIUS: add service type failed\n"); +#else /* RADIUS_LIB_RADIUSCLIENT unset => RADIUS_LIB_RADIUSCLIENT2 */ + +if ((h = rc_read_config(RADIUS_CONFIG_FILE)) != 0) + *errptr = string_sprintf("RADIUS: can't open %s", RADIUS_CONFIG_FILE); + +else if (rc_read_dictionary(h, rc_conf_str(h, "dictionary")) != 0) + *errptr = string_sprintf("RADIUS: can't read dictionary"); + +else if (rc_avpair_add(h, &send, PW_USER_NAME, user, 0, 0) == NULL) + *errptr = string_sprintf("RADIUS: add user name failed\n"); + +else if (rc_avpair_add(h, &send, PW_USER_PASSWORD, CS radius_args, 0, 0) == NULL) + *errptr = string_sprintf("RADIUS: add password failed\n"); + +else if (rc_avpair_add(h, &send, PW_SERVICE_TYPE, &service, 0, 0) == NULL) + *errptr = string_sprintf("RADIUS: add service type failed\n"); + +#endif /* RADIUS_LIB_RADIUSCLIENT */ + if (*errptr != NULL) { DEBUG(D_auth) debug_printf("%s\n", *errptr); return ERROR; } +#ifdef RADIUS_LIB_RADIUSCLIENT result = rc_auth(0, send, &received, msg); +#else +result = rc_auth(h, 0, send, &received, msg); +#endif + DEBUG(D_auth) debug_printf("RADIUS code returned %d\n", result); switch (result) @@ -133,7 +162,7 @@ switch (result) return ERROR; } -#else /* RADIUS_LIB_RADIUSCLIENT not set => RADIUS_LIB_RADLIB is set */ +#else /* RADIUS_LIB_RADLIB is set */ /* Authenticate using the libradius library */ diff --git a/src/src/buildconfig.c b/src/src/buildconfig.c index 3f4ff308d..46bf4738b 100644 --- a/src/src/buildconfig.c +++ b/src/src/buildconfig.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/buildconfig.c,v 1.6 2005/02/17 11:58:25 ph10 Exp $ */ +/* $Cambridge: exim/src/src/buildconfig.c,v 1.7 2005/03/29 14:19:21 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -677,6 +677,7 @@ while (fgets(buffer, sizeof(buffer), base) != NULL) else if (strcmp(name, "RADIUS_LIB_TYPE") == 0) { if (strcmp(value, "RADIUSCLIENT") == 0 || + strcmp(value, "RADIUSCLIENTNEW") == 0 || strcmp(value, "RADLIB") == 0) { fprintf(new, "#define RADIUS_LIB_%s\n", value); -- 2.30.2 From 8b417f2c8e0df074cbb139081e5f1fb7992946dd Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 14:53:09 +0000 Subject: [PATCH 05/16] Installed Lars Mainka's patch for OpenSSL support of CRL collections. --- doc/doc-txt/ChangeLog | 5 +++- src/ACKNOWLEDGMENTS | 3 ++- src/src/tls-openssl.c | 55 ++++++++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 0e14c76c3..18e8d1ff8 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.103 2005/03/29 14:19:21 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.104 2005/03/29 14:53:09 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -96,6 +96,9 @@ PH/17 The API for radiusclient changed at release 0.4.0. Unfortunately, the API. The code is untested by me (my Linux distribution still has 0.3.2 of radiusclient), but it was contributed by a Radius user. +PH/18 Installed Lars Mainka's patch for the support of CRL collections in + files or directories, for OpenSSL. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index faaedb639..2b5426b9d 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.17 2005/03/29 14:19:21 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.18 2005/03/29 14:53:09 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -163,6 +163,7 @@ Chris Liddiard Fix for bug in exiqsumm Chris Lightfoot Patch for -restore-times in exim_lock Edgar Lovecraft Patch for ${str2b64: Torsten Luettgert Suggested patch for proper integer overflow detection +Lars Mainka Patch for OpenSSL crl collections David Madole Patch for SPA forced expansion failure bug Lionel Elie Mamane Patch for IPv4/IPv6 listen() problem on USAGI Linux Patch for recognizing IPv6 "scoped addresses" diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index a4a8e8b9f..693e6dc14 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/tls-openssl.c,v 1.3 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/tls-openssl.c,v 1.4 2005/03/29 14:53:09 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -526,34 +526,51 @@ if (expcerts != NULL) #if OPENSSL_VERSION_NUMBER > 0x00907000L + /* This bit of code is now the version supplied by Lars Mainka. (I have + * merely reformatted it into the Exim code style.) + + * "From here I changed the code to add support for multiple crl's + * in pem format in one file or to support hashed directory entries in + * pem format instead of a file. This method now uses the library function + * X509_STORE_load_locations to add the CRL location to the SSL context. + * OpenSSL will then handle the verify against CA certs and CRLs by + * itself in the verify callback." */ + if (!expand_check(crl, US"tls_crl", &expcrl)) return DEFER; if (expcrl != NULL && *expcrl != 0) { - BIO *crl_bio; - X509_CRL *crl_x509; - X509_STORE *cvstore; - - cvstore = SSL_CTX_get_cert_store(ctx); /* cert validation store */ - - crl_bio = BIO_new(BIO_s_file_internal()); - if (crl_bio != NULL) + struct stat statbufcrl; + if (Ustat(expcrl, &statbufcrl) < 0) + { + log_write(0, LOG_MAIN|LOG_PANIC, + "failed to stat %s for certificates revocation lists", expcrl); + return DEFER; + } + else { - if (BIO_read_filename(crl_bio, expcrl)) + /* is it a file or directory? */ + uschar *file, *dir; + X509_STORE *cvstore = SSL_CTX_get_cert_store(ctx); + if ((statbufcrl.st_mode & S_IFMT) == S_IFDIR) { - crl_x509 = PEM_read_bio_X509_CRL(crl_bio, NULL, NULL, NULL); - BIO_free(crl_bio); - X509_STORE_add_crl(cvstore, crl_x509); - X509_CRL_free(crl_x509); - X509_STORE_set_flags(cvstore, - X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + file = NULL; + dir = expcrl; + DEBUG(D_tls) debug_printf("SSL CRL value is a directory %s\n", dir); } else { - BIO_free(crl_bio); - return tls_error(US"BIO_read_filename", host); + file = expcrl; + dir = NULL; + DEBUG(D_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); + + /* setting the flags to check against the complete crl chain */ + + X509_STORE_set_flags(cvstore, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); } - else return tls_error(US"BIO_new", host); } #endif /* OPENSSL_VERSION_NUMBER > 0x00907000L */ -- 2.30.2 From 901f42cb9f12332dd04a14cea87d47ef7e66e2e2 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 15:19:25 +0000 Subject: [PATCH 06/16] Test for failure of the fork() when a root process creates a log file. --- doc/doc-txt/ChangeLog | 11 ++++++++++- src/src/log.c | 19 +++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 18e8d1ff8..4cb08c1dc 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.104 2005/03/29 14:53:09 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.105 2005/03/29 15:19:25 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -99,6 +99,15 @@ PH/17 The API for radiusclient changed at release 0.4.0. Unfortunately, the PH/18 Installed Lars Mainka's patch for the support of CRL collections in files or directories, for OpenSSL. +PH/19 When an Exim process that is running as root has to create an Exim log + file, it does so in a subprocess that runs as exim:exim so as to get the + ownership right at creation (otherwise, other Exim processes might see + the file with the wrong ownership). There was no test for failure of this + fork() call, which would lead to the process getting stuck as it waited + for a non-existent subprocess. Forks do occasionally fail when resources + run out. I reviewed all the other calls to fork(); they all seem to check + for failure. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/log.c b/src/src/log.c index 0d8b3d0d6..d2ef9e518 100644 --- a/src/src/log.c +++ b/src/src/log.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/log.c,v 1.2 2005/01/04 10:00:42 ph10 Exp $ */ +/* $Cambridge: exim/src/src/log.c,v 1.3 2005/03/29 15:19:25 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -321,8 +321,9 @@ if (*fd >= 0) /* Open was not successful: try creating the file. If this is a root process, we must do the creating in a subprocess set to exim:exim in order to ensure that the file is created with the right ownership. Otherwise, there can be a -race if an exim process is trying to write to the log at the same time. The use -of SIGUSR1 by the exiwhat utility can provoke a lot of simultaneous writing. */ +race if another Exim process is trying to write to the log at the same time. +The use of SIGUSR1 by the exiwhat utility can provoke a lot of simultaneous +writing. */ euid = geteuid(); @@ -350,10 +351,16 @@ else if (euid == root_uid) _exit((create_log(buffer) < 0)? 1 : 0); } - /* Wait for the subprocess. If it succeeded retry the open. */ + /* If we created a subprocess, wait for it. If it succeeded retry the open. */ - while (waitpid(pid, &status, 0) != pid); - if (status == 0) *fd = Uopen(buffer, O_APPEND|O_WRONLY, LOG_MODE); + if (pid > 0) + { + while (waitpid(pid, &status, 0) != pid); + if (status == 0) *fd = Uopen(buffer, O_APPEND|O_WRONLY, LOG_MODE); + } + + /* If we failed to create a subprocess, we are in a bad way. We fall through + with *fd still < 0, and errno set, letting the code below handle the error. */ } /* If we now have an open file, set the close-on-exec flag and return. */ -- 2.30.2 From d1d97a7641e06d3372f2ded9e5cb1e97b86d3c40 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 15:21:57 +0000 Subject: [PATCH 07/16] Small documentation change from Michael Haardt. --- doc/doc-txt/README.SIEVE | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/doc-txt/README.SIEVE b/doc/doc-txt/README.SIEVE index 0622dc906..53d5b01ed 100644 --- a/doc/doc-txt/README.SIEVE +++ b/doc/doc-txt/README.SIEVE @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/README.SIEVE,v 1.2 2005/03/01 10:21:43 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/README.SIEVE,v 1.3 2005/03/29 15:21:57 ph10 Exp $ Notes on the Sieve implementation for Exim @@ -114,13 +114,14 @@ This may be implemented in future by adding a header line to mails that are filed into "inbox" due to an error in the filter. -Strings Containing Header Names +Strings Containing Header Names Or Envelope Elements RFC 3028 does not specify what happens if a string denoting a header -field does not contain a valid header name, e.g. it contains a colon. +field or envelope element does not contain a valid name, e.g. it +contains a colon for a header or it is not "from" or "to" for envelopes. This implementation generates an error instead of ignoring the header -field in order to ease script debugging, which fits in the common -picture of Sieve. +field in order to ease script debugging, which fits in the common picture +of Sieve. Header Test With Invalid MIME Encoding In Header -- 2.30.2 From f9b9210ed00d36e87538b5d4abe51c079826fb9c Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 29 Mar 2005 15:53:12 +0000 Subject: [PATCH 08/16] Fix non-check for read() error in sync check before writing banner. --- doc/doc-txt/ChangeLog | 11 ++++++++++- src/src/smtp_in.c | 21 ++++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 4cb08c1dc..cf31d4690 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.105 2005/03/29 15:19:25 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.106 2005/03/29 15:53:12 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -108,6 +108,15 @@ PH/19 When an Exim process that is running as root has to create an Exim log run out. I reviewed all the other calls to fork(); they all seem to check for failure. +PH/20 When checking for unexpected SMTP input at connect time (before writing + the banner), Exim was not dealing correctly with a non-positive return + from the read() function. If the client had disconnected by this time, + the result was a log entry for a synchronization error with an empty + string after "input=" when read() returned zero. If read() returned -1 + (an event I could not check), uninitialized data bytes were printed. + There were reports of junk text (parts of files, etc) appearing after + "input=". + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 7348e9b15..c10293c87 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/smtp_in.c,v 1.14 2005/03/22 10:11:43 ph10 Exp $ */ +/* $Cambridge: exim/src/src/smtp_in.c,v 1.15 2005/03/29 15:53:12 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1616,14 +1616,17 @@ if (smtp_enforce_sync && sender_host_address != NULL && !sender_host_notsocket) &tzero) > 0) { int rc = read(fileno(smtp_in), smtp_inbuffer, in_buffer_size); - if (rc > 150) rc = 150; - smtp_inbuffer[rc] = 0; - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: " - "synchronization error (input sent without waiting for greeting): " - "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), - string_printing(smtp_inbuffer)); - smtp_printf("554 SMTP synchronization error\r\n"); - return FALSE; + if (rc > 0) + { + if (rc > 150) rc = 150; + smtp_inbuffer[rc] = 0; + log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol violation: " + "synchronization error (input sent without waiting for greeting): " + "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), + string_printing(smtp_inbuffer)); + smtp_printf("554 SMTP synchronization error\r\n"); + return FALSE; + } } } -- 2.30.2 From 75faf2411c4a910c57bd09e93dbb02e7279c05a7 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Wed, 30 Mar 2005 08:23:11 +0000 Subject: [PATCH 09/16] Minor update to one of the wishes. --- doc/doc-misc/WishList | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/doc-misc/WishList b/doc/doc-misc/WishList index 119e31e2d..4d10b94d3 100644 --- a/doc/doc-misc/WishList +++ b/doc/doc-misc/WishList @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-misc/WishList,v 1.26 2005/03/15 15:46:24 ph10 Exp $ +$Cambridge: exim/doc/doc-misc/WishList,v 1.27 2005/03/30 08:23:11 ph10 Exp $ EXIM 4 WISH LIST ---------------- @@ -301,7 +301,8 @@ This would allow special handling of certain errors from certain hosts. In particular, it would allow failing of certain 4xx codes. This is now available for 4xx responses to RCPT commands. Is anything more -needed? +needed? Apparently, yes; there's been a request for a similar feature for MAIL +commands. ------------------------------------------------------------------------------ (148) 15-May-2000 S Warn recipient if message rejected for quota excession. -- 2.30.2 From fb6f3d5c1822aa3062ad3aac9a63c57c350562f0 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Mon, 4 Apr 2005 08:27:28 +0000 Subject: [PATCH 10/16] Update WishList with suggestion about -bP from Bugzilla. Better continue to keep this list until a proper merge is done. --- doc/doc-misc/WishList | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/doc-misc/WishList b/doc/doc-misc/WishList index 4d10b94d3..4d25700c3 100644 --- a/doc/doc-misc/WishList +++ b/doc/doc-misc/WishList @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-misc/WishList,v 1.27 2005/03/30 08:23:11 ph10 Exp $ +$Cambridge: exim/doc/doc-misc/WishList,v 1.28 2005/04/04 08:27:28 ph10 Exp $ EXIM 4 WISH LIST ---------------- @@ -1895,5 +1895,10 @@ This is yet another problem caused by duplicating the SMTP code between the transport and the callout verification. See item 294 above. Merging the transport and the callout code could prevent this kind of thing from happening. ------------------------------------------------------------------------------ ---- HWM 323 ------------------------------------------------------------------ + +(324) 04-Apr-05 ? Make -bP show ACLs + +This is in the Bugzilla as #10. +------------------------------------------------------------------------------ +--- HWM 324 ------------------------------------------------------------------ ---------------------------- End of WishList --------------------------------- -- 2.30.2 From 54cdb463ab15d0a064cfe0a276b3e3974767c8c7 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Mon, 4 Apr 2005 10:33:49 +0000 Subject: [PATCH 11/16] Added acl_not_smtp_mime. This involved a bit of refactoring of the content scanning code. Also, updated doc/OptionList.txt with all the content-scanning options (none had been added.) --- doc/doc-txt/ChangeLog | 4 +- doc/doc-txt/NewStuff | 6 +- doc/doc-txt/OptionLists.txt | 6 +- src/src/functions.h | 6 +- src/src/globals.c | 5 +- src/src/globals.h | 5 +- src/src/mime.c | 12 +- src/src/readconf.c | 5 +- src/src/receive.c | 333 ++++++++++++++++++++---------------- 9 files changed, 222 insertions(+), 160 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index cf31d4690..87e001f27 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.106 2005/03/29 15:53:12 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.107 2005/04/04 10:33:49 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -117,6 +117,8 @@ PH/20 When checking for unexpected SMTP input at connect time (before writing There were reports of junk text (parts of files, etc) appearing after "input=". +PH/21 Added acl_not_smtp_mime to allow for MIME scanning for non-SMTP messages. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 51ac28c37..6f3ac86d1 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.31 2005/03/29 14:19:21 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.32 2005/04/04 10:33:49 ph10 Exp $ New Features in Exim -------------------- @@ -96,6 +96,10 @@ PH/03 There is a new value for RADIUS_LIB_TYPE that can be set in in use from radiusclient 0.4.0 onwards, be used. It does not appear to be possible to detect the different versions automatically. +PH/04 There is a new option called acl_not_smtp_mime that allows you to scan + MIME parts in non-SMTP messages. It operates in exactly the same way as + acl_smtp_mime + Version 4.50 ------------ diff --git a/doc/doc-txt/OptionLists.txt b/doc/doc-txt/OptionLists.txt index 49b76b3d6..ba727b0bb 100644 --- a/doc/doc-txt/OptionLists.txt +++ b/doc/doc-txt/OptionLists.txt @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.6 2005/03/03 08:54:59 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/OptionLists.txt,v 1.7 2005/04/04 10:33:49 ph10 Exp $ LISTS OF EXIM OPTIONS --------------------- @@ -52,6 +52,7 @@ in fact some of them were inherited from earlier versions. ----------------------------------------------------------------------------------------- accept_8bitmime boolean false main 1.60 acl_not_smtp string* unset main 4.11 +acl_not_smtp_mime string* unset main 4.51 with content scan acl_smtp_auth string* unset main 4.00 acl_smtp_connect string* unset main 4.11 acl_smtp_data string* unset main 4.00 @@ -60,6 +61,7 @@ acl_smtp_expn string* unset main acl_smtp_helo string* unset main 4.20 acl_smtp_mail string* unset main 4.11 acl_smtp_mailauth string* unset main 4.21 +acl_smtp_mime string* unset main 4.50 with content scan acl_smtp_predata string* unset main 4.43 acl_smtp_quit string* unset main 4.43 acl_smtp_rcpt string* unset main 4.00 @@ -83,6 +85,7 @@ auth_advertise_hosts host list "*" main authenticated_sender string* unset smtp 4.14 authenticate_hosts host list unset smtp 3.13 auto_thaw time 0s main +av_scanner string* + main 4.50 with content scan batch_id string unset appendfile 4.00 unset lmtp 4.00 unset pipe 4.00 @@ -466,6 +469,7 @@ smtp_receive_timeout time 5m main smtp_reserve_hosts host list unset main smtp_return_error_details boolean false main 4.11 socket string* unset lmtp 4.11 +spamd_address string + main 4.50 with content scan split_spool_directory boolean false main 1.70 spool_directory string ++ main srv_fail_domains domain list unset dnslookup 4.43 diff --git a/src/src/functions.h b/src/src/functions.h index 88bc53d74..1563a55c3 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/functions.h,v 1.12 2005/03/08 15:32:02 tom Exp $ */ +/* $Cambridge: exim/src/src/functions.h,v 1.13 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -152,8 +152,8 @@ extern void md5_start(md5 *); extern void millisleep(int); #ifdef WITH_CONTENT_SCAN struct mime_boundary_context; -extern int mime_acl_check(FILE *f, struct mime_boundary_context *, - uschar **, uschar **); +extern int mime_acl_check(uschar *acl, FILE *f, + struct mime_boundary_context *, uschar **, uschar **); extern int mime_decode(uschar **); extern int mime_regex(uschar **); #endif diff --git a/src/src/globals.c b/src/src/globals.c index 2324e4072..5fe414b43 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/globals.c,v 1.20 2005/03/22 14:11:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/globals.c,v 1.21 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -160,6 +160,9 @@ int address_expansions_count = sizeof(address_expansions)/sizeof(uschar **); tree_node *acl_anchor = NULL; uschar *acl_not_smtp = NULL; +#ifdef WITH_CONTENT_SCAN +uschar *acl_not_smtp_mime = NULL; +#endif uschar *acl_smtp_auth = NULL; uschar *acl_smtp_connect = NULL; uschar *acl_smtp_data = NULL; diff --git a/src/src/globals.h b/src/src/globals.h index 404838126..37faa9d50 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/globals.h,v 1.13 2005/03/22 14:11:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/globals.h,v 1.14 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -102,6 +102,9 @@ extern uschar **address_expansions[ADDRESS_EXPANSIONS_COUNT]; extern BOOL accept_8bitmime; /* Allow *BITMIME incoming */ extern tree_node *acl_anchor; /* Tree of named ACLs */ extern uschar *acl_not_smtp; /* ACL run for non-SMTP messages */ +#ifdef WITH_CONTENT_SCAN +extern uschar *acl_not_smtp_mime; /* For MIME parts of ditto */ +#endif extern uschar *acl_smtp_auth; /* ACL run for AUTH */ extern uschar *acl_smtp_connect; /* ACL run on SMTP connection */ extern uschar *acl_smtp_data; /* ACL run after DATA received */ diff --git a/src/src/mime.c b/src/src/mime.c index f97d25abb..05b6e3e2a 100644 --- a/src/src/mime.c +++ b/src/src/mime.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/mime.c,v 1.6 2005/03/08 16:57:28 ph10 Exp $ */ +/* $Cambridge: exim/src/src/mime.c,v 1.7 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -502,8 +502,8 @@ int mime_get_header(FILE *f, uschar *header) { } -int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar - **user_msgptr, uschar **log_msgptr) { +int mime_acl_check(uschar *acl, FILE *f, struct mime_boundary_context *context, + uschar **user_msgptr, uschar **log_msgptr) { int rc = OK; uschar *header = NULL; struct mime_boundary_context nested_context; @@ -512,7 +512,7 @@ int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar header = (uschar *)malloc(MIME_MAX_HEADER_SIZE+1); if (header == NULL) { log_write(0, LOG_PANIC, - "acl_smtp_mime: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); + "MIME ACL: can't allocate %d bytes of memory.", MIME_MAX_HEADER_SIZE+1); return DEFER; }; @@ -659,7 +659,7 @@ int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar mime_is_coverletter = !(context && context->context == MBC_ATTACHMENT); /* call ACL handling function */ - rc = acl_check(ACL_WHERE_MIME, NULL, acl_smtp_mime, user_msgptr, log_msgptr); + rc = acl_check(ACL_WHERE_MIME, NULL, acl, user_msgptr, log_msgptr); mime_stream = NULL; mime_current_boundary = NULL; @@ -680,7 +680,7 @@ int mime_acl_check(FILE *f, struct mime_boundary_context *context, uschar else nested_context.context = MBC_COVERLETTER_ONESHOT; - rc = mime_acl_check(f, &nested_context, user_msgptr, log_msgptr); + rc = mime_acl_check(acl, f, &nested_context, user_msgptr, log_msgptr); if (rc != OK) break; } else if ( (mime_content_type != NULL) && diff --git a/src/src/readconf.c b/src/src/readconf.c index 302255ddf..0fe00cf6b 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/readconf.c,v 1.5 2005/02/17 11:58:26 ph10 Exp $ */ +/* $Cambridge: exim/src/src/readconf.c,v 1.6 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -135,6 +135,9 @@ static optionlist optionlist_config[] = { { "*set_system_filter_user", opt_bool|opt_hidden, &system_filter_uid_set }, { "accept_8bitmime", opt_bool, &accept_8bitmime }, { "acl_not_smtp", opt_stringptr, &acl_not_smtp }, +#ifdef WITH_CONTENT_SCAN + { "acl_not_smtp_mime", opt_stringptr, &acl_not_smtp_mime }, +#endif { "acl_smtp_auth", opt_stringptr, &acl_smtp_auth }, { "acl_smtp_connect", opt_stringptr, &acl_smtp_connect }, { "acl_smtp_data", opt_stringptr, &acl_smtp_data }, diff --git a/src/src/receive.c b/src/src/receive.c index e4ce9cb23..325544643 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/receive.c,v 1.12 2005/03/08 15:32:02 tom Exp $ */ +/* $Cambridge: exim/src/src/receive.c,v 1.13 2005/04/04 10:33:49 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -510,7 +510,7 @@ for (count = 0; count < recipients_count; count++) { if ((--recipients_count - count) > 0) memmove(recipients_list + count, recipients_list + count + 1, - (recipients_count - count)*sizeof(recipient_item)); + (recipients_count - count)*sizeof(recipient_item)); return TRUE; } } @@ -1008,6 +1008,146 @@ return s; +/************************************************* +* Run the MIME ACL on a message * +*************************************************/ + +/* This code is in a subroutine so that it can be used for both SMTP +and non-SMTP messages. It is called with a non-NULL ACL pointer. + +Arguments: + acl The ACL to run (acl_smtp_mime or acl_not_smtp_mime) + smtp_yield_ptr Set FALSE to kill messages after dropped connection + smtp_reply_ptr Where SMTP reply is being built + blackholed_by_ptr Where "blackholed by" message is being built + +Returns: TRUE to carry on; FALSE to abandon the message +*/ + +static BOOL +run_mime_acl(uschar *acl, BOOL *smtp_yield_ptr, uschar **smtp_reply_ptr, + uschar **blackholed_by_ptr) +{ +FILE *mbox_file; +uschar rfc822_file_path[2048]; +unsigned long mbox_size; +header_line *my_headerlist; +uschar *user_msg, *log_msg; +int mime_part_count_buffer = -1; +int rc; + +memset(CS rfc822_file_path,0,2048); + +/* check if it is a MIME message */ +my_headerlist = header_list; +while (my_headerlist != NULL) { + /* skip deleted headers */ + if (my_headerlist->type == '*') { + my_headerlist = my_headerlist->next; + continue; + }; + if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) { + DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n"); + goto DO_MIME_ACL; + }; + my_headerlist = my_headerlist->next; +}; + +DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n"); +return TRUE; + +DO_MIME_ACL: +/* make sure the eml mbox file is spooled up */ +mbox_file = spool_mbox(&mbox_size); +if (mbox_file == NULL) { + /* error while spooling */ + log_write(0, LOG_MAIN|LOG_PANIC, + "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected."); + Uunlink(spool_name); + unspool_mbox(); + smtp_respond(451, TRUE, US"temporary local problem"); + message_id[0] = 0; /* Indicate no message accepted */ + *smtp_reply_ptr = US""; /* Indicate reply already sent */ + return FALSE; /* Indicate skip to end of receive function */ +}; + +mime_is_rfc822 = 0; + +MIME_ACL_CHECK: +mime_part_count = -1; +rc = mime_acl_check(acl, mbox_file, NULL, &user_msg, &log_msg); +fclose(mbox_file); + +if (Ustrlen(rfc822_file_path) > 0) { + mime_part_count = mime_part_count_buffer; + + if (unlink(CS rfc822_file_path) == -1) { + log_write(0, LOG_PANIC, + "acl_smtp_mime: can't unlink RFC822 spool file, skipping."); + goto END_MIME_ACL; + }; +}; + +/* check if we must check any message/rfc822 attachments */ +if (rc == OK) { + uschar temp_path[1024]; + int n; + struct dirent *entry; + DIR *tempdir; + + snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id); + + tempdir = opendir(CS temp_path); + n = 0; + do { + entry = readdir(tempdir); + if (entry == NULL) break; + if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) { + snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name); + debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path); + break; + }; + } while (1); + closedir(tempdir); + + if (entry != NULL) { + mbox_file = Ufopen(rfc822_file_path,"r"); + if (mbox_file == NULL) { + log_write(0, LOG_PANIC, + "acl_smtp_mime: can't open RFC822 spool file, skipping."); + unlink(CS rfc822_file_path); + goto END_MIME_ACL; + }; + /* set RFC822 expansion variable */ + mime_is_rfc822 = 1; + mime_part_count_buffer = mime_part_count; + goto MIME_ACL_CHECK; + }; +}; + +END_MIME_ACL: +add_acl_headers(US"MIME"); +if (rc == DISCARD) + { + recipients_count = 0; + *blackholed_by_ptr = US"MIME ACL"; + } +else if (rc != OK) + { + Uunlink(spool_name); + unspool_mbox(); + if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0) + *smtp_yield_ptr = FALSE; /* No more messsages after dropped connection */ + *smtp_reply_ptr = US""; /* Indicate reply already sent */ + message_id[0] = 0; /* Indicate no message accepted */ + return FALSE; /* Cause skip to end of receive function */ + }; + +return TRUE; +} + + + /************************************************* * Receive message * *************************************************/ @@ -2754,127 +2894,13 @@ else #endif #ifdef WITH_CONTENT_SCAN - /* MIME ACL hook */ - if (acl_smtp_mime != NULL && recipients_count > 0) - { - FILE *mbox_file; - uschar rfc822_file_path[2048]; - unsigned long mbox_size; - header_line *my_headerlist; - uschar *user_msg, *log_msg; - int mime_part_count_buffer = -1; - - memset(CS rfc822_file_path,0,2048); - - /* check if it is a MIME message */ - my_headerlist = header_list; - while (my_headerlist != NULL) { - /* skip deleted headers */ - if (my_headerlist->type == '*') { - my_headerlist = my_headerlist->next; - continue; - }; - if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0) { - DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n"); - goto DO_MIME_ACL; - }; - my_headerlist = my_headerlist->next; - }; - - DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n"); - goto NO_MIME_ACL; - - DO_MIME_ACL: - /* make sure the eml mbox file is spooled up */ - mbox_file = spool_mbox(&mbox_size); - if (mbox_file == NULL) { - /* error while spooling */ - log_write(0, LOG_MAIN|LOG_PANIC, - "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected."); - Uunlink(spool_name); - unspool_mbox(); - smtp_respond(451, TRUE, US"temporary local problem"); - message_id[0] = 0; /* Indicate no message accepted */ - smtp_reply = US""; /* Indicate reply already sent */ - goto TIDYUP; /* Skip to end of function */ - }; - - mime_is_rfc822 = 0; - - MIME_ACL_CHECK: - mime_part_count = -1; - rc = mime_acl_check(mbox_file, NULL, &user_msg, &log_msg); - fclose(mbox_file); - - if (Ustrlen(rfc822_file_path) > 0) { - mime_part_count = mime_part_count_buffer; - - if (unlink(CS rfc822_file_path) == -1) { - log_write(0, LOG_PANIC, - "acl_smtp_mime: can't unlink RFC822 spool file, skipping."); - goto END_MIME_ACL; - }; - }; - - /* check if we must check any message/rfc822 attachments */ - if (rc == OK) { - uschar temp_path[1024]; - int n; - struct dirent *entry; - DIR *tempdir; - - snprintf(CS temp_path, 1024, "%s/scan/%s", spool_directory, message_id); - - tempdir = opendir(CS temp_path); - n = 0; - do { - entry = readdir(tempdir); - if (entry == NULL) break; - if (strncmpic(US entry->d_name,US"__rfc822_",9) == 0) { - snprintf(CS rfc822_file_path, 2048,"%s/scan/%s/%s", spool_directory, message_id, entry->d_name); - debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n", rfc822_file_path); - break; - }; - } while (1); - closedir(tempdir); - - if (entry != NULL) { - mbox_file = Ufopen(rfc822_file_path,"r"); - if (mbox_file == NULL) { - log_write(0, LOG_PANIC, - "acl_smtp_mime: can't open RFC822 spool file, skipping."); - unlink(CS rfc822_file_path); - goto END_MIME_ACL; - }; - /* set RFC822 expansion variable */ - mime_is_rfc822 = 1; - mime_part_count_buffer = mime_part_count; - goto MIME_ACL_CHECK; - }; - }; - - END_MIME_ACL: - add_acl_headers(US"MIME"); - if (rc == DISCARD) - { - recipients_count = 0; - blackholed_by = US"MIME ACL"; - } - else if (rc != OK) - { - Uunlink(spool_name); - unspool_mbox(); - if (smtp_handle_acl_fail(ACL_WHERE_MIME, rc, user_msg, log_msg) != 0) - smtp_yield = FALSE; /* No more messsages after dropped connection */ - smtp_reply = US""; /* Indicate reply already sent */ - message_id[0] = 0; /* Indicate no message accepted */ - goto TIDYUP; /* Skip to end of function */ - }; - } - - NO_MIME_ACL: + if (acl_smtp_mime != NULL && + !run_mime_acl(acl_smtp_mime, &smtp_yield, &smtp_reply, &blackholed_by)) + goto TIDYUP; #endif /* WITH_CONTENT_SCAN */ + /* Check the recipients count again, as the MIME ACL might have changed + them. */ if (acl_smtp_data != NULL && recipients_count > 0) { @@ -2906,39 +2932,56 @@ else /* Handle non-SMTP and batch SMTP (i.e. non-interactive) messages. Note that we cannot take different actions for permanent and temporary rejections. */ - else if (acl_not_smtp != NULL) + else { - uschar *user_msg, *log_msg; - rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg); - if (rc == DISCARD) - { - recipients_count = 0; - blackholed_by = US"non-SMTP ACL"; - if (log_msg != NULL) blackhole_log_msg = string_sprintf(": %s", log_msg); - } - else if (rc != OK) + +#ifdef WITH_CONTENT_SCAN + if (acl_not_smtp_mime != NULL && + !run_mime_acl(acl_not_smtp_mime, &smtp_yield, &smtp_reply, + &blackholed_by)) + goto TIDYUP; +#endif /* WITH_CONTENT_SCAN */ + + if (acl_not_smtp != NULL) { - Uunlink(spool_name); - log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s", - sender_address, log_msg); - if (user_msg == NULL) user_msg = US"local configuration problem"; - if (smtp_batched_input) + uschar *user_msg, *log_msg; + rc = acl_check(ACL_WHERE_NOTSMTP, NULL, acl_not_smtp, &user_msg, &log_msg); + if (rc == DISCARD) { - moan_smtp_batch(NULL, "%d %s", 550, user_msg); - /* Does not return */ + recipients_count = 0; + blackholed_by = US"non-SMTP ACL"; + if (log_msg != NULL) + blackhole_log_msg = string_sprintf(": %s", log_msg); } - else + else if (rc != OK) { - fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET); - give_local_error(ERRMESS_LOCAL_ACL, user_msg, - US"message rejected by non-SMTP ACL: ", error_rc, data_file, - header_list); - /* Does not return */ + Uunlink(spool_name); +#ifdef WITH_CONTENT_SCAN + unspool_mbox(); +#endif + log_write(0, LOG_MAIN|LOG_REJECT, "F=<%s> rejected by non-SMTP ACL: %s", + sender_address, log_msg); + if (user_msg == NULL) user_msg = US"local configuration problem"; + if (smtp_batched_input) + { + moan_smtp_batch(NULL, "%d %s", 550, user_msg); + /* Does not return */ + } + else + { + fseek(data_file, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET); + give_local_error(ERRMESS_LOCAL_ACL, user_msg, + US"message rejected by non-SMTP ACL: ", error_rc, data_file, + header_list); + /* Does not return */ + } } + add_acl_headers(US"non-SMTP"); } - add_acl_headers(US"non-SMTP"); } + /* The applicable ACLs have been run */ + if (deliver_freeze) frozen_by = US"ACL"; /* for later logging */ if (queue_only_policy) queued_by = US"ACL"; -- 2.30.2 From cf00dad6749f2b3c2ba9b1e02034b23944b7ee0c Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 5 Apr 2005 13:58:34 +0000 Subject: [PATCH 12/16] Kjetil Homme's patch for extended macro features (redefinition, definition between driver and ACL definitions). --- doc/doc-txt/ChangeLog | 5 +- doc/doc-txt/NewStuff | 32 +++++- src/ACKNOWLEDGMENTS | 5 +- src/src/acl.c | 15 +-- src/src/readconf.c | 222 +++++++++++++++++++++++++++++------------- 5 files changed, 195 insertions(+), 84 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 87e001f27..ff8c2835d 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.107 2005/04/04 10:33:49 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.108 2005/04/05 13:58:34 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -119,6 +119,9 @@ PH/20 When checking for unexpected SMTP input at connect time (before writing PH/21 Added acl_not_smtp_mime to allow for MIME scanning for non-SMTP messages. +PH/22 Added support for macro redefinition, and (re)definition in between + driver and ACL definitions. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 6f3ac86d1..b2563f30c 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.32 2005/04/04 10:33:49 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.33 2005/04/05 13:58:34 ph10 Exp $ New Features in Exim -------------------- @@ -100,6 +100,36 @@ PH/04 There is a new option called acl_not_smtp_mime that allows you to scan MIME parts in non-SMTP messages. It operates in exactly the same way as acl_smtp_mime +PH/05 It is now possible to redefine a macro within the configuration file. + The macro must have been previously defined within the configuration (or + an included file). A definition on the command line using the -D option + causes all definitions and redefinitions within the file to be ignored. + In other words, -D overrides any values that are set in the file. + Redefinition is specified by using '==' instead of '='. For example: + + MAC1 = initial value + ... + MAC1 == updated value + + Redefinition does not alter the order in which the macros are applied to + the subsequent lines of the configuration file. It is still the same + order in which the macros were originally defined. All that changes is + the macro's value. Redefinition makes it possible to accumulate values. + For example: + + MAC1 = initial value + ... + MAC1 == MAC1 and something added + + This can be helpful in situations where the configuration file is built + from a number of other files. + +PH/06 Macros may now be defined or redefined between router, transport, + authenticator, or ACL definitions, as well as in the main part of the + configuration. They may not, however, be changed within an individual + driver or ACL, or in the local_scan, retry, or rewrite sections of the + configuration. + Version 4.50 ------------ diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index 2b5426b9d..ce5402eb8 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.18 2005/03/29 14:53:09 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.19 2005/04/05 13:58:35 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 29 March 2005 +Last updated: 05 April 2005 THE OLD LIST @@ -41,6 +41,7 @@ Yann Golanski Numerical hash function Jason Gunthorpe IPv6 support (Linux) Michael Haardt LDAP support enhancement Steve Haslam First code for TLS +Kjetil Torgrim Homme Suggested patch for macro extensions John Horne Proof-reading documentation (repeatedly) Pierre Humblet Cygwin support Paul Kelly MySQL interface diff --git a/src/src/acl.c b/src/src/acl.c index 704e9cb5e..1d20ff7c7 100644 --- a/src/src/acl.c +++ b/src/src/acl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/acl.c,v 1.26 2005/03/29 10:56:48 ph10 Exp $ */ +/* $Cambridge: exim/src/src/acl.c,v 1.27 2005/04/05 13:58:35 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -589,18 +589,11 @@ while ((s = (*func)()) != NULL) s++; } - /* Read the name of a verb or a condition, or the start of a new ACL */ + /* Read the name of a verb or a condition, or the start of a new ACL, which + can be started by a name, or by a macro definition. */ s = readconf_readname(name, sizeof(name), s); - if (*s == ':') - { - if (negated || name[0] == 0) - { - *error = string_sprintf("malformed ACL name in \"%s\"", saveline); - return NULL; - } - break; - } + if (*s == ':' || isupper(name[0] && *s == '=')) return yield; /* If a verb is unrecognized, it may be another condition or modifier that continues the previous verb. */ diff --git a/src/src/readconf.c b/src/src/readconf.c index 0fe00cf6b..cf4048aae 100644 --- a/src/src/readconf.c +++ b/src/src/readconf.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/readconf.c,v 1.6 2005/04/04 10:33:49 ph10 Exp $ */ +/* $Cambridge: exim/src/src/readconf.c,v 1.7 2005/04/05 13:58:35 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -435,6 +435,122 @@ return US""; +/************************************************* +* Deal with an assignment to a macro * +*************************************************/ + +/* This function is called when a line that starts with an upper case letter is +encountered. The argument "line" should contain a complete logical line, and +start with the first letter of the macro name. The macro name and the +replacement text are extracted and stored. Redefinition of existing, +non-command line, macros is permitted using '==' instead of '='. + +Arguments: + s points to the start of the logical line + +Returns: nothing +*/ + +static void +read_macro_assignment(uschar *s) +{ +uschar name[64]; +int namelen = 0; +BOOL redef = FALSE; +macro_item *m; +macro_item *mlast = NULL; + +while (isalnum(*s) || *s == '_') + { + if (namelen >= sizeof(name) - 1) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, + "macro name too long (maximum is %d characters)", sizeof(name) - 1); + name[namelen++] = *s++; + } +name[namelen] = 0; + +while (isspace(*s)) s++; +if (*s++ != '=') + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "malformed macro definition"); + +if (*s == '=') + { + redef = TRUE; + s++; + } +while (isspace(*s)) s++; + +/* If an existing macro of the same name was defined on the command line, we +just skip this definition. It's an error to attempt to redefine a macro without +redef set to TRUE, or to redefine a macro when it hasn't been defined earlier. +It is also an error to define a macro whose name begins with the name of a +previously defined macro. Note: it is documented that the other way round +works. */ + +for (m = macros; m != NULL; m = m->next) + { + int len = Ustrlen(m->name); + + if (Ustrcmp(m->name, name) == 0) + { + if (!m->command_line && !redef) + log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "macro \"%s\" is already " + "defined (use \"==\" if you want to redefine it", name); + break; + } + + if (len < namelen && Ustrstr(name, m->name) != NULL) + log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " + "a macro because previously defined macro \"%s\" is a substring", + name, m->name); + + /* We cannot have this test, because it is documented that a substring + macro is permitted (there is even an example). + * + * if (len > namelen && Ustrstr(m->name, name) != NULL) + * log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " + * "a macro because it is a substring of previously defined macro \"%s\"", + * name, m->name); + */ + + mlast = m; + } + +/* Check for an overriding command-line definition. */ + +if (m != NULL && m->command_line) return; + +/* Redefinition must refer to an existing macro. */ + +if (redef) + { + if (m == NULL) + log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "can't redefine an undefined macro " + "\"%s\"", name); + } + +/* We have a new definition. The macro_item structure includes a final vector +called "name" which is one byte long. Thus, adding "namelen" gives us enough +room to store the "name" string. */ + +else + { + m = store_get(sizeof(macro_item) + namelen); + if (macros == NULL) macros = m; else mlast->next = m; + Ustrncpy(m->name, name, namelen); + m->name[namelen] = 0; + m->next = NULL; + m->command_line = FALSE; + } + +/* Set the value of the new or redefined macro */ + +m->replacement = string_copy(s); +} + + + + /************************************************* * Read configuration line * @@ -2631,65 +2747,7 @@ a macro definition. */ while ((s = get_config_line()) != NULL) { - if (isupper(s[0])) - { - macro_item *m; - macro_item *mlast = NULL; - uschar name[64]; - int namelen = 0; - - while (isalnum(*s) || *s == '_') - { - if (namelen >= sizeof(name) - 1) - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "macro name too long (maximum is %d characters)", sizeof(name) - 1); - name[namelen++] = *s++; - } - name[namelen] = 0; - while (isspace(*s)) s++; - if (*s++ != '=') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, - "malformed macro definition"); - while (isspace(*s)) s++; - - /* If an existing macro of the same name was defined on the command line, - we just skip this definition. Otherwise it's an error to attempt to - redefine a macro. It is also an error to define a macro whose name begins - with the name of a previously-defined macro. */ - - for (m = macros; m != NULL; m = m->next) - { - int len = Ustrlen(m->name); - - if (Ustrcmp(m->name, name) == 0) - { - if (m->command_line) break; - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "macro \"%s\" is already " - "defined", name); - } - - if (len < namelen && Ustrstr(name, m->name) != NULL) - log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as " - "a macro because previously defined macro \"%s\" is a substring", - name, m->name); - - mlast = m; - } - if (m != NULL) continue; /* Found an overriding command-line definition */ - - m = store_get(sizeof(macro_item) + namelen); - m->next = NULL; - m->command_line = FALSE; - if (mlast == NULL) macros = m; else mlast->next = m; - - /* This use of strcpy() is OK because we have obtained a block of store - whose size is based on the length of "name". The definition of the - macro_item structure includes a final vector called "name" which is one - byte long. Thus, adding "namelen" gives us enough room to store the "name" - string. */ - - Ustrcpy(m->name, name); - m->replacement = string_copy(s); - } + if (isupper(s[0])) read_macro_assignment(s); else if (Ustrncmp(s, "domainlist", 10) == 0) read_named_list(&domainlist_anchor, &domainlist_count, @@ -3071,16 +3129,33 @@ driver_instance **p = anchor; driver_instance *d = NULL; uschar *buffer; -/* Now process the configuration lines */ - while ((buffer = get_config_line()) != NULL) { uschar name[64]; + uschar *s; - /* Read the first name on the line and test for the start of a new driver. - If this isn't the start of a new driver, the line will be re-read. */ + /* Read the first name on the line and test for the start of a new driver. A + macro definition indicates the end of the previous driver. If this isn't the + start of a new driver, the line will be re-read. */ - uschar *s = readconf_readname(name, sizeof(name), buffer); + s = readconf_readname(name, sizeof(name), buffer); + + /* Handle macro definition, first finishing off the initialization of the + previous driver, if any. */ + + if (isupper(*name) && *s == '=') + { + if (d != NULL) + { + if (d->driver_name == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG, + "no driver defined for %s \"%s\"", class, d->name); + (d->info->init)(d); + d = NULL; + } + read_macro_assignment(buffer); + continue; + } /* If the line starts with a name terminated by a colon, we are at the start of the definition of a new driver. The rest of the line must be @@ -3128,7 +3203,8 @@ while ((buffer = get_config_line()) != NULL) continue; } - /* Give an error if we have not set up a current driver yet. */ + /* Not the start of a new driver. Give an error if we have not set up a + current driver yet. */ if (d == NULL) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%s name missing", class); @@ -3582,7 +3658,8 @@ if (skip) return; } -/* Read each ACL and add it into the tree */ +/* Read each ACL and add it into the tree. Macro (re)definitions are allowed +between ACLs. */ acl_line = get_config_line(); @@ -3593,8 +3670,15 @@ while(acl_line != NULL) uschar *error; p = readconf_readname(name, sizeof(name), acl_line); - if (*p != ':') - log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing ACL name"); + if (isupper(*name) && *p == '=') + { + read_macro_assignment(acl_line); + acl_line = get_config_line(); + continue; + } + + if (*p != ':' || name[0] == 0) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name"); node = store_get(sizeof(tree_node) + Ustrlen(name)); Ustrcpy(node->name, name); -- 2.30.2 From acb1b3461349256ee2422aa39b6f2d810681ae47 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 5 Apr 2005 14:02:30 +0000 Subject: [PATCH 13/16] cyrus_sasl authenticator was not using the expanded hostname (even though it did expand it :-) --- doc/doc-txt/ChangeLog | 5 ++++- src/src/auths/cyrus_sasl.c | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index ff8c2835d..8a7274491 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.108 2005/04/05 13:58:34 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.109 2005/04/05 14:02:30 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -122,6 +122,9 @@ PH/21 Added acl_not_smtp_mime to allow for MIME scanning for non-SMTP messages. PH/22 Added support for macro redefinition, and (re)definition in between driver and ACL definitions. +PH/23 The cyrus_sasl authenticator was expanding server_hostname, but then + forgetting to use the resulting value; it was using the unexpanded value. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index 4d75aa434..849c3d1c0 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */ +/* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.2 2005/04/05 14:02:30 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -190,8 +190,9 @@ if (rc != SASL_OK) return DEFER; } -rc=sasl_server_new(CS ob->server_service, CS ob->server_hostname, - CS ob->server_realm, NULL, NULL, NULL, 0, &conn); +rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL, + NULL, NULL, 0, &conn); + if( rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; -- 2.30.2 From c5ddb310a1f89a0560eea67879921570b046b179 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 5 Apr 2005 14:33:27 +0000 Subject: [PATCH 14/16] Patch to fix Cyrus-SASL unavailable mechanisms problem. --- doc/doc-txt/ChangeLog | 27 ++++++++++++++++++++++++++- src/ACKNOWLEDGMENTS | 3 ++- src/src/auths/cyrus_sasl.c | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 8a7274491..d5c658131 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.109 2005/04/05 14:02:30 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.110 2005/04/05 14:33:27 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -125,6 +125,31 @@ PH/22 Added support for macro redefinition, and (re)definition in between PH/23 The cyrus_sasl authenticator was expanding server_hostname, but then forgetting to use the resulting value; it was using the unexpanded value. +PH/24 The cyrus_sasl authenticator was advertising mechanisms for which it + hadn't been configured. The fix is from Juergen Kreileder, who + understands it better than I do: + + "Here's what I see happening with three configured cyrus_sasl + authenticators configured (plain, login, cram-md5): + + On startup auth_cyrus_sasl_init() gets called for each of these. + This means three calls to sasl_listmech() without a specified mech_list. + => SASL tests which mechs of all available mechs actually work + => three warnings about OTP not working + => the returned list contains: plain, login, cram-md5, digest-md5, ... + + With the patch, sasl_listmech() also gets called three times. But now + SASL's mech_list option is set to the server_mech specified in the the + authenticator. Or in other words, the answer from sasl_listmech() + gets limited to just the mech you're testing for (which is different + for each call.) + => the return list contains just 'plain' or 'login', 'cram-md5' or + nothing depending on the value of ob->server_mech. + + I've just tested the patch: Authentication still works fine, + unavailable mechs specified in the exim configuration are still + caught, and the auth.log warnings about OTP are gone." + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index ce5402eb8..86bc64f60 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.19 2005/04/05 13:58:35 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.20 2005/04/05 14:33:27 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -159,6 +159,7 @@ Alex Kiernan Patch for libradius Tom Kistner SPA server code Writing and maintaining the content scanning extension (exiscan) +Jürgen Kreileder Fix for cyrus_sasl advertisement problem Friso Kuipers Patch for GDBM problem Chris Liddiard Fix for bug in exiqsumm Chris Lightfoot Patch for -restore-times in exim_lock diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index 849c3d1c0..8651dc605 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.2 2005/04/05 14:02:30 ph10 Exp $ */ +/* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.3 2005/04/05 14:33:27 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -7,7 +7,7 @@ /* Copyright (c) University of Cambridge 1995 - 2003 */ /* See the file NOTICE for conditions of use and distribution. */ -/* This code was contributed by Matthew Byng-Maddick */ +/* This code was originally contributed by Matthew Byng-Maddick */ /* Copyright (c) A L Digital 2004 */ @@ -71,18 +71,42 @@ auth_cyrus_sasl_options_block auth_cyrus_sasl_option_defaults = { enable consistency checks to be done, or anything else that needs to be set up. */ + +/* Auxiliary function, passed in data to sasl_server_init(). */ + +static int +mysasl_config(void *context, + const char *plugin_name, + const char *option, + const char **result, + unsigned int *len) +{ +if (context && !strcmp(option, "mech_list")) + { + *result = context; + if (len != NULL) *len = strlen(*result); + return SASL_OK; + } +return SASL_FAIL; +} + +/* Here's the real function */ + void auth_cyrus_sasl_init(auth_instance *ablock) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); -sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}}; -sasl_conn_t *conn; uschar *list, *listptr, *buffer; int rc, i; unsigned int len; uschar *rs_point; +sasl_conn_t *conn; +sasl_callback_t cbs[]={ + {SASL_CB_GETOPT, NULL, NULL }, + {SASL_CB_LIST_END, NULL, NULL}}; + /* default the mechanism to our "public name" */ if(ob->server_mech == NULL) ob->server_mech=string_copy(ablock->public_name); @@ -90,7 +114,12 @@ if(ob->server_mech == NULL) /* we're going to initialise the library to check that there is an * authenticator of type whatever mechanism we're using */ + +cbs[0].proc = &mysasl_config; +cbs[0].context = ob->server_mech; + rc=sasl_server_init(cbs, "exim"); + if( rc != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL library.", ablock->name); -- 2.30.2 From c2c19e9d1770ce26d595d9300f1f2e8c68125ba4 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Tue, 5 Apr 2005 15:47:50 +0000 Subject: [PATCH 15/16] Change 4.51/PH/05 wasn't implemented quite correctly. I think I've now sorted it. --- doc/doc-txt/ChangeLog | 4 ++-- src/src/deliver.c | 27 +++++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index d5c658131..22e76ad56 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.110 2005/04/05 14:33:27 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.111 2005/04/05 15:47:50 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -38,7 +38,7 @@ PH/04 Change 4.11/85 fixed an obscure bug concerned with addresses that are "previously delivered" was not happening when checking to see if an address could be batched with a previous (undelivered) one; under certain circumstances this could lead to multiple deliveries to the same - address. A one-line patch to add the appropriate test fixes the bug. + address. PH/05 Renamed the macro SOCKLEN_T as EXIM_SOCKLEN_T because AIX uses SOCKLEN_T in its include files, and this causes problems building Exim. diff --git a/src/src/deliver.c b/src/src/deliver.c index 7dbb94fc6..cc9b8ee0f 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/deliver.c,v 1.9 2005/03/22 14:50:10 ph10 Exp $ */ +/* $Cambridge: exim/src/src/deliver.c,v 1.10 2005/04/05 15:47:50 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1449,18 +1449,21 @@ return rc; *************************************************/ /* Check that this base address hasn't previously been delivered to its routed -transport. The check is necessary at delivery time in order to handle homonymic -addresses correctly in cases where the pattern of redirection changes between -delivery attempts (so the unique fields change). Non-homonymic previous -delivery is detected earlier, at routing time (which saves unnecessary -routing). +transport. If it has been delivered, mark it done. The check is necessary at +delivery time in order to handle homonymic addresses correctly in cases where +the pattern of redirection changes between delivery attempts (so the unique +fields change). Non-homonymic previous delivery is detected earlier, at routing +time (which saves unnecessary routing). + +Arguments: + addr the address item + testing TRUE if testing wanted only, without side effects -Argument: the address item Returns: TRUE if previously delivered by the transport */ static BOOL -previously_transported(address_item *addr) +previously_transported(address_item *addr, BOOL testing) { (void)string_format(big_buffer, big_buffer_size, "%s/%s", addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name); @@ -1470,7 +1473,7 @@ if (tree_search(tree_nonrecipients, big_buffer) != 0) DEBUG(D_deliver|D_route|D_transport) debug_printf("%s was previously delivered (%s transport): discarded\n", addr->address, addr->transport->name); - child_done(addr, tod_stamp(tod_log)); + if (!testing) child_done(addr, tod_stamp(tod_log)); return TRUE; } @@ -2057,7 +2060,7 @@ while (addr_local != NULL) attempts. Non-homonymic previous delivery is detected earlier, at routing time. */ - if (previously_transported(addr)) continue; + if (previously_transported(addr, FALSE)) continue; /* There are weird cases where logging is disabled */ @@ -2112,7 +2115,7 @@ while (addr_local != NULL) { BOOL ok = tp == next->transport && - !previously_transported(next) && + !previously_transported(next, TRUE) && (!uses_lp || Ustrcmp(next->local_part, addr->local_part) == 0) && (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0) && same_strings(next->p.errors_address, addr->p.errors_address) && @@ -3390,7 +3393,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) attempts. Non-homonymic previous delivery is detected earlier, at routing time. */ - if (previously_transported(addr)) continue; + if (previously_transported(addr, FALSE)) continue; /* Force failure if the message is too big. */ -- 2.30.2 From 31619da69c9e692f006db273d95d20ae279a7d39 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Wed, 6 Apr 2005 10:06:14 +0000 Subject: [PATCH 16/16] Show command line arguments in debugging output, even without log_selector=+arguments. --- doc/doc-txt/ChangeLog | 6 +++++- src/src/exim.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 22e76ad56..570e23a41 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.111 2005/04/05 15:47:50 ph10 Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.112 2005/04/06 10:06:14 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -150,6 +150,10 @@ PH/24 The cyrus_sasl authenticator was advertising mechanisms for which it unavailable mechs specified in the exim configuration are still caught, and the auth.log warnings about OTP are gone." +PH/25 When debugging is enabled, the contents of the command line are added + to the debugging output, even when log_selector=+arguments is not + specified. + A note about Exim versions 4.44 and 4.50 ---------------------------------------- diff --git a/src/src/exim.c b/src/src/exim.c index ffe596d15..35151c28c 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.17 2005/03/22 14:11:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.18 2005/04/06 10:06:14 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -3237,8 +3237,8 @@ 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 ((log_extra_selector & LX_arguments) != 0 && really_exim - && !list_options && !checking) +if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0) + && really_exim && !list_options && !checking) { int i; uschar *p = big_buffer; @@ -3270,7 +3270,11 @@ if ((log_extra_selector & LX_arguments) != 0 && really_exim (p - big_buffer) - 4), printing, quote); while (*p) p++; } - log_write(0, LOG_MAIN, "%s", big_buffer); + + if ((log_extra_selector & LX_arguments) != 0) + log_write(0, LOG_MAIN, "%s", big_buffer); + else + debug_printf("%s\n", big_buffer); } /* Set the working directory to be the top-level spool directory. We don't rely -- 2.30.2