Mercurial > notdcc
comparison dcclib/ask.c @ 0:c7f6b056b673
First import of vendor version
author | Peter Gervai <grin@grin.hu> |
---|---|
date | Tue, 10 Mar 2009 13:49:58 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c7f6b056b673 |
---|---|
1 /* Distributed Checksum Clearinghouse | |
2 * | |
3 * ask about a batch of checksums | |
4 * | |
5 * Copyright (c) 2008 by Rhyolite Software, LLC | |
6 * | |
7 * This agreement is not applicable to any entity which sells anti-spam | |
8 * solutions to others or provides an anti-spam solution as part of a | |
9 * security solution sold to other entities, or to a private network | |
10 * which employs the DCC or uses data provided by operation of the DCC | |
11 * but does not provide corresponding data to other users. | |
12 * | |
13 * Permission to use, copy, modify, and distribute this software without | |
14 * changes for any purpose with or without fee is hereby granted, provided | |
15 * that the above copyright notice and this permission notice appear in all | |
16 * copies and any distributed versions or copies are either unchanged | |
17 * or not called anything similar to "DCC" or "Distributed Checksum | |
18 * Clearinghouse". | |
19 * | |
20 * Parties not eligible to receive a license under this agreement can | |
21 * obtain a commercial license to use DCC by contacting Rhyolite Software | |
22 * at sales@rhyolite.com. | |
23 * | |
24 * A commercial license would be for Distributed Checksum and Reputation | |
25 * Clearinghouse software. That software includes additional features. This | |
26 * free license for Distributed ChecksumClearinghouse Software does not in any | |
27 * way grant permision to use Distributed Checksum and Reputation Clearinghouse | |
28 * software | |
29 * | |
30 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL | |
31 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
32 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC | |
33 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES | |
34 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
35 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
36 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
37 * SOFTWARE. | |
38 * | |
39 * Rhyolite Software DCC 1.3.103-1.146 $Revision$ | |
40 */ | |
41 | |
42 #include "dcc_ck.h" | |
43 #include "dcc_heap_debug.h" | |
44 #include "dcc_xhdr.h" | |
45 | |
46 static DCC_CKSUM_THOLDS dcc_tholds_log; | |
47 DCC_CKSUM_THOLDS dcc_tholds_rej; | |
48 static u_char dcc_honor_nospam[DCC_DIM_CKS]; | |
49 | |
50 static u_char trim_grey_ip_addr; /* remove IP address from grey triple */ | |
51 static struct in6_addr grey_ip_mask; | |
52 | |
53 static void honor_cnt(const DCC_GOT_CKS *cks, u_int *, DCC_CK_TYPES, DCC_TGTS); | |
54 | |
55 | |
56 | |
57 #ifdef DCC_PKT_VERSION5 | |
58 /* figure old server's target count before our latest report */ | |
59 static DCC_TGTS /* return corrected current count */ | |
60 save_p_tgts(DCC_GOT_SUM *g, /* put previous count in g->tgts */ | |
61 DCC_OPS op, | |
62 const DCC_TGTS local_tgts, /* real local target count */ | |
63 const DCC_TGTS gross_tgts, /* local count adjusted by blacklist */ | |
64 DCC_TGTS c_tgts) /* what the old DCC server said */ | |
65 { | |
66 DCC_CK_TYPES type = g->type; | |
67 | |
68 if (op == DCC_OP_QUERY) { | |
69 /* if we switched servers and converted a report | |
70 * to a query, then guess the total that the | |
71 * server would have produced for a report | |
72 * instead of the query we sent. | |
73 * | |
74 * Assume the server is not running with -K. | |
75 * If the server's current value is 0 for a body checksum | |
76 * then assume the report we sent to the other server has not | |
77 * been flooded. | |
78 * Assume other checksums will always be zero/unknown. */ | |
79 if (DB_GLOBAL_NOKEEP(0, type)) | |
80 return 0; | |
81 | |
82 /* Assume the current value is really the previous value | |
83 * because flooding has not happened */ | |
84 g->tgts = c_tgts; | |
85 | |
86 if (c_tgts < DCC_TGTS_TOO_MANY | |
87 && DCC_CK_IS_BODY(type)) { | |
88 c_tgts += local_tgts; | |
89 if (c_tgts > DCC_TGTS_TOO_MANY) | |
90 c_tgts = DCC_TGTS_TOO_MANY; | |
91 } | |
92 return c_tgts; | |
93 | |
94 } else if (c_tgts >= gross_tgts | |
95 && gross_tgts < DCC_TGTS_TOO_MANY) { | |
96 /* if possible infer server's value before our report */ | |
97 if (c_tgts >= DCC_TGTS_TOO_MANY) | |
98 g->tgts = c_tgts; | |
99 else | |
100 g->tgts = c_tgts - gross_tgts; | |
101 } | |
102 | |
103 return c_tgts; | |
104 } | |
105 | |
106 | |
107 | |
108 #endif /* DCC_PKT_VERSION5 */ | |
109 int /* 1=ok, 0=no answer, -1=fatal */ | |
110 ask_dcc(DCC_EMSG emsg, | |
111 DCC_CLNT_CTXT *ctxt, | |
112 DCC_CLNT_FGS clnt_fgs, /* DCC_CLNT_FG_* */ | |
113 DCC_HEADER_BUF *hdr, /* put results here */ | |
114 DCC_GOT_CKS *cks, /* and here */ | |
115 ASK_ST *ask_stp, /* and here */ | |
116 u_char spam, /* spam==0 && local_tgts==0 --> query */ | |
117 DCC_TGTS local_tgts) /* report these targets to DCC server */ | |
118 { | |
119 union { | |
120 DCC_HDR hdr; | |
121 DCC_REPORT r; | |
122 } rpt; | |
123 DCC_OP_RESP resp; | |
124 DCC_OPS op; | |
125 DCC_CK *ck; | |
126 DCC_GOT_SUM *g; | |
127 DCC_TGTS gross_tgts; | |
128 DCC_TGTS c_tgts; /* server's current, total count */ | |
129 DCC_CKS_WTGTS hdr_tgts; /* values for X-DCC header */ | |
130 DCC_CK_TYPES type; | |
131 DCC_SRVR_ID srvr_id; | |
132 int pkt_len, recv_len, exp_len; | |
133 int num_cks, ck_num, result; | |
134 | |
135 memset(hdr_tgts, 0, sizeof(hdr_tgts)); | |
136 | |
137 /* prepare a report for the nearest DCC server */ | |
138 if (local_tgts == 0 && !spam) { | |
139 /* because of greylisting, we can have a target count of 0 | |
140 * but need to report spam discovered by a DNSBL */ | |
141 op = DCC_OP_QUERY; | |
142 gross_tgts = 0; | |
143 rpt.r.tgts = 0; | |
144 } else { | |
145 op = DCC_OP_REPORT; | |
146 if (local_tgts == DCC_TGTS_TOO_MANY | |
147 || local_tgts == 0) { | |
148 spam = 1; | |
149 local_tgts = 1; | |
150 } | |
151 if (spam) { | |
152 *ask_stp |= (ASK_ST_CLNT_ISSPAM | ASK_ST_LOGIT); | |
153 gross_tgts = DCC_TGTS_TOO_MANY; | |
154 rpt.r.tgts = htonl(local_tgts | DCC_TGTS_SPAM); | |
155 } else { | |
156 gross_tgts = local_tgts; | |
157 rpt.r.tgts = htonl(local_tgts); | |
158 } | |
159 } | |
160 | |
161 ck = rpt.r.cks; | |
162 num_cks = 0; | |
163 for (g = cks->sums; g <= &cks->sums[DCC_CK_TYPE_LAST]; ++g) { | |
164 /* never tell the DCC server about some headers */ | |
165 if (!g->rpt2srvr) | |
166 continue; | |
167 ck->len = sizeof(*ck); | |
168 ck->type = g->type; | |
169 memcpy(ck->sum, g->sum, sizeof(ck->sum)); | |
170 ++ck; | |
171 ++num_cks; | |
172 } | |
173 if (num_cks == 0) { | |
174 /* pretend we always have at least a basic body checksum | |
175 * guess the DCC would have answered 0 */ | |
176 xhdr_init(hdr, 0); | |
177 xhdr_add_ck(hdr, DCC_CK_BODY, gross_tgts); | |
178 honor_cnt(cks, ask_stp, DCC_CK_BODY, local_tgts); | |
179 return 1; | |
180 } | |
181 | |
182 /* send the report and see what the DCC has to say */ | |
183 pkt_len = (sizeof(rpt.r) - sizeof(rpt.r.cks) | |
184 + num_cks * sizeof(rpt.r.cks[0])); | |
185 result = dcc_clnt_op(emsg, ctxt, clnt_fgs, 0, &srvr_id, 0, | |
186 &rpt.hdr, pkt_len, op, &resp, sizeof(resp)); | |
187 | |
188 /* try a query to different server if the first failed | |
189 * but a second was found */ | |
190 if (!result && srvr_id != DCC_ID_INVALID) { | |
191 if (dcc_clnt_debug) { | |
192 if (emsg && *emsg != '\0') { | |
193 dcc_trace_msg("retry with different server" | |
194 " after: %s", emsg); | |
195 *emsg = '\0'; | |
196 } else { | |
197 dcc_trace_msg("retry with different server"); | |
198 } | |
199 } | |
200 op = DCC_OP_QUERY; | |
201 result = dcc_clnt_op(emsg, ctxt, clnt_fgs | DCC_CLNT_FG_RETRY, | |
202 0, &srvr_id, 0, | |
203 &rpt.hdr, pkt_len, | |
204 op, &resp, sizeof(resp)); | |
205 } | |
206 if (!result) { | |
207 *ask_stp |= ASK_ST_LOGIT; | |
208 } else { | |
209 /* forget about it if the DCC server responded too strangely */ | |
210 recv_len = ntohs(resp.hdr.len); | |
211 #ifdef DCC_PKT_VERSION5 | |
212 if (resp.hdr.pkt_vers <= DCC_PKT_VERSION5) | |
213 exp_len = (sizeof(resp.ans5) - sizeof(resp.ans5.b) | |
214 + num_cks*sizeof(DCC_TGTS)); | |
215 else | |
216 #endif | |
217 exp_len = (sizeof(resp.ans) - sizeof(resp.ans.b) | |
218 + num_cks*sizeof(resp.ans.b[0])); | |
219 if (recv_len != exp_len) { | |
220 dcc_pemsg(EX_UNAVAILABLE, emsg, | |
221 "DCC %s: answered with %d instead of %d bytes", | |
222 dcc_srvr_nm(0), recv_len, exp_len); | |
223 *ask_stp |= ASK_ST_LOGIT; | |
224 result = -1; | |
225 } | |
226 } | |
227 | |
228 /* check the server's response to see if we have spam */ | |
229 ck_num = 0; | |
230 for (g = cks->sums; g <= &cks->sums[DCC_CK_TYPE_LAST]; ++g) { | |
231 if (!g->rpt2srvr) { | |
232 /* pretend we always have a basic body checksum */ | |
233 if (g == &cks->sums[DCC_CK_BODY]) | |
234 honor_cnt(cks, ask_stp, | |
235 DCC_CK_BODY, local_tgts); | |
236 continue; | |
237 } | |
238 type = g->type; /* g->type is valid only if rpt2srvr */ | |
239 | |
240 if (result <= 0) { | |
241 c_tgts = (DCC_CK_IS_BODY(type)) ? gross_tgts : 0; | |
242 | |
243 #ifdef DCC_PKT_VERSION5 | |
244 } else if (resp.hdr.pkt_vers <= DCC_PKT_VERSION5) { | |
245 c_tgts = save_p_tgts(g, op, | |
246 local_tgts, gross_tgts, | |
247 ntohl(resp.ans5.b[ck_num])); | |
248 } else { | |
249 #endif /* DCC_PKT_VERSION5 */ | |
250 /* server's total before our report */ | |
251 g->tgts = ntohl(resp.ans.b[ck_num].p); | |
252 /* new total */ | |
253 c_tgts = ntohl(resp.ans.b[ck_num].c); | |
254 #ifdef DCC_PKT_VERSION5 | |
255 } | |
256 #endif | |
257 ++ck_num; | |
258 | |
259 hdr_tgts[type] = c_tgts; | |
260 | |
261 /* notice DCC server's whitelist */ | |
262 if (dcc_honor_nospam[type]) { | |
263 if (c_tgts == DCC_TGTS_OK) { | |
264 *ask_stp |= ASK_ST_SRVR_NOTSPAM; | |
265 | |
266 } else if (c_tgts == DCC_TGTS_OK2) { | |
267 /* if server says it is half ok, | |
268 * look for two halves */ | |
269 if (*ask_stp & ASK_ST_SRVR_OK2) { | |
270 *ask_stp |= ASK_ST_SRVR_NOTSPAM; | |
271 } else { | |
272 *ask_stp |= ASK_ST_SRVR_OK2; | |
273 } | |
274 } | |
275 } | |
276 | |
277 honor_cnt(cks, ask_stp, type, c_tgts); | |
278 } | |
279 | |
280 /* honor server whitelist */ | |
281 if (*ask_stp & ASK_ST_SRVR_NOTSPAM) | |
282 *ask_stp &= ~ASK_ST_SRVR_ISSPAM; | |
283 | |
284 /* generate the header line now that we have checked all of | |
285 * the counts against their thresholds and so know if we | |
286 * must add "bulk". Add the header even if checking is turned off | |
287 * and we won't reject affected messages. Say "many" for DNSBL | |
288 * or local blacklist spam even without an answer from the DCC server | |
289 * so that SpamAssassin gets the message. */ | |
290 xhdr_init(hdr, srvr_id); | |
291 if (*ask_stp & ASK_ST_SRVR_ISSPAM) { | |
292 xhdr_add_str(hdr, DCC_XHDR_BULK); | |
293 } else if (*ask_stp & ASK_ST_CLNT_ISSPAM) { | |
294 xhdr_add_str(hdr, DCC_XHDR_BULK); | |
295 hdr_tgts[DCC_CK_BODY] = DCC_TGTS_TOO_MANY; | |
296 } else if (*ask_stp & ASK_ST_REP_ISSPAM) { | |
297 xhdr_add_str(hdr, DCC_XHDR_BULK_REP); | |
298 hdr_tgts[DCC_CK_BODY] = DCC_TGTS_TOO_MANY; | |
299 } | |
300 | |
301 for (g = cks->sums; g <= &cks->sums[DCC_CK_TYPE_LAST]; ++g) { | |
302 if (!g->rpt2srvr) { | |
303 /* pretend we always have a body checksum */ | |
304 if (g == &cks->sums[DCC_CK_BODY]) | |
305 xhdr_add_ck(hdr, DCC_CK_BODY, | |
306 hdr_tgts[DCC_CK_BODY]); | |
307 continue; | |
308 } | |
309 /* Add interesing counts to the header. | |
310 * Body checksums are always interestig if we have them. | |
311 * Pretend we always have a basic body checksum. */ | |
312 type = g->type; | |
313 if (DCC_CK_IS_BODY(type)) { | |
314 xhdr_add_ck(hdr, type, hdr_tgts[type]); | |
315 continue; | |
316 } | |
317 if (hdr_tgts[type] != 0) | |
318 xhdr_add_ck(hdr, type, hdr_tgts[type]); | |
319 } | |
320 | |
321 return result; | |
322 } | |
323 | |
324 | |
325 | |
326 /* check message's checksums in whiteclnt for dccproc or dccsight */ | |
327 u_char /* 1=ok 0=something to complain about */ | |
328 unthr_ask_white(DCC_EMSG emsg, | |
329 ASK_ST *ask_stp, | |
330 FLTR_SWS *swsp, | |
331 const char *white_nm, | |
332 DCC_GOT_CKS *cks, | |
333 DCC_CKS_WTGTS wtgts) | |
334 { | |
335 DCC_WHITE_LISTING listing; | |
336 int retval; | |
337 | |
338 /* assume DNSBLs are on unless turned off, because there is no reason | |
339 * to use `dccproc -B` if you don't want to use them */ | |
340 *swsp |= FLTR_SW_DNSBL_M; | |
341 | |
342 /* fake whiteclnt if not specified */ | |
343 if (!white_nm) { | |
344 dcc_merge_tholds(cks->tholds_rej, dcc_tholds_rej, 0); | |
345 return 1; | |
346 } | |
347 | |
348 /* don't filter if something is wrong with the file */ | |
349 if (!dcc_new_white_nm(emsg, &cmn_wf, white_nm)) { | |
350 *ask_stp |= ASK_ST_WLIST_NOTSPAM | ASK_ST_LOGIT; | |
351 return 0; | |
352 } | |
353 | |
354 /* let whiteclnt file turn off the DCC and other filters */ | |
355 *swsp = wf2sws(*swsp, &cmn_wf); | |
356 | |
357 /* combine the command-line thresholds with the thresholds from | |
358 * from the common /var/dcc/whiteclnt file */ | |
359 dcc_merge_tholds(cks->tholds_rej, dcc_tholds_rej, cmn_wf.wtbl); | |
360 | |
361 retval = 1; | |
362 switch (dcc_white_cks(emsg, &cmn_wf, cks, wtgts, &listing)) { | |
363 case DCC_WHITE_OK: | |
364 case DCC_WHITE_NOFILE: | |
365 break; | |
366 case DCC_WHITE_SILENT: | |
367 *ask_stp |= ASK_ST_LOGIT; | |
368 break; | |
369 case DCC_WHITE_COMPLAIN: | |
370 case DCC_WHITE_CONTINUE: | |
371 retval = 0; | |
372 *ask_stp |= ASK_ST_LOGIT; | |
373 break; | |
374 } | |
375 | |
376 switch (listing) { | |
377 case DCC_WHITE_LISTED: | |
378 /* do not send whitelisted checksums to DCC server */ | |
379 *ask_stp |= ASK_ST_WLIST_NOTSPAM; | |
380 break; | |
381 case DCC_WHITE_USE_DCC: | |
382 case DCC_WHITE_UNLISTED: | |
383 if (*swsp & FLTR_SW_TRAPS) | |
384 *ask_stp |= (ASK_ST_CLNT_ISSPAM | ASK_ST_WLIST_ISSPAM | |
385 | ASK_ST_LOGIT); | |
386 break; | |
387 case DCC_WHITE_BLACK: | |
388 *ask_stp |= (ASK_ST_WLIST_ISSPAM | |
389 | ASK_ST_CLNT_ISSPAM | ASK_ST_LOGIT); | |
390 break; | |
391 } | |
392 | |
393 if (*swsp & FLTR_SW_LOG_ALL) | |
394 *ask_stp |= ASK_ST_LOGIT; | |
395 | |
396 return retval; | |
397 } | |
398 | |
399 | |
400 | |
401 /* ask the DCC for dccproc or dccsight but not dccifd or dccm */ | |
402 u_char /* 1=ok 0=something to complain about */ | |
403 unthr_ask_dcc(DCC_EMSG emsg, | |
404 DCC_CLNT_CTXT *ctxt, | |
405 DCC_HEADER_BUF *hdr, /* put header here */ | |
406 ASK_ST *ask_stp, /* put state bites here */ | |
407 DCC_GOT_CKS *cks, /* these checksums */ | |
408 u_char spam, /* spam==0 && local_tgts==0 --> query */ | |
409 DCC_TGTS local_tgts) /* number of addressees */ | |
410 { | |
411 if (*ask_stp & ASK_ST_WLIST_NOTSPAM) { | |
412 if (spam) { | |
413 /* if dccproc says it is spam, then it is, even if | |
414 * the whiteclnt file says we cannot report it */ | |
415 *ask_stp |= (ASK_ST_CLNT_ISSPAM | ASK_ST_LOGIT); | |
416 xhdr_init(hdr, 0); | |
417 xhdr_add_ck(hdr, DCC_CK_BODY, DCC_TGTS_TOO_MANY); | |
418 } else { | |
419 xhdr_whitelist(hdr); | |
420 } | |
421 /* honor log threshold for whitelisted messages */ | |
422 dcc_honor_log_cnts(ask_stp, cks, local_tgts); | |
423 return 1; | |
424 | |
425 } else { | |
426 /* if allowed by whitelisting, report our checksums to the DCC | |
427 * and return with that result including setting logging */ | |
428 return (0 < ask_dcc(emsg, ctxt, DCC_CLNT_FG_NONE, | |
429 hdr, cks, ask_stp, spam, | |
430 local_tgts)); | |
431 } | |
432 } | |
433 | |
434 | |
435 | |
436 /* parse -g for dccm and dccproc */ | |
437 void | |
438 dcc_parse_honor(const char *arg0) | |
439 { | |
440 const char *arg; | |
441 DCC_CK_TYPES type, t2; | |
442 int i; | |
443 | |
444 arg = arg0; | |
445 if (!CLITCMP(arg, "not_") || !CLITCMP(arg, "not-")) { | |
446 arg += LITZ("not_"); | |
447 i = 0; | |
448 } else if (!CLITCMP(arg, "no_") || !CLITCMP(arg, "no-")) { | |
449 arg += LITZ("no_"); | |
450 i = 0; | |
451 } else { | |
452 i = 1; | |
453 } | |
454 | |
455 /* allow -g for ordinary checksums but not reputations or greylisting */ | |
456 type = dcc_str2type_thold(arg, -1); | |
457 if (type == DCC_CK_INVALID) { | |
458 dcc_error_msg("unrecognized checksum type in \"-g %s\"", | |
459 arg0); | |
460 return; | |
461 } | |
462 for (t2 = DCC_CK_TYPE_FIRST; t2 <= DCC_CK_TYPE_LAST; ++t2) { | |
463 if (t2 == type | |
464 || (type == SET_ALL_THOLDS && IS_ALL_CKSUM(t2)) | |
465 || (type == SET_CMN_THOLDS && IS_CMN_CKSUM(t2))) | |
466 dcc_honor_nospam[t2] = i; | |
467 } | |
468 } | |
469 | |
470 | |
471 | |
472 void | |
473 dcc_clear_tholds(void) | |
474 { | |
475 DCC_CK_TYPES type; | |
476 | |
477 memset(dcc_honor_nospam, 0, sizeof(dcc_honor_nospam)); | |
478 dcc_honor_nospam[DCC_CK_IP] = 1; | |
479 dcc_honor_nospam[DCC_CK_ENV_FROM] = 1; | |
480 dcc_honor_nospam[DCC_CK_FROM] = 1; | |
481 | |
482 for (type = DCC_CK_TYPE_FIRST; type <= DCC_CK_TYPE_LAST; ++type) { | |
483 dcc_tholds_log[type] = DCC_THOLD_UNSET; | |
484 dcc_tholds_rej[type] = DCC_THOLD_UNSET; | |
485 } | |
486 } | |
487 | |
488 | |
489 | |
490 u_char /* 1=merged from whiteclnt wtbl */ | |
491 dcc_merge_tholds(DCC_CKSUM_THOLDS out, | |
492 const DCC_CKSUM_THOLDS in, | |
493 const DCC_WHITE_TBL *wtbl) | |
494 { | |
495 DCC_CK_TYPES type; | |
496 DCC_TGTS tgts; | |
497 u_char result; | |
498 | |
499 if (in != out) | |
500 memcpy(out, in, sizeof(DCC_CKSUM_THOLDS)); | |
501 if (!wtbl) | |
502 return 0; | |
503 | |
504 result = 0; | |
505 for (type = DCC_CK_TYPE_FIRST; type <= DCC_CK_TYPE_LAST; ++type) { | |
506 tgts = wtbl->hdr.tholds_rej[type]; | |
507 if (tgts != DCC_THOLD_UNSET) { | |
508 out[type] = tgts; | |
509 result = 1; | |
510 } | |
511 } | |
512 return result; | |
513 } | |
514 | |
515 | |
516 | |
517 /* parse type,[log-thold,]rej-thold */ | |
518 u_char /* 1=need a log directory */ | |
519 dcc_parse_tholds(const char *f, /* "-c " or "-t " */ | |
520 const char *arg) /* optarg */ | |
521 { | |
522 DCC_CK_TYPES type; | |
523 DCC_TGTS log_tgts, rej_tgts; | |
524 char *thold_rej, *thold_log; | |
525 u_char log_tgts_set, rej_tgts_set; | |
526 | |
527 thold_log = strchr(arg, ','); | |
528 if (!thold_log) { | |
529 dcc_error_msg("missing comma in \"%s%s\"", f, arg); | |
530 return 0; | |
531 } | |
532 type = dcc_str2type_thold(arg, thold_log-arg); | |
533 if (type == DCC_CK_INVALID) { | |
534 dcc_error_msg("unrecognized checksum type in \"%s%s\"", f, arg); | |
535 return 0; | |
536 } | |
537 | |
538 thold_log = dcc_strdup(++thold_log); | |
539 | |
540 /* if there is only one threshold, take it as the spam threshold */ | |
541 thold_rej = strchr(thold_log, ','); | |
542 if (!thold_rej) { | |
543 thold_rej = thold_log; | |
544 thold_log = 0; | |
545 } else { | |
546 *thold_rej++ = '\0'; | |
547 } | |
548 | |
549 log_tgts_set = log_tgts = 0; | |
550 if (thold_log && *thold_log != '\0') { | |
551 log_tgts = dcc_str2thold(type, thold_log); | |
552 if (log_tgts == DCC_TGTS_INVALID) | |
553 dcc_error_msg("unrecognized logging threshold" | |
554 " \"%s\" in \"%s%s\"", | |
555 thold_log, f, arg); | |
556 else | |
557 log_tgts_set = 1; | |
558 } | |
559 | |
560 | |
561 rej_tgts_set = rej_tgts = 0; | |
562 if (!thold_rej || *thold_rej == '\0') { | |
563 if (!thold_log || *thold_log == '\0') | |
564 dcc_error_msg("no thresholds in \"%s%s\"", f, arg); | |
565 } else { | |
566 rej_tgts = dcc_str2thold(type, thold_rej); | |
567 if (rej_tgts == DCC_TGTS_INVALID) | |
568 dcc_error_msg("unrecognized rejection threshold" | |
569 " \"%s\" in \"%s%s\"", | |
570 thold_rej, f, arg); | |
571 else | |
572 rej_tgts_set = 1; | |
573 } | |
574 | |
575 | |
576 if (log_tgts_set || rej_tgts_set) { | |
577 DCC_CK_TYPES t2; | |
578 | |
579 for (t2 = DCC_CK_TYPE_FIRST; t2 <= DCC_CK_TYPE_LAST; ++t2) { | |
580 if (t2 == type | |
581 || (type == SET_ALL_THOLDS && IS_ALL_CKSUM(t2)) | |
582 || (type == SET_CMN_THOLDS && IS_CMN_CKSUM(t2))) { | |
583 if (log_tgts_set) | |
584 dcc_tholds_log[t2] = log_tgts; | |
585 if (rej_tgts_set) | |
586 dcc_tholds_rej[t2] = rej_tgts; | |
587 } | |
588 } | |
589 } | |
590 | |
591 dcc_free(thold_log); | |
592 return log_tgts_set; | |
593 } | |
594 | |
595 | |
596 | |
597 static void | |
598 honor_cnt(const DCC_GOT_CKS *cks, | |
599 ASK_ST *ask_stp, /* previous flag bits */ | |
600 DCC_CK_TYPES type, /* which kind of checksum */ | |
601 DCC_TGTS type_tgts) /* total count for the checksum */ | |
602 { | |
603 if (type >= DIM(dcc_honor_nospam)) | |
604 return; | |
605 | |
606 /* reject and log spam */ | |
607 if (cks->tholds_rej[type] <= DCC_TGTS_TOO_MANY | |
608 && cks->tholds_rej[type] <= type_tgts | |
609 && type_tgts <= DCC_TGTS_TOO_MANY) { | |
610 *ask_stp |= (ASK_ST_SRVR_ISSPAM | ASK_ST_LOGIT); | |
611 return; | |
612 } | |
613 | |
614 /* log messages that are bulkier than the log threshold */ | |
615 if (dcc_tholds_log[type] <= DCC_TGTS_TOO_MANY | |
616 && dcc_tholds_log[type] <= type_tgts) | |
617 *ask_stp |= ASK_ST_LOGIT; | |
618 } | |
619 | |
620 | |
621 | |
622 /* honor log threshold for local counts and white-/blacklists */ | |
623 void | |
624 dcc_honor_log_cnts(ASK_ST *ask_stp, /* previous flag bits */ | |
625 const DCC_GOT_CKS *cks, /* these server counts */ | |
626 DCC_TGTS tgts) | |
627 { | |
628 const DCC_GOT_SUM *g; | |
629 DCC_CK_TYPES type; | |
630 | |
631 if (*ask_stp & ASK_ST_LOGIT) | |
632 return; | |
633 | |
634 if (tgts == DCC_TGTS_TOO_MANY) { | |
635 *ask_stp |= ASK_ST_LOGIT; | |
636 return; | |
637 } | |
638 | |
639 /* pretend we always have a body checksum for the log threshold */ | |
640 if (dcc_tholds_log[DCC_CK_BODY] <= DCC_TGTS_TOO_MANY | |
641 && dcc_tholds_log[DCC_CK_BODY] <= tgts) { | |
642 *ask_stp |= ASK_ST_LOGIT; | |
643 return; | |
644 } | |
645 | |
646 for (g = cks->sums; g <= LAST(cks->sums); ++g) { | |
647 type = g->type; | |
648 if (type == DCC_CK_INVALID | |
649 || type == DCC_CK_ENV_TO) | |
650 continue; | |
651 if (dcc_tholds_log[type] > DCC_TGTS_TOO_MANY) | |
652 continue; | |
653 if (dcc_tholds_log[type] <= tgts) { | |
654 *ask_stp |= ASK_ST_LOGIT; | |
655 return; | |
656 } | |
657 } | |
658 } | |
659 | |
660 | |
661 | |
662 /* compute switch settings from bits in a whiteclnt file */ | |
663 FLTR_SWS | |
664 wf2sws(FLTR_SWS sws, const DCC_WF *wf) | |
665 { | |
666 static time_t complained; | |
667 time_t now; | |
668 DCC_PATH abs_nm; | |
669 int i; | |
670 | |
671 if (!grey_on | |
672 && (wf->wtbl_flags & (DCC_WHITE_FG_GREY_ON | |
673 | DCC_WHITE_FG_GREY_LOG_ON)) | |
674 && (now = time(0)) > complained+24*60*60) { | |
675 complained = now; | |
676 dcc_error_msg("%s wants greylisting" | |
677 " but it is turned off", | |
678 fnm2abs_err(abs_nm, wf->ascii_nm)); | |
679 } | |
680 | |
681 /* compute switch values from whiteclnt bits */ | |
682 | |
683 if (wf->wtbl_flags & DCC_WHITE_FG_NO_DISCARD) | |
684 sws |= FLTR_SW_NO_DISCARD; | |
685 else if (wf->wtbl_flags & DCC_WHITE_FG_DISCARD_OK) | |
686 sws &= ~FLTR_SW_NO_DISCARD; | |
687 | |
688 if ((wf->wtbl_flags & DCC_WHITE_FG_DCC_OFF)) | |
689 sws |= FLTR_SW_DCC_OFF; | |
690 else if (wf->wtbl_flags & DCC_WHITE_FG_DCC_ON) | |
691 sws &= ~FLTR_SW_DCC_OFF; | |
692 | |
693 if (grey_on && (wf->wtbl_flags & DCC_WHITE_FG_GREY_ON)) { | |
694 sws &= ~FLTR_SW_GREY_OFF; | |
695 } else if (!grey_on || (wf->wtbl_flags & DCC_WHITE_FG_GREY_OFF)) { | |
696 sws |= FLTR_SW_GREY_OFF; | |
697 } | |
698 | |
699 if (wf->wtbl_flags & DCC_WHITE_FG_LOG_ALL) { | |
700 sws |= FLTR_SW_LOG_ALL; | |
701 } else if (wf->wtbl_flags & DCC_WHITE_FG_LOG_NORMAL) { | |
702 sws &= ~FLTR_SW_LOG_ALL; | |
703 } | |
704 | |
705 if (wf->wtbl_flags & DCC_WHITE_FG_GREY_LOG_ON) { | |
706 sws &= ~FLTR_SW_GREY_LOG_OFF; | |
707 } else if (wf->wtbl_flags & DCC_WHITE_FG_GREY_LOG_OFF) { | |
708 sws |= FLTR_SW_GREY_LOG_OFF; | |
709 } | |
710 | |
711 if (wf->wtbl_flags & DCC_WHITE_FG_LOG_M) { | |
712 sws |= FLTR_SW_LOG_M; | |
713 } else if (wf->wtbl_flags & DCC_WHITE_FG_LOG_H) { | |
714 sws |= FLTR_SW_LOG_H; | |
715 } else if (wf->wtbl_flags & DCC_WHITE_FG_LOG_D) { | |
716 sws |= FLTR_SW_LOG_D; | |
717 } | |
718 | |
719 if (wf->wtbl_flags & DCC_WHITE_FG_MTA_FIRST) { | |
720 sws |= FLTR_SW_MTA_FIRST; | |
721 } else if (wf->wtbl_flags & DCC_WHITE_FG_MTA_LAST) { | |
722 sws &= ~FLTR_SW_MTA_FIRST; | |
723 } | |
724 | |
725 for (i = 0; i < MAX_DNSBL_GROUPS; ++i) { | |
726 if ((wf->wtbl_flags & DCC_WHITE_FG_DNSBL_ON(i)) | |
727 && dnsbls) { | |
728 sws |= FLTR_SW_DNSBL(i); | |
729 } else if (wf->wtbl_flags & DCC_WHITE_FG_DNSBL_OFF(i)) { | |
730 sws &= ~FLTR_SW_DNSBL(i); | |
731 } | |
732 } | |
733 | |
734 if (wf->wtbl_flags & DCC_WHITE_FG_TRAP_ACC) { | |
735 sws |= FLTR_SW_TRAP_ACC; | |
736 } else if (wf->wtbl_flags & DCC_WHITE_FG_TRAP_REJ) { | |
737 sws |= FLTR_SW_TRAP_REJ; | |
738 } | |
739 | |
740 return sws | FLTR_SW_SET; | |
741 } | |
742 | |
743 | |
744 | |
745 #define LOG_ASK_ST_BLEN 160 | |
746 #define LOG_ASK_ST_OFF "(off)" | |
747 #define LOG_ASK_ST_OVF " ...\n\n" | |
748 static int | |
749 log_ask_st_sub(char *buf, int blen, | |
750 const char *s, int slen, | |
751 u_char off) | |
752 { | |
753 int dlen, tlen; | |
754 | |
755 /* quit if no room at all in the log */ | |
756 if (blen >= LOG_ASK_ST_BLEN) | |
757 return LOG_ASK_ST_BLEN; | |
758 | |
759 /* quit if nothing to say */ | |
760 if (!s || !slen) | |
761 return blen; | |
762 | |
763 dlen = LOG_ASK_ST_BLEN - blen; | |
764 tlen = LITZ(LOG_ASK_ST_OVF)+2+slen; | |
765 if (off) /* notice if we need to say "(off)" */ | |
766 tlen += LITZ(LOG_ASK_ST_OFF); | |
767 if (dlen <= tlen) { | |
768 /* show truncation of the message with "..." */ | |
769 memcpy(&buf[blen], LOG_ASK_ST_OVF, LITZ(LOG_ASK_ST_OVF)); | |
770 blen += LITZ(LOG_ASK_ST_OVF); | |
771 if (blen < LOG_ASK_ST_BLEN) | |
772 memset(&buf[blen], ' ', LOG_ASK_ST_BLEN-blen); | |
773 return LOG_ASK_ST_BLEN; | |
774 } | |
775 | |
776 if (blen > 0 && buf[blen-1] != '\n') { | |
777 buf[blen++] = ' '; | |
778 buf[blen++] = ' '; | |
779 } | |
780 memcpy(buf+blen, s, slen); | |
781 blen += slen; | |
782 if (off) { | |
783 memcpy(buf+blen, LOG_ASK_ST_OFF, LITZ(LOG_ASK_ST_OFF)); | |
784 blen += LITZ(LOG_ASK_ST_OFF); | |
785 } | |
786 return blen; | |
787 } | |
788 | |
789 | |
790 | |
791 /* generate log file line of results */ | |
792 void | |
793 log_ask_st(LOG_WRITE_FNC fnc, void *cp, ASK_ST ask_st, FLTR_SWS sws, | |
794 u_char log_type, /* 0="" 1="per-user" 2="global" */ | |
795 const DCC_HEADER_BUF *hdr) | |
796 { | |
797 char buf[LOG_ASK_ST_BLEN+3]; | |
798 char dnsbl_buf[24]; | |
799 int blen, len, i; | |
800 #define S(str,off) (blen = log_ask_st_sub(buf, blen, str, LITZ(str), off)) | |
801 #define S0(bit,off,str) if (ask_st & bit) S(str,off) | |
802 #define S1(bit,s1off,str) S0(bit,(log_type != 2 && (s1off)),str) | |
803 #define S2(bit,str) S0(bit,0,str) | |
804 | |
805 blen = 0; | |
806 S2(ASK_ST_QUERY, "query"); | |
807 | |
808 /* the CGI scripts want to know why */ | |
809 if (sws & FLTR_SW_MTA_FIRST) { | |
810 S2(ASK_ST_MTA_ISSPAM, "MTA"DCC_XHDR_ISSPAM); | |
811 S2(ASK_ST_MTA_NOTSPAM, "MTA"DCC_XHDR_ISOK); | |
812 } | |
813 | |
814 S2(ASK_ST_WLIST_NOTSPAM, "wlist"DCC_XHDR_ISOK); | |
815 if (log_type != 2 && !(ask_st & ASK_ST_WLIST_NOTSPAM)) | |
816 S2(ASK_ST_WLIST_ISSPAM, "wlist"DCC_XHDR_ISSPAM); | |
817 | |
818 S1(ASK_ST_SRVR_ISSPAM, (sws & FLTR_SW_DCC_OFF), "DCC"DCC_XHDR_ISSPAM); | |
819 S1(ASK_ST_SRVR_NOTSPAM, (sws & FLTR_SW_DCC_OFF), "DCC"DCC_XHDR_ISOK); | |
820 S1(ASK_ST_REP_ISSPAM, !(sws & FLTR_SW_REP_ON), "Rep"DCC_XHDR_ISSPAM); | |
821 | |
822 for (i = 0; i < MAX_DNSBL_GROUPS; ++i) { | |
823 if (ask_st & ASK_ST_DNSBL_HIT(i)) { | |
824 if (have_dnsbl_groups) | |
825 len = snprintf(dnsbl_buf, sizeof(dnsbl_buf), | |
826 "DNSBL%d"DCC_XHDR_ISSPAM, i+1); | |
827 else | |
828 len = snprintf(dnsbl_buf, sizeof(dnsbl_buf), | |
829 "DNSBL"DCC_XHDR_ISSPAM); | |
830 /* log "DNSBLx-->spam" or "DNSBLx-->spam(off)" */ | |
831 blen = log_ask_st_sub(buf, blen, | |
832 dnsbl_buf, len, | |
833 log_type != 2 | |
834 && !(sws & FLTR_SW_DNSBL(i))); | |
835 } else if (ask_st & ASK_ST_DNSBL_TIMEO(i)) { | |
836 if (have_dnsbl_groups) | |
837 len = snprintf(dnsbl_buf, sizeof(dnsbl_buf), | |
838 "DNSBL%d(timeout)", i+1); | |
839 else | |
840 len = snprintf(dnsbl_buf, sizeof(dnsbl_buf), | |
841 "DNSBL(timeout)"); | |
842 blen = log_ask_st_sub(buf, blen, | |
843 dnsbl_buf, len, 0); | |
844 } | |
845 } | |
846 | |
847 if (!(sws & FLTR_SW_MTA_FIRST)) { | |
848 S2(ASK_ST_MTA_ISSPAM, "MTA"DCC_XHDR_ISSPAM); | |
849 S2(ASK_ST_MTA_NOTSPAM, "MTA"DCC_XHDR_ISOK); | |
850 } | |
851 blen = log_ask_st_sub(buf, blen, dcc_progname, dcc_progname_len, 0); | |
852 if (log_type == 1) { | |
853 blen = log_ask_st_sub(buf, blen, | |
854 "per-user", LITZ("per-user"), 0); | |
855 } else if (log_type == 2) { | |
856 blen = log_ask_st_sub(buf, blen, | |
857 "global", LITZ("global"), 0); | |
858 } | |
859 blen = log_ask_st_sub(buf, blen, "\n\n", 2, 0); | |
860 fnc(cp, buf, blen); | |
861 | |
862 if (hdr->used != 0) | |
863 xhdr_write(fnc, cp, hdr->buf, hdr->used, 0); | |
864 #undef S | |
865 #undef S0 | |
866 #undef S1 | |
867 #undef S2 | |
868 } | |
869 | |
870 | |
871 | |
872 /* parse -G options for DCC clients */ | |
873 u_char /* 0=bad */ | |
874 dcc_parse_client_grey(const char *arg) | |
875 { | |
876 int bits; | |
877 const char *p; | |
878 | |
879 while (*arg != '\0') { | |
880 if (dcc_ck_word_comma(&arg, "on")) { | |
881 grey_on = 1; | |
882 continue; | |
883 } | |
884 if (dcc_ck_word_comma(&arg, "off")) { | |
885 grey_on = 0; | |
886 continue; | |
887 } | |
888 if (dcc_ck_word_comma(&arg, "query")) { | |
889 grey_query_only = 1; | |
890 continue; | |
891 } | |
892 if (dcc_ck_word_comma(&arg, "noIP")) { | |
893 grey_on = 1; | |
894 trim_grey_ip_addr = 1; | |
895 memset(&grey_ip_mask, 0, sizeof(grey_ip_mask)); | |
896 continue; | |
897 } | |
898 if (!CLITCMP(arg, "IPmask/")) { | |
899 bits = 0; | |
900 for (p = arg+LITZ("IPmask/"); | |
901 *p >= '0' && *p <= '9'; | |
902 ++p) | |
903 bits = bits*10 + *p - '0'; | |
904 if (bits > 0 && bits < 128 | |
905 && (*p == '\0' || *p == ',')) { | |
906 arg = p; | |
907 if (*p == ',') | |
908 ++arg; | |
909 grey_on = 1; | |
910 trim_grey_ip_addr = 1; | |
911 /* assume giant blocks are really IPv4 */ | |
912 if (bits <= 32) | |
913 bits += 128-32; | |
914 dcc_bits2mask(&grey_ip_mask, bits); | |
915 continue; | |
916 } | |
917 } | |
918 return 0; | |
919 } | |
920 return 1; | |
921 } | |
922 | |
923 | |
924 | |
925 /* sanity check the DCC server's answer */ | |
926 u_char | |
927 dcc_ck_grey_answer(DCC_EMSG emsg, const DCC_OP_RESP *resp) | |
928 { | |
929 int recv_len; | |
930 | |
931 recv_len = ntohs(resp->hdr.len); | |
932 if (resp->hdr.op != DCC_OP_ANSWER) { | |
933 dcc_pemsg(EX_UNAVAILABLE, emsg, "DCC %s: %s %*s", | |
934 dcc_srvr_nm(1), | |
935 dcc_hdr_op2str(0, 0, &resp->hdr), | |
936 (resp->hdr.op == DCC_OP_ERROR | |
937 ? (recv_len - (ISZ(resp->error) | |
938 - ISZ(resp->error.msg))) | |
939 : 0), | |
940 resp->error.msg); | |
941 return 0; | |
942 } | |
943 | |
944 if (recv_len != sizeof(DCC_GREY_ANSWER)) { | |
945 dcc_pemsg(EX_UNAVAILABLE, emsg, | |
946 "greylist server %s answered with %d instead of" | |
947 " %d bytes", | |
948 dcc_srvr_nm(1), recv_len, ISZ(DCC_GREY_ANSWER)); | |
949 return 0; | |
950 } | |
951 | |
952 return 1; | |
953 } | |
954 | |
955 | |
956 | |
957 ASK_GREY_RESULT | |
958 ask_grey(DCC_EMSG emsg, | |
959 DCC_CLNT_CTXT *ctxt, | |
960 DCC_OPS op, /* DCC_OP_GREY_{REPORT,QUERY,WHITE} */ | |
961 DCC_SUM msg_sum, /* put msg+sender+target cksum here */ | |
962 DCC_SUM triple_sum, /* put greylist triple checksum here */ | |
963 const DCC_GOT_CKS *cks, | |
964 const DCC_SUM env_to_sum, | |
965 DCC_TGTS *pembargo_num, | |
966 DCC_TGTS *pearly_tgts, /* ++ report to DCC even if embargoed */ | |
967 DCC_TGTS *plate_tgts) /* ++ don't report to DCC */ | |
968 { | |
969 MD5_CTX ctx; | |
970 DCC_REPORT rpt; | |
971 DCC_OP_RESP resp; | |
972 DCC_CK *ck; | |
973 DCC_CK_TYPES type; | |
974 const DCC_GOT_SUM *g; | |
975 DCC_TGTS result_tgts; | |
976 int num_cks; | |
977 | |
978 if (cks->sums[DCC_CK_IP].type != DCC_CK_IP) { | |
979 dcc_pemsg(EX_UNAVAILABLE, emsg, | |
980 "IP address not available for greylisting"); | |
981 memset(triple_sum, 0, sizeof(*triple_sum)); | |
982 memset(msg_sum, 0, sizeof(*msg_sum)); | |
983 return ASK_GREY_FAIL; | |
984 } | |
985 if (cks->sums[DCC_CK_ENV_FROM].type != DCC_CK_ENV_FROM) { | |
986 dcc_pemsg(EX_UNAVAILABLE, emsg, | |
987 "env_From not available for greylisting"); | |
988 memset(triple_sum, 0, sizeof(*triple_sum)); | |
989 memset(msg_sum, 0, sizeof(*msg_sum)); | |
990 return ASK_GREY_FAIL; | |
991 } | |
992 | |
993 /* Check the common checksums for whitelisting at the greylist server. | |
994 * This assumes DCC_CK_GREY_TRIPLE > DCC_CK_GREY_MSG > other types */ | |
995 ck = rpt.cks; | |
996 num_cks = 0; | |
997 for (type = 0, g = cks->sums; | |
998 type <= DCC_CK_TYPE_LAST; | |
999 ++type, ++g) { | |
1000 /* greylisting needs a body checksum, even if | |
1001 * it is the fake checksum for a missing body */ | |
1002 if (!g->rpt2srvr && type != DCC_CK_BODY) | |
1003 continue; | |
1004 ck->type = type; | |
1005 ck->len = sizeof(*ck); | |
1006 memcpy(ck->sum, g->sum, sizeof(ck->sum)); | |
1007 ++ck; | |
1008 ++num_cks; | |
1009 } | |
1010 | |
1011 /* include in the request the grey message checksum as the checksum | |
1012 * of the body, the env_From sender, and env_To target checksums */ | |
1013 MD5Init(&ctx); | |
1014 MD5Update(&ctx, cks->sums[DCC_CK_BODY].sum, sizeof(DCC_SUM)); | |
1015 MD5Update(&ctx, cks->sums[DCC_CK_ENV_FROM].sum, sizeof(DCC_SUM)); | |
1016 MD5Update(&ctx, env_to_sum, sizeof(DCC_SUM)); | |
1017 MD5Final(msg_sum, &ctx); | |
1018 ck->type = DCC_CK_GREY_MSG; | |
1019 ck->len = sizeof(*ck); | |
1020 memcpy(ck->sum, msg_sum, sizeof(ck->sum)); | |
1021 ++ck; | |
1022 ++num_cks; | |
1023 | |
1024 /* include the triple checksum of the sender, the sender's IP | |
1025 * address, and the target */ | |
1026 MD5Init(&ctx); | |
1027 if (trim_grey_ip_addr) { | |
1028 struct in6_addr addr; | |
1029 DCC_SUM sum; | |
1030 int wno; | |
1031 | |
1032 for (wno = 0; wno < 4; ++wno) { | |
1033 addr.s6_addr32[wno] = (cks->ip_addr.s6_addr32[wno] | |
1034 & grey_ip_mask.s6_addr32[wno]); | |
1035 } | |
1036 dcc_ck_ipv6(sum, &addr); | |
1037 MD5Update(&ctx, sum, sizeof(DCC_SUM)); | |
1038 } else { | |
1039 MD5Update(&ctx, cks->sums[DCC_CK_IP].sum, sizeof(DCC_SUM)); | |
1040 } | |
1041 MD5Update(&ctx, cks->sums[DCC_CK_ENV_FROM].sum, sizeof(DCC_SUM)); | |
1042 MD5Update(&ctx, env_to_sum, sizeof(DCC_SUM)); | |
1043 MD5Final(triple_sum, &ctx); | |
1044 ck->type = DCC_CK_GREY3; | |
1045 ck->len = sizeof(*ck); | |
1046 memcpy(ck->sum, triple_sum, sizeof(ck->sum)); | |
1047 ++num_cks; | |
1048 | |
1049 if (!dcc_clnt_op(emsg, ctxt, DCC_CLNT_FG_GREY, 0, 0, 0, | |
1050 &rpt.hdr, (sizeof(rpt) - sizeof(rpt.cks) | |
1051 + num_cks*sizeof(rpt.cks[0])), | |
1052 op, &resp, sizeof(resp))) { | |
1053 return ASK_GREY_FAIL; | |
1054 } | |
1055 | |
1056 if (!dcc_ck_grey_answer(emsg, &resp)) | |
1057 return ASK_GREY_FAIL; | |
1058 | |
1059 /* see what the greylist server had to say */ | |
1060 result_tgts = ntohl(resp.gans.triple); | |
1061 switch (result_tgts) { | |
1062 case DCC_TGTS_OK: /* embargo ended just now */ | |
1063 /* if we have previously included this target in a count of | |
1064 * targets sent to the DCC, then do not include it now */ | |
1065 if (resp.gans.msg != 0 && plate_tgts) | |
1066 ++*plate_tgts; | |
1067 if (pembargo_num) | |
1068 *pembargo_num = 0; | |
1069 return ASK_GREY_EMBARGO_END; | |
1070 | |
1071 case DCC_TGTS_TOO_MANY: /* no current embargo */ | |
1072 if (pembargo_num) | |
1073 *pembargo_num = 0; | |
1074 return ((resp.gans.msg != 0) | |
1075 ? ASK_GREY_EMBARGO_END | |
1076 : ASK_GREY_PASS); | |
1077 | |
1078 case DCC_TGTS_GREY_WHITE: /* whitelisted for greylisting */ | |
1079 if (pembargo_num) | |
1080 *pembargo_num = 0; | |
1081 return ASK_GREY_WHITE; | |
1082 | |
1083 default: /* embargoed */ | |
1084 /* if this is a brand new embargo, | |
1085 * then count this target in the DCC report */ | |
1086 if (resp.gans.msg == 0 && pearly_tgts) | |
1087 ++*pearly_tgts; | |
1088 if (pembargo_num) | |
1089 *pembargo_num = result_tgts+1; | |
1090 return ASK_GREY_EMBARGO; | |
1091 } | |
1092 } |