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 }