/*
* Program: Synonym
* File: synonym.c
* Author: Ionut Nistor
* Date: 20 Feb 2003
*
* $Id: synonym.c,v 1.8.2.2 2004/01/19 12:20:30 diciu Exp $
*
* Licensed under the Modulo Consulting Software License
* (see file license.txt)
*
*/
const char synonym_c_objid[]="$Id: synonym.c,v 1.8.2.2 2004/01/19 12:20:30 diciu Exp $";
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <syslog.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#include <pthread.h>
#include <libmilter/mfapi.h>
#include "synonym.h"
#include "config.h"
#include "filtering.h"
#include "milter_data.h"
#ifdef DISCLAIMER_SUPPORT
#include "body_parser.h"
#endif
extern sfsistat mlfi_cleanup(SMFICTX *, BOOL);
_type_synonym_config synonym_config;
void free_matched_action_list(matched_action * m_list);
sfsistat
mlfi_envfrom(ctx, envfrom)
SMFICTX *ctx;
char **envfrom;
{
/* We got a connection let's se where it is from and store the originator for further reference */
synonym_priv *priv;
syslog(LOG_DEBUG, "Envfrom called");
priv = (synonym_priv*)malloc(sizeof(synonym_priv));
if(priv == NULL)
{
syslog(LOG_EMERG, "*** SERIOUS CONDITION - MEMORY ALLOCATION FAILED - SYSTEM UNSTABLE - TAKE IMMEDIATE ACTION ***");
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
priv->resulted_actions = NULL;
priv->headers = NULL;
priv->error_encountered = FALSE;
strncpy(priv->env_from, *envfrom, MAX_EMAIL);
priv->env_from[MAX_EMAIL] = '\0';
priv->env_to=NULL;
#ifdef DISCLAIMER_SUPPORT
/* initialise disclaimer data */
syslog(LOG_DEBUG, "Initialising disclaimer data");
priv->output_stream = NULL;
strcpy(priv->temp_filename, "");
priv->bp_state = NULL;
#endif
smfi_setpriv(ctx, priv);
return SMFIS_CONTINUE;
}
sfsistat
mlfi_envrcpt(ctx, envrcpt)
SMFICTX *ctx;
char **envrcpt;
{
synonym_priv * priv;
to_list *new_to;
priv = smfi_getpriv(ctx);
if(priv == NULL)
{
syslog(LOG_ERR, "Cannot get mail context. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->error_encountered)
return SMFIS_CONTINUE;
/* Allocate new 'to' element */
new_to = (to_list*)malloc(sizeof(to_list));
if(new_to == NULL)
{
syslog(LOG_EMERG, "*** SERIOUS CONDITION - MEMORY ALLOCATION FAILED - SYSTEM UNSTABLE - TAKE IMMEDIATE ACTION ***");
priv->error_encountered=TRUE;
return SMFIS_CONTINUE;
}
strncpy(new_to->email, *envrcpt, MAX_EMAIL);
new_to->email[MAX_EMAIL] = '\0';
new_to->next = NULL;
if(priv->env_to == NULL)
priv->env_to = new_to;
else
{
while(priv->env_to->next != NULL)
priv->env_to=priv->env_to->next;
priv->env_to->next = new_to;
}
return SMFIS_CONTINUE;
}
sfsistat
mlfi_header(ctx, headerf, headerv)
SMFICTX *ctx;
char *headerf;
char *headerv;
{
synonym_header *new_header, *temp_header;
synonym_priv * priv;
priv = smfi_getpriv(ctx);
if(priv == NULL)
{
syslog(LOG_ERR, "Cannot get mail context. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->error_encountered)
return SMFIS_CONTINUE;
/* Store the headers */
/* Alloc the new header */
new_header = (synonym_header*) malloc(sizeof(synonym_header));
if(new_header == NULL)
{
syslog(LOG_CRIT, "CRITICAL: Memory allocation problem - cannot process the email");
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
new_header->next = NULL;
/* Set the values */
strncpy(new_header->header_name, headerf, MAX_HEADER_NAME_SIZE);
new_header->header_name[MAX_HEADER_NAME_SIZE]='\0';
strncpy(new_header->header_value, headerv, MAX_HEADER_VALUE_SIZE);
new_header->header_value[MAX_HEADER_VALUE_SIZE]='\0';
/* Link it to the end of the list */
if(priv->headers == NULL)
priv->headers = new_header;
else
{
temp_header=priv->headers;
while(temp_header->next!=NULL)
temp_header = temp_header->next;
temp_header->next = new_header;
}
return SMFIS_CONTINUE;
}
sfsistat
mlfi_eoh(ctx)
SMFICTX *ctx;
{
synonym_priv * priv;
sresult result;
priv = smfi_getpriv(ctx);
if(priv == NULL)
{
syslog(LOG_ERR, "Cannot get mail context. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->error_encountered)
return SMFIS_CONTINUE;
if(synonym_config.rules == NULL)
{
syslog(LOG_ERR, "No rules appear to be configured. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->headers == NULL)
syslog(LOG_WARNING, "Message contains no headers. Weird");
/* Start processing rules - we should have all the required informtion at this point */
if((result = Synonym_Process_Rules(synonym_config.rules, priv->headers, priv->env_from, priv->env_to, &priv->resulted_actions)) != SYNONYM_OK)
{
syslog(LOG_ERR, "Failed to process the synonym rules - result code %d. Accepting message", result);
return SMFIS_CONTINUE;
}
/* We got all the actions that matched header conditions */
return SMFIS_CONTINUE;
}
sfsistat
mlfi_body(ctx, bodyp, bodylen)
SMFICTX *ctx;
u_char *bodyp;
size_t bodylen;
{
synonym_priv *priv;
#ifdef DISCLAIMER_SUPPORT
int temp_fd;
#endif
priv = smfi_getpriv(ctx);
if(priv == NULL)
{
syslog(LOG_ERR, "Cannot get mail context. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->error_encountered)
return SMFIS_CONTINUE; /* At some point there was an error so we proceed no longer */
syslog(LOG_DEBUG, "mlfi_body called");
if(priv!=NULL)
{
#ifdef DISCLAIMER_SUPPORT
/* dump the body content into a temporary file */
if(priv->output_stream == NULL)
{
syslog(LOG_DEBUG, "Output stream was not yet initialised");
strcpy(priv->temp_filename, "/tmp/synonymXXXXXX");
if((temp_fd=mkstemp(priv->temp_filename))<0)
{
syslog(LOG_ERR, "Failed to open the temporary file");
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
priv->output_stream = fdopen(temp_fd, "w");
if(priv->output_stream == NULL)
{
syslog(LOG_ERR, "Could not open file %s for write. ", priv->temp_filename);
close(temp_fd); // Close the file descriptor cause is was open - if fdopen fails, the fd remains open
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
if(fwrite((char *)bodyp, 1, bodylen, priv->output_stream)!= bodylen)
{
syslog(LOG_ERR, "Failed to write to the temp file. Check disk space");
fclose(priv->output_stream);
unlink(priv->temp_filename);
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
}
else
if(fwrite((char *)bodyp, 1, bodylen, priv->output_stream) != bodylen)
{
syslog(LOG_ERR, "Failed to add body data to the temp file");
fclose(priv->output_stream);
unlink(priv->temp_filename);
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
#endif
}
return SMFIS_CONTINUE;
}
sfsistat
mlfi_eom(ctx)
SMFICTX *ctx;
{
synonym_priv *priv;
matched_action *temp_action;
char smtp_reply[MAX_SMTP_REPLY_SIZE+1];
BOOL reject_email=FALSE, delete_email=FALSE, add_copy=FALSE;
char copyto_list[MAX_EMAIL*5 + 1 + sizeof(SYNONYM_COPIEDBY)]; /* We shall list max 5 addresses */
#ifdef DISCLAIMER_SUPPORT
struct stat statstruct;
long file_length = 0;
int count;
char fread_buffer[65000];
char filename[1000];
char newfilename[1000];
sfsistat rstat = SMFIS_CONTINUE;
int retval = 0;
int add_disclaimer = SUBTYPE_NONE;
char disclaimer_text[MAX_DISCLAIMER_SIZE+1], disclaimer_html[MAX_DISCLAIMER_SIZE+1];
char *all_headers = NULL;
synonym_header *temp_header;
FILE * fd_processed;
#endif
priv = smfi_getpriv(ctx);
if(priv == NULL)
{
syslog(LOG_ERR, "Cannot get mail context. Accepting message");
return SMFIS_CONTINUE;
}
if(priv->error_encountered)
return SMFIS_CONTINUE;
strcpy(copyto_list, SYNONYM_COPIEDBY);
/* Perform the matched actions */
if(priv->resulted_actions != NULL)
for(temp_action=priv->resulted_actions; temp_action != NULL; temp_action=temp_action->next)
switch(temp_action->action.action_type)
{
case ACTION_COPY:
add_copy = TRUE;
smfi_addrcpt(ctx, temp_action->action.action_custom_field);
if(strlen(copyto_list) + strlen(temp_action->action.action_custom_field) <= MAX_EMAIL*5 + 3)
{
strcat(copyto_list, temp_action->action.action_custom_field);
strcat(copyto_list, ", ");
}
break;
case ACTION_DELETE:
delete_email=TRUE;
break;
case ACTION_REJECT:
strncpy(smtp_reply, temp_action->action.action_custom_field, MAX_SMTP_REPLY_SIZE);
smtp_reply[MAX_SMTP_REPLY_SIZE] = '\0';
reject_email=TRUE;
break;
case ACTION_DISCLAIMER:
#ifdef DISCLAIMER_SUPPORT
if(temp_action->action.action_text_disclaimer[0] !='\0')
add_disclaimer = SUBTYPE_PLAIN;
if(temp_action->action.action_html_disclaimer[0] != '\0')
add_disclaimer = SUBTYPE_HTML;
if(temp_action->action.action_text_disclaimer[0] !='\0' && temp_action->action.action_html_disclaimer[0] != '\0')
add_disclaimer = SUBTYPE_BOTH;
strcpy(disclaimer_text, temp_action->action.action_text_disclaimer);
strcpy(disclaimer_html, temp_action->action.action_html_disclaimer);
#else
syslog(LOG_ERR, "Disclaimer matched though disclaimer support not available");
#endif
break;
default:
syslog(LOG_ERR, "Unknown action %d. Ignoring", temp_action->action.action_type);
break;
}
else
syslog(LOG_DEBUG, "No matched actions for email");
#ifdef DISCLAIMER_SUPPORT
if(add_disclaimer != SUBTYPE_NONE)
{
/* Cristi, call the c-client parser */
syslog(LOG_DEBUG, "Closing stream for body file and reopening for read access");
if(priv->output_stream != NULL)
fclose(priv->output_stream);
if(priv->temp_filename != NULL)
{
strcpy(filename, priv->temp_filename);
strcpy(newfilename, priv->temp_filename);
strcat(newfilename, ".new");
}
else
{
syslog(LOG_ERR, "Error reading temp filename from priv.");
return -1;
}
priv->output_stream = fopen(filename, "r");
if(priv->output_stream == NULL)
{
syslog(LOG_ERR, "Error opening old file for read");
return rstat;
}
file_length = stat(filename, &statstruct);
if(file_length == -1)
{
unlink(filename);
syslog(LOG_ERR, "Could not open body file for read");
return rstat;
}
syslog(LOG_DEBUG, "Mallocing body parser structure");
priv->bp_state = malloc(sizeof(body_parser_state));
if(priv->bp_state == NULL)
{
syslog(LOG_ERR, "Error on malloc of bp_state.");
return mlfi_cleanup(ctx, TRUE);
}
syslog(LOG_DEBUG, "Mallocing disclaimer structure");
priv->bp_state->d_state = malloc(sizeof(disclaimer_state));
if(priv->bp_state->d_state == NULL)
{
syslog(LOG_ERR, "Error on malloc of bp_state.");
return mlfi_cleanup(ctx, TRUE);
}
priv->bp_state->d_state->disclaimer_text = disclaimer_text;
priv->bp_state->d_state->disclaimer_html = disclaimer_html;
priv->bp_state->d_state->operation_mode = add_disclaimer;
priv->bp_state->d_state->disclaimer_text_processed = 0;
priv->bp_state->d_state->disclaimer_html_processed = 0;
/* Initialise the output stream for the body parser to write in */
priv->bp_state->out_stream = fopen(newfilename, "w");
if(priv->bp_state->out_stream == NULL)
{
syslog(LOG_DEBUG, "body_parser_finalize: Failed to open new body file for write");
return BODY_PARSER_FAILURE;
}
syslog(LOG_DEBUG, "Parsing stream to locate text/plain");
/* All the headers are needed in a string for c-client to interpret the message body */
all_headers = malloc(10000);
if(all_headers == NULL)
{
syslog(LOG_CRIT, "Failed to allocate memory for the headers");
priv->error_encountered = TRUE;
return SMFIS_CONTINUE;
}
all_headers[0] = '\0';
syslog(LOG_DEBUG, "Writing headers in string.");
for(temp_header = priv->headers; temp_header != NULL; temp_header = temp_header->next)
{
if(strlen(temp_header->header_name) + strlen(temp_header->header_value) + strlen(all_headers) + 1 < 10000)
{
strcat(all_headers, temp_header->header_name);
strcat(all_headers, ": ");
strcat(all_headers, temp_header->header_value);
strcat(all_headers, "\n");
}
else
{
syslog(LOG_ERR, "headers bigger than 10k. dropping.");
break;
}
}
syslog(LOG_DEBUG, "Finished writing headers in string.");
retval = body_parser_init(all_headers, priv->output_stream,
statstruct.st_size, priv->bp_state);
if(retval != BODY_PARSER_SUCCESS)
{
syslog(LOG_ERR, "Error in body_parser_init");
}
/*** NOT IMPLEMENTED YET ***/
//process_attachment_names(priv->bp_state->attachment_rule);
retval = body_parser_finalize(priv->bp_state);
if(retval == BODY_PARSER_SUCCESS)
{
fd_processed = fopen(newfilename, "r");
if(fd_processed == NULL)
{
syslog(LOG_ERR, "Failed to open new body for read");
}
syslog(LOG_DEBUG, "Opened new body for read");
while((count = fread(fread_buffer,
1, 65000, fd_processed)) != 0)
{
retval = smfi_replacebody(ctx, fread_buffer, count);
if(retval == MI_FAILURE)
syslog(LOG_ERR, "Error in replace body.");
}
syslog(LOG_DEBUG, "Body was replaced, last count is %d", count);
fclose(fd_processed);
}
free(all_headers);
smfi_addheader(ctx, "X-Synonym", SYNONYM_DISCLAIMERBY);
syslog(LOG_DEBUG, "Freeing disclaimer structure");
if(priv->bp_state->d_state != NULL)
free(priv->bp_state->d_state);
syslog(LOG_DEBUG, "Unlinking new body file");
unlink(newfilename);
}
if(priv->output_stream != NULL)
fclose(priv->output_stream);
if(priv->temp_filename != NULL)
unlink(priv->temp_filename);
#endif
mlfi_cleanup(ctx, TRUE);
if(reject_email)
{
if(smtp_reply[0]!='\0')
if(smfi_setreply(ctx, "550", "5.7.1", smtp_reply)!= MI_SUCCESS)
syslog(LOG_ERR, "Failed to set the smtp reply for message rejection");
return SMFIS_REJECT;
}
if(delete_email)
return SMFIS_DISCARD;
return SMFIS_CONTINUE;
}
sfsistat
mlfi_close(ctx)
SMFICTX *ctx;
{
return SMFIS_ACCEPT;
}
sfsistat
mlfi_abort(ctx)
SMFICTX *ctx;
{
return mlfi_cleanup(ctx, FALSE);
}
sfsistat
mlfi_cleanup(ctx, ok)
SMFICTX *ctx;
BOOL ok;
{
sfsistat rstat = SMFIS_CONTINUE;
synonym_priv *priv;
to_list * clist, * plist;
synonym_header *previous_header, *next_header;
priv = smfi_getpriv(ctx);
if (priv == NULL)
{
syslog(LOG_ERR, "This connection dropped before MAIL FROM:");
return rstat;
}
if (ok)
;
/* release private memory */
next_header = previous_header = priv->headers;
while(next_header != NULL)
{
previous_header = next_header;
next_header = next_header->next;
free(previous_header);
}
#ifdef DISCLAIMER_SUPPORT
/* free the disclaimer state structure */
if(priv->bp_state != NULL)
free(priv->bp_state);
#endif
/* Cristi, fix leak caused by matched action being abandoned */
syslog(LOG_DEBUG, "Freeing matched actions list");
if(priv->resulted_actions != NULL)
free_matched_action_list(priv->resulted_actions);
/* Free env to list */
clist = priv->env_to;
plist = clist;
while(clist != NULL)
{
/* all the members are statically allocated so nothing to do here */
plist = clist;
clist = clist->next;
free(plist);
}
free(priv);
smfi_setpriv(ctx, NULL);
/* return status */
return rstat;
}
struct smfiDesc smfilter =
{
"Synonym", /* filter name */
SMFI_VERSION, /* version code -- do not change */
#ifdef DISCLAIMER_SUPPORT
SMFIF_ADDHDRS | SMFIF_ADDRCPT | SMFIF_DELRCPT | SMFIF_CHGBODY, /* flags */
#else
SMFIF_ADDHDRS | SMFIF_ADDRCPT | SMFIF_DELRCPT, /* flags */
#endif
NULL, /* connection info filter */
NULL, /* SMTP HELO command filter */
mlfi_envfrom, /* envelope sender filter */
mlfi_envrcpt, /* envelope recipient filter */
mlfi_header, /* header filter */
mlfi_eoh, /* end of header */
mlfi_body, /* body block filter */
mlfi_eom, /* end of message */
mlfi_abort, /* message aborted */
mlfi_close /* connection cleanup */
};
int
main(argc, argv)
int argc;
char *argv[];
{
int c;
const char *args = "s:c:u:l:f:dh";
char socketname[256];
char configfile[256];
char runas_user[256];
BOOL daemon=FALSE;
struct stat statbuf;
char pid_str[1024];
int nread;
FILE *f_pidfile;
int pidno;
pid_t fork_result_id;
struct passwd *runas_pwent;
int loglevel=DEFAULT_LOGLEVEL, logfacility=DEFAULT_LOGFACILITY;
char loglevel_string[64], logfacility_string[64];
strcpy(loglevel_string, DEFAULT_LOGLEVEL_STRING);
strcpy(logfacility_string, DEFAULT_LOGFACILITY_STRING);
openlog("Synonym", LOG_NDELAY|LOG_PID, logfacility);
setlogmask(LOG_UPTO(loglevel));
/* load some default values */
strcpy(socketname, DEFAULT_SOCKET);
strcpy(configfile, DEFAULT_CONFIG);
strcpy(runas_user, DEFAULT_USER);
/* Process command line options */
while ((c = getopt(argc, argv, args)) != -1)
{
switch (c)
{
case 'f': /* Logging facility for syslog */
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid logging facility name\n");
exit(-1);
}
logfacility = -1;
if(!strcasecmp(optarg, "LOG_LOCAL0"))
logfacility=LOG_LOCAL0;
if(!strcasecmp(optarg, "LOG_LOCAL1"))
logfacility=LOG_LOCAL1;
if(!strcasecmp(optarg, "LOG_LOCAL2"))
logfacility=LOG_LOCAL2;
if(!strcasecmp(optarg, "LOG_LOCAL3"))
logfacility=LOG_LOCAL3;
if(!strcasecmp(optarg, "LOG_LOCAL4"))
logfacility=LOG_LOCAL4;
if(!strcasecmp(optarg, "LOG_LOCAL5"))
logfacility=LOG_LOCAL5;
if(!strcasecmp(optarg, "LOG_LOCAL6"))
logfacility=LOG_LOCAL6;
if(!strcasecmp(optarg, "LOG_LOCAL7"))
logfacility=LOG_LOCAL7;
if(!strcasecmp(optarg, "LOG_DAEMON"))
logfacility=LOG_DAEMON;
if(!strcasecmp(optarg, "LOG_MAIL"))
logfacility=LOG_MAIL;
if(!strcasecmp(optarg, "LOG_USER"))
logfacility=LOG_USER;
if(logfacility == -1)
{
fprintf(stderr, "Invalid logging facility name - %s\n Choose one of: LOG_LOCAL0, LOG_LOCAL1, ... LOG_LOCAL7, LOG_DAEMON, LOG_MAIL, LOG_USER\n", optarg);
exit(-1);
}
strcpy(logfacility_string, optarg);
break;
case 'l': /* Logging level for syslog */
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid logging level name\n");
exit(-1);
}
loglevel = -1;
if(!strcasecmp(optarg, "LOG_DEBUG"))
loglevel=LOG_DEBUG;
if(!strcasecmp(optarg, "LOG_INFO"))
loglevel=LOG_INFO;
if(!strcasecmp(optarg, "LOG_NOTICE"))
loglevel=LOG_NOTICE;
if(!strcasecmp(optarg, "LOG_WARNING"))
loglevel=LOG_WARNING;
if(!strcasecmp(optarg, "LOG_ERR"))
loglevel=LOG_ERR;
if(!strcasecmp(optarg, "LOG_CRIT"))
loglevel=LOG_CRIT;
if(!strcasecmp(optarg, "LOG_ALERT"))
loglevel=LOG_ALERT;
if(!strcasecmp(optarg, "LOG_EMERG"))
loglevel=LOG_EMERG;
if(loglevel == -1)
{
fprintf(stderr, "Invalid logging level name - %s\n Choose one of: LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT, LOG_ALERT, LOG_EMERG\n", optarg);
exit(-1);
}
strcpy(loglevel_string, optarg);
break;
case 's': /* Socket name (for comms with sendmail) */
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid socket name\n");
exit(-1);
}
strcpy(socketname, optarg);
break;
case 'c': /* synonym config file */
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid config file name\n");
exit(-1);
}
strcpy(configfile, optarg);
break;
case 'u': /* run-as username */
if (optarg == NULL || *optarg == '\0')
{
fprintf(stderr, "Invalid user name\n");
exit(-1);
}
strcpy(runas_user, optarg);
break;
case 'd':
daemon = TRUE;
break;
case 'h':
fprintf(stdout, "Synonym %s\nA flexible Milter-based extension for MTA level copy, drop and reject.\n\nUsage: synonym [-dh] [-c <configfile>] [-u <runas username>] [-s <milter socket>]\n\
-d\tRun as daemon\n-h\tDisplay this help\n-c\tConfiguration file\n-r\tUsername that Synonym will run as\
\n-s\tMilter communication socket (should be the same as in the sendmail configuration file)\n\nLicensed under the Modulo Consulting Software License\n(see /usr/share/doc/synonym/license.txt)\n\n", SYNONYM_VERSION);
exit(-1);
break;
}
}
closelog();
openlog("Synonym", LOG_NDELAY|LOG_PID, logfacility);
setlogmask(LOG_UPTO(loglevel));
syslog(LOG_INFO, "Log facility is %s", logfacility_string);
syslog(LOG_INFO, "Log level is %s", loglevel_string);
syslog(LOG_INFO, "Socket is %s", socketname);
syslog(LOG_INFO, "Config file is %s", configfile);
syslog(LOG_INFO, "Synonym will attempt to run as user %s", runas_user);
if((runas_pwent = getpwnam(runas_user)) == NULL)
{
fprintf(stderr, "Invalid user (cannot run as %s)\n", runas_user);
exit(-1);
}
if((runas_pwent->pw_uid == 0) || (runas_pwent->pw_gid == 0))
{
fprintf(stderr, "Synonym should not be run as root. Please specify a valid user.\n");
exit(-1);
}
if(setgid(runas_pwent->pw_gid)!=0)
{
fprintf(stderr, "Failed to drop privileges to gid %d\n", (int)runas_pwent->pw_gid);
exit(-1);
}
if(setuid(runas_pwent->pw_uid)!=0)
{
fprintf(stderr, "Failed to drop privileges to uid %d\n", (int)runas_pwent->pw_uid);
exit(-1);
}
if(Synonym_Get_Config(configfile, &synonym_config) != SYNONYM_OK)
{
fprintf(stderr, "Failed to load configuration (%s)\nPlease check the log file for more details\n", configfile);
exit(-1);
}
if((f_pidfile = fopen(PIDFILE, "r")) != NULL)
{
nread = fread(pid_str, 1, 1023, f_pidfile);
pid_str[nread] = '\0';
fclose(f_pidfile);
if((pidno = atoi(pid_str)) != 0)
{
if((kill(pidno, 0) == -1) && (errno == ESRCH)) /* pid exists but process is not running anymore */
{
syslog(LOG_WARNING, "Synonym was previously stopped uncleanly");
fprintf(stderr, "Synonym was previously stopped uncleanly\n");
unlink(PIDFILE);
}
else
{
syslog(LOG_ERR, "Synonym already running (%d)", pidno);
fprintf(stderr, "Synonym already running (%d)\n", pidno);
exit(-1);
}
}
else
{
fprintf(stderr, "Failed to read the PID from %s", PIDFILE);
exit(-1);
}
}
if(daemon)
{
fork_result_id = fork();
if(fork_result_id == -1) /* Error; we should exit */
{
syslog(LOG_ERR, "Failed to fork to background");
exit(-1);
}
if(fork_result_id != 0)
exit(0); /* we're parent - close ourselves */
/* we're child, detached */
syslog(LOG_INFO, "Synonym started as daemon");
}
f_pidfile = fopen(PIDFILE, "w");
if(f_pidfile == NULL)
{
syslog(LOG_ERR, "Failed to create pidfile %s", PIDFILE);
fprintf(stderr, "Failed to create pidfile %s\n", PIDFILE);
exit(-1);
}
sprintf(pid_str, "%d", (int)getpid());
if(fwrite(pid_str, 1, strlen(pid_str), f_pidfile) != strlen(pid_str))
{
syslog(LOG_ERR, "Failed to write the pid in %s", PIDFILE);
fprintf(stderr, "Failed to write the pid in %s\n", PIDFILE);
fclose(f_pidfile);
exit(-1);
}
fclose(f_pidfile);
if(strncmp(socketname, "local:", 6) == 0)
{/* Local socket already exists - we should delete it */
if(stat(&socketname[6], &statbuf) == 0)
{/* The file exists so we have to remove it */
syslog(LOG_INFO, "The local socket already exists");
/* Delete the socket file */
if(unlink(&socketname[6]) != 0)
{
fprintf(stderr, "Can't remove the socket file. Please try removing it manually\n");
exit(-1);
}
}
}
if(smfi_setconn(socketname) == MI_FAILURE)
{
fprintf(stderr, "Can't create comms socket. (check permissions)\n");
exit(-1);
}
if (smfi_register(smfilter) == MI_FAILURE)
{
fprintf(stderr, "Unable to register as sendmail milter\n");
exit(EX_UNAVAILABLE);
}
fclose(stdin);
fclose(stdout);
fclose(stderr);
smfi_main();
Synonym_Free_Config(&synonym_config);
if(unlink(PIDFILE) == -1)
syslog(LOG_ERR, "Failed to delete the pid file %s", PIDFILE);
syslog(LOG_WARNING, "Synonym exiting");
closelog();
return 0;
}
void free_matched_action_list(matched_action * m_list)
{
matched_action *current_action, *previous_action;
if(m_list == NULL)
return;
current_action = m_list;
previous_action = current_action;
while(current_action != NULL)
{
/* all the members are statically allocated so nothing to do here */
previous_action = current_action;
current_action = current_action->next;
free(previous_action);
}
m_list = NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1