/* * Copyright (c) 2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Mail delivery monitoring daemon. This program executes round-trip tests * to ensure that the mail system is performing. */ #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #include "smtp.h" #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif char *smtpHost = "localhost"; char *smtpPort = "2525"; char *testSndr = "root@localhost"; char *testRcpt = "mailmond@localhost"; char *testMaildir = "/var/mailmond/Maildir/"; char *testSpamdir = "/var/mailmond/Maildir/.Spam/"; int testIval = 30; int testDelayMax = 60; int Verbose = 0; char *SpamSample, *HamSample; size_t SpamSampleLen = 0; size_t HamSampleLen = 0; volatile int die_signal = 0; volatile int die_flag = 0; static int LoadConfig(const char *path) { char *data, *line, *pLine; size_t dataLen; FILE *f; if ((f = fopen(path, "r")) == NULL) { fprintf(stderr, "%s: %s\n", path, strerror(errno)); return (-1); } fseek(f, 0, SEEK_END); dataLen = (size_t)ftell(f); fseek(f, 0, SEEK_SET); if ((data = malloc(dataLen)) == NULL) { fprintf(stderr, "Out of memory\n"); return (-1); } if (fread(data, dataLen, 1, f) < 1) { fprintf(stderr, "Error reading config file\n"); fclose(f); return (-1); } pLine = data; while ((line = strsep(&pLine, "\n")) != NULL) { char *s = line; char *key, *val; if (s[0] == '#' || s[0] == '\0') { continue; } key = strsep(&line, "="); val = strsep(&line, "="); if (key == NULL || val == NULL) { continue; } if (!strcasecmp(key,"smtp.host")) { smtpHost = val; } else if (!strcasecmp(key,"smtp.port")) { smtpPort = val; } else if (!strcasecmp(key,"test.sender")) { testSndr = val; } else if (!strcasecmp(key,"test.recipient")) { testRcpt = val; } else if (!strcasecmp(key,"test.maildir")) { testMaildir = val; } else if (!strcasecmp(key,"test.spamdir")) { testSpamdir = val; } else if (!strcasecmp(key,"test.interval")) { testIval = atoi(val); } else if (!strcasecmp(key,"test.delayMax")) { testDelayMax = atoi(val); } else { fprintf(stderr, "%s: No such option: %s\n", path, key); } } fclose(f); printf("SMTP host = %s:%s\n", smtpHost, smtpPort); printf("Test sender = %s\n", testSndr); printf("Test recipient = %s\n", testRcpt); printf("Test maildir = %s\n", testMaildir); printf("Test spamdir = %s\n", testSpamdir); printf("Test interval = %d\n", testIval); printf("Test maximum delay = %d\n", testDelayMax); return (0); } static int LoadSamples(void) { FILE *f; if ((f = fopen("spam1.txt", "r")) == NULL) { fprintf(stderr, "spam1.txt: %s\n", strerror(errno)); return (-1); } fseek(f, 0, SEEK_END); SpamSampleLen = (size_t)ftell(f); fseek(f, 0, SEEK_SET); if ((SpamSample = malloc(SpamSampleLen)) == NULL) { fprintf(stderr, "Out of memory\n"); fclose(f); return (-1); } if (fread(SpamSample, SpamSampleLen, 1, f) < 1) { fprintf(stderr, "Error reading spam sample\n"); fclose(f); return (-1); } fclose(f); if ((f = fopen("nonspam1.txt", "r")) == NULL) { fprintf(stderr, "nonspam1.txt: %s\n", strerror(errno)); return (-1); } fseek(f, 0, SEEK_END); HamSampleLen = (size_t)ftell(f); fseek(f, 0, SEEK_SET); if ((HamSample = malloc(HamSampleLen)) == NULL) { fprintf(stderr, "Out of memory\n"); fclose(f); return (-1); } if (fread(HamSample, HamSampleLen, 1, f) < 1) { fprintf(stderr, "Error reading spam sample\n"); fclose(f); return (-1); } fclose(f); return (0); } static void Alarm(void) { syslog(LOG_ERR, "Mail system failure"); printf("FAILURE\n"); #if 0 printf("Stopping Postfix\n"); system("/usr/bin/sudo /usr/local/sbin/postfix.stop"); sleep(5); printf("Stopping mailprocd\n"); system("/usr/bin/sudo /usr/local/sbin/mailprocd.stop"); sleep(30); printf("Starting mailprocd\n"); system("/usr/bin/sudo /usr/local/sbin/mailprocd.run"); sleep(15); printf("Starting postfix\n"); system("/usr/bin/sudo /usr/local/sbin/postfix.run"); #endif } static int CheckMaildir(const char *maildir) { char path[MAXPATHLEN]; struct dirent *dent; DIR *dir; int nMsgs = 0; strlcpy(path, maildir, sizeof(path)); strlcat(path, "new", sizeof(path)); if ((dir = opendir(path)) == NULL) { fprintf(stderr, "%s: %s\n", path, strerror(errno)); return (-1); } while ((dent = readdir(dir)) != NULL) { if (dent->d_name[0] == '.') { continue; } strlcpy(path, maildir, sizeof(path)); strlcat(path, "new/", sizeof(path)); strlcat(path, dent->d_name, sizeof(path)); if (unlink(path) == -1) { fprintf(stderr, "rm %s: %s\n", path, strerror(errno)); } nMsgs++; } closedir(dir); return (nMsgs > 0) ? 0 : -1; } static void sig_die(int sigraised) { die_signal = sigraised; die_flag = 1; } int main(int argc, char *argv[]) { struct sigaction sa; extern char *__progname; const char *cfgPath = _PATH_MAILMOND_CONF; int c; while ((c = getopt(argc, argv, "Vc:?")) != -1) { switch (c) { case 'V': Verbose = 1; break; case 'c': cfgPath = optarg; break; default: printf("Usage: %s [-V] [-c cfg-file]\n", __progname); break; } } if (LoadConfig(cfgPath) == -1 || LoadSamples() == -1) exit(1); sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sigfillset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = sig_die; sigaction(SIGINT, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); for (;;) { if (Verbose) { printf("[%s:%s] Test\n", smtpHost, smtpPort); } if (SMTP_Inject(SpamSample, SpamSampleLen, testSndr, testRcpt, smtpHost, smtpPort) == 0 && SMTP_Inject(HamSample, HamSampleLen, testSndr, testRcpt, smtpHost, smtpPort) == 0) { if (die_flag) { goto cleanup; } sleep(testDelayMax); if (die_flag) { goto cleanup; } if (CheckMaildir(testMaildir) == -1 || CheckMaildir(testSpamdir) == -1) { Alarm(); } if (Verbose) { printf("[%s:%s] OK\n", smtpHost, smtpPort); } } else { Alarm(); } if (die_flag) { goto cleanup; } sleep(testIval); if (die_flag) { goto cleanup; } } cleanup: syslog(LOG_NOTICE, "exiting on signal %d", die_signal); fprintf(stderr, "Exiting on signal %d\n", die_signal); CheckMaildir(testMaildir); CheckMaildir(testSpamdir); return (0); }