Mercurial > notdcc
comparison dccsight/dccsight.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 server | |
2 * | |
3 * report the previously computed checksums of a message | |
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.70 $Revision$ | |
40 */ | |
41 | |
42 #include "dcc_ck.h" | |
43 #include "dcc_xhdr.h" | |
44 | |
45 | |
46 static DCC_EMSG dcc_emsg; | |
47 | |
48 static const char *homedir; | |
49 static const char *mapfile_nm = DCC_MAP_NM_DEF; | |
50 | |
51 static char *local_tgts_str; | |
52 static DCC_TGTS local_tgts = 1; | |
53 static u_char local_tgts_spam, local_tgts_set; | |
54 | |
55 static const char* white_nm; | |
56 static const char *ifile_nm; | |
57 static FILE *ifile; | |
58 static const char *grey_sum; | |
59 | |
60 static DCC_CLNT_CTXT *ctxt; | |
61 static u_char print_cksums; | |
62 | |
63 static ASK_ST ask_st; | |
64 static FLTR_SWS rcpt_sws; | |
65 | |
66 static DCC_GOT_CKS cks; | |
67 static DCC_CKS_WTGTS wtgts; | |
68 static u_char have_sum; | |
69 | |
70 static DCC_HEADER_BUF header; | |
71 | |
72 /* kludges to avoid linking with dnsbl.c */ | |
73 DNSBL *dnsbls; | |
74 u_char have_dnsbl_groups; | |
75 | |
76 static void do_grey(void); | |
77 static int add_cksum(DCC_EMSG, DCC_WF *, DCC_CK_TYPES, DCC_SUM, DCC_TGTS); | |
78 static void print_ck(void *arg, const char *, u_int); | |
79 | |
80 | |
81 static void NRATTRIB | |
82 usage(void) | |
83 { | |
84 dcc_logbad(EX_USAGE, | |
85 "usage: [-VdCQ] [-h homedir] [-m map] [-w whiteclnt]" | |
86 " [-t targets]\n" | |
87 " [-c type,[log-thold,][spam-thold]] [-g [not-]type]\n" | |
88 " [-i infile] [-G grey-cksum] [-L ltype,facility.level]"); | |
89 } | |
90 | |
91 | |
92 | |
93 int NRATTRIB | |
94 main(int argc, char **argv) | |
95 { | |
96 char buf[200]; | |
97 const char *bufp; | |
98 char type_str[DCC_XHDR_MAX_TYPE_LEN+1]; | |
99 DCC_CK_TYPES type; | |
100 u_long l; | |
101 u_char skip_heading, result; | |
102 char c1, c2, *p; | |
103 int i; | |
104 | |
105 dcc_syslog_init(0, argv[0], 0); | |
106 dcc_clear_tholds(); | |
107 | |
108 /* we must be SUID to read and write the system's common connection | |
109 * parameter memory mapped file. We also need to read the common | |
110 * local white list and write the mmap()'ed hash file */ | |
111 dcc_init_priv(); | |
112 | |
113 ifile = stdin; | |
114 while ((i = getopt(argc, argv, "VdCQh:m:w:t:c:g:i:G:L:")) != -1) { | |
115 switch (i) { | |
116 case 'V': | |
117 fprintf(stderr, DCC_VERSION"\n"); | |
118 exit(EX_OK); | |
119 break; | |
120 | |
121 case 'd': | |
122 ++dcc_clnt_debug; | |
123 break; | |
124 | |
125 case 'Q': | |
126 ask_st |= ASK_ST_QUERY; | |
127 break; | |
128 | |
129 case 'C': | |
130 print_cksums = 1; | |
131 break; | |
132 | |
133 case 'h': | |
134 homedir = optarg; | |
135 break; | |
136 | |
137 case 'm': | |
138 mapfile_nm = optarg; | |
139 break; | |
140 | |
141 case 'w': | |
142 white_nm = optarg; | |
143 break; | |
144 | |
145 case 't': | |
146 local_tgts_str = optarg; | |
147 if (!strcasecmp(optarg, "many")) { | |
148 local_tgts_spam = 1; | |
149 local_tgts = 1; | |
150 local_tgts_set = 1; | |
151 } else { | |
152 l = strtoul(optarg, &p, 10); | |
153 if (*p != '\0' || l > 1000) | |
154 dcc_error_msg("invalid count \"%s\"", | |
155 optarg); | |
156 else | |
157 local_tgts = l; | |
158 local_tgts_spam = 0; | |
159 local_tgts_set = 1; | |
160 } | |
161 break; | |
162 | |
163 case 'c': | |
164 dcc_parse_tholds("-c ", optarg); | |
165 break; | |
166 | |
167 case 'g': /* honor not-spam "counts" */ | |
168 dcc_parse_honor(optarg); | |
169 break; | |
170 | |
171 case 'i': | |
172 /* open the input file now, before changing to the | |
173 * home DCC directory */ | |
174 ifile_nm = optarg; | |
175 ifile = fopen(ifile_nm, "r"); | |
176 if (!ifile) | |
177 dcc_logbad(EX_USAGE, | |
178 "bad input file \"%s\": %s", | |
179 ifile_nm, ERROR_STR()); | |
180 break; | |
181 | |
182 case 'G': | |
183 grey_sum = optarg; | |
184 break; | |
185 | |
186 case 'L': | |
187 dcc_parse_log_opt(optarg); | |
188 break; | |
189 | |
190 default: | |
191 usage(); | |
192 } | |
193 } | |
194 argc -= optind; | |
195 argv += optind; | |
196 if (argc != 0) | |
197 usage(); | |
198 | |
199 dcc_clnt_unthread_init(); | |
200 dcc_cdhome(0, homedir, 1); | |
201 | |
202 /* open /var/dcc/map and start a connection to a DCC server */ | |
203 ctxt = dcc_clnt_init(dcc_emsg, 0, mapfile_nm, DCC_CLNT_FG_NONE); | |
204 if (!ctxt) | |
205 dcc_logbad(dcc_ex_code, "%s", dcc_emsg); | |
206 | |
207 if (grey_sum) { | |
208 if (ifile_nm) | |
209 dcc_logbad(EX_USAGE, "-i and -G incompatible"); | |
210 do_grey(); | |
211 exit(EX_OK); | |
212 } | |
213 | |
214 if (!ifile_nm) | |
215 ifile_nm = "stdin"; | |
216 | |
217 /* get the checksums */ | |
218 skip_heading = 0; | |
219 for (;;) { | |
220 bufp = fgets(buf, sizeof(buf), ifile); | |
221 if (!bufp) { | |
222 if (ferror(ifile)) | |
223 dcc_logbad(EX_DATAERR, "fgets(%s): %s", | |
224 ifile_nm, ERROR_STR()); | |
225 break; | |
226 } | |
227 | |
228 /* ignore blank lines */ | |
229 i = strlen(buf); | |
230 if (!i) { | |
231 skip_heading = 0; | |
232 continue; | |
233 } | |
234 | |
235 /* trim leading and trailing whitespace */ | |
236 p = &buf[i-1]; | |
237 bufp += strspn(bufp, DCC_WHITESPACE); | |
238 c2 = *p; /* should be '\n' */ | |
239 while (p > bufp) { | |
240 c1 = *(p-1); | |
241 if (c1 != '\r' && c1 != ' ' && c1 != '\t') | |
242 break; | |
243 *--p = c2; | |
244 } | |
245 if (*bufp == '\n' || *bufp == '\0') { | |
246 skip_heading = 0; | |
247 continue; | |
248 } | |
249 | |
250 /* ignore DCC header lines such as in the output | |
251 * of `dccproc -C` */ | |
252 if (skip_heading == 0 | |
253 && !CLITCMP(bufp, DCC_XHDR_START)) { | |
254 skip_heading = 1; | |
255 continue; | |
256 } | |
257 /* skip headings for the checksums */ | |
258 if (skip_heading <= 1 | |
259 && !CLITCMP(bufp, DCC_XHDR_REPORTED)) { | |
260 skip_heading = 2; | |
261 continue; | |
262 } | |
263 | |
264 /* handle the next checksum */ | |
265 bufp = dcc_parse_word(dcc_emsg, type_str, sizeof(type_str), | |
266 bufp, "checksum type", 0, 0); | |
267 if (!bufp) | |
268 dcc_logbad(dcc_ex_code, "%s", dcc_emsg); | |
269 type = dcc_str2type_wf(type_str, -1); | |
270 if (type != DCC_CK_ENV_TO | |
271 && 0 >= dcc_parse_hex_ck(dcc_emsg, &cmn_wf, | |
272 type_str, type, | |
273 bufp, 1, add_cksum)) | |
274 dcc_logbad(dcc_ex_code, "%s", dcc_emsg); | |
275 } | |
276 fclose(ifile); | |
277 | |
278 if (!have_sum) | |
279 dcc_logbad(EX_DATAERR, "no reportable checksums"); | |
280 | |
281 dcc_wf_init(&cmn_wf, 0); | |
282 if (!unthr_ask_white(dcc_emsg, &ask_st, &rcpt_sws, | |
283 white_nm, &cks, wtgts)) | |
284 dcc_error_msg("%s", dcc_emsg); | |
285 | |
286 if (!local_tgts_set) { | |
287 local_tgts = (ask_st & ASK_ST_QUERY) ? 0 : 1; | |
288 local_tgts_spam = 0; | |
289 } else if (local_tgts == 0) { | |
290 ask_st |= ASK_ST_QUERY; | |
291 local_tgts_spam = 0; | |
292 } else if (ask_st & ASK_ST_QUERY) { | |
293 dcc_error_msg("\"-t %s\" is incompatible with \"-Q\"", | |
294 local_tgts_str); | |
295 local_tgts = 0; | |
296 local_tgts_spam = 0; | |
297 } | |
298 if (local_tgts == DCC_TGTS_TOO_MANY) { | |
299 local_tgts = 1; | |
300 local_tgts_spam = 1; | |
301 } | |
302 if (local_tgts != 0 | |
303 && (ask_st & ASK_ST_CLNT_ISSPAM)) | |
304 local_tgts_spam = 1; | |
305 | |
306 result = unthr_ask_dcc(dcc_emsg, ctxt, &header, &ask_st, | |
307 &cks, local_tgts_spam, local_tgts); | |
308 if (!result) { | |
309 dcc_error_msg("%s", dcc_emsg); | |
310 } else if (header.buf[0] != '\0') { | |
311 printf("%s", header.buf); | |
312 } else if (dcc_clnt_debug) { | |
313 if (ask_st & ASK_ST_WLIST_NOTSPAM) | |
314 printf("no header; checksums are locally whitelisted"); | |
315 else | |
316 printf("no header"); | |
317 } | |
318 | |
319 if (print_cksums) | |
320 dcc_print_cks(print_ck, 0, local_tgts_spam, local_tgts, | |
321 &cks, wtgts, 0); | |
322 | |
323 exit(EX_OK); | |
324 } | |
325 | |
326 | |
327 | |
328 static void NRATTRIB | |
329 do_grey(void) | |
330 { | |
331 union { | |
332 u_int32_t n[4]; | |
333 DCC_SUM sum; | |
334 } u; | |
335 DCC_REPORT rpt; | |
336 DCC_OP_RESP resp; | |
337 | |
338 if (4 != sscanf(grey_sum, DCC_CKSUM_HEX_PAT, | |
339 &u.n[0], &u.n[1], &u.n[2], &u.n[3])) | |
340 dcc_logbad(EX_USAGE, | |
341 "unrecognized greylist checksum"); | |
342 u.n[0] = htonl(u.n[0]); | |
343 u.n[1] = htonl(u.n[1]); | |
344 u.n[2] = htonl(u.n[2]); | |
345 u.n[3] = htonl(u.n[3]); | |
346 | |
347 memset(&rpt, 0, sizeof(rpt)); | |
348 memcpy(rpt.cks[0].sum, u.sum, sizeof(rpt.cks[0].sum)); | |
349 rpt.cks[0].type = DCC_CK_GREY3; | |
350 rpt.cks[0].len = sizeof(rpt.cks[0]); | |
351 if (!dcc_clnt_op(dcc_emsg, ctxt, DCC_CLNT_FG_GREY, 0, 0, 0, | |
352 &rpt.hdr, (sizeof(rpt) - sizeof(rpt.cks) | |
353 + sizeof(rpt.cks[0])), | |
354 (ask_st & ASK_ST_QUERY) | |
355 ? DCC_OP_GREY_QUERY : DCC_OP_GREY_WHITE, | |
356 &resp, sizeof(resp))) | |
357 dcc_logbad(dcc_ex_code, "%s", dcc_emsg); | |
358 | |
359 if (!dcc_ck_grey_answer(dcc_emsg, &resp)) | |
360 dcc_logbad(dcc_ex_code, "%s", dcc_emsg); | |
361 | |
362 switch (ntohl(resp.gans.triple)) { | |
363 case DCC_TGTS_OK: /* embargo ended just now */ | |
364 printf(DCC_XHDR_EMBARGO_ENDED"\n"); | |
365 break; | |
366 case DCC_TGTS_TOO_MANY: /* no current embargo */ | |
367 printf(DCC_XHDR_EMBARGO_PASS"\n"); | |
368 break; | |
369 case DCC_TGTS_GREY_WHITE: /* whitelisted for greylisting */ | |
370 printf(DCC_XHDR_EMBARGO_OK"\n"); | |
371 break; | |
372 default: /* embargoed */ | |
373 printf(DCC_XHDR_EMBARGO"\n"); | |
374 break; | |
375 } | |
376 exit(EX_OK); | |
377 } | |
378 | |
379 | |
380 | |
381 static int | |
382 add_cksum(DCC_EMSG emsg, DCC_WF *wf UATTRIB, | |
383 DCC_CK_TYPES type, DCC_SUM sum, DCC_TGTS tgts) | |
384 { | |
385 static DCC_SUM zero; | |
386 | |
387 if (cks.sums[type].type != DCC_CK_INVALID | |
388 && type != DCC_CK_SUB) { | |
389 dcc_pemsg(EX_DATAERR, emsg, "duplicate %s checksum", | |
390 dcc_type2str_err(type, 0, 0, 0)); | |
391 } | |
392 | |
393 /* envelope Rcpt_To values are never sent to the server */ | |
394 if (type == DCC_CK_ENV_TO) | |
395 return 1; | |
396 | |
397 /* do not send FUZ2 missing checksum */ | |
398 if (type == DCC_CK_FUZ2 | |
399 && !memcmp(sum, zero, sizeof(DCC_SUM))) | |
400 return 1; | |
401 | |
402 memcpy(cks.sums[type].sum, sum, sizeof(cks.sums[type].sum)); | |
403 cks.sums[type].type = type; | |
404 cks.sums[type].rpt2srvr = 1; | |
405 cks.sums[type].tgts = DCC_TGTS_INVALID; | |
406 if (tgts) | |
407 have_sum = 1; | |
408 return 1; | |
409 } | |
410 | |
411 | |
412 | |
413 static void | |
414 print_ck(void *arg UATTRIB, const char *buf, u_int buf_len) | |
415 { | |
416 fwrite(buf, buf_len, 1, stdout); | |
417 } |