--- Local/sa-exim.c.orig 2025-12-18 04:08:13.593344000 +0100 +++ Local/sa-exim.c 2025-12-18 04:10:17.527828000 +0100 @@ -29,10 +29,7 @@ #include "sa-exim.h" /* Exim includes */ -#include "local_scan.h" -extern FILE *smtp_out; /* Exim's incoming SMTP output file */ -extern int body_linecount; /* Line count in body */ -extern uschar *primary_hostname; +#include #ifdef DLOPEN_LOCAL_SCAN @@ -409,6 +406,11 @@ if (buffer[strlen(buffer)-1] == '\n') { buffer[strlen(buffer)-1]=0; + /* and any carriage return */ + if (buffer[strlen(buffer)-1] == '\r') + { + buffer[strlen(buffer)-1]=0; + } } if (SAEximDebug > 5) { @@ -515,6 +517,7 @@ int pid; int writefd[2]; int readfd[2]; + char *spamc_argv[10]; int i; /* These are the only values that we want working after the longjmp * The automatic ones can be clobbered, but we don't really care */ @@ -536,8 +539,8 @@ time_t beforescan; time_t afterscan; time_t afterwait; - time_t scantime=0; - time_t fulltime=0; + int scantime=0; + int fulltime=0; struct stat stbuf; uschar *expand; @@ -550,8 +553,9 @@ static char *SAspamcpath=SPAMC_LOCATION; static char *SAsafemesgidchars=SAFEMESGIDCHARS static char *SAspamcSockPath=NULL; - static char *SAspamcPort="783"; - static char *SAspamcHost="127.0.0.1"; + static char *SAspamcPort=NULL; + static char *SAspamcHost=NULL; + static char *SAspamcUser=NULL; static char *SAEximRunCond="0"; static char *SAEximRejCond="1"; static int SAmaxbody=250*1024; @@ -602,6 +606,10 @@ /* Do not put a %s in there, or you'll segfault */ static char *SAmsgerror="Temporary local error while processing message, please contact postmaster"; + /* This needs to be retrieved through expand_string in order + not to violate the API. */ + uschar *primary_hostname=expand_string("$primary_hostname"); + /* New values we read from spamassassin */ char *xspamstatus=NULL; char *xspamflag=NULL; @@ -712,6 +720,7 @@ M_CHECKFORSTR(SAspamcSockPath); M_CHECKFORSTR(SAspamcPort); M_CHECKFORSTR(SAspamcHost); + M_CHECKFORSTR(SAspamcUser); M_CHECKFORSTR(SAEximRunCond); M_CHECKFORSTR(SAEximRejCond); M_CHECKFORVAR(SAmaxbody, "%d"); @@ -914,6 +923,22 @@ ret=dup2(readfd[1],2); CHECKERR(ret,"dup2 stderr",__LINE__); + i = 0; + spamc_argv[i++] = "spamc"; + if (SAspamcUser && SAspamcUser[0]) + { + expand=expand_string(SAspamcUser); + if (expand == NULL) + { + log_write(0, LOG_MAIN | LOG_PANIC, "SA: SAspamcUser expansion failure on %s, will run as Exim user instead.", SAspamcUser); + } + else if (expand[0] != '\0') + { + spamc_argv[i++] = "-u"; + spamc_argv[i++] = expand; + } + } + /* * I could implement the spamc protocol and talk to spamd directly * instead of forking spamc, but considering the overhead spent @@ -924,17 +949,30 @@ /* Ok, we cheat, spamc cares about how big the whole message is and * we only know about the body size, so I'll give an extra 16K * to account for any headers that can accompany the message */ + + spamc_argv[i++] = "-s"; + spamc_argv[i++] = string_sprintf("%d", SAmaxbody+16384); + if(SAspamcSockPath) { - ret=execl(SAspamcpath, "spamc", "-s", string_sprintf("%d", SAmaxbody+16384), "-U", SAspamcSockPath, NULL); - CHECKERR(ret,string_sprintf("exec %s", SAspamcpath),__LINE__); + spamc_argv[i++] = "-U"; + spamc_argv[i++] = SAspamcSockPath; } else { - ret=execl(SAspamcpath, "spamc", "-s", string_sprintf("%d", SAmaxbody+16384), "-d", SAspamcHost, "-p", SAspamcPort, NULL); - CHECKERR(ret,string_sprintf("exec %s", SAspamcpath),__LINE__); + if (SAspamcHost) { + spamc_argv[i++] = "-d"; + spamc_argv[i++] = SAspamcHost; + } + if (SAspamcPort) { + spamc_argv[i++] = "-p"; + spamc_argv[i++] = SAspamcPort; + } } - + spamc_argv[i++] = NULL; + + ret=execv(SAspamcpath, spamc_argv); + CHECKERR(ret,string_sprintf("exec %s", SAspamcpath),__LINE__); } if (SAEximDebug > 8) @@ -1045,6 +1083,11 @@ if (buffer[strlen(buffer)-1] == '\n') { buffer[strlen(buffer)-1]=0; + /* and any carriage return */ + if (buffer[strlen(buffer)-1] == '\r') + { + buffer[strlen(buffer)-1]=0; + } } restart: if (SAEximDebug > 5) @@ -1154,7 +1197,7 @@ { if (SAEximDebug > 5) { - log_write(0, LOG_MAIN, "SA: Debug6: spamc read got newline, end of headers", buffer); + log_write(0, LOG_MAIN, "SA: Debug6: spamc read got newline, end of headers"); } goto exit; } @@ -1214,11 +1257,11 @@ { if (SAEximDebug > 8) { - log_write(0, LOG_MAIN, "SA: Debug9: Read body from SA; line %d (read %d)", line, strlen(buffer)); + log_write(0, LOG_MAIN, "SA: Debug9: Read body from SA; line %d (read %zd)", line, strlen(buffer)); } stret=write(fd, buffer, strlen(buffer)); - CHECKERR(stret,string_sprintf("SA body write to msg"),__LINE__); + CHECKERR(stret,string_sprintf("%s", "SA body write to msg"),__LINE__); if (SAEximDebug > 8) { log_write(0, LOG_MAIN, "SA: Debug9: Wrote to msg; line %d (wrote %d)", line, ret); @@ -1229,18 +1272,20 @@ } } + if (SAEximDebug > 1) { log_write(0, LOG_MAIN, "SA: Debug2: body_linecount before SA: %d", body_linecount); } /* update global variable $body_linecount to reflect the new body size*/ - body_linecount = (line - 1); + if (body_linecount > 0) body_linecount = (line - 1); // Not updating if zero, indicating spool_wireformat if (SAEximDebug > 1) { log_write(0, LOG_MAIN, "SA: Debug2: body_linecount after SA: %d", body_linecount); } + } fclose((FILE *)readfh); @@ -1331,6 +1376,9 @@ if (dorej && doteergrube) { + char *teergrubewaitstr; + teergrubewaitstr=string_sprintf(SAmsgteergrubewait, spamstatus); + /* By default, we'll only save temp bounces by message ID so * that when the same message is submitted several times, we * overwrite the same file on disk and not create a brand new @@ -1353,20 +1401,8 @@ for (i=0;i