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