#include "policyd.h" /* * * * Policy Daemon * * policy daemon is used in conjuction with postfix to combat spam. * * Copyright (C) 2004 Cami Sardinha (cami@mweb.co.za) * * * 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 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 * * * */ /* * function: throttle_rcpt * purpose: throttle users based on envelope RCPT * return: 0 for new record, 1 for update */ signed int throttle_rcpt (unsigned int fd) { if(DEBUG > 0) logmessage("DEBUG: fd: %d checking throttle-rcpt\n", fd); /* build up & execute query */ snprintf(mysqlquery_array[fd], 512, "SELECT _rcpt,_count_max,_count_cur,_time_limit,_date,_count_tot" " FROM throttle_rcpt WHERE _rcpt='%s'", triplet_array[fd][2]); if(db_charquery(fd) == -1) return(db_failure(fd, "throttle_rcpt")); /* max messages is disabled in database, fall back to config default */ if(atol(mysqlchar_array[fd][1]) == 0) snprintf(mysqlchar_array[fd][1], sizeof(mysqlchar_array[fd][1]), "%d", RECIPIENTMSGLIMIT); /* max time limit is disabled in database, fall back to config defaults */ if(atol(mysqlchar_array[fd][3]) == 0) snprintf(mysqlchar_array[fd][3], sizeof(mysqlchar_array[fd][3]), "%d", RECIPIENTTIMELIMIT); /* prepare attributes & thresholds */ trcpt[fd] = atof(mysqlchar_array[fd][2]) / atof(mysqlchar_array[fd][1]) * 100; /* percentage won, set attribute accordingly */ switch (trcpt[fd]) { case 0 ... 49: tattrib_array[fd][0] = 'a'; break; case 50 ... 89: tattrib_array[fd][0] = 'w'; break; case 90 ... 1000: tattrib_array[fd][0] = 'p'; break; default: logmessage("fatal: throttle_rcpt(): invalid tresult: %d\n", trcpt[fd]); } /* user is not in the database */ if(strlen(mysqlchar_array[fd][0]) < 2) { logmessage("rcpt=%lu, throttle_rcpt=new(a), host=%s, from=%s, to=%s, " "count=1/%d(1), threshold=0%\n", rcpt_count, /* recipient count */ host_array[fd][2], /* host */ triplet_array[fd][1], /* from */ triplet_array[fd][2], /* to */ atol(mysqlchar_array[fd][1]) /* count_max */ ); /* build up & execute query */ snprintf(mysqlquery_array[fd], 512, "INSERT DELAYED INTO throttle_rcpt (_date,_rcpt,_count_max,_time_limit) " "VALUES (%d, '%s', %ld, %ld)", timenow, triplet_array[fd][2], atol(mysqlchar_array[fd][1]), atol(mysqlchar_array[fd][3])); if(db_doquery(fd) == -1) return(db_failure(fd, "throttle_rcpt")); /* recipient does not exist in the database, insert and allow */ return (0); } /* if time has expired, clear quota for message count */ if(timenow > (unsigned int)(atol(mysqlchar_array[fd][4])+atol(mysqlchar_array[fd][3]))) { logmessage("rcpt=%lu, throttle_rcpt=clear(a), host=%s, from=%s, to=%s, " "count=0/%d(%d), threshold=0%\n", rcpt_count, /* recipient count */ host_array[fd][2], /* host */ triplet_array[fd][1], /* from */ triplet_array[fd][2], /* to */ atol(mysqlchar_array[fd][1]), /* count_max */ atol(mysqlchar_array[fd][5]) /* count_tot */ ); /* build up & execute query */ snprintf(mysqlquery_array[fd], 512, "UPDATE throttle_rcpt SET" " _count_cur=1," " _count_tot=_count_tot+1," " _abuse_tot=_abuse_tot+_abuse_cur," " _date=%d," " _abuse_cur=0" " WHERE _rcpt='%s'", timenow, triplet_array[fd][2]); if(db_doquery(fd) == -1) return(db_failure(fd, "throttle_rcpt")); /* counter reset because of expiry, allow mail */ return (0); } /* if the recipient is past his quota and the timeout has not expired */ /* then reject the message */ if(atol(mysqlchar_array[fd][2]) >= atol(mysqlchar_array[fd][1])) { logmessage("rcpt=%lu, throttle_rcpt=abuse(f), host=%s, from=%s, to=%s, " "count=%d/%d(%d), threshold=%d%\n", rcpt_count, /* recipient count */ host_array[fd][2], /* host */ triplet_array[fd][1], /* from */ triplet_array[fd][2], /* to */ atol(mysqlchar_array[fd][2]), /* count_cur */ atol(mysqlchar_array[fd][1]), /* count_max */ atol(mysqlchar_array[fd][5]), /* count_tot */ trcpt[fd] /* rcpt percentage */ ); /* build up & execute query */ snprintf(mysqlquery_array[fd], 512, "UPDATE throttle_rcpt SET" " _abuse_cur=1" " WHERE _rcpt='%s'", triplet_array[fd][2]); if(db_doquery(fd) == -1) return(db_failure(fd, "throttle-rcpt")); return (-7); } /* if the recipient has not reached his quota, increase count */ logmessage("rcpt=%lu, throttle_rcpt=update(%c), host=%s, from=%s, to=%s, " "count=%d/%d(%d), threshold=%d%\n", rcpt_count, /* recipient count */ tattrib_array[fd][0], /* attribute state */ host_array[fd][2], /* host */ triplet_array[fd][1], /* from */ triplet_array[fd][2], /* to */ atol(mysqlchar_array[fd][2])+1, /* count_cur */ atol(mysqlchar_array[fd][1]), /* count_max */ atol(mysqlchar_array[fd][5])+1, /* count_tot */ trcpt[fd] /* rcpt percentage */ ); /* build up & execute query */ snprintf(mysqlquery_array[fd], 512, "UPDATE throttle_rcpt SET" " _count_cur=_count_cur+1," " _abuse_cur=0" " WHERE _rcpt='%s'", triplet_array[fd][2]); if(db_doquery(fd) == -1) return(db_failure(fd, "throttle_rcpt")); return (0); /* never reached */ } /* EOF */