/* kbs - Simple, easily fooled, POP3 spam filter Copyright (C) 2003 Ian Cowburn (ianc@noddybox.demon.co.uk) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------- Rules database */ static const char id[]="$Id$"; #include #include #include #include #include #include "global.h" #include "dbase.h" #include "dstring.h" #include "config.h" #include "debug.h" #include "util.h" static const char header_id[]=KBS_DBASE_H; /* ---------------------------------------- TYPES */ struct Domain { RE_Expression name; int def_block; int no_user; int no_block; int no_allow; int no_allow_to; char **user; RE_Expression *block; RE_Expression *allow; RE_Expression *allow_to; Domain *next; Domain *prev; }; /* ---------------------------------------- GLOBALS */ static Domain *head; static Domain *tail; static int no_trusted_users=0; static int no_trusted_domains=0; static int no_blacklist=0; static char **trusted_user=NULL; static char **trusted_domain=NULL; static RE_Expression *blacklist=NULL; static DString reason=NULL; /* ---------------------------------------- PRVIVATE FUNCTIONS */ static int IsTrustedUser(const char *username, const char *domain) { char *p; int f; int res=FALSE; p=CopyStr(username); p=CatStr(p,"@"); p=CatStr(p,domain); for(f=0;fname,domain)) return dom; dom=dom->next; } return NULL; } static void DeJunk(DString ds, const char *p) { int last_ws=FALSE; while(*p) { if (isspace(*p)) { if (!last_ws) DSAddChar(ds,' '); last_ws=TRUE; } else last_ws=FALSE; if (isalnum(*p)) { DSAddChar(ds,*p); } p++; } } /* ---------------------------------------- INTERFACES */ Domain *DBNewDomain(RE_Expression name) { Domain *dom; dom=Malloc(sizeof *dom); dom->name=name; dom->def_block=FALSE; dom->no_user=0; dom->no_block=0; dom->no_allow=0; dom->user=NULL; dom->block=NULL; dom->allow=NULL; dom->allow_to=NULL; if (tail) tail->next=dom; else head=tail=dom; dom->prev=tail; dom->next=NULL; return dom; } void DBDefault(Domain *domain, int block) { domain->def_block=block; } void DBBlockUser(Domain *domain, const char *username) { domain->no_user++; domain->user=Realloc(domain->user,sizeof(char *)*domain->no_user); domain->user[domain->no_user-1]=CopyStr(username); } void DBAllowSubject(Domain *domain, RE_Expression re) { domain->no_allow++; domain->allow=Realloc(domain->allow,sizeof(RE_Expression)*domain->no_allow); domain->allow[domain->no_allow-1]=re; } void DBBlockSubject(Domain *domain, RE_Expression re) { domain->no_block++; domain->block=Realloc(domain->block,sizeof(RE_Expression)*domain->no_block); domain->block[domain->no_block-1]=re; } void DBAllowTo(Domain *domain, RE_Expression re) { domain->no_allow_to++; domain->allow_to=Realloc(domain->allow_to, sizeof(RE_Expression)*domain->no_allow_to); domain->allow_to[domain->no_allow_to-1]=re; } void DBTrustedUser(const char *username) { no_trusted_users++; trusted_user=Realloc(trusted_user,sizeof(char *)*no_trusted_users); trusted_user[no_trusted_users-1]=CopyStr(username); } void DBTrustedDomain(const char *domain) { no_trusted_domains++; trusted_domain=Realloc(trusted_domain,sizeof(char *)*no_trusted_domains); trusted_domain[no_trusted_domains-1]=CopyStr(domain); } void DBBlacklist(RE_Expression re) { no_blacklist++; blacklist=Realloc(blacklist,sizeof(RE_Expression)*no_blacklist); blacklist[no_blacklist-1]=re; } int DBBlockMessage(const POP3Message *msg) { static const char *html="text/html"; DString ds; const Domain *dom; int f; int show; KBSDEBUG(("msg.id=%d\n",msg->id)); KBSDEBUG(("msg.to='%s'\n",msg->to)); KBSDEBUG(("msg.from='%s'\n",msg->from)); KBSDEBUG(("msg.from_uname='%s'\n",msg->from_uname)); KBSDEBUG(("msg.from_domain='%s'\n",msg->from_domain)); KBSDEBUG(("msg.subject='%s'\n",msg->subject)); KBSDEBUG(("msg.content_type='%s'\n",msg->content_type)); show=ConfigInt(CONFIG_SHOWMATCH); reason=DSReset(reason); if (IsTrustedDomain(msg->from_domain)) return FALSE; if (IsTrustedUser(msg->from_uname,msg->from_domain)) return FALSE; if (ConfigInt(CONFIG_BLOCKHTML) && (strncmp(msg->content_type,html,strlen(html))==0 || strcmp(msg->content_type,"UNKNOWN")==0)) { DSAddCP(reason,"HTML message or unknown content type"); return TRUE; } for(f=0;ffrom_domain)) { if (show) { DSAddCP(reason,"blacklisted - "); DSAddCP(reason,REGetExpression(blacklist[f])); } else DSAddCP(reason,"blacklisted"); return TRUE; } } if (!(dom=GetDomain(msg->from_domain))) return FALSE; ds=DSInit(); if (ConfigInt(CONFIG_DEJUNK)) DeJunk(ds,msg->subject); else DSAddCP(ds,msg->subject); for(f=0;fno_allow;f++) { if (RESearch(dom->allow[f],ds->text)) { DSFree(ds); return FALSE; } } if (dom->no_allow_to) { int found=FALSE; int f; for(f=0;fno_allow_to && !found;f++) if (RESearch(dom->allow_to[f],msg->to)) found=TRUE; if (!found) { if (show) { DSAddCP(reason,"disallowed to address - "); DSAddCP(reason,msg->to); } else DSAddCP(reason,"disallowed to address"); DSFree(ds); return TRUE; } } 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); if (show) { DSAddCP(reason,"disallowed name - "); DSAddCP(reason,dom->user[f]); } else DSAddCP(reason,"disallowed name"); return TRUE; } } for(f=0;fno_block;f++) { if (RESearch(dom->block[f],ds->text)) { if (show) { DSAddCP(reason,"disallowed subject - "); DSAddCP(reason,REGetExpression(dom->block[f])); } else DSAddCP(reason,"disallowed subject"); DSFree(ds); return TRUE; } } DSAddCP(reason,"default block"); DSFree(ds); return dom->def_block; } const char *DBBlockReason(void) { return reason->text; } void DBClose(void) { Domain *d; int f; DSFree(reason); for(f=0;fnext; for(f=0;fno_user;f++) free(t->user[f]); free(t->user); for(f=0;fno_block;f++) REFree(t->block[f]); free(t->block); for(f=0;fno_allow;f++) REFree(t->allow[f]); free(t->allow); for(f=0;fno_allow_to;f++) REFree(t->allow_to[f]); free(t->allow_to); free(t); } no_trusted_users=0; no_trusted_domains=0; head=tail=NULL; trusted_user=NULL; trusted_domain=NULL; } void DBDump(void) { Domain *d; int f; for(f=0;fname,d->def_block ? "block":"allow")); for(f=0;fno_user;f++) KBSDEBUG((" user[%d]='%s'\n", f,d->user[f])); for(f=0;fno_block;f++) KBSDEBUG((" block[%d]='%s'\n", f,REGetExpression(d->block[f]))); for(f=0;fno_allow;f++) KBSDEBUG((" allow[%d]='%s'\n", f,REGetExpression(d->allow[f]))); for(f=0;fno_allow_to;f++) KBSDEBUG((" allow_to[%d]='%s'\n", f,REGetExpression(d->allow_to[f]))); d=d->next; } } /* END OF FILE */