#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_host
 *  purpose: throttle users based on host
 *   return: 0 for new record, 1 for update
 */
int
throttle_host (unsigned int fd)
{

  if(DEBUG > 0)
    logmessage("DEBUG: fd: %d checking throttle-host\n", fd);

  /* user is not in the database */
  if(strlen(mysqlchar_array[fd][0]) < 2)
  {
    if(atol(triplet_array[fd][3]) >= atol(mysqlchar_array[fd][7]))
      goto abuse;
    
    logmessage("rcpt=%lu, throttle=new(a), host=%s, from=%s, to=%s, size=%d/%d, "
      "quota=%d/%d, count=1/%d(1), rcpt=1/%d(1), threshold=0%|0%|0%\n",
      rcpt_count,                       /* recipient count      */
      host_array[fd][2],                /* host                 */
      triplet_array[fd][1],             /* from                 */
      triplet_array[fd][2],             /* to                   */
      atol(triplet_array[fd][3]),       /* size_cur             */
      atol(mysqlchar_array[fd][7]),     /* size_max             */
      atol(triplet_array[fd][3]),       /* quota_cur            */
      atol(mysqlchar_array[fd][5]),     /* quota_max            */
      atol(mysqlchar_array[fd][1]),     /* count_max            */
      atol(mysqlchar_array[fd][9])      /* rcpt_max             */
    );

    /* build up & execute query */
    snprintf(mysqlquery_array[fd], 512,
      "INSERT DELAYED INTO throttle "
      "(_date,_from,_quota_cur,_quota_max,_rcpt_max,_mail_size,_count_max,_time_limit)"
      " VALUES (%d, '%s', %d, %ld, %ld, %ld, %ld, %ld)",
      timenow,
      host_array[fd][2],
      atoi(triplet_array[fd][3]),
      atol(mysqlchar_array[fd][5]),
      atol(mysqlchar_array[fd][9]),
      atol(mysqlchar_array[fd][7]),
      atol(mysqlchar_array[fd][1]),
      atol(mysqlchar_array[fd][6]));
    if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

    /* sender does not exist in the database, insert and allow */
    return (0);
  }

  /* if sender is sending a message bigger than allowed, reject */
  if(atol(triplet_array[fd][3]) >= atol(mysqlchar_array[fd][7]))
  {
abuse:
    logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
      "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%\n",
      rcpt_count,                       /* recipient count      */
      host_array[fd][2],                /* host                 */
      triplet_array[fd][1],             /* from                 */
      triplet_array[fd][2],             /* to                   */
      atol(triplet_array[fd][3]),       /* size_cur             */
      atol(mysqlchar_array[fd][7]),     /* size_max             */
      atol(mysqlchar_array[fd][4]),     /* quota_cur            */
      atol(mysqlchar_array[fd][5]),     /* quota_max            */
      atol(mysqlchar_array[fd][2]),     /* count_cur            */
      atol(mysqlchar_array[fd][1]),     /* count_max            */
      atol(mysqlchar_array[fd][8]),     /* count_tot            */
      atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
      atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
      atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
      tquota[fd],                       /* quota percentage     */
      tcount[fd],                       /* count percentage     */
      trcpt[fd]                         /* rcpt  percentage     */
    );

    return (-3);
  }

  /* if time has expired, clear quota for size+message+rcpt count */
  if(timenow > (unsigned int)(atol(mysqlchar_array[fd][6])+atol(mysqlchar_array[fd][3])))
  {
    logmessage("rcpt=%lu, throttle=clear(a), host=%s, from=%s, to=%s, size=%d/%d, "
      "quota=%d/%d, count=1/%d(%d), rcpt=1/%d(%d), threshold=0%|0%|0%\n",
      rcpt_count,                       /* recipient count      */
      host_array[fd][2],                /* host                 */
      triplet_array[fd][1],             /* from                 */
      triplet_array[fd][2],             /* to                   */
      atol(triplet_array[fd][3]),       /* size_cur             */
      atol(mysqlchar_array[fd][7]),     /* size_max             */
      atoi(triplet_array[fd][3]),       /* quota_cur            */
      atol(mysqlchar_array[fd][5]),     /* quota_max            */
      atol(mysqlchar_array[fd][1]),     /* count_max            */
      atol(mysqlchar_array[fd][8])+instance_inc[fd], /* count_tot            */
      atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
      atol(mysqlchar_array[fd][11])+1   /* rcpt_tot             */
    );
      
    /* build up & execute query */
    snprintf(mysqlquery_array[fd], 512,
      "UPDATE throttle SET"
      " _rcpt_cur=1,"
      " _rcpt_tot=_rcpt_tot+1,"
      " _date=%d,"
      " _quota_cur=%d,"
      " _count_cur=1,"
      " _count_tot=_count_tot+%d,"
      " _abuse_tot=_abuse_tot+_abuse_cur,"
      " _abuse_cur=0"
      " WHERE _from='%s'",
      timenow,
      atoi(triplet_array[fd][3]),
      instance_inc[fd],
      mysqlchar_array[fd][0]);
    if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

    /* counter reset because of expiry, allow mail */
    return (0);
  }
  
  /* if the sender 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]) || /* count  */
     atol(mysqlchar_array[fd][4])  >= atol(mysqlchar_array[fd][5]) || /* quota  */
     atol(mysqlchar_array[fd][10]) >= atol(mysqlchar_array[fd][9])) /* rcpt max */
  {
    if((instance_inc[fd] == 0) && (atol(mysqlchar_array[fd][10]) < atol(mysqlchar_array[fd][9])))
      goto update;
    
    logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
      "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), abuse=%d, threshold=%d%|%d%|%d%\n",
      rcpt_count,                       /* recipient count      */
      host_array[fd][2],                /* host                 */
      triplet_array[fd][1],             /* from                 */
      triplet_array[fd][2],             /* to                   */
      atol(triplet_array[fd][3]),       /* size_cur             */
      atol(mysqlchar_array[fd][7]),     /* size_max             */
      atol(mysqlchar_array[fd][4]),     /* quota_cur            */
      atol(mysqlchar_array[fd][5]),     /* quota_max            */
      atol(mysqlchar_array[fd][2]),     /* count_cur            */
      atol(mysqlchar_array[fd][1]),     /* count_max            */
      atol(mysqlchar_array[fd][8]),     /* count_tot            */
      atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
      atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
      atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
      atol(mysqlchar_array[fd][14]),    /* abuse_tot            */
      tquota[fd],                       /* quota percentage     */
      tcount[fd],                       /* count percentage     */
      trcpt[fd]                         /* rcpt  percentage     */
    );

    /* build up & execute query */
    snprintf(mysqlquery_array[fd], 512,
      "UPDATE throttle SET"
      " _abuse_cur=1"
      " WHERE _from='%s'",
      mysqlchar_array[fd][0]);
    if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

    if(SENDER_THROTTLE_AUTOBLACKLIST == 1)
    {
      if(atol(mysqlchar_array[fd][14]) >= SENDER_THROTTLE_AUTOBLACKLIST_NUMBER-1) /* _abuse_tot */
      {
        int expire=0;

        /* never auto expire blacklist? */
        if(SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE > 0)
            expire=timenow+SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE;
        
        snprintf(mysqlquery_array[fd], 512,
                 "INSERT DELAYED INTO blacklist (_blacklist,_description,_expire) "
                 "VALUES ('%s','# sender throttle autoblacklisted',%d)",
                 mysqlchar_array[fd][0], expire);
        
        /* execute query */
        if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

        logmessage("rcpt=%lu, throttle=blacklisted(f), host=%s, from=%s, to=%s, size=%d/%d, "
                   "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), abuse=%d, threshold=%d%|%d%|%d%\n",
                   rcpt_count,                       /* recipient count      */
                   host_array[fd][2],                /* host                 */
                   triplet_array[fd][1],             /* from                 */
                   triplet_array[fd][2],             /* to                   */
                   atol(triplet_array[fd][3]),       /* size_cur             */
                   atol(mysqlchar_array[fd][7]),     /* size_max             */
                   atol(mysqlchar_array[fd][4]),     /* quota_cur            */
                   atol(mysqlchar_array[fd][5]),     /* quota_max            */
                   atol(mysqlchar_array[fd][2]),     /* count_cur            */
                   atol(mysqlchar_array[fd][1]),     /* count_max            */
                   atol(mysqlchar_array[fd][8]),     /* count_tot            */
                   atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
                   atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
                   atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
                   atol(mysqlchar_array[fd][14]),    /* abuse_tot            */
                   tquota[fd],                       /* quota percentage     */
                   tcount[fd],                       /* count percentage     */
                   trcpt[fd]                         /* rcpt  percentage     */
            );
      }
    }
    return (-5);
  }

