From b69343fc8f931319ca56cc6464961ddeb3134a0a Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Sun, 5 Oct 2008 01:20:16 +0000 Subject: [PATCH] Applied the patch to add dtx's ClamAV integration module. --- citadel/docs/citadel.html | 6 + citadel/modules/serv_virus.c | 190 +++++++++++++++++++++++++++++ citadel/tuiconfig.c | 5 +- webcit/inetconf.c | 8 +- webcit/static/t/aide_inetconf.html | 1 + 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 citadel/modules/serv_virus.c diff --git a/citadel/docs/citadel.html b/citadel/docs/citadel.html index e5e577a45..bb028372b 100644 --- a/citadel/docs/citadel.html +++ b/citadel/docs/citadel.html @@ -140,6 +140,12 @@ others
IGnet protocol design
+ + Edward Flick
+ + ClamAV integration module
+
+ diff --git a/citadel/modules/serv_virus.c b/citadel/modules/serv_virus.c new file mode 100644 index 000000000..258738c48 --- /dev/null +++ b/citadel/modules/serv_virus.c @@ -0,0 +1,190 @@ +/* + * $Id$ + * + * This module allows Citadel to use clamd to filter incoming messages + * arriving via SMTP. For more information on clamd, visit + * http://clamav.net (the ClamAV project is not in any way + * affiliated with the Citadel project). + */ + +#define CLAMD_PORT "3310" + +#include "sysdep.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include "citadel.h" +#include "server.h" +#include "citserver.h" +#include "support.h" +#include "config.h" +#include "control.h" +#include "room_ops.h" +#include "user_ops.h" +#include "policy.h" +#include "database.h" +#include "msgbase.h" +#include "internet_addressing.h" +#include "domain.h" +#include "clientsocket.h" + + +#include "ctdl_module.h" + + + +/* + * Connect to the clamd server and scan a message. + */ +int clamd(struct CtdlMessage *msg) { + int sock = (-1); + int streamsock = (-1); + char clamhosts[SIZ]; + int num_clamhosts; + char buf[SIZ]; + char hostbuf[SIZ]; + char portbuf[SIZ]; + int is_virus = 0; + int clamhost; + char *msgtext; + size_t msglen; + + /* Don't care if you're logged in. You can still spread viruses. + */ + /* if (CC->logged_in) return(0); */ + + /* See if we have any clamd hosts configured */ + num_clamhosts = get_hosts(clamhosts, "clamav"); + if (num_clamhosts < 1) return(0); + + /* Try them one by one until we get a working one */ + for (clamhost=0; clamhost\n", buf); + + /* Assuming a host:port entry */ + extract_token(hostbuf, buf, 0, ':', sizeof hostbuf); + if (extract_token(portbuf, buf, 1, ':', sizeof portbuf)==-1) + /* Didn't specify a port so we'll try the psuedo-standard 3310 */ + sock = sock_connect(hostbuf, CLAMD_PORT, "tcp"); + else + /* Port specified lets try connecting to it! */ + sock = sock_connect(hostbuf, portbuf, "tcp"); + + if (sock >= 0) CtdlLogPrintf(CTDL_DEBUG, "Connected!\n"); + } + + if (sock < 0) { + /* If the service isn't running, just pass the mail + * through. Potentially throwing away mails isn't good. + */ + return(0); + } + + /* Command */ + CtdlLogPrintf(CTDL_DEBUG, "Transmitting STREAM command\n"); + sprintf(buf, "STREAM\r\n"); + sock_write(sock, buf, strlen(buf)); + + CtdlLogPrintf(CTDL_DEBUG, "Waiting for PORT number\n"); + if (sock_getln(sock, buf, sizeof buf) < 0) { + goto bail; + } + + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); + if (strncasecmp(buf, "PORT", 4)!=0) { + goto bail; + } + + /* Should have received a port number to connect to */ + extract_token(portbuf, buf, 1, ' ', sizeof portbuf); + + /* Attempt to establish connection to STREAM socket */ + streamsock = sock_connect(hostbuf, portbuf, "tcp"); + + if (streamsock < 0) { + /* If the service isn't running, just pass the mail + * through. Potentially throwing away mails isn't good. + */ + return(0); + } + else { + CtdlLogPrintf(CTDL_DEBUG, "STREAM socket connected!\n"); + } + + + + /* Message */ + CC->redirect_buffer = malloc(SIZ); + CC->redirect_len = 0; + CC->redirect_alloc = SIZ; + CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, 0); + msgtext = CC->redirect_buffer; + msglen = CC->redirect_len; + CC->redirect_buffer = NULL; + CC->redirect_len = 0; + CC->redirect_alloc = 0; + + sock_write(streamsock, msgtext, msglen); + free(msgtext); + + /* Close the streamsocket connection; this tells clamd + * that we're done. + */ + close(streamsock); + + /* Response */ + CtdlLogPrintf(CTDL_DEBUG, "Awaiting response\n"); + if (sock_getln(sock, buf, sizeof buf) < 0) { + goto bail; + } + CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf); + if (strncasecmp(buf, "stream: OK", 10)!=0) { + is_virus = 1; + } + + if (is_virus) { + if (msg->cm_fields['0'] != NULL) { + free(msg->cm_fields['0']); + } + msg->cm_fields['0'] = strdup("message rejected by virus filter"); + } + +bail: close(sock); + return(is_virus); +} + + + +CTDL_MODULE_INIT(virus) +{ + if (!threading) + { + CtdlRegisterMessageHook(clamd, EVT_SMTPSCAN); + } + + /* return our Subversion id for the Log */ + return "$Id$"; +} diff --git a/citadel/tuiconfig.c b/citadel/tuiconfig.c index 785784722..15461953e 100644 --- a/citadel/tuiconfig.c +++ b/citadel/tuiconfig.c @@ -390,7 +390,8 @@ void get_inet_rec_type(CtdlIPC *ipc, char *buf) { keyopt(" <4> SpamAssassin (Address of SpamAssassin server)\n"); keyopt(" <5> RBL (domain suffix of spam hunting RBL)\n"); keyopt(" <6> masq domains (Domains as which users are allowed to masquerade)\n"); - sel = intprompt("Which one", 1, 1, 6); + keyopt(" <7> ClamAV (Address of ClamAV clamd server)\n"); + sel = intprompt("Which one", 1, 1, 7); switch(sel) { case 1: strcpy(buf, "localhost"); return; @@ -404,6 +405,8 @@ void get_inet_rec_type(CtdlIPC *ipc, char *buf) { return; case 6: strcpy(buf, "masqdomain"); return; + case 7: strcpy(buf, "clamav"); + return; } } diff --git a/webcit/inetconf.c b/webcit/inetconf.c index cc04419c7..f865e7607 100644 --- a/webcit/inetconf.c +++ b/webcit/inetconf.c @@ -26,6 +26,7 @@ void display_inetconf(void) ic_rbl, ic_spamass, ic_masq, + ic_clamav, ic_max }; @@ -42,6 +43,7 @@ void display_inetconf(void) ic_keyword[3] = "rbl"; ic_keyword[4] = "spamassassin"; ic_keyword[5] = "masqdomain"; + ic_keyword[6] = "clamav"; ic_boxtitle[0] = _("Local host aliases"); ic_boxtitle[1] = _("Directory domains"); @@ -49,6 +51,7 @@ void display_inetconf(void) ic_boxtitle[3] = _("RBL hosts"); ic_boxtitle[4] = _("SpamAssassin hosts"); ic_boxtitle[5] = _("Masqueradable domains"); + ic_boxtitle[6] = _("ClamAV clamd hosts"); ic_desc[0] = _("(domains for which this host receives mail)"); ic_desc[1] = _("(domains mapped with the Global Address Book)"); @@ -56,6 +59,7 @@ void display_inetconf(void) ic_desc[3] = _("(hosts running a Realtime Blackhole List)"); ic_desc[4] = _("(hosts running the SpamAssassin service)"); ic_desc[5] = _("(Domains as which users are allowed to masquerade)"); + ic_desc[6] = _("(hosts running the ClamAV clamd service)"); for (i=0; i

+
-- 2.30.2