1 #include "policyd.h"
2 
3 
4 /*
5  *
6  *
7  *                           Policy Daemon
8  *
9  *  policy daemon is used in conjuction with postfix to combat spam.
10  *
11  *  Copyright (C) 2004 Cami Sardinha (cami@mweb.co.za)
12  *
13  *
14  *  This program is free software; you can redistribute it and/or modify it
15  *  under the terms of the  GNU General  Public License as published by the
16  *  Free Software Foundation;  either version 2 of the License, or (at your
17  *  option) any later version.
18  *
19  *  This program  is  distributed  in the hope that  it will be useful, but
20  *  WITHOUT  WARRANTY; without even the implied warranty of MERCHANTABILITY
21  *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  *  for more details.
23  *
24  *  You should have received a copy of the GNU General Public License along
25  *  with this program; if not, write to the Free  Software Foundation Inc.,
26  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  *
28  *
29  *
30  */
31 
32 /*
33  * function: throttle_from
34  *  purpose: throttle users based on envelope FROM
35  *   return: 0 for new record, 1 for update
36  */
37 int
throttle_from(unsigned int fd)38 throttle_from (unsigned int fd)
39 {
40 
41   if(DEBUG > 0)
42     logmessage("DEBUG: fd: %d checking throttle-from\n", fd);
43 
44   /* user is not in the database */
45   if(strlen(mysqlchar_array[fd][0]) < 2)
46   {
47     if(atol(triplet_array[fd][3]) >= atol(mysqlchar_array[fd][7]))
48       goto abuse;
49 
50     logmessage("rcpt=%lu, throttle=new(a), host=%s, from=%s, to=%s, size=%d/%d, "
51       "quota=%d/%d, count=1/%d(1), rcpt=1/%d(1), threshold=0%|0%|0%\n",
52       rcpt_count,                       /* recipient count      */
53       host_array[fd][2],                /* host                 */
54       triplet_array[fd][1],             /* from                 */
55       triplet_array[fd][2],             /* to                   */
56       atol(triplet_array[fd][3]),       /* size_cur             */
57       atol(mysqlchar_array[fd][7]),     /* size_max             */
58       atol(triplet_array[fd][3]),       /* quota_cur            */
59       atol(mysqlchar_array[fd][5]),     /* quota_max            */
60       atol(mysqlchar_array[fd][1]),     /* count_max            */
61       atol(mysqlchar_array[fd][9])      /* rcpt_max             */
62     );
63 
64     /* build up & execute query */
65     snprintf(mysqlquery_array[fd], 512,
66       "INSERT DELAYED INTO throttle "
67       "(_date,_from,_quota_cur,_quota_max,_rcpt_max,_mail_size,_count_max,_time_limit)"
68       " VALUES (%d, '%s', %d, %ld, %ld, %ld, %ld, %ld)",
69       timenow,
70       triplet_array[fd][1],
71       atoi(triplet_array[fd][3]),
72       atol(mysqlchar_array[fd][5]),
73       atol(mysqlchar_array[fd][9]),
74       atol(mysqlchar_array[fd][7]),
75       atol(mysqlchar_array[fd][1]),
76       atol(mysqlchar_array[fd][6]));
77     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
78 
79     /* sender does not exist in the database, insert and allow */
80     return (0);
81   }
82 
83   /* if sender is sending a message bigger than allowed, reject */
84   if(atol(triplet_array[fd][3]) >= atol(mysqlchar_array[fd][7]))
85   {
86 abuse:
87     logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
88       "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%\n",
89       rcpt_count,                       /* recipient count      */
90       host_array[fd][2],                /* host                 */
91       triplet_array[fd][1],             /* from                 */
92       triplet_array[fd][2],             /* to                   */
93       atol(triplet_array[fd][3]),       /* size_cur             */
94       atol(mysqlchar_array[fd][7]),     /* size_max             */
95       atol(mysqlchar_array[fd][4]),     /* quota_cur            */
96       atol(mysqlchar_array[fd][5]),     /* quota_max            */
97       atol(mysqlchar_array[fd][2]),     /* count_cur            */
98       atol(mysqlchar_array[fd][1]),     /* count_max            */
99       atol(mysqlchar_array[fd][8]),     /* count_tot            */
100       atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
101       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
102       atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
103       tquota[fd],                       /* quota percentage     */
104       tcount[fd],                       /* count percentage     */
105       trcpt[fd]                         /* rcpt  percentage     */
106     );
107 
108     return (-3);
109   }
110 
111   /* if time has expired, clear quota for size+message+rcpt count */
112   if(timenow > (unsigned int)(atol(mysqlchar_array[fd][6])+atol(mysqlchar_array[fd][3])))
113   {
114     logmessage("rcpt=%lu, throttle=clear(a), host=%s, from=%s, to=%s, size=%d/%d, "
115       "quota=%d/%d, count=1/%d(%d), rcpt=1/%d(%d), threshold=0%|0%|0%\n",
116       rcpt_count,                       /* recipient count      */
117       host_array[fd][2],                /* host                 */
118       triplet_array[fd][1],             /* from                 */
119       triplet_array[fd][2],             /* to                   */
120       atol(triplet_array[fd][3]),       /* size_cur             */
121       atol(mysqlchar_array[fd][7]),     /* size_max             */
122       atoi(triplet_array[fd][3]),       /* quota_cur            */
123       atol(mysqlchar_array[fd][5]),     /* quota_max            */
124       atol(mysqlchar_array[fd][1]),     /* count_max            */
125       atol(mysqlchar_array[fd][8])+instance_inc[fd], /* count_tot            */
126       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
127       atol(mysqlchar_array[fd][11])+1   /* rcpt_tot             */
128     );
129 
130     /* build up & execute query */
131     snprintf(mysqlquery_array[fd], 512,
132       "UPDATE throttle SET"
133       " _rcpt_cur=1,"
134       " _rcpt_tot=_rcpt_tot+1,"
135       " _date=%d,"
136       " _quota_cur=%d,"
137       " _count_cur=1,"
138       " _count_tot=_count_tot+%d,"
139       " _abuse_tot=_abuse_tot+_abuse_cur,"
140       " _abuse_cur=0"
141       " WHERE _from='%s'",
142       timenow,
143       atoi(triplet_array[fd][3]),
144       instance_inc[fd],
145       mysqlchar_array[fd][0]);
146     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
147 
148     /* counter reset because of expiry, allow mail */
149     return (0);
150   }
151 
152   /* if the sender is past his quota and the timeout has not expired */
153   /* then reject the message */
154   if(atol(mysqlchar_array[fd][2])  >= atol(mysqlchar_array[fd][1]) || /* count  */
155      atol(mysqlchar_array[fd][4])  >= atol(mysqlchar_array[fd][5]) || /* quota  */
156      atol(mysqlchar_array[fd][10]) >= atol(mysqlchar_array[fd][9])) /* rcpt max */
157   {
158     if((instance_inc[fd] == 0) && (atol(mysqlchar_array[fd][10]) < atol(mysqlchar_array[fd][9])))
159       goto update;
160 
161     logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
162       "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), abuse=%d, threshold=%d%|%d%|%d%\n",
163       rcpt_count,                       /* recipient count      */
164       host_array[fd][2],                /* host                 */
165       triplet_array[fd][1],             /* from                 */
166       triplet_array[fd][2],             /* to                   */
167       atol(triplet_array[fd][3]),       /* size_cur             */
168       atol(mysqlchar_array[fd][7]),     /* size_max             */
169       atol(mysqlchar_array[fd][4]),     /* quota_cur            */
170       atol(mysqlchar_array[fd][5]),     /* quota_max            */
171       atol(mysqlchar_array[fd][2]),     /* count_cur            */
172       atol(mysqlchar_array[fd][1]),     /* count_max            */
173       atol(mysqlchar_array[fd][8]),     /* count_tot            */
174       atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
175       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
176       atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
177       atol(mysqlchar_array[fd][14]),    /* abuse_tot            */
178       tquota[fd],                       /* quota percentage     */
179       tcount[fd],                       /* count percentage     */
180       trcpt[fd]                         /* rcpt  percentage     */
181     );
182 
183     /* build up & execute query */
184     snprintf(mysqlquery_array[fd], 512,
185       "UPDATE throttle SET"
186       " _abuse_cur=1"
187       " WHERE _from='%s'",
188       mysqlchar_array[fd][0]);
189     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
190 
191     if(SENDER_THROTTLE_AUTOBLACKLIST == 1)
192     {
193       if(atol(mysqlchar_array[fd][14]) >= SENDER_THROTTLE_AUTOBLACKLIST_NUMBER-1) /* _abuse_tot */
194       {
195         int expire=0;
196 
197         /* never auto expire blacklist? */
198         if(SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE > 0)
199             expire=timenow+SENDER_THROTTLE_AUTOBLACKLIST_EXPIRE;
200 
201         snprintf(mysqlquery_array[fd], 512,
202                  "INSERT DELAYED INTO blacklist_sender (_blacklist,_description,_expire) "
203                  "VALUES ('%s','# sender throttle autoblacklisted',%d)",
204                  mysqlchar_array[fd][0], expire);
205 
206         /* execute query */
207         if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
208 
209         logmessage("rcpt=%lu, throttle=blacklisted(f), host=%s, from=%s, to=%s, size=%d/%d, "
210                    "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), abuse=%d, threshold=%d%|%d%|%d%\n",
211                    rcpt_count,                       /* recipient count      */
212                    host_array[fd][2],                /* host                 */
213                    triplet_array[fd][1],             /* from                 */
214                    triplet_array[fd][2],             /* to                   */
215                    atol(triplet_array[fd][3]),       /* size_cur             */
216                    atol(mysqlchar_array[fd][7]),     /* size_max             */
217                    atol(mysqlchar_array[fd][4]),     /* quota_cur            */
218                    atol(mysqlchar_array[fd][5]),     /* quota_max            */
219                    atol(mysqlchar_array[fd][2]),     /* count_cur            */
220                    atol(mysqlchar_array[fd][1]),     /* count_max            */
221                    atol(mysqlchar_array[fd][8]),     /* count_tot            */
222                    atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
223                    atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
224                    atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
225                    atol(mysqlchar_array[fd][14]),    /* abuse_tot            */
226                    tquota[fd],                       /* quota percentage     */
227                    tcount[fd],                       /* count percentage     */
228                    trcpt[fd]                         /* rcpt  percentage     */
229             );
230       }
231     }
232 
233     return (-5);
234   }
235 
236 update:
237 
238   /* sender has not reached his quota, increase count */
239   logmessage("rcpt=%lu, throttle=update(%c), host=%s, from=%s, to=%s, size=%d/%d, "
240     "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%\n",
241     rcpt_count,                                              /* recipient count */
242     tattrib_array[fd][0],                                    /* attribute state */
243     host_array[fd][2],                                       /* host            */
244     triplet_array[fd][1],                                    /* from            */
245     triplet_array[fd][2],                                    /* to              */
246     atol(triplet_array[fd][3]),                              /* size_cur        */
247     atol(mysqlchar_array[fd][7]),                            /* size_max        */
248     atol(mysqlchar_array[fd][4])+atol(triplet_array[fd][3]), /* quota_cur       */
249     atol(mysqlchar_array[fd][5]),     			     /* quota_max       */
250     atol(mysqlchar_array[fd][2])+instance_inc[fd],   	     /* count_cur       */
251     atol(mysqlchar_array[fd][1]),                            /* count_max       */
252     atol(mysqlchar_array[fd][8])+instance_inc[fd],           /* count_tot       */
253     atol(mysqlchar_array[fd][10])+1,                         /* rcpt_cur        */
254     atol(mysqlchar_array[fd][9]),                            /* rcpt_max        */
255     atol(mysqlchar_array[fd][11])+1,                         /* rcpt_tot        */
256     tquota[fd],                                              /* quota percentage*/
257     tcount[fd],                                              /* count percentage*/
258     trcpt[fd]                                                /* rcpt  percentage*/
259   );
260 
261   /* build up & execute query */
262   snprintf(mysqlquery_array[fd], 512,
263     "UPDATE throttle SET"
264     " _rcpt_cur=_rcpt_cur+1,"
265     " _rcpt_tot=_rcpt_tot+1,"
266     " _quota_cur=_quota_cur+%ld,"
267     " _count_cur=_count_cur+%d,"
268     " _count_tot=_count_tot+%d,"
269     " _abuse_cur=0"
270     " WHERE _from='%s'",
271     atol(triplet_array[fd][3]),
272     instance_inc[fd],
273     instance_inc[fd],
274     mysqlchar_array[fd][0]);
275   if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
276 
277   return (0); /* never reached */
278 }
279 
280 /* EOF */
281