update:

  /* sender has not reached his quota, increase count */
  logmessage("rcpt=%lu, throttle=update(%c), host=%s, from=%s, to=%s, size=%d/%d, "
    "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%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(triplet_array[fd][3]),                              /* size_cur        */
    atol(mysqlchar_array[fd][7]),                            /* size_max        */
    atol(mysqlchar_array[fd][4])+atol(triplet_array[fd][3]), /* quota_cur       */
    atol(mysqlchar_array[fd][5]),                            /* quota_max       */
    atol(mysqlchar_array[fd][2])+instance_inc[fd],           /* count_cur       */
    atol(mysqlchar_array[fd][1]),                            /* count_max       */
    atol(mysqlchar_array[fd][8])+instance_inc[fd],           /* count_tot       */
    atol(mysqlchar_array[fd][10])+1,                         /* rcpt_cur        */ 
    atol(mysqlchar_array[fd][9]),                            /* rcpt_max        */ 
    atol(mysqlchar_array[fd][11])+1,                         /* rcpt_tot        */
    tquota[fd],                                              /* quota percentage*/
    tcount[fd],                                              /* count percentage*/
    trcpt[fd]                                                /* rcpt  percentage*/
  );
      
  /* build up & execute query */
  snprintf(mysqlquery_array[fd], 512,
    "UPDATE throttle SET"
    " _rcpt_cur=_rcpt_cur+1,"
    " _rcpt_tot=_rcpt_tot+1,"
    " _quota_cur=_quota_cur+%ld,"
    " _count_cur=_count_cur+%d,"
    " _count_tot=_count_tot+%d,"
    " _abuse_cur=0"
    " WHERE _from='%s'",
    atol(triplet_array[fd][3]),
    instance_inc[fd],
    instance_inc[fd],
    mysqlchar_array[fd][0]);
  if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));

  return (0); /* never reached */
}
 
/* EOF */
