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 /*
34 * function: greylist_check
35 * purpose: check if triplet exists in mysql
36 * return: 0 for new record, 1 for update
37 */
38 int
greylist_check(unsigned int fd)39 greylist_check(unsigned int fd)
40 {
41
42 if(DEBUG > 0)
43 logmessage("DEBUG: fd: %d checking greylist\n", fd);
44
45 /* set sane defaults */
46 mysql_array[fd][0] = -2;
47 mysql_optarray[fd][0] = OPTINOUTALL;
48
49 /* opt-in/opt-out? */
50 if(OPTINOUT == 1)
51 {
52
53 /* build up & execute query */
54 snprintf(mysqlquery_array[fd], 512,
55 "SELECT _optin FROM policy WHERE _rcpt='%s' OR _rcpt='@%s' ORDER BY _priority DESC LIMIT 1",
56 triplet_array[fd][2], host_array[fd][9]);
57 if(db_optquery(fd) == -1) return(db_failure(fd, "greylist"));
58
59 /* user is opted out */
60 if(mysql_optarray[fd][0] == 0)
61 {
62 logmessage("rcpt=%lu, greylist=optout, host=%s (%s), from=%s, to=%s, size=%s\n",
63 rcpt_count, /* recipient count */
64 host_array[fd][2], /* host address */
65 host_array[fd][0], /* hostname */
66 triplet_array[fd][1], /* sender */
67 triplet_array[fd][2], /* recipient */
68 triplet_array[fd][3]); /* size */
69
70 return (0);
71 }
72 }
73
74
75 /* domain or mail address is in training mode? */
76 if(TRAINING_POLICY_TIMEOUT != 0)
77 {
78 /* build up & execute query */
79 snprintf(mysqlquery_array[fd], 512,
80 "SELECT COUNT(*) FROM policy_training WHERE _rcpt='%s' OR _rcpt='@%s'",
81 triplet_array[fd][2], host_array[fd][9]);
82 if(db_optquery(fd) == -1) return(db_failure(fd, "greylist"));
83
84 /* training policy is activated for domain or email address */
85 if(mysql_optarray[fd][0] >= 1)
86 mysql_optarray[fd][0] = 2;
87 }
88
89
90 /* build up & execute query */
91 snprintf(mysqlquery_array[fd], 512,
92 "SELECT _count,_datenew,_datelast FROM triplet WHERE _host='%s' AND _from='%s' AND _rcpt='%s'",
93 triplet_array[fd][0], triplet_array[fd][1], triplet_array[fd][2]);
94 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
95
96 /* update the greylist xheader */
97 if(GREYLIST_X_HEADER==1)
98 snprintf(xgreylist_array[fd], 128, "%s host: %s count: %d size: %s\n\n",
99 POSTFIX_X_HEADER, host_array[fd][2], mysql_array[fd][0], triplet_array[fd][3]);
100
101
102 /* triplet not found in greylist database */
103 if(mysql_array[fd][0]==-2)
104 {
105 /* build up & execute query */
106 snprintf(mysqlquery_array[fd], 512,
107 "INSERT DELAYED INTO triplet (_datenew,_datelast,_host,_from,_rcpt) VALUES (%d,%d,'%s','%s','%s')",
108 timenow, timenow, triplet_array[fd][0], triplet_array[fd][1], triplet_array[fd][2]);
109 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
110
111 /* auto black listing is enabled */
112 if(AUTO_BLACK_LISTING == 1)
113 {
114 /* perform query to see how many triplets there are for a host/network */
115 /* build up & execute query */
116 snprintf(mysqlquery_array[fd], 512,
117 "SELECT COUNT(*) FROM triplet WHERE _host='%s' AND _count = 0",
118 triplet_array[fd][0]);
119 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
120
121 if(DEBUG > 0)
122 logmessage("DEBUG: fd: %d unauth triplet: %d\n", fd, mysql_array[fd][0]);
123
124 /* host has more than allowed number of unauthenticated triplets */
125 if(mysql_array[fd][0] >= AUTO_BLACKLIST_NUMBER)
126 {
127 int expire=0;
128
129 /* never auto expire blacklist? */
130 if(AUTO_BLACKLIST_EXPIRE > 0)
131 expire=timenow+AUTO_BLACKLIST_EXPIRE;
132
133 /* blacklist netblock /24 */
134 if(BLACKLIST_NETBLOCK==1)
135 { /* blacklist netblock */
136 snprintf(mysqlquery_array[fd], 512,
137 "INSERT DELAYED INTO blacklist (_blacklist,_description,_expire) VALUES ('%s.%%','# autoblacklisted', %d)",
138 triplet_array[fd][0], expire);
139 } else { /* blacklist host ip */
140 snprintf(mysqlquery_array[fd], 512,
141 "INSERT DELAYED INTO blacklist (_blacklist,_description,_expire) VALUES ('%s','# autoblacklisted',%d)",
142 host_array[fd][2], expire);
143 }
144 /* execute query */
145 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
146
147 logmessage("rcpt=%lu, greylist=abl, host=%s (%s), from=%s, to=%s, size=%s, expire=%d\n",
148 rcpt_count, /* recipient count */
149 host_array[fd][2], /* host address */
150 host_array[fd][0], /* hostname */
151 triplet_array[fd][1], /* sender */
152 triplet_array[fd][2], /* recipient */
153 triplet_array[fd][3], /* size */
154 expire); /* expiry date */
155
156 /* build up & execute query */
157 snprintf(mysqlquery_array[fd], 512,
158 "DELETE QUICK from triplet WHERE _host='%s'", triplet_array[fd][0]);
159 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
160
161 /* reject */
162 return (-1);
163 }
164 }
165
166
167 /* not in training mode, reject if this is the first attempt */
168 if((TRAINING_MODE == 0) && (mysql_optarray[fd][0] != 2))
169 {
170 logmessage("rcpt=%lu, greylist=new, host=%s (%s), from=%s, to=%s, size=%s\n",
171 rcpt_count, /* recipient count */
172 host_array[fd][2], /* host address */
173 host_array[fd][0], /* hostname */
174 triplet_array[fd][1], /* sender */
175 triplet_array[fd][2], /* recipient */
176 triplet_array[fd][3]); /* size */
177
178 /* reject */
179 return (-1);
180 }
181
182 /* in training mode, always accept */
183 if((TRAINING_MODE == 1) || (mysql_optarray[fd][0] == 2))
184 {
185 logmessage("rcpt=%lu, greylist=new_train, host=%s (%s), from=%s, to=%s, size=%s\n",
186 rcpt_count,
187 host_array[fd][2], /* host */
188 host_array[fd][0], /* hostname */
189 triplet_array[fd][1], /* from */
190 triplet_array[fd][2], /* rcpt */
191 triplet_array[fd][3] /* size */
192 );
193
194 /* accept */
195 return (0);
196 }
197
198 } else { /* triplet exists in database */
199
200 /* has TRIPLET_TIME expired since triplet creation? */
201 if(timenow < (unsigned int)(mysql_array[fd][1]+TRIPLET_TIME))
202 {
203 /* not in training mode */
204 if((TRAINING_MODE == 0) && (mysql_optarray[fd][0] != 2))
205 {
206 logmessage("rcpt=%lu, greylist=abuse, host=%s (%s), from=%s, to=%s, size=%s\n",
207 rcpt_count, /* recipient count */
208 host_array[fd][2], /* host address */
209 host_array[fd][0], /* hostname */
210 triplet_array[fd][1], /* sender */
211 triplet_array[fd][2], /* recipient */
212 triplet_array[fd][3]); /* size */
213
214 return (-1);
215 }
216 }
217
218
219 /* implement autowhitelisting */
220 if(AUTO_WHITE_LISTING==1)
221 {
222 /* expire auto-whitelisted hosts if enabled */
223 int expire=0;
224 if(AUTO_WHITELIST_EXPIRE > 0)
225 expire=timenow+AUTO_WHITELIST_EXPIRE;
226
227 /* save an sql lookup if awl == 1 */
228 if(AUTO_WHITELIST_NUMBER == 1)
229 goto awl;
230
231 /* check how many auth triplets there are for a host/network */
232 /* build up & execute query */
233 snprintf(mysqlquery_array[fd], 512,
234 "SELECT COUNT(*) FROM triplet WHERE _host='%s' AND _count > 0",
235 triplet_array[fd][0]);
236 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
237
238 if(DEBUG > 0)
239 logmessage("DEBUG: fd: %d whitelist result: %d\n", fd, mysql_array[fd][0]);
240
241 if(mysql_array[fd][0] >= AUTO_WHITELIST_NUMBER)
242 goto awl; /* auto whitelist network/host */
243 else
244 goto nawl; /* dont auto white list network */
245
246 awl:
247
248 if(AUTO_WHITELIST_NETBLOCK==1)
249 {
250 /* build up & execute query */
251 snprintf(mysqlquery_array[fd], 512,
252 "INSERT DELAYED INTO whitelist (_whitelist,_description,_expire) VALUES ('%s.%%','# autowhitelisted host',%d)",
253 triplet_array[fd][0], expire);
254 } else {
255 /* build up & execute query */
256 snprintf(mysqlquery_array[fd], 512,
257 "INSERT DELAYED INTO whitelist (_whitelist,_description,_expire) VALUES ('%s','# autowhitelisted host',%d)",
258 host_array[fd][2], expire);
259 }
260 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
261
262 /* build up & execute query */
263 snprintf(mysqlquery_array[fd], 512,
264 "DELETE QUICK from triplet WHERE _host='%s'", triplet_array[fd][0]);
265 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
266
267 logmessage("rcpt=%lu, greylist=awl, host=%s (%s), from=%s, to=%s, size=%s, expire=%d\n",
268 rcpt_count, /* recipient count */
269 host_array[fd][2], /* host address */
270 host_array[fd][0], /* hostname */
271 triplet_array[fd][1], /* sender */
272 triplet_array[fd][2], /* recipient */
273 triplet_array[fd][3], /* size */
274 expire); /* expiry date */
275
276 return(0);
277 }
278
279 nawl:
280
281 /* build up & execute query */
282 snprintf(mysqlquery_array[fd], 512,
283 "UPDATE triplet SET _datelast='%d',_count=_count+1 WHERE _host='%s' AND _from='%s' AND _rcpt='%s'",
284 timenow, triplet_array[fd][0], triplet_array[fd][1], triplet_array[fd][2]);
285 if(db_doquery(fd) == -1) return(db_failure(fd, "greylist"));
286
287 /* training mode */
288 if((TRAINING_MODE == 0) && (mysql_optarray[fd][0] != 2))
289 {
290 /* yes, it has.. update */
291 logmessage("rcpt=%lu, greylist=update, host=%s (%s), from=%s, to=%s, size=%s\n",
292 rcpt_count, /* recipient count */
293 host_array[fd][2], /* host address */
294 host_array[fd][0], /* hostname */
295 triplet_array[fd][1], /* sender */
296 triplet_array[fd][2], /* recipient */
297 triplet_array[fd][3]); /* size */
298 }
299
300 /* training mode */
301 if((TRAINING_MODE == 1) || (mysql_optarray[fd][0] == 2))
302 {
303 /* yes, it has.. update */
304 logmessage("rcpt=%lu, greylist=update_train, host=%s (%s), from=%s, to=%s, size=%s\n",
305 rcpt_count, /* recipient count */
306 host_array[fd][2], /* host address */
307 host_array[fd][0], /* hostname */
308 triplet_array[fd][1], /* sender */
309 triplet_array[fd][2], /* recipient */
310 triplet_array[fd][3]); /* size */
311 }
312
313 return (0);
314 }
315
316 return (0); /* never reached */
317 }
318
319 /* EOF */
320