From 1c161a8cbe16aa59cc8bf4d60d5fa64fdcbc6aa5 Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 8 Dec 2003 02:20:14 +0000 Subject: Added subject_macro; Tweaked check order; Fixed some warnings --- doc/INSTRUCTION | 78 +++++++++++++++++++++++++++++++------- src/Makefile | 13 ++++--- src/config.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/dbase.c | 36 +++++++++--------- src/dstring.c | 9 +++-- src/pop3.c | 5 +-- 6 files changed, 207 insertions(+), 47 deletions(-) diff --git a/doc/INSTRUCTION b/doc/INSTRUCTION index ef0cdc6..e55fdef 100644 --- a/doc/INSTRUCTION +++ b/doc/INSTRUCTION @@ -23,19 +23,21 @@ order: [trusted settings] +[subject macros] + [domain settings] -Note it is *highly* recommended to set .kbsrc to be only readable by the -user - this is as passwords are stored in there. +It is *highly* recommended to set .kbsrc to be only readable by the user - this +is as passwords are stored in there. Blank lines and text proceeded with a hash (#) are ignored. Each token is delimited with white space - if the value you want to use includes spaces, simple quote them (with either single or double quotes). -Note that escapes aren't used (to make regular expression writing easier), so -if you want to include a quote in a string, simply use the other sort of quote. -If you want both, sorry, you're stuck! +Escapes aren't used (to make regular expression writing easier), so if you want +to include a quote in a string, simply use the other sort of quote. If you +want both, sorry, you're stuck! To see an example kbsrc file, see kbsrc in the src directory. @@ -89,12 +91,13 @@ And understand the following variables: Defaults to off. blockhtml Whether messages that are pure HTML (content part just - reported as "text/html" are blocked. + reported as "text/html" are blocked. Also blocks + messages with an empty, or missing, content type. Defaults to off. testmode Whether things will be really deleted, or just - the actions logged. Note that the log is still - filled out as if the deletion occured. + the actions logged. The log is still filled out as if + the deletion occured. Defaults to off, though it is recommended to use this for early runs to ensure your rules are not too harsh (or too easy for that matter). @@ -119,12 +122,47 @@ other tests. } +Subject Macros +============== + +This command is simply to ease the writing of regular expressions where you +want to match expressions where numbers or alternative characters are +often used to try and fool filters: + + subject_macro + +e.g. + + subject_macro "i" "[i1!l]" # Common spam spellings for 'i' + subject_macro "e" "[e3]" + subject_macro "s" "[s5]" + ... + ... + disallow_subject " ?free movies ?" + +Subject macros are only expanded one time - if the result of an expansion +includes another macro, that will not be expanded. Also remember +that macros are case sensitive - this allows easy constructions like this +which would break if the 'i' in the '[]' was expanded: + + set casesense off + ... + ... + subject "i" "[i1!l]" + ... + ... + disallow_subject "i...[I12]" + +Even though it's not obvious from the examples above, the source string can +be any number of characters. + + Domain settings =============== -These define the rules applied to a certain domain. Note the order these -appear in is important, as the first match when checking domain names will -be used. +These define the rules applied to a certain domain. The order domains +appear in is important, as the first match found when checking domain names +will be used. domain { @@ -147,9 +185,21 @@ always let through. The block_subject means that subjects that match that regular expression are always blocked and deleted. -Note that multiple allow_subject and block_subject commands can be in one -domain. +Multiple allow and block commands can be in one domain. + +The commands inside a domain can appear in any order, but the checks are always +done in this order: + +1. If a trusted domain, allow message. +2. If a trusted user, allow message. +3. If an HTML message and these are blocked, delete message. +4. If the domain is not matched in a domain command, allow message. +5. If the subject is allowed for the domain, allow message. +6. If the username is blocked for the domain, delete message. +7. If the subject is disallowed for the domain, delete message. +8. Delete the message if the default is to block. + ------------------------------------------------------------------------------- -$Id: INSTRUCTION,v 1.3 2003-12-07 01:46:44 ianc Exp $ +$Id: INSTRUCTION,v 1.4 2003-12-08 02:20:14 ianc Exp $ diff --git a/src/Makefile b/src/Makefile index 481148b..808d8ef 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,10 +18,11 @@ # # ------------------------------------------------------------------------- # -# $Id: Makefile,v 1.3 2003-12-05 19:38:37 ianc Exp $ +# $Id: Makefile,v 1.4 2003-12-08 02:20:14 ianc Exp $ # -CFLAGS += -g +# CFLAGS assumes that gcc is being used - simply comment out if required +CFLAGS = -g -Wall -Werror TARGET = kbs @@ -60,8 +61,8 @@ kbs.o: /usr/include/limits.h /usr/include/sys/limits.h kbs.o: /usr/include/machine/_limits.h /usr/include/sys/syslimits.h kbs.o: /usr/include/stdio.h /usr/include/string.h /usr/include/strings.h kbs.o: /usr/include/stdarg.h /usr/include/time.h /usr/include/sys/timespec.h -kbs.o: /usr/include/errno.h global.h config.h pop3.h msg.h dbase.h dstring.h -kbs.o: util.h +kbs.o: /usr/include/errno.h global.h config.h pop3.h msg.h dbase.h rexp.h +kbs.o: dstring.h util.h pop3.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h pop3.o: /usr/include/sys/_types.h /usr/include/machine/_types.h pop3.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h @@ -80,12 +81,12 @@ config.o: /usr/include/errno.h /usr/include/ctype.h /usr/include/runetype.h config.o: global.h config.h dstring.h dbase.h msg.h rexp.h util.h rexp.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h rexp.o: /usr/include/sys/_types.h /usr/include/machine/_types.h -rexp.o: /usr/include/regex.h global.h rexp.h config.h +rexp.o: /usr/include/regex.h global.h rexp.h config.h util.h dbase.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h dbase.o: /usr/include/sys/_types.h /usr/include/machine/_types.h dbase.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h dbase.o: /usr/include/ctype.h /usr/include/runetype.h global.h dbase.h msg.h -dbase.o: dstring.h config.h rexp.h util.h +dbase.o: rexp.h dstring.h config.h util.h dstring.o: /usr/include/stdlib.h /usr/include/sys/cdefs.h dstring.o: /usr/include/sys/_types.h /usr/include/machine/_types.h dstring.o: /usr/include/string.h /usr/include/strings.h /usr/include/stdio.h diff --git a/src/config.c b/src/config.c index 616fabf..268198d 100644 --- a/src/config.c +++ b/src/config.c @@ -53,6 +53,7 @@ typedef enum { TOK_BlockUser, TOK_AllowSubject, TOK_BlockSubject, + TOK_SubjectMacro, TOK_VarHostname, TOK_VarPort, TOK_VarUsername, @@ -77,10 +78,17 @@ typedef struct Command Token token; } Command; +typedef struct + { + char *macro; + char *expansion; + } Macro; + /* ---------------------------------------- GLOBALS */ static DString error; + static char *hostname=NULL; static char *username=NULL; static char *password=NULL; @@ -93,6 +101,9 @@ static int testmode=FALSE; static int blockhtml=FALSE; static int verbose=TRUE; +static int no_macro=0; +static Macro *macro=NULL; + /* ---------------------------------------- COMMAND TABLE */ @@ -110,6 +121,7 @@ static const Command cmd_table[]= {"block_user", TOK_BlockUser}, {"allow_subject", TOK_AllowSubject}, {"block_subject", TOK_BlockSubject}, + {"subject_macro", TOK_SubjectMacro}, /* Variables */ @@ -143,6 +155,48 @@ static const Command cmd_table[]= static Token GetToken(FILE *fp, DString *ret); +/* ---------------------------------------- COMMAND HANDLER UTILS +*/ +static DString ExpandRE(DString re) +{ + DString new; + Macro *m; + char *p; + int f; + + new=DSInit(); + + p=re->text; + + while(*p) + { + m=NULL; + + for(f=0;fexpansion); + p+=strlen(m->macro); + } + } + + DSFree(re); + return new; +} + + /* ---------------------------------------- COMMAND HANDLERS */ static int DoSet(FILE *fp) @@ -252,7 +306,6 @@ static int DoDomain(FILE *fp) { DString ds; Token tok; - int status=TRUE; Domain *domain; RE_Expression re; @@ -327,6 +380,8 @@ static int DoDomain(FILE *fp) case TOK_AllowSubject: GetToken(fp,&ds); + ds=ExpandRE(ds); + if (!(re=RECompile(ds->text))) { DSAddCP(error,"Bad regular expression: "); @@ -341,6 +396,8 @@ static int DoDomain(FILE *fp) case TOK_BlockSubject: GetToken(fp,&ds); + ds=ExpandRE(ds); + if (!(re=RECompile(ds->text))) { DSAddCP(error,"Bad regular expression: "); @@ -371,7 +428,6 @@ static int DoTrustedUsers(FILE *fp) { DString ds; Token tok; - int status=TRUE; ds=DSInit(); @@ -406,7 +462,6 @@ static int DoTrustedDomains(FILE *fp) { DString ds; Token tok; - int status=TRUE; ds=DSInit(); @@ -433,6 +488,42 @@ static int DoTrustedDomains(FILE *fp) } +static int DoSubjectMacro(FILE *fp) +{ + DString arg[2]; + int f; + + for(f=0;f<2;f++) + { + arg[f]=DSInit(); + + if (GetToken(fp,&arg[f])==TOK_EOF) + { + DSAddCP(error,"Unexpected EOF in subject_macro"); + return FALSE; + } + } + + if (arg[0]->len==0 || arg[1]->len==0) + { + DSAddCP(error,"Can't use zero length strings in subject_macro"); + return FALSE; + } + + no_macro++; + + macro=Realloc(macro,sizeof *macro * no_macro); + + macro[no_macro-1].macro=CopyStr(arg[0]->text); + macro[no_macro-1].expansion=CopyStr(arg[1]->text); + + for(f=0;f<2;f++) + DSFree(arg[f]); + + return TRUE; +} + + /* ---------------------------------------- PRVIVATE FUNCTIONS */ static int Getc(FILE *fp) @@ -570,7 +661,6 @@ static int Parse(FILE *fp) { DString txt; Token tok; - char *p; txt=DSInit(); @@ -600,6 +690,11 @@ static int Parse(FILE *fp) ok=FALSE; break; + case TOK_SubjectMacro: + if (!DoSubjectMacro(fp)) + ok=FALSE; + break; + case TOK_Expression: DSAddCP(error,"Unknown command in config file: "); DSAddDS(error,txt); @@ -725,6 +820,16 @@ int ConfigInt(ConfigIntVar var) void ConfigClose(void) { + int f; + + for(f=0;fcontent_type,html,strlen(html))==0) + (strncmp(msg->content_type,html,strlen(html))==0 || + strcmp(msg->content_type,"UNKNOWN")==0)) { reason="HTML message"; return TRUE; @@ -245,22 +246,6 @@ int DBBlockMessage(const POP3Message *msg) if (!(dom=GetDomain(msg->from_domain))) return FALSE; - for(f=0;fno_user;f++) - { - int res; - - if (ConfigInt(CONFIG_CASESENSE)) - res=strcmp(dom->user[f],msg->from_uname); - else - res=strcasecmp(dom->user[f],msg->from_uname); - - if (res==0) - { - reason="disallowed name"; - return TRUE; - } - } - ds=DSInit(); if (ConfigInt(CONFIG_DEJUNK)) @@ -277,6 +262,23 @@ int DBBlockMessage(const POP3Message *msg) } } + for(f=0;fno_user;f++) + { + int res; + + if (ConfigInt(CONFIG_CASESENSE)) + res=strcmp(dom->user[f],msg->from_uname); + else + res=strcasecmp(dom->user[f],msg->from_uname); + + if (res==0) + { + DSFree(ds); + reason="disallowed name"; + return TRUE; + } + } + for(f=0;fno_block;f++) { if (RESearch(dom->block[f],ds->text)) diff --git a/src/dstring.c b/src/dstring.c index e614e83..7e13067 100644 --- a/src/dstring.c +++ b/src/dstring.c @@ -87,6 +87,8 @@ DString DSAddChar(DString to, char c) to->text[to->len++]=c; to->text[to->len]=0; + + return to; } @@ -96,15 +98,16 @@ DString DSAddCP(DString to, const char *from) to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE); strcat(to->text,from); + + return to; } DString DSAddDS(DString to, const DString from) { - to->len+=from->len; - to->text=Realloc(to->text,(((to->len+1)/BLOCKSIZE)+1)*BLOCKSIZE); + DSAddCP(to,from->text); - strcat(to->text,from->text); + return to; } diff --git a/src/pop3.c b/src/pop3.c index 660283e..d9fab19 100644 --- a/src/pop3.c +++ b/src/pop3.c @@ -31,6 +31,7 @@ static const char id[]="$Id$"; #include #include +#include #include #include #include @@ -183,7 +184,6 @@ static int GetChar(void) static char buff[BLOCKSIZE]; static ssize_t len=0; static int ptr=0; - int ch; if (len==0 || ptr==len) { @@ -214,10 +214,9 @@ static int GetChar(void) static int GetLine(DString t) { - size_t size; int done; - int ch; int last; + int ch; done=FALSE; -- cgit v1.2.3