/*
- This program is RSPAMD agent for use with
+ This program is RSPAMD agent for use with
exim (http://www.exim.org) MTA by its local_scan feature.
To enable exim local scan please copy this file to exim source tree
- Local/local_scan.c, edit Local/Makefile to add
-
- LOCAL_SCAN_SOURCE=Local/local_scan.c
+ Local/local_scan.c, edit Local/Makefile to add
+
+ LOCAL_SCAN_SOURCE=Local/local_scan.c
LOCAL_SCAN_HAS_OPTIONS=yes
-
- and compile exim.
-
+
+ and compile exim.
+
Comment out RSPAM_UNIXSOCKET definition below if you have remote RSPAMD
daemon
-
+
AND
-
+
use Exim parameters daemonIP and daemonPort to configure remote
RSPAMD daemon.
-
- For exim compilation with local scan feature details please visit
+
+ For exim compilation with local scan feature details please visit
http://www.exim.org/exim-html-4.50/doc/html/spec_toc.html#TOC333
-
+
For RSPAMD details please visit
http://rspamd.sourceforge.net
*/
static uschar *socket_name = US"/var/run/rspamd.sock";
static int strange = 0;
-optionlist local_scan_options[] =
-{
- {"rspam_ip", opt_stringptr, &daemonIP},
+optionlist local_scan_options[] =
+{
+ {"rspam_ip", opt_stringptr, &daemonIP},
{"rspam_port", opt_int, &daemonPort},
{"rspam_tmp", opt_stringptr, &temp_dir},
{"rspam_sock", opt_stringptr, &socket_name},
-
+
};
int local_scan_options_count = sizeof (local_scan_options) / sizeof (optionlist);
char psMsg [MAX_SIZE_FILE]; /* max size SO can swallow */
int iLen, result = _OK;
- if ((iLen = read (fd, psMsg, sizeof (psMsg))) > 0)
+ if ((iLen = read (fd, psMsg, sizeof (psMsg))) > 0)
{
- if (write (iFdMsg, psMsg, (unsigned int) iLen) != iLen)
+ if (write (iFdMsg, psMsg, (unsigned int) iLen) != iLen)
result = ERR_WRITE;
}
else
void CleanupInp (char *sName)
{
- if (sName) unlink (sName);
+ if (sName) unlink (sName);
close (iFdInp);
return;
size_t nleft;
int nwritten;
const char *ptr;
-
+
ptr = vptr;
nleft = n;
while (nleft > 0)
else
return (-1);
}
-
+
nleft -= nwritten;
ptr += nwritten;
}
-
+
return (n);
}
log_write (0, LOG_MAIN, "rspam-exim: file %s is great %d bytes", sFile, MAX_SIZE_FILE);
return ERR_WRITE;
}
-
+
/* send greeting */
// if(FakeSMTPCommand(sock, "PROCESS", "RSPAMC/1.0", sFile, 1, 0) != _OK)
// return ERR_WRITE;
if(FakeSMTPCommand(sock, "SYMBOLS", "RSPAMC/1.1", sFile, 1, 0) != _OK)
// if(FakeSMTPCommand(sock, "CHECK", "RSPAMC/1.0", sFile, 1, 0) != _OK)
return ERR_WRITE;
-
-
+
+
/* sender IP */
if (FakeSMTPCommand (sock, "IP:", sender_host_address, sFile, 1, 0) != _OK)
return ERR_WRITE;
/* mail from */
- if (FakeSMTPCommand (sock, "From:",
+ if (FakeSMTPCommand (sock, "From:",
strlen (sender_address) == 0 ? "MAILER-DAEMON" : (char*) sender_address, sFile, 1, 0) != _OK)
return ERR_WRITE;
sprintf(str, "%d", recipients_count);
if (FakeSMTPCommand (sock, "Recipient-Number:", str, sFile, 1, 0) != _OK)
return ERR_WRITE;
-
+
/* envelope rcpto */
for (i = 0; i < recipients_count; i ++)
{
if (FakeSMTPCommand (sock, "\r\n", "", sFile, 1, 0) != _OK)
return ERR_WRITE;
-
+
if (written (sock, psBuf, bytesRead) != bytesRead)
return ERR_WRITE;
}
*/
int iStatus;
struct header_line *h_line;
-
+
iFdInp = mOpenTmp ((char *)temp_dir, "sp-inp", pInpFile);
- if (iFdInp == -1)
+ if (iFdInp == -1)
{
return ERR_WRITE;
}
h_line = h_line->next;
continue;
}
-
+
if (write (iFdInp, h_line->text, strlen (h_line->text)) != strlen (h_line->text))
{
CleanupInp ("");
CleanupInp ("");
return ERR_WRITE;
}
-
+
/* Read msg */
- if ((iStatus = ReadFd (iFdInp, local_scan_fd)))
+ if ((iStatus = ReadFd (iFdInp, local_scan_fd)))
{
return iStatus;
}
else
break;
}
-
+
iStatus = SendEnvelope (sFile);
if (iStatus != _OK)
{
close (sock);
return iStatus;
}
-
+
/* fprintf (stderr, "Transmit OK\n"); */
return _OK;
}
h_line = h_line->next;
continue;
}
-
+
if (strncasecmp (h_line->text, hdr, strlen(hdr)) == 0)
{
h_line->type = '*';
- while (h_line->next &&
+ while (h_line->next &&
(*h_line->next->text == ' ' || *h_line->next->text == '\t'))
{
h_line = h_line->next;
char *subject, *strP;
h_line = header_list;
-
+
while (h_line != NULL)
{
if (h_line->type == '*') /* internal header */
h_line = h_line->next;
continue;
}
-
+
if (strncasecmp (h_line->text, "Subject", strlen("Subject")) == 0)
{
strP = strchr (h_line->text, ':');
header_add (' ', "Subject: %s%s", label, subject ? subject : "");
}
-int
+int
io_read(int fd, char *buf, size_t size)
{
int nfd, next = 0, rcount = 15;
size_t len = 0;
fd_set fds;
struct timeval tv;
-
+
if((sock < 0) || (buf == NULL))
return -1;
-
+
FD_ZERO(&fds);
repeat_read:
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_SET(fd, &fds);
-
+
// log_write(0, LOG_MAIN, "rspam-exim: before select");
if((nfd=select(fd+1, &fds, NULL, NULL, &tv)) == -1) {
}
// log_write(0, LOG_MAIN, "rspam-exim: select return %d fds, rcount %d, next %d", nfd, rcount, next);
-
+
if((nfd>0) && (FD_ISSET(fd, &fds))) {
next += len = read(fd, buf + next, size - next);
// log_write(0, LOG_MAIN, "rspam-exim: read %d bytes", len);
-// if(next<size)
+// if(next<size)
// goto repeat_read;
}
rcount--;
char *hdr = NULL, *hdrv = NULL, *spmStr = NULL, *symbols=NULL, *urls=NULL;
char answ [4096], state[6], metric[128], back;
float sm=0, smd=0, smr=0;
-
+
memset (answ, '\0', sizeof (answ));
// log_write(0, LOG_MAIN, "rspam-exim: before read from %d", sock);
// Len = read (sock, answ, sizeof (answ) - 1);
continue;
}
- /* Metric: default; False; 6.00 / 10.00 */
+ /* Metric: default; False; 6.00 / 10.00 */
/* Process metric */
if (strncmp (tok, "Metric:", 7) == 0)
{
tmp = tok;
- while( (*tmp++) &&
+ while( (*tmp++) &&
((*tmp!='\r') || (*tmp!='\n'))
);
back = *tmp;
*tmp = back;
continue;
}
-
+
if (strncmp (tok, "Symbol:", 7) == 0)
{
tmp = tok;
- while( (*tmp++) &&
+ while( (*tmp++) &&
((*tmp!='\r') || (*tmp!='\n'))
);
back = *tmp;
if (strncmp (tok, "Urls:", 5) == 0)
{
tmp = tok;
- while( (*tmp++) &&
+ while( (*tmp++) &&
((*tmp!='\r') || (*tmp!='\n'))
);
back = *tmp;
*tmp = '\0';
if(urf>0) {
tok[0] = tok[1]= tok[2]= tok[3]= tok[4] = ' ';
- urls = string_sprintf ("%s\n%s", urls, tok+3);
+ urls = string_sprintf ("%s\n%s", urls, tok+3);
} else {
tok += 5;
while(*tok && isspace(*tok)) tok++;
}
}
-
+
/* do not forget the symbols */
if (symbols != NULL && strlen(symbols))
{
header_del ((uschar *) "X-Spam-Urls");
header_add (' ', "%s: %s\n", "X-Spam-Urls", urls);
}
-
+
log_write (0, LOG_MAIN, "rspam-exim: For message from %s will return %s, mailfrom: <%s>, rcpto: <%s>", sender_host_address, rej == 2 ? "DISCARD" : rej == 1 ? "REJECT" : "ACCEPT", sender_address, recipients_list[0].address);
-
+
}
else
{
if((sm>0) && (smr>0) && (sm>=smr)) {
result = LOCAL_SCAN_REJECT;
- }
+ }
return result;
}
if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
{
log_write(0, LOG_MAIN, "rspam-exim: socket() failed");
- exit (1);
+ exit (EXIT_FAILURE);
}
memset (&ssun, '\0', sizeof (struct sockaddr_un));
ssun.sun_family = AF_UNIX;
{
close (sock);
log_write(0, LOG_MAIN, "rspam-exim: UNIX socket name %s too long", socket_name);
- exit (1);
+ exit (EXIT_FAILURE);
}
strcpy (ssun.sun_path, socket_name);
#else
if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
{
log_write(0, LOG_MAIN, "rspam-exim: socket() failed");
- exit (1);
+ exit (EXIT_FAILURE);
}
memset (&ssin, '\0', sizeof (struct sockaddr_in));
ssin.sin_family = AF_INET;
SPOOL_DATA_START_OFFSET;
return REJECT_ON_ERROR ? LOCAL_SCAN_TEMPREJECT:LOCAL_SCAN_ACCEPT;
}
-
+
retval = WaitForScanResult (return_text);
if(!strange)
unlink (sFileInp);
close (sock);
SPOOL_DATA_START_OFFSET;
-
+
return retval;
}
if (fd_out == -1) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
close (fd_out);
if (map == NULL) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
}
if (fd_out == -1) {
rspamd_fprintf (stderr, "cannot open tempfile %s: %s\n", tmppath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
if (len > 0 && write (fd_out, map, len) == -1) {
unlink (tmppath);
munmap (map, len);
close (fd_out);
- exit (errno);
+ exit (EXIT_FAILURE);
}
if (len > 0) {
rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor,
err);
unlink (tmppath);
- exit (errno);
+ exit (EXIT_FAILURE);
}
if (!g_spawn_async (NULL, child_argv, NULL,
rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor,
err);
unlink (tmppath);
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_strfreev (child_argv);
rspamd_fprintf (stderr, "failed to wait for %s: %s\n", editor,
strerror (errno));
unlink (tmppath);
- exit (errno);
+ exit (EXIT_FAILURE);
}
}
unlink (tmppath);
rspamd_fprintf (stderr, "%s returned error code: %d - %e\n", editor,
retcode, err);
- exit (retcode);
+ exit (EXIT_FAILURE);
}
#else
if (retcode != 0) {
rspamd_fprintf (stderr, "cannot map %s: %s\n", tmppath,
strerror (errno));
unlink (tmppath);
- exit (errno);
+ exit (EXIT_FAILURE);
}
rspamd_snprintf (run_cmdline, sizeof (run_cmdline), "%s.new", fname);
strerror (errno));
unlink (tmppath);
munmap (map, len);
- exit (errno);
+ exit (EXIT_FAILURE);
}
if (write (fd_out, map, len) == -1) {
unlink (run_cmdline);
close (fd_out);
munmap (map, len);
- exit (errno);
+ exit (EXIT_FAILURE);
}
unlink (tmppath);
if (fd_input == -1) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_assert (fstat (fd_input, &st) != -1);
close (fd_input);
rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd_input, 0);
close (fd_sig);
rspamd_fprintf (stderr, "cannot map %s: %s\n", fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_assert (rspamd_cryptobox_MAX_SIGBYTES >=
if (rename (sigpath, fname) == -1) {
rspamd_fprintf (stderr, "cannot rename %s to %s: %s\n", sigpath, fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
unlink (sigpath);
if (write (fd_sig, sig, rspamd_cryptobox_signature_bytes (mode)) == -1) {
rspamd_fprintf (stderr, "cannot write signature to %s: %s\n", sigpath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
close (fd_sig);
if (fd_input == -1) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", fname,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_assert (fstat (fd_input, &st) != -1);
close (fd_input);
rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd_input, 0);
close (fd_sig);
rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_assert (fstat (fd_sig, &st_sig) != -1);
rspamd_fprintf (stderr, "invalid signature size %s: %ud\n", fname,
(guint)st_sig.st_size);
munmap (map, st.st_size);
- exit (errno);
+ exit (EXIT_FAILURE);
}
map_sig = mmap (NULL, st_sig.st_size, PROT_READ, MAP_SHARED, fd_sig, 0);
munmap (map, st.st_size);
rspamd_fprintf (stderr, "cannot map %s: %s\n", sigpath,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
ret = rspamd_cryptobox_verify (map_sig, st_sig.st_size,
rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message);
g_error_free (error);
g_option_context_free (context);
- exit (1);
+ exit (EXIT_FAILURE);
}
g_option_context_free (context);
if (verify && (!pubkey && !pubkey_file)) {
rspamd_fprintf (stderr, "no pubkey for verification\n");
- exit (1);
+ exit (EXIT_FAILURE);
}
else if (!verify && (!keypair_file)) {
rspamd_fprintf (stderr, "no keypair for signing\n");
- exit (1);
+ exit (EXIT_FAILURE);
}
if (verify) {
if (fd == -1) {
rspamd_fprintf (stderr, "cannot open %s: %s\n", pubkey_file,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
g_assert (fstat (fd, &st) != -1);
if (map == MAP_FAILED) {
rspamd_fprintf (stderr, "cannot read %s: %s\n", pubkey_file,
strerror (errno));
- exit (errno);
+ exit (EXIT_FAILURE);
}
/* XXX: assume base32 pubkey now */
pubkey_file,
(guint)flen,
rspamd_cryptobox_pk_sig_bytes (mode));
- exit (errno);
+ exit (EXIT_FAILURE);
}
munmap (map, fsize);
pubkey_file,
(guint)strlen (pubkey),
rspamd_cryptobox_pk_sig_bytes (mode));
- exit (errno);
+ exit (EXIT_FAILURE);
}
}
(top = ucl_parser_get_object (parser)) == NULL) {
rspamd_fprintf (stderr, "cannot load keypair: %s\n",
ucl_parser_get_error (parser));
- exit (EINVAL);
+ exit (EXIT_FAILURE);
}
ucl_parser_free (parser);