#include #include #include #include #include #include #include #include #include #include #include // #define DEBUG 1 /* ankar magic Black and White list processing for Qmail the actual program to be executed is /usr/bin/procmail -m HOME=$HOME PARM=$PARM /export/home/procmailrcs/GlobalFilter where $PARM is a string of ssss equal to the antispam level of the user The procmail filter matches X--Hol-blacklist: yes or X--Hol-whitelist: yes and sends incoming email directly into the new or .sparm maildirs otherwise it Greps ^X--Mailscanner: ssss which is the mailscanner score in the emails header #=============================cut here for GlobalFilter.quota========================================== # set variables LINEBUF=131072 ARG=$1 SHELL=/bin/sh PATH=/bin:/usr/sbin/:/usr/bin:/usr/local/bin:/usr/bin/mh:/usr/lib/mh: VERBOSE=off MAILDIR=$HOME/Maildir/ JUNKMAILDIR=$HOME/Maildir/.JunkMail/ #LOGFILE=/tmp/quota.procmail.log LOGFILE=/dev/null FORMAIL=/usr/bin/formail SENDMAIL=/usr/sbin/sendmail TOGREP="^X--MailScanner-SpamScore: " # Whitelist :0 w * ^X--Hol-whitelist:.yes |deliverquota -c -w 90 $MAILDIR $MAILDIRQUOTA # blacklist :0 E w * ^X--Hol-blacklist:.yes |deliverquota -c -w 90 $JUNKMAILDIR $MAILDIRQUOTA ######## Spam Filter :0 E w * H ?? ? grep "$TOGREP$PARM" |deliverquota -c -w 90 $JUNKMAILDIR $MAILDIRQUOTA :0 E w |deliverquota -c -w 90 $MAILDIR $MAILDIRQUOTA ######## End of spam report process #--------------------------------------------------------- :0 e w { EXITCODE="77" :0 /dev/null } #--------------------------------------------------------- #===================================cut here=========================================== */ /***********************************************************************/ #define TIMEOUT 9 /* server can be slow sometimes this is just here to avoid hanging processes */ #define BLACKYES "X--Hol-blacklist: yes" #define WHITEYES "X--Hol-whitelist: yes" #define PROG "/usr/bin/procmail" #define FILTER "/export/home/procmailrcs/GlobalFilter.quota" #define CHECKFILE "/export/home/procmailrcs/MYSQL.OK" #define MYSERVER "SERVER" /* same host must be in CheckMy */ #define MYUSER "mail" #define MYPASS "pass" #define MYPORT 3306 #define MYDB "ERP" #define QUERY "SELECT type \ from \ rmail_spamlists \ where \ uid=%d \ and \ ( \ LOWER(originator)=LOWER('%s') \ or \ LOWER(originator)=LOWER('%s') \ ) \ order by \ weight asc \ limit 1" #define MAXLIST 100 #define MAXLISTEL 2048 /* big email addresses :-) */ #define MAXLINE 10240 #define QMAILSOFTERR 111 #define QMAILHARDERR 100 #define QMAILOK 99 #define BLACK 5 #define WHITE 10 #define UNKNOWN 15 /***********************************************************************/ /***********************************************************************/ void makeparms(int argc ,char **argv,char *command); int domysql(const char *from,const char *fromdom); inline void getfromdom(const char *line, char *from,char *fromdom); int checkstatus(void); /* globals */ static jmp_buf env_alrm; /* for alarms */ static int MYSQLOK=1; /***********************************************************************/ void catch_alarm (int sig) { siglongjmp(env_alrm, 1); } /*======================================================================*/ int main (int argc ,char **argv){ char command[MAXLISTEL],line[MAXLINE]; char email[MAXLISTEL]; char from[MAXLISTEL]; /* from address */ char fromdom[MAXLISTEL]; /* from domain part*/ int linesize=MAXLINE-1; FILE *OUT; int i; // openlog("BWQuotaSpamFilter",LOG_NDELAY|LOG_PID,LOG_MAIL); openlog("BWQSF",LOG_NDELAY|LOG_PID,LOG_MAIL); makeparms(argc,argv,command); /* I will need this later */ checkstatus(); strncpy(email,getenv("RECIPIENT"),MAXLISTEL); signal (SIGALRM, catch_alarm); /* set up the alarm functions */ alarm(0); int caughtALRM=0; /* pipe if you can */ if ( (OUT=popen(command,"w"))==NULL) { syslog(LOG_ERR,"Cannot open Pipe to %s",command ); closelog(); exit(QMAILSOFTERR); } putenv("LINEBUF=131072"); /* read the input pipe it to the procmail filter */ /* retrieve the from field, not option for locale encoded stuff */ int foundfrom=0; while ( fgets(line, linesize, stdin)!=NULL) { fputs(line,OUT); /* procmail gets everything */ /* only process while in header */ if ( ! foundfrom ) if ( strncmp(line,"From: ",6) == 0 ) { foundfrom=1; /* in any case */ #ifdef DEBUG syslog(LOG_INFO,"Found From = \'%s\'",line); /* if debug */ #endif getfromdom(line,from,fromdom); #ifdef DEBUG syslog(LOG_INFO,"Message to %s from %s",email,from); /* if debug */ #endif /* timeout checking */ caughtALRM=sigsetjmp(env_alrm,1); if (caughtALRM==1) { syslog(LOG_CRIT,"[ALARM] MYSQL Server timeout no BW processing"); alarm(0); continue; } alarm(TIMEOUT); int color=UNKNOWN; color=domysql(from,fromdom); /* all the work is in this function */ alarm(0); switch(color) { case WHITE: syslog(LOG_WARNING,"Originator %-30s in white list of %s",from,email); fprintf(OUT,"%s\n",WHITEYES); break; case BLACK: syslog(LOG_WARNING,"Originator %-30s in black list of %s",from,email); fprintf(OUT,"%s\n",BLACKYES); break; default: syslog(LOG_INFO, "Originator %-30s in neither list of %s",from,email); break; } } /* From */ }/* fgets */ fclose(stdin); int ret=pclose(OUT); if ( ret != 0 ) { syslog(LOG_ERR,"Delivery failed error %d",ret/256); } else { ret=QMAILOK; } closelog(); return(ret); /* qmail success */ } /*======================================================================*/ /***********************************************************************/ int domysql(const char *from,const char *fromdom){ MYSQL DB; MYSQL_ROW row; MYSQL_RES *res; char query[MAXLISTEL]; int i,result=UNKNOWN; if (MYSQLOK==0) { /* was reported bad */ return(1); } sprintf(query,QUERY,(long)getuid(),from,fromdom); /* qmail must have our uid set up already */ #ifdef DEBUG syslog(LOG_INFO,"query=%s",query); /* if debug */ #endif mysql_init(&DB); /* a must */ mysql_real_connect(&DB, MYSERVER,MYUSER,MYPASS,MYDB,MYPORT,NULL,0); if ( &DB == NULL ) { syslog(LOG_ERR,"Mysql Connect Failed %s", mysql_error(&DB)); return(-1); /* error */ } mysql_query(&DB, query); res = mysql_store_result(&DB); if ( res == NULL) { mysql_close(&DB); syslog(LOG_ERR,"Mysql query Failed %s", mysql_error(&DB)); return(-1); /* error */ } if ( ! (row = mysql_fetch_row(res)) ) { #ifdef DEBUG syslog(LOG_INFO,"Mysql no data"); /* if debug */ #endif mysql_free_result(res); mysql_close(&DB); return(0); /* not an error , just no data */ } int mytype=row[0]?atoi(row[0]):UNKNOWN; /* thanks cakrit */ mysql_free_result(res); mysql_close(&DB); switch(mytype){ case 0: result=BLACK; break; case 1: result=WHITE; break; default: result=UNKNOWN; break; } return(result); } /***********************************************************************/ /***********************************************************************/ void makeparms(int argc ,char **argv, char *command){ register int i; char prog[]=PROG; char m[]="-m"; char HOME[MAXLISTEL]; char PARM[MAXLISTEL]; char MQUOTA[MAXLISTEL]; char filter[]=FILTER; char *newargv[MAXLIST]; /* pointers to above for old execvp usage*/ char newparams[MAXLIST][MAXLISTEL]; /* parameter list for procmail */ #ifdef DEBUG syslog(LOG_INFO,"MakeArgs Param %s",argv[1]); #endif strncpy(HOME,"HOME=",MAXLISTEL); strncat(HOME,getenv("HOME"),MAXLISTEL-5); if ( argc > 1 ) { strncpy(PARM,"PARM=",MAXLISTEL); for (i=1;i<=atoi(argv[1]);i++) strcat(PARM,"s"); } i=0; /* for local storage */ strncpy(newparams[i++],prog,MAXLISTEL); strncpy(newparams[i++],m,MAXLISTEL); strncpy(newparams[i++],HOME,MAXLISTEL); if ( argc > 1 ) strncpy(newparams[i++],PARM,MAXLISTEL); if ( getenv("MAILDIRQUOTA") ) { strncpy(MQUOTA,"MAILDIRQUOTA=",MAXLISTEL); strncat(MQUOTA, getenv("MAILDIRQUOTA"),MAXLISTEL ); strncpy(newparams[i++],MQUOTA,MAXLISTEL); } strncpy(newparams[i++],filter,MAXLISTEL); strncpy(newparams[i++],"2> /dev/null",MAXLISTEL); /* we cannot read the output any way */ newparams[i][0]='\0'; /* initialize the new **argv array */ /* not needed any more */ for (i=0; newparams[i][0] != '\0' ;i++) newargv[i]=(char *) newparams[i]; newargv[i]=(char *) NULL; /* make the popen command */ i=1; strncpy(command,PROG,MAXLISTEL); for (i=1; newargv[i] != NULL ; i++) { strcat(command," "); strcat(command,newargv[i]); } #ifdef DEBUG syslog(LOG_INFO,"command=%s",command); /* if debug */ #endif } /***********************************************************************/ /***********************************************************************/ void getfromdom(const char *line, char *from ,char *fromdom){ /* scan from field for b&w list */ char *wheretofindemail; char *wheretofinddomain; bzero(from,MAXLISTEL); bzero(fromdom,MAXLISTEL); /* locate the originator mail */ wheretofindemail=strstr(line,"<"); if (wheretofindemail!=NULL) { wheretofindemail++; /* copy it over */ strncpy(from,wheretofindemail,MAXLISTEL); wheretofindemail=strstr(from,">"); /* terminate nicely */ *wheretofindemail='\0'; #ifdef DEBUG syslog(LOG_INFO,"from is <%s>",from); #endif } else { /* From address not in <> */ wheretofindemail=(char *)line; wheretofindemail+=6; strncpy(from,wheretofindemail,MAXLISTEL); from[strlen(from)-1]='\0'; #ifdef DEBUG syslog(LOG_INFO,"from is %s",from); #endif } /* now locate the domain */ wheretofinddomain=strchr(from,'@'); wheretofinddomain++; strncpy(fromdom,wheretofinddomain,MAXLISTEL); } /***********************************************************************/ /***********************************************************************/ int checkstatus(void){ struct stat check; extern char **environ; char **myenv; int i; myenv=environ; #ifdef DEBUG for ( i=0; myenv[i] != NULL;i++ ) { syslog(LOG_INFO,"ENV %s",myenv[i]); } #endif if (!getenv("RECIPIENT")) { syslog(LOG_CRIT,"No RECIPIENT in $ENV, exiting"); closelog(); exit(QMAILHARDERR); } if (strlen(getenv("RECIPIENT")) <1 ) { syslog(LOG_CRIT,"RECIPIENT too small in $ENV, exiting %s",getenv("RECIPIENT")); closelog(); exit(QMAILHARDERR); } /* oooh sometimes it does not exist if (!getenv("SENDER")) { syslog(LOG_CRIT,"No SENDER in $ENV, exiting"); closelog(); exit(QMAILHARDERR); } if (strlen(getenv("SENDER")) <1 ) { syslog(LOG_CRIT,"SENDER too small in $ENV, exiting %s",getenv("SENDER")); closelog(); exit(QMAILHARDERR); } */ #ifdef DEBUG if ( getenv("MAILDIRQUOTA") ) { syslog(LOG_INFO,"User Quota %s",getenv("MAILDIRQUOTA")); } #endif if (getenv("HOME")==NULL) { syslog(LOG_CRIT,"No HOME in $ENV, exiting"); closelog(); exit(QMAILHARDERR); } /* check the file that reports mysql status */ if ( stat(CHECKFILE,&check) == -1 ) { syslog(LOG_ERR,"Mysql is Reported down by %s, no BWlist processing",CHECKFILE); MYSQLOK=0; } } /***********************************************************************/