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_sasl
34  *  purpose: throttle users based on SASL info
35  *   return: 0 for new record, 1 for update
36  */
37 int
throttle_sasl(unsigned int fd)38 throttle_sasl (unsigned int fd)
39 {
40 
41   if(DEBUG > 0)
42     logmessage("DEBUG: fd: %d checking throttle-sasl\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%, sasl_username=%s\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       triplet_array[fd][4]              /* sasl_username        */
63     );
64 
65     /* build up & execute query */
66     snprintf(mysqlquery_array[fd], 512,
67       "INSERT DELAYED INTO throttle "
68       "(_date,_from,_quota_cur,_quota_max,_rcpt_max,_mail_size,_count_max, _time_limit)"
69       " VALUES (%d, '%s', %d, %ld, %ld, %ld, %ld, %ld)",
70       timenow,
71       triplet_array[fd][4],
72       atoi(triplet_array[fd][3]),
73       atol(mysqlchar_array[fd][5]),
74       atol(mysqlchar_array[fd][9]),
75       atol(mysqlchar_array[fd][7]),
76       atol(mysqlchar_array[fd][1]),
77       atol(mysqlchar_array[fd][6]));
78     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
79 
80     /* sender does not exist in the database, insert and allow */
81     return (0);
82   }
83 
84   /* if sender is sending a message bigger than allowed, reject */
85   if(atol(triplet_array[fd][3]) >= atol(mysqlchar_array[fd][7]))
86   {
87 abuse:
88     logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
89       "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%, sasl_username=%s\n",
90       rcpt_count,                       /* recipient count      */
91       host_array[fd][2],                /* host                 */
92       triplet_array[fd][1],             /* from                 */
93       triplet_array[fd][2],             /* to                   */
94       atol(triplet_array[fd][3]),       /* size_cur             */
95       atol(mysqlchar_array[fd][7]),     /* size_max             */
96       atol(mysqlchar_array[fd][4]),     /* quota_cur            */
97       atol(mysqlchar_array[fd][5]),     /* quota_max            */
98       atol(mysqlchar_array[fd][2]),     /* count_cur            */
99       atol(mysqlchar_array[fd][1]),     /* count_max            */
100       atol(mysqlchar_array[fd][8]),     /* count_tot            */
101       atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
102       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
103       atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
104       tquota[fd],                       /* quota percentage     */
105       tcount[fd],                       /* count percentage     */
106       trcpt[fd],                        /* rcpt  percentage     */
107       triplet_array[fd][4]              /* sasl_username        */
108     );
109 
110     return (-3);
111   }
112 
113   /* if time has expired, clear quota for size+message count */
114   if(timenow > (unsigned int)(atol(mysqlchar_array[fd][6])+atol(mysqlchar_array[fd][3])))
115   {
116     logmessage("rcpt=%lu, throttle=clear(a), host=%s, from=%s, to=%s, size=%d/%d, "
117       "quota=%d/%d, count=1/%d(%d), rcpt=1/%d(%d), threshold=0%|0%|0%, sasl_username=%s\n",
118       rcpt_count,                       /* recipient count      */
119       host_array[fd][2],                /* host                 */
120       triplet_array[fd][1],             /* from                 */
121       triplet_array[fd][2],             /* to                   */
122       atol(triplet_array[fd][3]),       /* size_cur             */
123       atol(mysqlchar_array[fd][7]),     /* size_max             */
124       atoi(triplet_array[fd][3]),       /* quota_cur            */
125       atol(mysqlchar_array[fd][5]),     /* quota_max            */
126       atol(mysqlchar_array[fd][1]),     /* count_max            */
127       atol(mysqlchar_array[fd][8]),     /* count_tot            */
128       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
129       atol(mysqlchar_array[fd][11])+1,  /* rcpt_tot             */
130       triplet_array[fd][4]              /* sasl_username        */
131     );
132 
133     /* build up & execute query */
134     snprintf(mysqlquery_array[fd], 512,
135       "UPDATE throttle SET"
136       " _rcpt_cur=1,"
137       " _rcpt_tot=_rcpt_tot+1,"
138       " _date=%d,"
139       " _quota_cur=%d,"
140       " _count_cur=1,"
141       " _count_tot=_count_tot+%d,"
142       " _abuse_tot=_abuse_tot+_abuse_cur,"
143       " _abuse_cur=0"
144       " WHERE _from='%s'",
145       timenow,
146       atoi(triplet_array[fd][3]),
147       instance_inc[fd],
148       triplet_array[fd][4]);
149     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
150 
151     /* counter reset because of expiry, allow mail */
152     return (0);
153   }
154 
155   /* if the sender is past his quota and the timeout has not expired */
156   /* then reject the message */
157   if(atol(mysqlchar_array[fd][2])  >= atol(mysqlchar_array[fd][1]) || /* count  */
158      atol(mysqlchar_array[fd][4])  >= atol(mysqlchar_array[fd][5]) || /* quota  */
159      atol(mysqlchar_array[fd][10]) >= atol(mysqlchar_array[fd][9])) /* rcpt max */
160   {
161     if((instance_inc[fd] == 0) && (atol(mysqlchar_array[fd][10]) < atol(mysqlchar_array[fd][9])))
162       goto update;
163 
164     logmessage("rcpt=%lu, throttle=abuse(f), host=%s, from=%s, to=%s, size=%d/%d, "
165       "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%, sasl_username=%s\n",
166       rcpt_count,                       /* recipient count      */
167       host_array[fd][2],                /* host                 */
168       triplet_array[fd][1],             /* from                 */
169       triplet_array[fd][2],             /* to                   */
170       atol(triplet_array[fd][3]),       /* size_cur             */
171       atol(mysqlchar_array[fd][7]),     /* size_max             */
172       atol(mysqlchar_array[fd][4]),     /* quota_cur            */
173       atol(mysqlchar_array[fd][5]),     /* quota_max            */
174       atol(mysqlchar_array[fd][2]),     /* count_cur            */
175       atol(mysqlchar_array[fd][1]),     /* count_max            */
176       atol(mysqlchar_array[fd][8]),     /* count_tot            */
177       atol(mysqlchar_array[fd][10]),    /* rcpt_cur             */
178       atol(mysqlchar_array[fd][9]),     /* rcpt_max             */
179       atol(mysqlchar_array[fd][11]),    /* rcpt_tot             */
180       tquota[fd],                       /* quota percentage     */
181       tcount[fd],                       /* count percentage     */
182       trcpt[fd],                        /* rcpt  percentage     */
183       triplet_array[fd][4]              /* sasl_username        */
184     );
185 
186     /* build up & execute query */
187     snprintf(mysqlquery_array[fd], 512,
188       "UPDATE throttle SET"
189       " _abuse_cur=1"
190       " WHERE _from='%s'",
191       triplet_array[fd][1]);
192     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
193 
194     return (-5);
195   }
196 
197 update:
198 
199   /* if the sender has not reached his quota, increase count */
200   logmessage("rcpt=%lu, throttle=update(%c), host=%s, from=%s, to=%s, size=%d/%d, "
201     "quota=%d/%d, count=%d/%d(%d), rcpt=%d/%d(%d), threshold=%d%|%d%|%d%, sasl_username=%s\n",
202     rcpt_count,                                              /* recipient count  */
203     tattrib_array[fd][0],                                    /* attribute state  */
204     host_array[fd][2],                                       /* host             */
205     triplet_array[fd][1],                                    /* from             */
206     triplet_array[fd][2],                                    /* to               */
207     atol(triplet_array[fd][3]),                              /* size_cur         */
208     atol(mysqlchar_array[fd][7]),                            /* size_max         */
209     atol(mysqlchar_array[fd][4])+atol(triplet_array[fd][3]), /* quota_cur        */
210     atol(mysqlchar_array[fd][5]),                            /* quota_max        */
211     atol(mysqlchar_array[fd][2])+instance_inc[fd],           /* count_cur        */
212     atol(mysqlchar_array[fd][1]),                            /* count_max        */
213     atol(mysqlchar_array[fd][8])+instance_inc[fd],           /* count_tot        */
214     atol(mysqlchar_array[fd][10])+1,                         /* rcpt_cur         */
215     atol(mysqlchar_array[fd][9]),                            /* rcpt_max         */
216     atol(mysqlchar_array[fd][11])+1,                         /* rcpt_tot         */
217     tquota[fd],                                              /* quota percentage */
218     tcount[fd],                                              /* count percentage */
219     trcpt[fd],                                               /* rcpt  percentage */
220     triplet_array[fd][4]                                     /* sasl_username    */
221   );
222 
223   /* build up & execute query */
224   snprintf(mysqlquery_array[fd], 512,
225     "UPDATE throttle SET"
226     " _rcpt_cur=_rcpt_cur+1,"
227     " _rcpt_tot=_rcpt_tot+1,"
228     " _quota_cur=_quota_cur+%ld,"
229     " _count_cur=_count_cur+%d,"
230     " _count_tot=_count_tot+%d,"
231     " _abuse_cur=0"
232     " WHERE _from='%s'",
233     atol(triplet_array[fd][3]),
234     instance_inc[fd],
235     instance_inc[fd],
236     triplet_array[fd][4]);
237   if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
238 
239   return (0); /* never reached */
240 }
241 
242 /* EOF */
243