diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dccsight/dccsight.c	Tue Mar 10 13:49:58 2009 +0100
@@ -0,0 +1,417 @@
+/* Distributed Checksum Clearinghouse server
+ *
+ * report the previously computed checksums of a message
+ *
+ * Copyright (c) 2008 by Rhyolite Software, LLC
+ *
+ * This agreement is not applicable to any entity which sells anti-spam
+ * solutions to others or provides an anti-spam solution as part of a
+ * security solution sold to other entities, or to a private network
+ * which employs the DCC or uses data provided by operation of the DCC
+ * but does not provide corresponding data to other users.
+ *
+ * Permission to use, copy, modify, and distribute this software without
+ * changes for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear in all
+ * copies and any distributed versions or copies are either unchanged
+ * or not called anything similar to "DCC" or "Distributed Checksum
+ * Clearinghouse".
+ *
+ * Parties not eligible to receive a license under this agreement can
+ * obtain a commercial license to use DCC by contacting Rhyolite Software
+ * at sales@rhyolite.com.
+ *
+ * A commercial license would be for Distributed Checksum and Reputation
+ * Clearinghouse software.  That software includes additional features.  This
+ * free license for Distributed ChecksumClearinghouse Software does not in any
+ * way grant permision to use Distributed Checksum and Reputation Clearinghouse
+ * software
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
+ * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Rhyolite Software DCC 1.3.103-1.70 $Revision$
+ */
+
+#include "dcc_ck.h"
+#include "dcc_xhdr.h"
+
+
+static DCC_EMSG dcc_emsg;
+
+static const char *homedir;
+static const char *mapfile_nm = DCC_MAP_NM_DEF;
+
+static char *local_tgts_str;
+static DCC_TGTS local_tgts = 1;
+static u_char local_tgts_spam, local_tgts_set;
+
+static const char* white_nm;
+static const char *ifile_nm;
+static FILE *ifile;
+static const char *grey_sum;
+
+static DCC_CLNT_CTXT *ctxt;
+static u_char print_cksums;
+
+static ASK_ST ask_st;
+static FLTR_SWS rcpt_sws;
+
+static DCC_GOT_CKS cks;
+static DCC_CKS_WTGTS wtgts;
+static u_char have_sum;
+
+static DCC_HEADER_BUF header;
+
+/* kludges to avoid linking with dnsbl.c */
+DNSBL *dnsbls;
+u_char have_dnsbl_groups;
+
+static void do_grey(void);
+static int add_cksum(DCC_EMSG, DCC_WF *, DCC_CK_TYPES, DCC_SUM, DCC_TGTS);
+static void print_ck(void *arg, const char *, u_int);
+
+
+static void NRATTRIB
+usage(void)
+{
+	dcc_logbad(EX_USAGE,
+		   "usage: [-VdCQ] [-h homedir] [-m map] [-w whiteclnt]"
+		   " [-t targets]\n"
+		   "   [-c type,[log-thold,][spam-thold]] [-g [not-]type]\n"
+		   "   [-i infile] [-G grey-cksum] [-L ltype,facility.level]");
+}
+
+
+
+int NRATTRIB
+main(int argc, char **argv)
+{
+	char buf[200];
+	const char *bufp;
+	char type_str[DCC_XHDR_MAX_TYPE_LEN+1];
+	DCC_CK_TYPES type;
+	u_long l;
+	u_char skip_heading, result;
+	char c1, c2, *p;
+	int i;
+
+	dcc_syslog_init(0, argv[0], 0);
+	dcc_clear_tholds();
+
+	/* we must be SUID to read and write the system's common connection
+	 * parameter memory mapped file.  We also need to read the common
+	 * local white list and write the mmap()'ed hash file */
+	dcc_init_priv();
+
+	ifile = stdin;
+	while ((i = getopt(argc, argv, "VdCQh:m:w:t:c:g:i:G:L:")) != -1) {
+		switch (i) {
+		case 'V':
+			fprintf(stderr, DCC_VERSION"\n");
+			exit(EX_OK);
+			break;
+
+		case 'd':
+			++dcc_clnt_debug;
+			break;
+
+		case 'Q':
+			ask_st |= ASK_ST_QUERY;
+			break;
+
+		case 'C':
+			print_cksums = 1;
+			break;
+
+		case 'h':
+			homedir = optarg;
+			break;
+
+		case 'm':
+			mapfile_nm = optarg;
+			break;
+
+		case 'w':
+			white_nm = optarg;
+			break;
+
+		case 't':
+			local_tgts_str = optarg;
+			if (!strcasecmp(optarg, "many")) {
+				local_tgts_spam = 1;
+				local_tgts = 1;
+				local_tgts_set = 1;
+			} else {
+				l = strtoul(optarg, &p, 10);
+				if (*p != '\0' || l > 1000)
+					dcc_error_msg("invalid count \"%s\"",
+						      optarg);
+				else
+					local_tgts = l;
+					local_tgts_spam = 0;
+					local_tgts_set = 1;
+			}
+			break;
+
+		case 'c':
+			dcc_parse_tholds("-c ", optarg);
+			break;
+
+		case 'g':		/* honor not-spam "counts" */
+			dcc_parse_honor(optarg);
+			break;
+
+		case 'i':
+			/* open the input file now, before changing to the
+			 * home DCC directory */
+			ifile_nm = optarg;
+			ifile = fopen(ifile_nm, "r");
+			if (!ifile)
+				dcc_logbad(EX_USAGE,
+					   "bad input file \"%s\": %s",
+					   ifile_nm, ERROR_STR());
+			break;
+
+		case 'G':
+			grey_sum = optarg;
+			break;
+
+		case 'L':
+			dcc_parse_log_opt(optarg);
+			break;
+
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	if (argc != 0)
+		usage();
+
+	dcc_clnt_unthread_init();
+	dcc_cdhome(0, homedir, 1);
+
+	/* open /var/dcc/map and start a connection to a DCC server */
+	ctxt = dcc_clnt_init(dcc_emsg, 0, mapfile_nm, DCC_CLNT_FG_NONE);
+	if (!ctxt)
+		dcc_logbad(dcc_ex_code, "%s", dcc_emsg);
+
+	if (grey_sum) {
+		if (ifile_nm)
+			dcc_logbad(EX_USAGE, "-i and -G incompatible");
+		do_grey();
+		exit(EX_OK);
+	}
+
+	if (!ifile_nm)
+		ifile_nm = "stdin";
+
+	/* get the checksums */
+	skip_heading = 0;
+	for (;;) {
+		bufp = fgets(buf, sizeof(buf), ifile);
+		if (!bufp) {
+			if (ferror(ifile))
+				dcc_logbad(EX_DATAERR, "fgets(%s): %s",
+					   ifile_nm, ERROR_STR());
+			break;
+		}
+
+		/* ignore blank lines */
+		i = strlen(buf);
+		if (!i) {
+			skip_heading = 0;
+			continue;
+		}
+
+		/* trim leading and trailing whitespace */
+		p = &buf[i-1];
+		bufp += strspn(bufp, DCC_WHITESPACE);
+		c2 = *p;		/* should be '\n' */
+		while (p > bufp) {
+			c1 = *(p-1);
+			if (c1 != '\r' && c1 != ' ' && c1 != '\t')
+				break;
+			*--p = c2;
+		}
+		if (*bufp == '\n' || *bufp == '\0') {
+			skip_heading = 0;
+			continue;
+		}
+
+		/* ignore DCC header lines such as in the output
+		 * of `dccproc -C` */
+		if (skip_heading == 0
+		    && !CLITCMP(bufp, DCC_XHDR_START)) {
+			skip_heading = 1;
+			continue;
+		}
+		/* skip headings for the checksums */
+		if (skip_heading <= 1
+		    && !CLITCMP(bufp, DCC_XHDR_REPORTED)) {
+			skip_heading = 2;
+			continue;
+		}
+
+		/* handle the next checksum */
+		bufp = dcc_parse_word(dcc_emsg, type_str, sizeof(type_str),
+				      bufp, "checksum type", 0, 0);
+		if (!bufp)
+			dcc_logbad(dcc_ex_code, "%s", dcc_emsg);
+		type = dcc_str2type_wf(type_str, -1);
+		if (type != DCC_CK_ENV_TO
+		    && 0 >= dcc_parse_hex_ck(dcc_emsg, &cmn_wf,
+					     type_str, type,
+					     bufp, 1, add_cksum))
+			dcc_logbad(dcc_ex_code, "%s", dcc_emsg);
+	}
+	fclose(ifile);
+
+	if (!have_sum)
+		dcc_logbad(EX_DATAERR, "no reportable checksums");
+
+	dcc_wf_init(&cmn_wf, 0);
+	if (!unthr_ask_white(dcc_emsg, &ask_st, &rcpt_sws,
+			     white_nm, &cks, wtgts))
+		dcc_error_msg("%s", dcc_emsg);
+
+	if (!local_tgts_set) {
+		local_tgts = (ask_st & ASK_ST_QUERY) ? 0 : 1;
+		local_tgts_spam = 0;
+	} else if (local_tgts == 0) {
+		ask_st |= ASK_ST_QUERY;
+		local_tgts_spam = 0;
+	} else if (ask_st & ASK_ST_QUERY) {
+		dcc_error_msg("\"-t %s\" is incompatible with \"-Q\"",
+			      local_tgts_str);
+		local_tgts = 0;
+		local_tgts_spam = 0;
+	}
+	if (local_tgts == DCC_TGTS_TOO_MANY) {
+		local_tgts = 1;
+		local_tgts_spam = 1;
+	}
+	if (local_tgts != 0
+	    && (ask_st & ASK_ST_CLNT_ISSPAM))
+		local_tgts_spam = 1;
+
+	result = unthr_ask_dcc(dcc_emsg, ctxt, &header, &ask_st,
+			       &cks, local_tgts_spam, local_tgts);
+	if (!result) {
+		dcc_error_msg("%s", dcc_emsg);
+	} else if (header.buf[0] != '\0') {
+		printf("%s", header.buf);
+	} else if (dcc_clnt_debug) {
+		if (ask_st & ASK_ST_WLIST_NOTSPAM)
+			printf("no header; checksums are locally whitelisted");
+		else
+			printf("no header");
+	}
+
+	if (print_cksums)
+		dcc_print_cks(print_ck, 0, local_tgts_spam, local_tgts,
+			      &cks, wtgts, 0);
+
+	exit(EX_OK);
+}
+
+
+
+static void NRATTRIB
+do_grey(void)
+{
+	union {
+	    u_int32_t n[4];
+	    DCC_SUM sum;
+	} u;
+	DCC_REPORT rpt;
+	DCC_OP_RESP resp;
+
+	if (4 != sscanf(grey_sum, DCC_CKSUM_HEX_PAT,
+			&u.n[0], &u.n[1], &u.n[2], &u.n[3]))
+		dcc_logbad(EX_USAGE,
+			   "unrecognized greylist checksum");
+	u.n[0] = htonl(u.n[0]);
+	u.n[1] = htonl(u.n[1]);
+	u.n[2] = htonl(u.n[2]);
+	u.n[3] = htonl(u.n[3]);
+
+	memset(&rpt, 0, sizeof(rpt));
+	memcpy(rpt.cks[0].sum, u.sum, sizeof(rpt.cks[0].sum));
+	rpt.cks[0].type = DCC_CK_GREY3;
+	rpt.cks[0].len = sizeof(rpt.cks[0]);
+	if (!dcc_clnt_op(dcc_emsg, ctxt, DCC_CLNT_FG_GREY, 0, 0, 0,
+			 &rpt.hdr, (sizeof(rpt) - sizeof(rpt.cks)
+				    + sizeof(rpt.cks[0])),
+			 (ask_st & ASK_ST_QUERY)
+			 ? DCC_OP_GREY_QUERY : DCC_OP_GREY_WHITE,
+			 &resp, sizeof(resp)))
+		dcc_logbad(dcc_ex_code, "%s", dcc_emsg);
+
+	if (!dcc_ck_grey_answer(dcc_emsg, &resp))
+		dcc_logbad(dcc_ex_code, "%s", dcc_emsg);
+
+	switch (ntohl(resp.gans.triple)) {
+	case DCC_TGTS_OK:		/* embargo ended just now */
+		printf(DCC_XHDR_EMBARGO_ENDED"\n");
+		break;
+	case DCC_TGTS_TOO_MANY:		/* no current embargo */
+		printf(DCC_XHDR_EMBARGO_PASS"\n");
+		break;
+	case DCC_TGTS_GREY_WHITE:	/* whitelisted for greylisting */
+		printf(DCC_XHDR_EMBARGO_OK"\n");
+		break;
+	default:			/* embargoed */
+		printf(DCC_XHDR_EMBARGO"\n");
+		break;
+	}
+	exit(EX_OK);
+}
+
+
+
+static int
+add_cksum(DCC_EMSG emsg, DCC_WF *wf UATTRIB,
+	  DCC_CK_TYPES type, DCC_SUM sum, DCC_TGTS tgts)
+{
+	static DCC_SUM zero;
+
+	if (cks.sums[type].type != DCC_CK_INVALID
+	    && type != DCC_CK_SUB) {
+		dcc_pemsg(EX_DATAERR, emsg, "duplicate %s checksum",
+			  dcc_type2str_err(type, 0, 0, 0));
+	}
+
+	/* envelope Rcpt_To values are never sent to the server */
+	if (type == DCC_CK_ENV_TO)
+		return 1;
+
+	/* do not send FUZ2 missing checksum */
+	if (type == DCC_CK_FUZ2
+	    && !memcmp(sum, zero, sizeof(DCC_SUM)))
+		return 1;
+
+	memcpy(cks.sums[type].sum, sum, sizeof(cks.sums[type].sum));
+	cks.sums[type].type = type;
+	cks.sums[type].rpt2srvr = 1;
+	cks.sums[type].tgts = DCC_TGTS_INVALID;
+	if (tgts)
+		have_sum = 1;
+	return 1;
+}
+
+
+
+static void
+print_ck(void *arg UATTRIB, const char *buf, u_int buf_len)
+{
+	fwrite(buf, buf_len, 1, stdout);
+}