Search
j0ke.net Open Build Service
>
Projects
>
server:mail
>
clamav
> clamav-milter.patch
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File clamav-milter.patch of Package clamav (Revision 18)
Currently displaying revision
18
,
show latest
--- clamav-milter/Makefile.in +++ clamav-milter/Makefile.in @@ -58,10 +58,11 @@ ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \ $(top_srcdir)/m4/argz.m4 $(top_srcdir)/m4/fdpassing.m4 \ - $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltdl.m4 \ - $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ - $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltdl.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ $(top_srcdir)/m4/mmap_private.m4 $(top_srcdir)/m4/resolv.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ --- clamav-milter/clamav-milter.c +++ clamav-milter/clamav-milter.c @@ -211,6 +211,14 @@ return 1; } + if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) { + localnets_free(); + whitelist_free(); + logg_close(); + optfree(opts); + return 1; + } + if(optget(opts, "AddHeader")->enabled) { char myname[255]; --- clamav-milter/clamfi.c +++ clamav-milter/clamfi.c @@ -61,6 +61,7 @@ } loginfected; #define CLAMFIBUFSZ 1424 +static const char *HDR_UNAVAIL = "UNKNOWN"; struct CLAMFI { char buffer[CLAMFIBUFSZ]; @@ -74,6 +75,7 @@ unsigned int totsz; unsigned int bufsz; unsigned int all_whitelisted; + unsigned int gotbody; }; @@ -91,12 +93,15 @@ }; -void makesanehdr(char *hdr) { +static const char *makesanehdr(char *hdr) { + char *ret = hdr; + if(!hdr) return HDR_UNAVAIL; while(*hdr) { if(*hdr=='\'' || *hdr=='\t' || *hdr=='\r' || *hdr=='\n' || !isprint(*hdr)) *hdr = ' '; hdr++; } + return ret; } static void nullify(SMFICTX *ctx, struct CLAMFI *cf, enum CFWHAT closewhat) { @@ -113,9 +118,22 @@ static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, SMFICTX *ctx) { - if(cf->totsz >= maxfilesize) + if(cf->totsz >= maxfilesize || len == 0) return SMFIS_CONTINUE; + if(!cf->totsz) { + sfsistat ret; + if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) { + logg("!Failed to initiate streaming/fdpassing\n"); + nullify(ctx, cf, CF_NONE); + return FailAction; + } + cf->totsz = 1; /* do not infloop */ + if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) + return ret; + cf->totsz -= 1; + } + if(cf->totsz + len > maxfilesize) len = maxfilesize - cf->totsz; @@ -166,35 +184,28 @@ if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_CONTINUE; /* whatever */ - if(loginfected == LOGINF_FULL) { - if(headerf && !strcasecmp(headerf, "Subject") && !cf->msg_subj) - cf->msg_subj = strdup(headerv); - if(headerf && !strcasecmp(headerf, "Date") && !cf->msg_date) - cf->msg_date = strdup(headerv); - if(headerf && !strcasecmp(headerf, "Message-ID") && !cf->msg_id) - cf->msg_id = strdup(headerv); + if(!cf->totsz && cf->all_whitelisted) { + logg("*Skipping scan (all destinations whitelisted)\n"); + nullify(ctx, cf, CF_NONE); + return SMFIS_ACCEPT; } - if(!cf->totsz) { - if(cf->all_whitelisted) { - logg("*Skipping scan (all destinations whitelisted)\n"); - nullify(ctx, cf, CF_NONE); - return SMFIS_ACCEPT; - } - if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) { - logg("!Failed to initiate streaming/fdpassing\n"); - nullify(ctx, cf, CF_NONE); - return FailAction; - } - if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) - return ret; + if(!headerf) return SMFIS_CONTINUE; /* just in case */ + + if(loginfected == LOGINF_FULL) { + if(!cf->msg_subj && !strcasecmp(headerf, "Subject")) + cf->msg_subj = strdup(headerv ? headerv : ""); + if(!cf->msg_date && !strcasecmp(headerf, "Date")) + cf->msg_date = strdup(headerv ? headerv : ""); + if(!cf->msg_id && !strcasecmp(headerf, "Message-ID")) + cf->msg_id = strdup(headerv ? headerv : ""); } if((ret = sendchunk(cf, (unsigned char *)headerf, strlen(headerf), ctx)) != SMFIS_CONTINUE) return ret; if((ret = sendchunk(cf, (unsigned char *)": ", 2, ctx)) != SMFIS_CONTINUE) return ret; - if((ret = sendchunk(cf, (unsigned char *)headerv, strlen(headerv), ctx)) != SMFIS_CONTINUE) + if(headerv && (ret = sendchunk(cf, (unsigned char *)headerv, strlen(headerv), ctx)) != SMFIS_CONTINUE) return ret; return sendchunk(cf, (unsigned char *)"\r\n", 2, ctx); } @@ -205,6 +216,14 @@ if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_CONTINUE; /* whatever */ + + if(!cf->gotbody) { + sfsistat ret = sendchunk(cf, (unsigned char *)"\r\n", 2, ctx); + if(ret != SMFIS_CONTINUE) + return ret; + cf->gotbody = 1; + } + return sendchunk(cf, bodyp, len, ctx); } @@ -225,6 +244,14 @@ if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_CONTINUE; /* whatever */ + if(!cf->totsz) { + /* got no headers and no body */ + logg("*Not scanning an empty message\n"); + ret = CleanAction(ctx); + nullify(ctx, cf, CF_NONE); + return ret; + } + if(cf->local) { if(nc_send(cf->main, "nFILDES\n", 8)) { logg("!FD scan request failed\n"); @@ -286,18 +313,19 @@ } if(loginfected) { - const char *from = smfi_getsymval(ctx, "{mail_addr}"), *to = smfi_getsymval(ctx, "{rcpt_addr}"); - - if(!from) from = "UNKNOWN"; - if(!to) to = "UNKNOWN"; - + const char *from = smfi_getsymval(ctx, "{mail_addr}"); + const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); + + if(!from) from = HDR_UNAVAIL; + if(!to) to = HDR_UNAVAIL; if(loginfected == LOGINF_FULL) { const char *id = smfi_getsymval(ctx, "{i}"); + const char *msg_subj = makesanehdr(cf->msg_subj); + const char *msg_date = makesanehdr(cf->msg_date); + const char *msg_id = makesanehdr(cf->msg_id); - makesanehdr(cf->msg_subj); - makesanehdr(cf->msg_date); - makesanehdr(cf->msg_id); - logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id ? id : "UNKNOWN", from, to, cf->msg_subj, cf->msg_id, cf->msg_date, vir); + if(!id) id = HDR_UNAVAIL; + logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id, from, to, msg_subj, msg_id, msg_date, vir); } else logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir); } } @@ -504,12 +532,18 @@ sfsistat clamfi_envfrom(SMFICTX *ctx, char **argv) { struct CLAMFI *cf; + const char *login = smfi_getsymval(ctx, "{auth_authen}"); + + if(login && smtpauthed(login)) { + logg("*Skipping scan for authenticated user %s\n", login); + return SMFIS_ACCEPT; + } if(whitelisted(argv[0], 1)) { logg("*Skipping scan for %s (whitelisted from)\n", argv[0]); return SMFIS_ACCEPT; } - + if(!(cf = (struct CLAMFI *)malloc(sizeof(*cf)))) { logg("!Failed to allocate CLAMFI struct\n"); return FailAction; @@ -518,6 +552,7 @@ cf->bufsz = 0; cf->main = cf->alt = -1; cf->all_whitelisted = 1; + cf->gotbody = 0; cf->msg_subj = cf->msg_date = cf->msg_id = NULL; smfi_setpriv(ctx, (void *)cf); --- clamav-milter/netcode.c +++ clamav-milter/netcode.c @@ -129,7 +129,7 @@ close(s); return -1; } - if (getsockopt(s, SOL_SOCKET, SO_ERROR, &s_err, &s_len) || s_err) { + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &s_err, &s_len) || s_err) { logg("*Failed to establish a connection to clamd\n"); close(s); return -1; @@ -163,8 +163,6 @@ tv.tv_usec = 0; while(1) { fd_set fds; - int s_err; - socklen_t s_len = sizeof(s_err); FD_ZERO(&fds); FD_SET(s, &fds); @@ -177,12 +175,10 @@ tv.tv_usec = 0; continue; } - logg("!Failed stream to clamd\n"); + logg("!Failed to stream to clamd\n"); close(s); return 1; } - len-=s_len; - buf+=s_len; break; } } --- clamav-milter/whitelist.c +++ clamav-milter/whitelist.c @@ -25,8 +25,8 @@ #include <stdio.h> #include <string.h> #include <sys/types.h> -#include <regex.h> +#include "libclamav/regex/regex.h" #include "shared/output.h" #include "whitelist.h" @@ -38,17 +38,20 @@ struct WHLST *wfrom = NULL; struct WHLST *wto = NULL; +int skipauth = 0; +regex_t authreg; + void whitelist_free(void) { struct WHLST *w; while(wfrom) { w = wfrom->next; - regfree(&wfrom->preg); + cli_regfree(&wfrom->preg); free(wfrom); wfrom = w; } while(wto) { w = wto->next; - regfree(&wto->preg); + cli_regfree(&wto->preg); free(wto); wto = w; } @@ -85,14 +88,14 @@ } if(!len) continue; if (!(w = (struct WHLST *)malloc(sizeof(*w)))) { - logg("!Out of memory loading whitelist\n"); + logg("!Out of memory loading whitelist file\n"); whitelist_free(); return 1; } w->next = (*addto); (*addto) = w; - if (regcomp(&w->preg, ptr, REG_ICASE|REG_NOSUB)) { - logg("!Failed to compile regex '%s'\n", ptr); + if (cli_regcomp(&w->preg, ptr, REG_ICASE|REG_NOSUB)) { + logg("!Failed to compile regex '%s' in whitelist file\n", ptr); whitelist_free(); return 1; } @@ -108,13 +111,30 @@ else w = wto; while(w) { - if(!regexec(&w->preg, addr, 0, NULL, 0)) + if(!cli_regexec(&w->preg, addr, 0, NULL, 0)) return 1; w = w->next; } return 0; } + +int smtpauth_init(const char *r) { + if (cli_regcomp(&authreg, r, REG_ICASE|REG_NOSUB|REG_EXTENDED)) { + logg("!Failed to compile regex '%s' for SkipAuthSenders\n", r); + return 1; + } + skipauth = 1; + return 0; +} + + +int smtpauthed(const char *login) { + if(skipauth && !cli_regexec(&authreg, login, 0, NULL, 0)) + return 1; + return 0; +} + /* * Local Variables: --- clamav-milter/whitelist.h +++ clamav-milter/whitelist.h @@ -24,4 +24,6 @@ int whitelist_init(const char *fname); void whitelist_free(void); int whitelisted(const char *addr, int from); +int smtpauth_init(const char *r); +int smtpauthed(const char *login); #endif --- etc/clamav-milter.conf +++ etc/clamav-milter.conf @@ -94,7 +94,7 @@ #LocalNet 192.168.0.0/24 #LocalNet 1111:2222:3333::/48 -# This option specifies a file which contains a list of POSIX regular +# This option specifies a file which contains a list of basic POSIX regular # expressions. Addresses (sent to or from - see below) matching these regexes # will not be scanned. Optionally each line can start with the string "From:" # or "To:" (note: no whitespace after the colon) indicating if it is, @@ -105,6 +105,13 @@ # Default unset (no exclusion applied) #Whitelist /etc/whitelisted_addresses +# Messages from authenticated SMTP users matching this extended POSIX +# regular expression (egrep-like) will not be scanned. +# Note: this is the AUTH login name! +# +# Default: unset (no whitelisting based on SMTP auth) +#SkipAuthenticated ^(tom|dick|henry)$ + ## ## Actions --- shared/optparser.c +++ shared/optparser.c @@ -382,7 +382,9 @@ { "Chroot", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "Chroot to the specified directory.\nChrooting is performed just after reading the config file and before\ndropping privileges.", "/newroot" }, - { "Whitelist", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned. Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be whitelisted.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/whitelisted_addresses" }, + { "Whitelist", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option specifies a file which contains a list of basic POSIX regular\nexpressions. Addresses (sent to or from - see below) matching these regexes\nwill not be scanned. Optionally each line can start with the string \"From:\"\nor \"To:\" (note: no whitespace after the colon) indicating if it is,\nrespectively, the sender or recipient that is to be whitelisted.\nIf the field is missing, \"To:\" is assumed.\nLines starting with #, : or ! are ignored.", "/etc/whitelisted_addresses" }, + + { "SkipAuthenticated", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "Messages from authenticated SMTP users matching this extended POSIX\nregular expression (egrep-like) will not be scanned.\nNote: this is the AUTH login name!", "SkipAuthenticated ^(tom|dick|henry)$" }, { "LogInfected", NULL, 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER, "This option allows to tune what is logged when a message is infected.\nPossible values are Off (the default - nothing is logged),\nBasic (minimal info logged), Full (verbose info logged)", "Basic" },