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