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: throttle_check
35  *  purpose: throttle users based on SASL info or envelope FROM
36  *   return: 0 for new record, 1 for update
37  */
38 int
throttle_check(unsigned int fd)39 throttle_check (unsigned int fd)
40 {
41   unsigned int tnum = 0;
42   unsigned int tresult = 0;
43 
44   mysql_optarray[fd][0] = 0;
45 
46   if(DEBUG > 0)
47     logmessage("DEBUG: fd: %d checking throttle\n", fd);
48 
49   /* build up & execute query */
50   if(SENDER_THROTTLE_HOST == 1)
51   {
52     tnum = 1;
53     snprintf(mysqlquery_array[fd], 512,
54       "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
55       " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
56       " _log_warn, _log_panic, _abuse_tot"
57       " FROM throttle WHERE _from='%s' OR _from='%s' OR _from='%s' OR _from='%s'"
58       " ORDER BY _priority DESC LIMIT 1",
59       host_array[fd][2], host_array[fd][3], host_array[fd][4], host_array[fd][5]);
60 
61   } else if((SENDER_THROTTLE_SASL == 1) && (triplet_array[fd][4][0] != 0x00))  {
62     tnum = 2;
63     snprintf(mysqlquery_array[fd], 512,
64       "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
65       " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
66       " _log_warn, _log_panic, _abuse_tot"
67       " FROM throttle WHERE _from='%s'", triplet_array[fd][4]);
68   } else {
69     tnum = 3;
70     snprintf(mysqlquery_array[fd], 512,
71       "SELECT _from,_count_max,_count_cur,_date,_quota_cur,_quota_max,"
72       " _time_limit,_mail_size,_count_tot,_rcpt_max,_rcpt_cur,_rcpt_tot,"
73       " _log_warn, _log_panic, _abuse_tot"
74       " FROM throttle WHERE _from='%s' OR _from='@%s'"
75       " ORDER BY _priority DESC LIMIT 1",
76       triplet_array[fd][1], host_array[fd][7]);
77   }
78   if(db_charquery(fd) == -1) return(db_failure(fd, "throttle"));
79 
80   /* max messages is disabled in database, fall back to config default */
81   if(atol(mysqlchar_array[fd][1]) == 0)
82     snprintf(mysqlchar_array[fd][1], sizeof(mysqlchar_array[fd][1]),
83       "%d", SENDERMSGLIMIT);
84 
85   /* max user quota is disabled in database, fall back to config defaults */
86   if(atol(mysqlchar_array[fd][5]) == 0)
87     snprintf(mysqlchar_array[fd][5], sizeof(mysqlchar_array[fd][5]),
88       "%d", SENDERQUOTALIMIT);
89 
90   /* max time limit is disabled in database, fall back to config defaults */
91   if(atol(mysqlchar_array[fd][6]) == 0)
92     snprintf(mysqlchar_array[fd][6], sizeof(mysqlchar_array[fd][6]),
93       "%d", SENDERTIMELIMIT);
94 
95   /* max message size is disabled in database, fall back to config defaults */
96   if(atol(mysqlchar_array[fd][7]) == 0)
97     snprintf(mysqlchar_array[fd][7], sizeof(mysqlchar_array[fd][7]),
98       "%d", SENDERMSGSIZE);
99 
100   /* max rcpt limit is disabled in database, fall back to config defaults */
101   if(atol(mysqlchar_array[fd][9]) == 0)
102     snprintf(mysqlchar_array[fd][9], sizeof(mysqlchar_array[fd][9]),
103       "%d", SENDERRCPTLIMIT);
104 
105   /* check postfix policy instance */
106   snprintf(mysqlquery_array[fd], 512,
107     "SELECT COUNT(_instance) from throttle_from_instance \
108        WHERE _instance='%s'", triplet_array[fd][6]);
109   if(db_optquery(fd) == -1) return(db_failure(fd, "throttle"));
110 
111   /* is instance recorded? */
112   if(mysql_optarray[fd][0] == 0)
113   {
114     int expire=0;
115 
116     /* its not, so record it */
117     if(SENDERTIMELIMIT > 0)
118       expire=timenow;
119 
120     snprintf(mysqlquery_array[fd], 512,
121       "INSERT DELAYED INTO throttle_from_instance (_instance,_expire) VALUES ('%s',%d)",
122       triplet_array[fd][6], expire);
123     if(db_doquery(fd) == -1) return(db_failure(fd, "throttle"));
124 
125     instance_inc[fd] = 1;
126   } else {
127     instance_inc[fd] = 0;
128   }
129 
130   /* prepare attributes & thresholds */
131   /* count, quota, rcpt */
132   tquota[fd] = atof(mysqlchar_array[fd][4]) / atof(mysqlchar_array[fd][5]) * 100;
133   tcount[fd] = atof(mysqlchar_array[fd][2]) / atof(mysqlchar_array[fd][1]) * 100;
134   trcpt[fd] = atof(mysqlchar_array[fd][10]) / atof(mysqlchar_array[fd][9]) * 100;
135 
136   /* catch wierd ones */
137   if(DEBUG >= 4)
138     logmessage("DEBUG: fd: %d: tquota[fd]: %d, tcount[fd]: %d, trcpt[fd]: %d\n",
139        fd, tquota[fd], tcount[fd], trcpt[fd]);
140 
141   /* highest percentage always wins.. mmm.. ugly stuff*/
142   if(tquota[fd] >= tcount[fd] && tquota[fd] >= trcpt[fd]) {
143     tresult = tquota[fd];
144     if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }
145 
146   if(tcount[fd] >= tquota[fd] && tcount[fd] >= trcpt[fd]) {
147     tresult = tcount[fd];
148     if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }
149 
150   if(trcpt[fd]  >= tcount[fd] && trcpt[fd] >= tquota[fd]) {
151     tresult = trcpt[fd];
152     if (DEBUG >= 4) logmessage("tquota[fd] won\n"); }
153 
154   if(DEBUG >= 4)
155     logmessage("DEBUG: fd: %d: tresult: %d\n", fd, tresult);
156 
157   /* percentage won, set attribute accordingly */
158   switch (tresult)
159   {
160 
161     case 0 ... 49:      tattrib_array[fd][0] = 'a'; break;
162     case 50 ... 89:     tattrib_array[fd][0] = 'w'; break;
163     case 90 ... 900000: tattrib_array[fd][0] = 'p'; break;
164     /* allow for big percentage overshoot */
165 
166     default:
167       logmessage("fatal: throttle_check(): invalid tresult: %d\n", tresult);
168       return (-1);
169   }
170 
171   /* we selectively choose which throttle module we want */
172   switch(tnum)
173   {
174     case 1:
175       return(throttle_host(fd));
176 
177     case 2:
178       return(throttle_sasl(fd));
179 
180     case 3:
181       return(throttle_from(fd));
182 
183     default:
184       logmessage("fatal: throttle_check(): no tnum\n");
185       return (-1);
186   }
187 
188   return (0); /* never reached */
189 }
190 
191 /* EOF */
192