1. Check the exit status of pipes and treat non-zero exit statuses as failures. 2. Be compatible with libmilter versions prior to sendmail 8.14's. 3. Add "-b" command-line option to fork into the background. --- Action.c 2010/10/28 16:53:24 1.1 +++ Action.c 2010/10/28 16:58:06 @@ -596,6 +596,8 @@ /* ActionPipe: Pipes the full mail to the program specified in arg. */ bool ActionPipe(Action* pipeto, time_t* stamp, mlfiPriv_t* priv) { + bool ok = TRUE; + if (pipeto->allTo && pipeto->addrItr == NULL) { /* We need to perform the action for every matched TO address, this is the first iteration so we need to set our iterator to the first matched @@ -621,7 +623,13 @@ PrintMail(pipe, stamp, priv); /* Close pipe and return */ - pclose(pipe); + if (pclose(pipe)) { + /* Non-zero exit status */ + char msg[strlen(program)+30]; // 30 bytes is for the message text below + sprintf(msg, "Failure executing program '%s'.", program); + MemErrorPrint("ActionPipe", msg, 2); + ok = FALSE; + } /* Free dynamically generated program name */ free(program); @@ -633,8 +641,9 @@ pipeto->addrItr = pipeto->addrItr->next; if (pipeto->addrItr) - return (ActionPipe(pipeto, stamp, priv)); + if (! ActionPipe(pipeto, stamp, priv)) + ok = FALSE; } - return (TRUE); + return (ok); } --- ArchiveSMTP.c 2010/10/28 16:16:00 1.1 +++ ArchiveSMTP.c 2010/10/28 18:13:28 @@ -53,9 +53,15 @@ mlfi_eom, /* end of message */ mlfi_abort, /* message aborted */ mlfi_close, /* connection cleanup */ +#if SMFI_VERSION > 2 mlfi_unknown, /* unknown SMTP commands */ +#endif +#if SMFI_VERSION > 3 mlfi_data, /* DATA command */ +#endif +#ifdef SM_LM_VRS_MAJOR mlfi_negotiate /* Once, at the start of each SMTP connection */ +#endif }; /* mlfi_envfrom: @@ -491,6 +497,7 @@ return SMFIS_CONTINUE; } +#ifdef SM_LM_VRS_MAJOR /* mlfi_negotiate: Tells the MTA what our conditions are and stuff like that. */ sfsistat mlfi_negotiate (SMFICTX *ctx, @@ -555,13 +562,18 @@ DebugPrint("ArchiveSMTP:mlfi_negotiate:%s\n", "returning\n"); return SMFIS_CONTINUE; } +#endif /* Unused Callbacks: Defined only so we can negotiate with an MTA that doesn't support ignoring these callbacks. */ sfsistat mlfi_connect (SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { return SMFIS_CONTINUE; } sfsistat mlfi_helo (SMFICTX *ctx, char *helohost) { return SMFIS_CONTINUE; } +#if SMFI_VERSION > 3 sfsistat mlfi_data (SMFICTX *ctx) { return SMFIS_CONTINUE; } +#endif +#if SMFI_VERSION > 2 sfsistat mlfi_unknown (SMFICTX *ctx, const char *arg) { return SMFIS_CONTINUE; } +#endif sfsistat mlfi_eoh (SMFICTX *ctx) { return SMFIS_CONTINUE; } sfsistat mlfi_close (SMFICTX *ctx) { return SMFIS_CONTINUE; } @@ -938,7 +950,7 @@ static void usage(char *prog) { fprintf(stderr, - "Usage: %s [-adhnv] [-r pidfile] [-t timeout] [-u username] -f filename -p port\n", + "Usage: %s [-abdhnv] [-r pidfile] [-t timeout] [-u username] -f filename -p port\n", prog); } @@ -965,7 +977,7 @@ */ /* Our argument list */ - const char *args = "adf:hnp:r:t:u:v"; + const char *args = "abdf:hnp:r:t:u:v"; /* Argument Set Flags */ bool sockPortSet = FALSE; @@ -975,6 +987,7 @@ bool pidFileSet = FALSE; bool timeOutSet = FALSE; bool deleteSock = TRUE; + bool background = FALSE; /* Argument Strings */ char *sockPort = NULL; @@ -993,6 +1006,9 @@ case 'a': /* Always store mail, reject mail if storage fails */ alwaysAccept = FALSE; break; + case 'b': /* fork into background */ + background = TRUE; + break; case 'd': /* Don't delete socket on start up */ deleteSock = FALSE; break; @@ -1030,10 +1046,16 @@ } } + if (background && daemon(0, 0)) { + fprintf(stderr, "Unable to background (errno: %d:%s)\n", userName, errno, strerror(errno)); + exit(EX_SOFTWARE); + } + /* Verbose start-up message */ VerbosePrint(1, "ArchiveSMTP Version %s started. ", ArchiveSMTPVersion); VerbosePrint(1, "Running with verbose level %d.\n", verboseLevel); +#ifdef SM_LM_VRS_MAJOR /* Print out library version information if running verbose level > 1 */ if (verboseLevel > 1) { VerbosePrint(2, "- %s", "Compiled with libmilter v"); @@ -1053,6 +1075,7 @@ VerbosePrint(2, "%d.", vRuntimeMinor); VerbosePrint(2, "%d\n\n", vRuntimePatch); } +#endif /* First action should be to switch user if one was given */ if (userNameSet) { --- archivesmtp.8 2010/10/28 18:16:11 1.1 +++ archivesmtp.8 2010/10/28 18:17:10 @@ -13,7 +13,7 @@ .Nd SMTP mail archiver .Sh SYNOPSIS \" Section Header - required - don't modify .Nm -.Op Fl adhnv \" [-abcd] +.Op Fl abdhnv \" [-abcd] .Op Fl r Ar pidfile \" [-a path] .Op Fl t Ar timeout .Op Fl u Ar username @@ -33,6 +33,9 @@ temporary failure message should something prevent its storage. Use with care, simply having a rule with a path that is not writable would result in all messages that match the rule being rejected. +.It Fl b +Detach from the terminal and run in the background (useful from init +scripts). .It Fl d Don't unlink local or unix domain sockets prior to attempting to open them, if they exist the open will fail and the program will exit with an error. In normal