Mercurial > notdcc
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); +}