diff options
author | gilles <gilles@poolp.org> | 2016-07-06 17:19:20 +0200 |
---|---|---|
committer | gilles <gilles@poolp.org> | 2016-07-06 17:19:20 +0200 |
commit | da8bc3dc23bc6350ee05ef7744c4c42386aab836 (patch) | |
tree | d245f1084fbe74a78fd043699cedf28e9188338d | |
parent | disable entering sub directories for experimental filters (diff) | |
download | OpenSMTPD-extras-da8bc3dc23bc6350ee05ef7744c4c42386aab836.tar.xz OpenSMTPD-extras-da8bc3dc23bc6350ee05ef7744c4c42386aab836.zip |
remove all experimental filters from -extras
33 files changed, 0 insertions, 5858 deletions
diff --git a/extras/filters/filter-clamav/Makefile.am b/extras/filters/filter-clamav/Makefile.am deleted file mode 100644 index 4d05005..0000000 --- a/extras/filters/filter-clamav/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-clamav - -filter_clamav_SOURCES = $(SRCS) -filter_clamav_SOURCES += filter_clamav.c - -man_MANS = filter-clamav.8 diff --git a/extras/filters/filter-clamav/filter-clamav.8 b/extras/filters/filter-clamav/filter-clamav.8 deleted file mode 100644 index aae4abd..0000000 --- a/extras/filters/filter-clamav/filter-clamav.8 +++ /dev/null @@ -1,95 +0,0 @@ -.\" -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 16 2016 $ -.Dt FILTER-CLAMAV 8 -.Os -.Sh NAME -.Nm filter-clamav -.Nd smtpd filter for Clam AntiVirus clamd -.Sh SYNOPSIS -.Nm -.Op Fl Cdv -.Op Fl c Ar path -.Op Fl h Ar host -.Op Fl p Ar port -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to filter mails based on the decision from Clam AntiVirus's -.Xr clamd 8 -daemon. -Mails are piped to the daemon, which scans the mail for viruses. -.Pp -The options are as follows: -.Bl -tag -width "-h host" -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl h Ar host -Set the ClamAV -.Ar host -to be used. -.Pp -The default -.Ar host -is 127.0.0.1. -.It Fl p Ar port -Set the -.Ar port -ClamAV is listening on. -.Pp -The default -.Ar port -is 3310. -.It Fl v -Produce more verbose output. -.El -.Pp -.Nm -runs by default in a chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -Mails which contain a virus are rejected with a SMTP 554 reply. -Non-virus mails are accepted. -.\"Accepted messages are marked with a -.\".Dq X-Filter-ClamAV -.\"header. -.Sh CLAM ANTIVIRUS CONFIGURATION -By default -.Nm -expects Clam AntiVirus' -.Xr clamd 8 -to listen on 127.0.0.1 port 3310 for incoming requests. -This requires to uncomment the TCPAddr and TCPSocket option in the default -configuration of the daemon. -.Sh SEE ALSO -.Xr filter_api 3 , -.Xr smtpd.conf 5 , -.Xr clamd 8 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Nm -was written in 2015. -.Sh AUTHORS -.An Joerg Jung Aq Mt jung@openbsd.org diff --git a/extras/filters/filter-clamav/filter_clamav.c b/extras/filters/filter-clamav/filter_clamav.c deleted file mode 100644 index 7f505d2..0000000 --- a/extras/filters/filter-clamav/filter_clamav.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include <sys/types.h> -#include <arpa/inet.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <limits.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#define CLAMAV_HOST "127.0.0.1" -#define CLAMAV_PORT "3310" - -struct clamav { - uint64_t id; - struct iobuf iobuf; - struct io io; - int r; - enum { CL_DATA, CL_EOM, CL_STA } s; -}; - -static struct sockaddr_storage clamav_ss; - -static void -clamav_clear(struct clamav *cl) -{ - if (cl == NULL) - return; - io_clear(&cl->io); - iobuf_clear(&cl->iobuf); - free(cl); -} - -static int -clamav_result(struct clamav *cl) -{ - if (cl->r == INT_MIN) { - log_warnx("warn: result: failed"); - return -1; - } - if (cl->r) { - log_warnx("warn: session %016"PRIx64": result: REJECT virus", cl->id); - return filter_api_reject_code(cl->id, FILTER_CLOSE, 554, "5.7.1 Virus found"); - } - return filter_api_accept(cl->id); -} - -#define CLAMAV_EXPAND(tok) #tok -#define CLAMAV_QUOTE(tok) CLAMAV_EXPAND(tok) - -static int -clamav_status(struct clamav *cl, const char *l) { - char s[BUFSIZ + 1]; - - if (sscanf(l, "stream: %"CLAMAV_QUOTE(BUFSIZ)"s", s) != 1) { - (errno ? log_warn : log_warnx)("warn: result: sscanf"); - return -1; - } - log_info("info: result: %s", l); - cl->r = (strcmp(s, "OK") != 0); - return 0; -} - -static int -clamav_response(struct clamav *cl, const char *l) -{ - switch (cl->s) { - case CL_STA: - if (clamav_status(cl, l) == -1) - return -1; - break; - default: - fatalx("response: bad state"); - } - return 0; -} - -static void -clamav_io(struct io *io, int evt) -{ - struct clamav *cl = io->arg; - char *l; - - switch (evt) { - case IO_CONNECTED: - io_set_write(io); - break; - case IO_LOWAT: - if (cl->s == CL_EOM) { - cl->s++; - io_set_read(io); - } - break; - case IO_DATAIN: - while ((l = iobuf_getline(&cl->iobuf, NULL))) { - if (iobuf_len(&cl->iobuf) >= LINE_MAX) { - log_warnx("warn: io: iobuf_getline"); - goto fail; - } - if (clamav_response(cl, l) == -1) - goto fail; - } - iobuf_normalize(&cl->iobuf); - break; - case IO_DISCONNECTED: - if (cl->s == CL_STA) { - if (iobuf_len(&cl->iobuf)) { - log_warnx("warn: io: incomplete"); - goto fail; - } - if (clamav_result(cl) == -1) - goto fail; - io_clear(io); - break; - } /* FALLTHROUGH */ - case IO_TIMEOUT: - case IO_ERROR: - log_warnx("warn: io: %s %s", io_strevent(evt), cl->io.error); - goto fail; - default: - fatalx("io: bad event"); - } - return; -fail: - if (cl->s > CL_DATA) - filter_api_reject_code(cl->id, FILTER_FAIL, 451, "4.7.1 Virus filter failed"); - filter_api_set_udata(cl->id, NULL); - clamav_clear(cl); -} - -static void -clamav_init(struct clamav *cl, uint64_t id) -{ - iobuf_xinit(&cl->iobuf, LINE_MAX, LINE_MAX, "init"); - io_init(&cl->io, -1, cl, clamav_io, &cl->iobuf); - cl->id = id; - cl->r = INT_MIN; -} - -static int -clamav_on_data(uint64_t id) -{ - struct clamav *cl; - - clamav_init((cl = xcalloc(1, sizeof(struct clamav), "on_data")), id); - if (io_connect(&cl->io, (struct sockaddr *)&clamav_ss, NULL) == -1) { - log_warnx("warn: on_data: io_connect %s", cl->io.error); - clamav_clear(cl); - return filter_api_accept(id); - } - iobuf_xfqueue(&cl->iobuf, "on_data", "nINSTREAM\n"); - filter_api_set_udata(id, cl); - return filter_api_accept(id); -} - -static void -clamav_on_dataline(uint64_t id, const char *l) -{ - struct clamav *cl; - uint32_t n = htonl(strlen(l) + 1); - - filter_api_writeln(id, l); - if ((cl = filter_api_get_udata(id)) == NULL) - return; - if (iobuf_queue(&cl->iobuf, &n, sizeof(uint32_t)) != (int)sizeof(uint32_t)) - fatalx("on_dataline: iobuf_queue"); - iobuf_xfqueue(&cl->iobuf, "on_dataline", "%s\n", l); - io_reload(&cl->io); -} - -static int -clamav_on_eom(uint64_t id, size_t size) -{ - struct clamav *cl; - uint32_t n = htonl(0); - - if ((cl = filter_api_get_udata(id)) == NULL) - return filter_api_accept(id); - if (iobuf_queue(&cl->iobuf, &n, sizeof(uint32_t)) != (int)sizeof(uint32_t)) - fatalx("on_eom: iobuf_queue"); - io_reload(&cl->io); - cl->s++; - return 1; /* defer accept or reject */ -} - -static void -clamav_on_tx_commit(uint64_t id) -{ - clamav_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -static void -clamav_on_tx_rollback(uint64_t id) -{ - clamav_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - - -static void -clamav_resolve(const char *h, const char *p) -{ - struct addrinfo hints, *addresses, *ai; - int fd, r; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - if ((r = getaddrinfo(h, p, &hints, &addresses))) - fatalx("resolve: getaddrinfo %s", gai_strerror(r)); - for (ai = addresses; ai; ai = ai->ai_next) { - if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) - continue; - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) { - close(fd); - continue; - } - write(fd, "nPING\n", 6); - close(fd); - memmove(&clamav_ss, ai->ai_addr, ai->ai_addrlen); - break; - } - freeaddrinfo(addresses); - if (!ai) - fatalx("resolve: failed"); -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - char *h = CLAMAV_HOST, *p = CLAMAV_PORT; - - log_init(1); - - while ((ch = getopt(argc, argv, "dh:p:v")) != -1) { - switch (ch) { - case 'd': - d = 1; - break; - case 'h': - h = optarg; - break; - case 'p': - p = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (h) - h = strip(h); - if (p) - p = strip(p); - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - clamav_resolve(h, p); - - filter_api_on_data(clamav_on_data); - filter_api_on_dataline(clamav_on_dataline); - filter_api_on_eom(clamav_on_eom); - filter_api_on_tx_commit(clamav_on_tx_commit); - filter_api_on_tx_rollback(clamav_on_tx_rollback); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-dkim-signer/Makefile.am b/extras/filters/filter-dkim-signer/Makefile.am deleted file mode 100644 index e24ba41..0000000 --- a/extras/filters/filter-dkim-signer/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk - -pkglibexec_PROGRAMS = filter-dkim-signer - -filter_dkim_signer_SOURCES = $(SRCS) -filter_dkim_signer_SOURCES += filter_dkim_signer.c - -man_MANS = filter-dkim-signer.8 diff --git a/extras/filters/filter-dkim-signer/filter-dkim-signer.8 b/extras/filters/filter-dkim-signer/filter-dkim-signer.8 deleted file mode 100644 index 5b7dc42..0000000 --- a/extras/filters/filter-dkim-signer/filter-dkim-signer.8 +++ /dev/null @@ -1,108 +0,0 @@ -.\" -.\" Copyright (c) 2015 Bernard Spil <brnrd@FreeBSD.org> -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 18 2016 $ -.Dt FILTER-DKIM-SIGNER 8 -.Os -.Sh NAME -.Nm filter-dkim-signer -.Nd smtpd filter to add DKIM signatures -.Sh SYNOPSIS -.Nm -.Op Fl Cdv -.Op Fl c Ar path -.Op Fl D Ar domain -.Op Fl p Ar private-key -.Op Fl s Ar selector -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to add rsa-sha256 DKIM signatures to -SMTP headers -.Pp -The options are as follows: -.Bl -tag -width "-p private-key" -.It Fl C -No -.Xr chroot 2 -mode, if this option is specified, -.Nm -will not run in a chroot. -.It Fl c Ar path -Set the chroot -.Ar path . -.Pp -The default -.Ar path -is -.Pa /var/empty -(compile option). -.It Fl D Ar domain -Set the DKIM -.Ar domain -to be added. -.Pp -The default -.Ar domain -is retrieved with gethostname(). -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl p Ar private-key -The file-name that contains the RSA -.Ar private-key -to be used for signing -.Pp -The default -.Ar private-key -is /etc/ssl/private/rsa.private -.It Fl s Ar selector -Set the DKIM -.Ar selector -.Pp -The default -.Ar selector -is "default" -.It Fl v -Produce more verbose output. -.El -.Pp -.Nm -runs by default in a chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -With -.Nm -enabled, an rsa-sha256 DKIM signature header is added to mails passing -through the filter. -.Sh SEE ALSO -.Xr chroot 2 , -.Xr filter_api 3 , -.Xr smtpd.conf 5 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Nm -was written in 2014. -.Sh AUTHORS -.An Sunil Nimmagadda diff --git a/extras/filters/filter-dkim-signer/filter_dkim_signer.c b/extras/filters/filter-dkim-signer/filter_dkim_signer.c deleted file mode 100644 index 2707ad4..0000000 --- a/extras/filters/filter-dkim-signer/filter_dkim_signer.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) 2014 Sunil Nimmagadda <sunil@nimmagadda.net> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include <sys/types.h> -#include <sys/queue.h> - -#include <inttypes.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include <openssl/pem.h> -#include <openssl/rand.h> -#include <openssl/rsa.h> -#include <openssl/sha.h> - -#include <smtpd-api.h> - -#define DKIM_SIGNER_CRLF "\r\n" -#define DKIM_SIGNER_CRLF_LEN 2 -#define DKIM_SIGNER_PRIVATE_KEY "/etc/ssl/private/rsa.private" -#define DKIM_SIGNER_TEMPLATE "DKIM-Signature: v=1; a=rsa-sha256; " \ - "c=simple/simple; d=%s; " \ - "h=%s; " \ - "s=%s; " \ - "bh=%s; " \ - "b=" - -struct entry { - SIMPLEQ_ENTRY(entry) entries; - char *line; -}; - -struct dkim_signer { - SIMPLEQ_HEAD(, entry) lines; - SHA256_CTX hdr_ctx; - SHA256_CTX body_ctx; - char b64_rsa_sig[BUFSIZ]; - char b64_body_hash[BUFSIZ]; - char hdrs_list[BUFSIZ]; - char hdr_hash[SHA256_DIGEST_LENGTH]; - char body_hash[SHA256_DIGEST_LENGTH]; - SHA256_CTX *ctx; - size_t nlines; - size_t emptylines; -}; - -static RSA *dkim_signer_rsa; -static const char *dkim_signer_domain, *dkim_signer_selector = "default"; - -static int -dkim_signer_add_hdr_line(struct dkim_signer *s, const char *line) -{ - const char *want_hdrs[] = { - "from:", "to:", "subject:", "date:", "message-id:" - }; - size_t i; - - for (i = 0; i < nitems(want_hdrs); i++) { - if (strncasecmp(want_hdrs[i], line, strlen(want_hdrs[i]))) - continue; - - if (strlcat(s->hdrs_list, want_hdrs[i], - sizeof(s->hdrs_list)) >= sizeof(s->hdrs_list)) - fatalx("headers list overflow"); - else - return 1; - } - - return 0; -} - -static void -dkim_signer_clear(struct dkim_signer *s) -{ - struct entry *n; - - if (s == NULL) - return; - while (!SIMPLEQ_EMPTY(&s->lines)) { - n = SIMPLEQ_FIRST(&s->lines); - SIMPLEQ_REMOVE_HEAD(&s->lines, entries); - free(n->line); - free(n); - } - free(s); -} - -static int -dkim_signer_on_data(uint64_t id) -{ - struct dkim_signer *s = xmalloc(sizeof *s, "dkim_signer: on_data"); - - SIMPLEQ_INIT(&s->lines); - SHA256_Init(&s->hdr_ctx); - SHA256_Init(&s->body_ctx); - s->ctx = &s->hdr_ctx; - s->nlines = 0; - s->emptylines = 0; - s->hdrs_list[0] = '\0'; - - filter_api_set_udata(id, s); - return filter_api_accept(id); -} - -static void -dkim_signer_on_dataline(uint64_t id, const char *line) -{ - struct dkim_signer *s; - struct entry *n; - - if ((s = filter_api_get_udata(id)) == NULL) - return; - n = xmalloc(sizeof *n, "dkim_signer: on_dataline"); - n->line = xstrdup(line, "dkim_signer: on_dataline"); - SIMPLEQ_INSERT_TAIL(&s->lines, n, entries); - - /* first emptyline seperates headers and body */ - if (s->ctx == &s->hdr_ctx && strlen(line) == 0) { - s->ctx = &s->body_ctx; - return; - } - - if (s->ctx == &s->hdr_ctx) { - if (dkim_signer_add_hdr_line(s, line) == 0) - return; /* skip unwanted headers */ - } else { - s->nlines += 1; - /* - * treat trailing two or more emptylines at end of - * message as a single emptyline - */ - if (strlen(line) == 0) { - s->emptylines += 1; - return; - } else { - while (s->emptylines--) - SHA256_Update(s->ctx, DKIM_SIGNER_CRLF, DKIM_SIGNER_CRLF_LEN); - - s->emptylines = 0; - } - } - - SHA256_Update(s->ctx, line, strlen(line)); - /* explicitly terminate with a CRLF */ - SHA256_Update(s->ctx, DKIM_SIGNER_CRLF, DKIM_SIGNER_CRLF_LEN); -} - -static int -dkim_signer_on_eom(uint64_t id, size_t size) -{ - struct dkim_signer *s; - struct entry *n; - char *dkim_header = NULL, *dkim_sig = NULL, *rsa_sig = NULL; - int dkim_sig_len, rsa_sig_len, r = 0; - - if ((s = filter_api_get_udata(id)) == NULL) { - log_warnx("warn: on_eom: get_udata failed"); - goto done; - } - /* empty body should be treated as a single CRLF */ - if (s->nlines == 0) - SHA256_Update(&s->body_ctx, DKIM_SIGNER_CRLF, DKIM_SIGNER_CRLF_LEN); - - SHA256_Final(s->body_hash, &s->body_ctx); - if (base64_encode(s->body_hash, sizeof(s->body_hash), - s->b64_body_hash, sizeof(s->b64_body_hash)) == -1) { - log_warnx("warn: on_eom: __b64_ntop failed"); - goto done; - } - - /* trim trailing colon in the hdrs_list */ - s->hdrs_list[strlen(s->hdrs_list) - 1] = '\0'; - - if ((dkim_sig_len = asprintf(&dkim_sig, DKIM_SIGNER_TEMPLATE, - dkim_signer_domain, s->hdrs_list, dkim_signer_selector, - s->b64_body_hash)) == -1) { - log_warn("warn: on_eom: asprintf failed"); - goto done; - } - - SHA256_Update(&s->hdr_ctx, dkim_sig, dkim_sig_len); - SHA256_Final(s->hdr_hash, &s->hdr_ctx); - - rsa_sig = xmalloc(RSA_size(dkim_signer_rsa), "dkim_signer: on_eom"); - if (RSA_sign(NID_sha256, s->hdr_hash, sizeof(s->hdr_hash), - rsa_sig, &rsa_sig_len, dkim_signer_rsa) == 0) - fatalx("dkim_signer: on_eom: RSA_sign"); - - if (base64_encode(rsa_sig, rsa_sig_len, s->b64_rsa_sig, - sizeof(s->b64_rsa_sig)) == -1) { - log_warnx("warn: on_eom: __b64_ntop failed"); - goto done; - } - - if (asprintf(&dkim_header, "%s%s", dkim_sig, s->b64_rsa_sig) == -1) { - log_warn("warn: on_eom: asprintf failed"); - goto done; - } - - /* prepend dkim header to the mail */ - filter_api_writeln(id, dkim_header); - - /* write out message */ - SIMPLEQ_FOREACH(n, &s->lines, entries) - filter_api_writeln(id, n->line); - r = 1; -done: - free(dkim_header); - free(dkim_sig); - free(rsa_sig); - return r ? filter_api_accept(id) : filter_api_reject(id, FILTER_FAIL); -} - -static void -dkim_signer_on_tx_commit(uint64_t id) -{ - dkim_signer_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -static void -dkim_signer_on_tx_rollback(uint64_t id) -{ - dkim_signer_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -int -main(int argc, char **argv) -{ - int ch, C = 0, d = 0, v = 0; - const char *p = DKIM_SIGNER_PRIVATE_KEY; - char *c = NULL, *D = NULL, *s = NULL; - FILE *fp; - static char hostname[SMTPD_MAXHOSTNAMELEN]; - - log_init(1); - - while ((ch = getopt(argc, argv, "Cc:D:dp:s:v")) != -1) { - switch (ch) { - case 'C': - C = 1; - break; - case 'c': - c = optarg; - break; - case 'D': - D = optarg; - break; - case 'd': - d = 1; - break; - case 'p': - p = optarg; - break; - case 's': - s = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (c) - c = strip(c); - if (D) - dkim_signer_domain = strip(D); - if (s) - dkim_signer_selector = strip(s); - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - OpenSSL_add_all_algorithms(); - OpenSSL_add_all_ciphers(); - OpenSSL_add_all_digests(); - if (dkim_signer_domain == NULL) { - if (gethostname(hostname, sizeof(hostname)) == -1) - fatal("gethostname"); - dkim_signer_domain = hostname; - } - if ((fp = fopen(p, "r")) == NULL) - fatal("fopen %s", p); - if ((dkim_signer_rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL)) == NULL) - fatalx("PEM_read_RSAPrivateKey"); - - filter_api_on_data(dkim_signer_on_data); - filter_api_on_dataline(dkim_signer_on_dataline); - filter_api_on_eom(dkim_signer_on_eom); - filter_api_on_tx_commit(dkim_signer_on_tx_commit); - filter_api_on_tx_rollback(dkim_signer_on_tx_rollback); - if (c) - filter_api_set_chroot(c); - if (C) - filter_api_no_chroot(); - - /* XXX */ - /* - * OpenSSL will not be able to seed PRNG after chroot which will - * lead to runtime failures if we don't seed PRNG pre-chroot. We - * shouldn't have to do that, LibreSSL does not suffer from this - * shortcoming but luckily provides RAND_status() as a no-op for - * ABI compat... - */ - RAND_status(); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-dnsbl/Makefile.am b/extras/filters/filter-dnsbl/Makefile.am deleted file mode 100644 index 1db4695..0000000 --- a/extras/filters/filter-dnsbl/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-dnsbl - -filter_dnsbl_SOURCES = $(SRCS) -filter_dnsbl_SOURCES += filter_dnsbl.c - -man_MANS = filter-dnsbl.8 - -if !NO_LIBASR -LDADD += -lasr -endif diff --git a/extras/filters/filter-dnsbl/filter-dnsbl.8 b/extras/filters/filter-dnsbl/filter-dnsbl.8 deleted file mode 100644 index 254a5db..0000000 --- a/extras/filters/filter-dnsbl/filter-dnsbl.8 +++ /dev/null @@ -1,103 +0,0 @@ -.\" -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 16 2016 $ -.Dt FILTER-DNSBL 8 -.Os -.Sh NAME -.Nm filter-dnsbl -.Nd smtpd filter for DNSBL checks -.Sh SYNOPSIS -.Nm -.Op Fl Cdv -.Op Fl c Ar path -.Op Fl h Ar host -.Op Fl w Ar host -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to check new connections against a -DNS-based Blackhole List (DNSBL) and optional a DNS-based Whitelist (DNSWL). -.Pp -The options are as follows: -.Bl -tag -width "-c path" -.It Fl C -No -.Xr chroot 2 -mode, if this option is specified, -.Nm -will not run in a chroot. -.It Fl c Ar path -Set the chroot -.Ar path . -.Pp -The default -.Ar path -is -.Pa /var/empty -(compile option). -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl h Ar host -Set the DNSBL -.Ar host -to be queried. -.Pp -The default -.Ar host -is dnsbl.sorbs.net. -.It Fl v -Produce more verbose output. -.It Fl w Ar host -Set the DNSWL -.Ar host -to be queried. -.Pp -The default is to not query a DNSWL -.Ar host . -.El -.Pp -.Nm -runs by default in a chroot. -In order to make DNS queries working, a valid -.Pa resolv.conf -is required within the chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -The remote IP address of new connections is used in a DNS query against the -DNSBL and optional DNSWL. -If the remote address is listed in the DNSBL, the connection is rejected, -otherwise accepted. -If the optional DNSWL host is given, it is queried first and if the remote -address is listed the connection is accepted (without checking the DNSBL). -.Sh SEE ALSO -.Xr chroot 2 , -.Xr filter_api 3 , -.Xr smtpd.conf 5 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Nm -was written in 2013. -.Sh AUTHORS -.An Eric Faurot Aq Mt eric@openbsd.org diff --git a/extras/filters/filter-dnsbl/filter_dnsbl.c b/extras/filters/filter-dnsbl/filter_dnsbl.c deleted file mode 100644 index 6835538..0000000 --- a/extras/filters/filter-dnsbl/filter_dnsbl.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> - * Copyright (c) 2016 Joerg Jung <jung@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/socket.h> - -#include <ctype.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <asr.h> - -#include <smtpd-api.h> - -struct dnsbl { - uint64_t id; - struct asr_query *aq_bl, *aq_wl; -}; - -static const char *dnsbl_host = "dnsbl.sorbs.net", *dnswl_host; - -static void -dnsbl_event_black(struct asr_result *ar, void *p) -{ - struct dnsbl *dl = p; - - if (ar->ar_addrinfo) - freeaddrinfo(ar->ar_addrinfo); - if (ar->ar_gai_errno == EAI_NODATA || ar->ar_gai_errno == EAI_NONAME) { - log_info("info: event_black: ACCEPT address"); - filter_api_accept(dl->id); - } else if (ar->ar_gai_errno) { - log_warnx("warn: session %016"PRIx64": event_black: getaddrinfo '%s'", dl->id, gai_strerror(ar->ar_gai_errno)); - filter_api_reject_code(dl->id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); - } else { - log_warnx("warn: session %016"PRIx64": event_black: REJECT address", dl->id); - filter_api_reject_code(dl->id, FILTER_CLOSE, 554, "5.7.1 Address in DNSBL"); - } - free(dl); -} - -static void -dnsbl_event_white(struct asr_result *ar, void *p) -{ - struct dnsbl *dl = p; - - if (ar->ar_addrinfo) - freeaddrinfo(ar->ar_addrinfo); - if (ar->ar_gai_errno == EAI_NODATA || ar->ar_gai_errno == EAI_NONAME) { - log_debug("debug: event_white: address not in DNSWL"); - event_asr_run(dl->aq_bl, dnsbl_event_black, dl); - } else if (ar->ar_gai_errno) { - log_warnx("warn: session %016"PRIx64": event_white: getaddrinfo '%s'", dl->id, gai_strerror(ar->ar_gai_errno)); - filter_api_reject_code(dl->id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); - asr_abort(dl->aq_bl); - free(dl); - } else { - log_info("info: event_white: ACCEPT address"); - filter_api_accept(dl->id); - asr_abort(dl->aq_bl); - free(dl); - } -} - -static struct asr_query * -dnsbl_query(in_addr_t ia, const char *h) -{ - struct asr_query *aq; - struct addrinfo hints; - char buf[512]; - - ia = ntohl(ia); - if (snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%s.", - ia & 0xff, (ia >> 8) & 0xff, (ia >> 16) & 0xff, (ia >> 24) & 0xff, h) >= sizeof(buf)) { - log_warnx("warn: query: host name too long: %s", buf); - return NULL; - } - log_debug("debug: query: checking %s", buf); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (!(aq = getaddrinfo_async(buf, NULL, &hints, NULL))) { - log_warn("warn: query: getaddrinfo_async"); - return NULL; - } - return aq; -} - -static int -dnsbl_on_connect(uint64_t id, struct filter_connect *conn) -{ - struct dnsbl *dl; - in_addr_t ia; - - if (conn->remote.ss_family != AF_INET) - return filter_api_accept(id); - ia = ((const struct sockaddr_in *)&conn->remote)->sin_addr.s_addr; - dl = xcalloc(1, sizeof(struct dnsbl), "on_connect"); - dl->id = id; - if (!(dl->aq_bl = dnsbl_query(ia, dnsbl_host)) || (dnswl_host && - !(dl->aq_wl = dnsbl_query(ia, dnswl_host)))) { - free(dl); - return filter_api_reject_code(id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); - } - dnswl_host ? event_asr_run(dl->aq_wl, dnsbl_event_white, dl) : - event_asr_run(dl->aq_bl, dnsbl_event_black, dl); - return 1; -} - -int -main(int argc, char **argv) -{ - int ch, C = 0, d = 0, v = 0; - char *c = NULL, *h = NULL, *w = NULL; - - log_init(1); - - while ((ch = getopt(argc, argv, "Cc:dh:vw:")) != -1) { - switch (ch) { - case 'C': - C = 1; - break; - case 'c': - c = optarg; - break; - case 'd': - d = 1; - break; - case 'h': - h = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - case 'w': - w = optarg; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (c) - c = strip(c); - if (h) - dnsbl_host = strip(h); - if (w) - dnswl_host = strip(w); - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - - filter_api_on_connect(dnsbl_on_connect); - if (c) - filter_api_set_chroot(c); /* getaddrinfo requires resolv.conf */ - if (C) - filter_api_no_chroot(); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-lua/Makefile.am b/extras/filters/filter-lua/Makefile.am deleted file mode 100644 index 58f8a7d..0000000 --- a/extras/filters/filter-lua/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-lua - -filter_lua_SOURCES = $(SRCS) -filter_lua_SOURCES += filter_lua.c - -CFLAGS += ${LUA_CPPFLAGS} -LDFLAGS += ${LUA_LDFLAGS} diff --git a/extras/filters/filter-lua/filter_lua.c b/extras/filters/filter-lua/filter_lua.c deleted file mode 100644 index c2c8781..0000000 --- a/extras/filters/filter-lua/filter_lua.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> - * Copyright (c) 2014 Emmanuel Vadot <manu@bocal.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> -#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501 -#define luaL_Reg luaL_reg -void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { - luaL_checkstack(L, nup+1, "too many upvalues"); - for (; l->name != NULL; l++) { /* fill the table with given functions */ - int i; - lua_pushstring(L, l->name); - for (i = 0; i < nup; i++) /* copy upvalues to the top */ - lua_pushvalue(L, -(nup + 1)); - lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ - lua_settable(L, -(nup + 3)); /* table must be below the upvalues, the name and the closure */ - } - lua_pop(L, nup); /* remove upvalues */ -} -#define luaL_newlib(L, l) \ - (lua_newtable((L)),luaL_setfuncs((L), (l), 0)) -#endif - -#include <smtpd-api.h> - -#define ID_STR_SZ 20 - -lua_State *L; - -static int -l_filter_accept(lua_State *L) -{ - uint64_t id; - const char *s_hex_id; - - if (lua_gettop(L) != 1) - return 0; - - s_hex_id = luaL_checklstring(L, 1, NULL); - id = strtoumax(s_hex_id, NULL, 16); - filter_api_accept(id); - return 0; -} - -static int -l_filter_reject(lua_State *L) -{ - uint64_t id; - const char *s_hex_id; - uint32_t action; - - if (lua_gettop(L) != 2) - return 0; - - s_hex_id = luaL_checklstring(L, 1, NULL); - id = strtoumax(s_hex_id, NULL, 16); - action = luaL_checkinteger(L, 2); - switch (action) { - case FILTER_FAIL: - case FILTER_CLOSE: - filter_api_reject(id, action); - break; - } - - return 0; -} - -static int -l_filter_reject_code(lua_State *L) -{ - uint64_t id; - const char *s_hex_id; - uint32_t action; - uint32_t code; - const char *line; - - if (lua_gettop(L) != 4) - return 0; - - s_hex_id = luaL_checklstring(L, 1, NULL); - id = strtoumax(s_hex_id, NULL, 16); - action = luaL_checkinteger(L, 2); - code = luaL_checkinteger(L, 3); - line = luaL_checklstring(L, 4, NULL); - - switch (action) { - case FILTER_FAIL: - case FILTER_CLOSE: - filter_api_reject_code(id, action, code, line); - break; - } - - return 0; -} - -static int -l_filter_writeln(lua_State *L) -{ - uint64_t id; - const char *s_hex_id; - const char *line; - - if (lua_gettop(L) != 2) - return 0; - - s_hex_id = luaL_checklstring(L, 1, NULL); - id = strtoumax(s_hex_id, NULL, 16); - line = luaL_checklstring(L, 2, NULL); - - filter_api_writeln(id, line); - - return 0; -} - -static const luaL_Reg l_filter [] = { - {"accept", l_filter_accept}, - {"reject", l_filter_reject}, - {"reject_code", l_filter_reject_code}, - {"writeln", l_filter_writeln}, - {NULL, NULL} -}; - -static int -on_connect(uint64_t id, struct filter_connect *conn) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - - lua_getglobal(L, "on_connect"); - lua_pushstring(L, s_id); - lua_pushstring(L, - filter_api_sockaddr_to_text((struct sockaddr *)&conn->local)); - lua_pushstring(L, - filter_api_sockaddr_to_text((struct sockaddr *)&conn->remote)); - lua_pushstring(L, conn->hostname); - - if (lua_pcall(L, 4, 0, 0)) { - log_warnx("warn: on_connect: %s", - lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static int -on_helo(uint64_t id, const char *helo) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_helo"); - lua_pushstring(L, s_id); - lua_pushstring(L, helo); - - if (lua_pcall(L, 2, 0, 0)) { - log_warnx("warn: on_helo: %s", - lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static int -on_mail(uint64_t id, struct mailaddr *mail) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_mail"); - lua_pushstring(L, s_id); - lua_pushstring(L, filter_api_mailaddr_to_text(mail)); - - if (lua_pcall(L, 2, 0, 0)) { - log_warnx("warn: on_mail: %s", - lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static int -on_rcpt(uint64_t id, struct mailaddr *rcpt) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_rcpt"); - lua_pushstring(L, s_id); - lua_pushstring(L, filter_api_mailaddr_to_text(rcpt)); - - if (lua_pcall(L, 2, 0, 0)) { - log_warnx("warn: on_rcpt: %s", - lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static int -on_data(uint64_t id) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_data"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_data: %s", - lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static void -on_dataline(uint64_t id, const char *line) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_dataline"); - lua_pushstring(L, s_id); - lua_pushstring(L, line); - - if (lua_pcall(L, 2, 0, 0)) { - log_warnx("warn: on_dataline: %s", - lua_tostring(L, -1)); - exit(1); - } -} - -static int -on_eom(uint64_t id, size_t size) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_eom"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_eom: %s", lua_tostring(L, -1)); - exit(1); - } - - return 1; -} - -static void -on_tx_begin(uint64_t id) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_tx_begin"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_tx_begin: %s", - lua_tostring(L, -1)); - exit(1); - } -} - -static void -on_tx_commit(uint64_t id) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_tx_commit"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_tx_commit: %s", - lua_tostring(L, -1)); - exit(1); - } -} - -static void -on_tx_rollback(uint64_t id) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_tx_rollback"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_tx_rollback: %s", - lua_tostring(L, -1)); - exit(1); - } -} - -static void -on_disconnect(uint64_t id) -{ - char s_id[ID_STR_SZ]; - - (void)snprintf(s_id, sizeof(s_id), "%016"PRIx64"", id); - lua_getglobal(L, "on_disconnect"); - lua_pushstring(L, s_id); - - if (lua_pcall(L, 1, 0, 0)) { - log_warnx("warn: on_disconnect: %s", - lua_tostring(L, -1)); - exit(1); - } -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - char *c = NULL, *path; - - log_init(1); - - while ((ch = getopt(argc, argv, "c:dv")) != -1) { - switch (ch) { - case 'c': - c = optarg; - break; - case 'd': - d = 1; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - if (argc == 0) - errx(1, "missing path"); - - if (c) - c = strip(c); - path = argv[0]; - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - - if ((L = luaL_newstate()) == NULL) { - log_warnx("warn: can't create lua state"); - return 1; - } - luaL_openlibs(L); - luaL_newlib(L, l_filter); -#if 0 - luaL_newmetatable(L, "filter"); - lua_setmetatable(L, -2); - - lua_pushnumber(L, FILTER_OK); - lua_setfield(L, -2, "FILTER_OK"); - lua_pushnumber(L, FILTER_FAIL); - lua_setfield(L, -2, "FILTER_FAIL"); - lua_pushnumber(L, FILTER_CLOSE); - lua_setfield(L, -2, "FILTER_CLOSE"); -#endif - lua_setglobal(L, "filter"); - - if (luaL_dofile(L, path) != 0) { - log_warnx("warn: error loading script: %s", path); - return 1; - } - - lua_getglobal(L, "on_connect"); - if (lua_isfunction(L, -1)) { - log_debug("debug: on_connect is present"); - filter_api_on_connect(on_connect); - } - - lua_getglobal(L, "on_helo"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_helo is present"); - filter_api_on_helo(on_helo); - } - - lua_getglobal(L, "on_mail"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_mail is present"); - filter_api_on_mail(on_mail); - } - - lua_getglobal(L, "on_rcpt"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_rcpt is present"); - filter_api_on_rcpt(on_rcpt); - } - - lua_getglobal(L, "on_data"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_data is present"); - filter_api_on_data(on_data); - } - - lua_getglobal(L, "on_dataline"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_dataline is present"); - filter_api_on_dataline(on_dataline); - } - - lua_getglobal(L, "on_eom"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_eom is present"); - filter_api_on_eom(on_eom); - } - - lua_getglobal(L, "on_tx_begin"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_tx_begin is present"); - filter_api_on_tx_begin(on_tx_begin); - } - - lua_getglobal(L, "on_tx_commit"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_tx_commit is present"); - filter_api_on_tx_commit(on_tx_commit); - } - - lua_getglobal(L, "on_tx_rollback"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_tx_rollback is present"); - filter_api_on_tx_rollback(on_tx_rollback); - } - - lua_getglobal(L, "on_disconnect"); - if (lua_isfunction(L, 1)) { - log_debug("debug: on_disconnect is present"); - filter_api_on_disconnect(on_disconnect); - } - - filter_api_no_chroot(); - if (c) - filter_api_set_chroot(c); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-pause/Makefile.am b/extras/filters/filter-pause/Makefile.am deleted file mode 100644 index 21a226f..0000000 --- a/extras/filters/filter-pause/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-pause - -filter_pause_SOURCES = $(SRCS) -filter_pause_SOURCES += filter_pause.c - -man_MANS = filter-pause.8 diff --git a/extras/filters/filter-pause/filter-pause.8 b/extras/filters/filter-pause/filter-pause.8 deleted file mode 100644 index 341ed2b..0000000 --- a/extras/filters/filter-pause/filter-pause.8 +++ /dev/null @@ -1,90 +0,0 @@ -.\" -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 16 2016 $ -.Dt FILTER-PAUSE 8 -.Os -.Sh NAME -.Nm filter-pause -.Nd smtpd filter to pause on new connections -.Sh SYNOPSIS -.Nm -.Op Fl dv -.Op Fl s Ar seconds -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to pause on new connections before emitting the standard -initial SMTP greeting. -This is useful to avoid the so called -.Dq slamming -technique used by some senders of spam mails. -.Pp -The options are as follows: -.Bl -tag -width "-s seconds" -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl s Ar seconds -Set the number of -.Ar seconds -to pause before sending the initial greeting. -The accepted values are within the range of 1s and 300s. -.Pp -The default -.Ar seconds -value is 5s. -.It Fl v -Produce more verbose output. -.El -.Pp -.Nm -runs by default in a chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -With -.Nm -enabled, -.Xr smtpd 8 -simply waits the specified amount of -.Ar seconds -on each new connection. -If the remote server starts sending SMTP commands before the greeting, the -connection is rejected. -Otherwise, the connection is accepted and normally processed. -.Sh SEE ALSO -.Xr filter_api 3 , -.Xr smtpd.conf 5 , -.Xr smtpd 8 -.Sh STANDARDS -.Rs -.%A J. Klensin -.%D October 2008 -.%R RFC 5321 -.%T Simple Mail Transfer Protocol -.Re -.Sh HISTORY -The first version of -.Nm -was written in 2015. -.Sh AUTHORS -.An Joerg Jung Aq Mt jung@openbsd.org diff --git a/extras/filters/filter-pause/filter_pause.c b/extras/filters/filter-pause/filter_pause.c deleted file mode 100644 index 4a0613a..0000000 --- a/extras/filters/filter-pause/filter_pause.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <smtpd-api.h> - -static unsigned short pause_seconds = 5; - -static void -pause_timer(uint64_t id, void *p) -{ - filter_api_accept(id); -} - -static int -pause_on_connect(uint64_t id, struct filter_connect *conn) -{ - log_debug("debug: on_connect: sleeping %u", pause_seconds); - filter_api_timer(id, pause_seconds * 1000, pause_timer, NULL); - return 1; -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - const char *errstr, *s = NULL; - - log_init(1); - - while ((ch = getopt(argc, argv, "ds:v")) != -1) { - switch (ch) { - case 'd': - d = 1; - break; - case 's': - s = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (s) { /* RFC 5321 4.5.3.2 Initial 220 Message: 5 Minutes */ - pause_seconds = strtonum(s, 1, 300, &errstr); - if (errstr) - fatalx("seconds option is %s: %s", errstr, s); - } - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - - filter_api_on_connect(pause_on_connect); - filter_api_loop(); - - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-perl/Makefile.am b/extras/filters/filter-perl/Makefile.am deleted file mode 100644 index cd3d861..0000000 --- a/extras/filters/filter-perl/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-perl - -filter_perl_SOURCES = $(SRCS) -filter_perl_SOURCES += filter_perl.c - -CFLAGS += ${PERL_CPPFLAGS} -LDFLAGS += ${PERL_LDFLAGS} diff --git a/extras/filters/filter-perl/filter_perl.c b/extras/filters/filter-perl/filter_perl.c deleted file mode 100644 index e58d004..0000000 --- a/extras/filters/filter-perl/filter_perl.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 2014 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/socket.h> - -#include <inttypes.h> -#include <stdarg.h> -#include <stdio.h> -#include <unistd.h> - -#include <EXTERN.h> -#include <XSUB.h> -#include <perl.h> - -#include <smtpd-api.h> - -static PerlInterpreter *my_perl; /* fix build */ -static PerlInterpreter *pi; -static CV *pl_on_connect; -static CV *pl_on_helo; -static CV *pl_on_mail; -static CV *pl_on_rcpt; -static CV *pl_on_data; -static CV *pl_on_eom; -static CV *pl_on_tx_begin; -static CV *pl_on_tx_commit; -static CV *pl_on_tx_rollback; -static CV *pl_on_dataline; -static CV *pl_on_disconnect; - -EXTERN_C void xs_init(pTHX); -EXTERN_C void boot_DynaLoader(pTHX_ CV* cv); - -EXTERN_C void -xs_init(pTHX) -{ - static const char file[] = __FILE__; - dXSUB_SYS; - PERL_UNUSED_CONTEXT; - - /* DynaLoader is a special case */ - newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); -} - -XS(XS_filter_accept); -XS(XS_filter_reject); -XS(XS_filter_reject_code); -XS(XS_filter_writeln); - -XS(XS_filter_accept) -{ - dXSARGS; - uint64_t id; - int ret; - - id = SvUV(ST(0)); - ret = filter_api_accept(id); - XPUSHs(sv_2mortal(newSViv(ret))); - XSRETURN(1); -} - -XS(XS_filter_reject) -{ - dXSARGS; - uint64_t id; - int ret; - - id = SvUV(ST(0)); - ret = filter_api_reject(id, FILTER_CLOSE); - XPUSHs(sv_2mortal(newSViv(ret))); - XSRETURN(1); -} - -XS(XS_filter_reject_code) -{ - dXSARGS; - XSRETURN(1); -} - -XS(XS_filter_writeln) -{ - dXSARGS; - uint64_t id; - const char *line; - - id = SvUV(ST(0)); - line = SvPVX(ST(1)); - filter_api_writeln(id, line); - XSRETURN(1); -} - -void -call_sub_sv(SV *plsub, const char *format, ...) -{ - va_list ap; - dSP; - - va_start(ap, format); - - ENTER; - SAVETMPS; - - PUSHMARK(SP); - while (*format) { - switch (*format++) { - case 's': - XPUSHs(sv_2mortal(newSVpv(va_arg(ap, char *), 0))); - break; - case 'i': - XPUSHs(sv_2mortal(newSVuv(va_arg(ap, uint64_t)))); - break; - } - } - PUTBACK; - - perl_call_sv(plsub, G_DISCARD); - - FREETMPS; - LEAVE; - - va_end(ap); -} - -static int -on_connect(uint64_t id, struct filter_connect *conn) -{ - char local[SMTPD_MAXHOSTNAMELEN]; - char remote[SMTPD_MAXHOSTNAMELEN]; - - (void)snprintf(local, sizeof local, "%s", - filter_api_sockaddr_to_text((struct sockaddr *)&conn->local)); - (void)snprintf(remote, sizeof remote, "%s", - filter_api_sockaddr_to_text((struct sockaddr *)&conn->remote)); - - call_sub_sv((SV *)pl_on_connect, "%i%s%s%s", id, local, remote, conn->hostname); -} - -static int -on_helo(uint64_t id, const char *helo) -{ - call_sub_sv((SV *)pl_on_helo, "%i%s", id, helo); -} - -static int -on_mail(uint64_t id, struct mailaddr *mail) -{ - const char *mailaddr; - - mailaddr = filter_api_mailaddr_to_text(mail); - call_sub_sv((SV *)pl_on_mail, "%i%s", id, mailaddr); -} - -static int -on_rcpt(uint64_t id, struct mailaddr *rcpt) -{ - const char *mailaddr; - - mailaddr = filter_api_mailaddr_to_text(rcpt); - call_sub_sv((SV *)pl_on_rcpt, "%i%s", id, mailaddr); -} - -static int -on_data(uint64_t id) -{ - call_sub_sv((SV *)pl_on_data, "%i", id); -} - -static int -on_eom(uint64_t id, size_t size) -{ - call_sub_sv((SV *)pl_on_eom, "%i", id); -} - -static void -on_tx_begin(uint64_t id) -{ - call_sub_sv((SV *)pl_on_tx_begin, "%i", id); - return; -} - -static void -on_tx_commit(uint64_t id) -{ - call_sub_sv((SV *)pl_on_tx_commit, "%i", id); - return; -} - -static void -on_tx_rollback(uint64_t id) -{ - call_sub_sv((SV *)pl_on_tx_rollback, "%i", id); - return; -} - -static void -on_disconnect(uint64_t id) -{ - call_sub_sv((SV *)pl_on_disconnect, "%i", id); - return; -} - -static void -on_dataline(uint64_t id, const char *line) -{ - call_sub_sv((SV *)pl_on_dataline, "%i%s", id, line); -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - char *c = NULL, *fake_argv[3] = { "-e", NULL, NULL }; - - log_init(1); - - while ((ch = getopt(argc, argv, "c:dv")) != -1) { - switch (ch) { - case 'c': - c = optarg; - break; - case 'd': - d = 1; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - if (argc == 0) - errx(1, "missing path"); - - if (c) - c = strip(c); - fake_argv[1] = argv[0]; - - log_init(d); - log_verbose(v); - - pi = perl_alloc(); - perl_construct(pi); - perl_parse(pi, xs_init, 2, fake_argv, NULL); - - newXS("smtpd::filter_api_accept", XS_filter_accept, __FILE__); - newXS("smtpd::filter_api_reject", XS_filter_reject, __FILE__); - newXS("smtpd::filter_api_writeln", XS_filter_writeln, __FILE__); - - log_debug("debug: starting..."); - - if ((pl_on_connect = perl_get_cv("on_connect", FALSE))) - filter_api_on_connect(on_connect); - if ((pl_on_helo = perl_get_cv("on_helo", FALSE))) - filter_api_on_helo(on_helo); - if ((pl_on_mail = perl_get_cv("on_mail", FALSE))) - filter_api_on_mail(on_mail); - if ((pl_on_rcpt = perl_get_cv("on_rcpt", FALSE))) - filter_api_on_rcpt(on_rcpt); - if ((pl_on_data = perl_get_cv("on_data", FALSE))) - filter_api_on_data(on_data); - if ((pl_on_eom = perl_get_cv("on_eom", FALSE))) - filter_api_on_eom(on_eom); - if ((pl_on_tx_begin = perl_get_cv("on_tx_begin", FALSE))) - filter_api_on_tx_begin(on_tx_begin); - if ((pl_on_tx_commit = perl_get_cv("on_tx_commit", FALSE))) - filter_api_on_tx_commit(on_tx_commit); - if ((pl_on_tx_rollback = perl_get_cv("on_tx_rollback", FALSE))) - filter_api_on_rollback(on_tx_rollback); - if ((pl_on_dataline = perl_get_cv("on_dataline", FALSE))) - filter_api_on_dataline(on_dataline); - if ((pl_on_disconnect = perl_get_cv("on_disconnect", FALSE))) - filter_api_on_disconnect(on_disconnect); - - filter_api_no_chroot(); - if (c) - filter_api_set_chroot(c); - - filter_api_loop(); - log_debug("debug: exiting"); - - perl_destruct(pi); - perl_free(pi); - - return 1; -} diff --git a/extras/filters/filter-python/Makefile.am b/extras/filters/filter-python/Makefile.am deleted file mode 100644 index 8a7329a..0000000 --- a/extras/filters/filter-python/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-python - -filter_python_SOURCES = $(SRCS) -filter_python_SOURCES += filter_python.c - -CFLAGS += ${PYTHON_CPPFLAGS} -LDFLAGS += ${PYTHON_LDFLAGS} diff --git a/extras/filters/filter-python/filter_python.c b/extras/filters/filter-python/filter_python.c deleted file mode 100644 index 33c1f4b..0000000 --- a/extras/filters/filter-python/filter_python.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (c) 2014 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/socket.h> - -#include <inttypes.h> -#include <stdio.h> -#include <unistd.h> - -/* _GNU_SOURCE is not properly protected in Python.h ... */ -#undef _GNU_SOURCE -#include <Python.h> -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <smtpd-api.h> - -static PyObject *py_on_connect; -static PyObject *py_on_helo; -static PyObject *py_on_mail; -static PyObject *py_on_rcpt; -static PyObject *py_on_data; -static PyObject *py_on_eom; -static PyObject *py_on_dataline; - -static PyObject *py_on_tx_begin; -static PyObject *py_on_tx_commit; -static PyObject *py_on_tx_rollback; -static PyObject *py_on_disconnect; - - -static PyObject * -py_filter_accept(PyObject *self, PyObject *args) -{ - uint64_t id; - - if (!PyArg_ParseTuple(args, "K", &id)) - return NULL; - filter_api_accept(id); - Py_RETURN_TRUE; -} - -static PyObject * -py_filter_reject(PyObject *self, PyObject *args) -{ - uint64_t id; - uint32_t action; - - if (!PyArg_ParseTuple(args, "Ki", &id, &action)) - return NULL; - - switch (action) { - case FILTER_FAIL: - case FILTER_CLOSE: - filter_api_reject(id, action); - Py_RETURN_TRUE; - break; - } - Py_RETURN_FALSE; -} - -static PyObject * -py_filter_reject_code(PyObject *self, PyObject *args) -{ - uint64_t id; - uint32_t action; - uint32_t code; - const char *line; - - if (!PyArg_ParseTuple(args, "Kiis", &id, &action, &code, &line)) - return NULL; - - switch (action) { - case FILTER_FAIL: - case FILTER_CLOSE: - filter_api_reject_code(id, action, code, line); - Py_RETURN_TRUE; - break; - } - Py_RETURN_FALSE; -} - -static PyObject * -py_filter_writeln(PyObject *self, PyObject *args) -{ - uint64_t id; - const char *line; - - if (!PyArg_ParseTuple(args, "Ks", &id, &line)) - return NULL; - filter_api_writeln(id, line); - Py_RETURN_TRUE; -} - -static PyMethodDef py_methods[] = { - { "accept", py_filter_accept, METH_VARARGS, "accept" }, - { "reject", py_filter_reject, METH_VARARGS, "reject" }, - { "reject_code", py_filter_reject_code, METH_VARARGS, "reject_code" }, - { "writeln", py_filter_writeln, METH_VARARGS, "writeln" }, - { NULL, NULL, 0, NULL } -}; - - -static int -on_connect(uint64_t id, struct filter_connect *conn) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_local; - PyObject *py_remote; - PyObject *py_hostname; - - py_args = PyTuple_New(4); - py_id = PyLong_FromUnsignedLongLong(id); - py_local = PyString_FromString(filter_api_sockaddr_to_text((struct sockaddr *)&conn->local)); - py_remote = PyString_FromString(filter_api_sockaddr_to_text((struct sockaddr *)&conn->remote)); - py_hostname = PyString_FromString(conn->hostname); - - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_local); - PyTuple_SetItem(py_args, 2, py_remote); - PyTuple_SetItem(py_args, 3, py_hostname); - - py_ret = PyObject_CallObject(py_on_connect, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_connect: handler failed"); - exit(1); - } - - return 1; -} - -static int -on_helo(uint64_t id, const char *helo) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_helo; - - py_args = PyTuple_New(2); - py_id = PyLong_FromUnsignedLongLong(id); - py_helo = PyString_FromString(helo); - - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_helo); - - py_ret = PyObject_CallObject(py_on_helo, py_args); - Py_DECREF(py_args); - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_helo: handler failed"); - exit(1); - } - return 1; -} - -static int -on_mail(uint64_t id, struct mailaddr *mail) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_sender; - - py_args = PyTuple_New(2); - py_id = PyLong_FromUnsignedLongLong(id); - py_sender = PyString_FromString(filter_api_mailaddr_to_text(mail)); - - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_sender); - - py_ret = PyObject_CallObject(py_on_mail, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_mail: handler failed"); - exit(1); - } - - return 1; -} - -static int -on_rcpt(uint64_t id, struct mailaddr *rcpt) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_rcpt; - - py_args = PyTuple_New(2); - py_id = PyLong_FromUnsignedLongLong(id); - py_rcpt = PyString_FromString(filter_api_mailaddr_to_text(rcpt)); - - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_rcpt); - - py_ret = PyObject_CallObject(py_on_rcpt, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_rcpt: handler failed"); - exit(1); - } - - return 1; -} - -static int -on_data(uint64_t id) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - - py_args = PyTuple_New(1); - py_id = PyLong_FromUnsignedLongLong(id); - PyTuple_SetItem(py_args, 0, py_id); - py_ret = PyObject_CallObject(py_on_data, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_data: handler failed"); - exit(1); - } - - return 1; -} - -static int -on_eom(uint64_t id, size_t sz) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_sz; - - py_args = PyTuple_New(2); - py_id = PyLong_FromUnsignedLongLong(id); - py_sz = PyLong_FromSize_t(sz); - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_sz); - py_ret = PyObject_CallObject(py_on_eom, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_eom: handler failed"); - exit(1); - } - - return 1; -} - -static void -on_tx_begin(uint64_t id) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - - py_args = PyTuple_New(1); - py_id = PyLong_FromUnsignedLongLong(id); - PyTuple_SetItem(py_args, 0, py_id); - py_ret = PyObject_CallObject(py_on_tx_begin, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_tx_begin: handler failed"); - exit(1); - } -} - -static void -on_tx_commit(uint64_t id) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - - py_args = PyTuple_New(1); - py_id = PyLong_FromUnsignedLongLong(id); - PyTuple_SetItem(py_args, 0, py_id); - py_ret = PyObject_CallObject(py_on_tx_commit, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_tx_commit: handler failed"); - exit(1); - } -} - -static void -on_tx_rollback(uint64_t id) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - - py_args = PyTuple_New(1); - py_id = PyLong_FromUnsignedLongLong(id); - PyTuple_SetItem(py_args, 0, py_id); - py_ret = PyObject_CallObject(py_on_tx_rollback, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_tx_rollback: handler failed"); - exit(1); - } -} - -static void -on_disconnect(uint64_t id) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - - py_args = PyTuple_New(1); - py_id = PyLong_FromUnsignedLongLong(id); - PyTuple_SetItem(py_args, 0, py_id); - py_ret = PyObject_CallObject(py_on_disconnect, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_disconnect: handler failed"); - exit(1); - } -} - -static void -on_dataline(uint64_t id, const char *line) -{ - PyObject *py_args; - PyObject *py_ret; - PyObject *py_id; - PyObject *py_line; - - py_args = PyTuple_New(2); - py_id = PyLong_FromUnsignedLongLong(id); - py_line = PyString_FromString(line); - - PyTuple_SetItem(py_args, 0, py_id); - PyTuple_SetItem(py_args, 1, py_line); - - py_ret = PyObject_CallObject(py_on_dataline, py_args); - Py_DECREF(py_args); - - if (py_ret == NULL) { - PyErr_Print(); - log_warnx("warn: on_dataline: handler failed"); - exit(1); - } -} - -static char * -loadfile(const char * path) -{ - FILE *f; - off_t oz; - size_t sz; - char *buf; - - if ((f = fopen(path, "r")) == NULL) - err(1, "fopen"); - - if (fseek(f, 0, SEEK_END) == -1) - err(1, "fseek"); - - oz = ftello(f); - - if (fseek(f, 0, SEEK_SET) == -1) - err(1, "fseek"); - - if (oz >= SIZE_MAX) - errx(1, "too big"); - - sz = oz; - - buf = xmalloc(sz + 1, "loadfile"); - - if (fread(buf, 1, sz, f) != sz) - err(1, "fread"); - - buf[sz] = '\0'; - - fclose(f); - - return buf; -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - char *c = NULL, *path, *buf; - PyObject *self, *code, *module; - - log_init(1); - - while ((ch = getopt(argc, argv, "c:dv")) != -1) { - switch (ch) { - case 'c': - c = optarg; - break; - case 'd': - d = 1; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - if (argc == 0) - errx(1, "missing path"); - - if (c) - c = strip(c); - path = argv[0]; - - log_init(d); - log_verbose(v); - - Py_Initialize(); - self = Py_InitModule("filter", py_methods); - PyModule_AddIntConstant(self, "FILTER_OK", FILTER_OK); - PyModule_AddIntConstant(self, "FILTER_FAIL", FILTER_FAIL); - PyModule_AddIntConstant(self, "FILTER_CLOSE", FILTER_CLOSE); - - buf = loadfile(path); - code = Py_CompileString(buf, path, Py_file_input); - free(buf); - - if (code == NULL) { - PyErr_Print(); - log_warnx("warn: failed to compile %s", path); - return 1; - } - - module = PyImport_ExecCodeModuleEx("myfilter", code, path); - - if (module == NULL) { - PyErr_Print(); - log_warnx("warn: failed to install module %s", path); - return 1; - } - - log_debug("debug: starting..."); - - py_on_connect = PyObject_GetAttrString(module, "on_connect"); - if (py_on_connect && PyCallable_Check(py_on_connect)) - filter_api_on_connect(on_connect); - - py_on_helo = PyObject_GetAttrString(module, "on_helo"); - if (py_on_helo && PyCallable_Check(py_on_helo)) - filter_api_on_helo(on_helo); - - py_on_mail = PyObject_GetAttrString(module, "on_mail"); - if (py_on_mail && PyCallable_Check(py_on_mail)) - filter_api_on_mail(on_mail); - - py_on_rcpt = PyObject_GetAttrString(module, "on_rcpt"); - if (py_on_rcpt && PyCallable_Check(py_on_rcpt)) - filter_api_on_rcpt(on_rcpt); - - py_on_data = PyObject_GetAttrString(module, "on_data"); - if (py_on_data && PyCallable_Check(py_on_data)) - filter_api_on_data(on_data); - - py_on_eom = PyObject_GetAttrString(module, "on_eom"); - if (py_on_eom && PyCallable_Check(py_on_eom)) - filter_api_on_eom(on_eom); - - py_on_tx_begin = PyObject_GetAttrString(module, "on_tx_begin"); - if (py_on_tx_begin && PyCallable_Check(py_on_tx_begin)) - filter_api_on_tx_begin(on_tx_begin); - - py_on_tx_commit = PyObject_GetAttrString(module, "on_tx_commit"); - if (py_on_tx_commit && PyCallable_Check(py_on_tx_commit)) - filter_api_on_tx_commit(on_tx_commit); - - py_on_tx_rollback = PyObject_GetAttrString(module, "on_tx_rollback"); - if (py_on_tx_rollback && PyCallable_Check(py_on_tx_rollback)) - filter_api_on_tx_rollback(on_tx_rollback); - - py_on_dataline = PyObject_GetAttrString(module, "on_dataline"); - if (py_on_dataline && PyCallable_Check(py_on_dataline)) - filter_api_on_dataline(on_dataline); - - py_on_disconnect = PyObject_GetAttrString(module, "on_disconnect"); - if (py_on_disconnect && PyCallable_Check(py_on_disconnect)) - filter_api_on_disconnect(on_disconnect); - - filter_api_no_chroot(); - if (c) - filter_api_set_chroot(c); - - filter_api_loop(); - log_debug("debug: exiting"); - - Py_Finalize(); - - return 1; -} diff --git a/extras/filters/filter-regex/Makefile.am b/extras/filters/filter-regex/Makefile.am deleted file mode 100644 index 1ed4e7e..0000000 --- a/extras/filters/filter-regex/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-regex - -filter_regex_SOURCES = $(SRCS) -filter_regex_SOURCES += filter_regex.c - -man_MANS = filter-regex.8 filter-regex.conf.5 - -filter-regex.8: filter-regex.8.in - $(SED) -e 's|[@]SYSCONFDIR@|$(sysconfdir)|g' < filter-regex.8.in > "$@" -filter-regex.conf.5: filter-regex.conf.5.in - $(SED) -e 's|[@]SYSCONFDIR@|$(sysconfdir)|g' < filter-regex.conf.5.in > "$@" - -clean-local: - rm -f filter-regex.8 filter-regex.conf.5 diff --git a/extras/filters/filter-regex/filter-regex.8.in b/extras/filters/filter-regex/filter-regex.8.in deleted file mode 100644 index 33ffad3..0000000 --- a/extras/filters/filter-regex/filter-regex.8.in +++ /dev/null @@ -1,90 +0,0 @@ -.\" -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 16 2016 $ -.Dt FILTER-REGEX 8 -.Os -.Sh NAME -.Nm filter-regex -.Nd smtpd filter for regular expression filtering -.Sh SYNOPSIS -.Nm -.Op Fl dv -.Op Fl l Ar limit -.Op Ar file -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to filter mails using regular expressions matching SMTP -session parameters. -.Pp -The options are as follows: -.Bl -tag -width "-l limit" -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl l Ar limit -Set the number of bytes -.Ar limit -after which the regular expression processing is stopped and the mail is -accepted. -The accepted values are within the range of 1 and SIZE_MAX. -.Pp -The default -.Ar limit -value is 0 (unlimited). -.It Fl v -Produce more verbose output. -.El -.Pp -.Nm -runs by default in a chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -Depending if one of the regular expressions matches mails are either accepted -or rejected with a SMTP 554 reply. -Non-matching mails are always accepted. -.Sh FILES -.Bl -tag -width "@SYSCONFDIR@/filter-regex.conf" -compact -.It Pa @SYSCONFDIR@/filter-regex.conf -Default -.Nm -configuration file. -.El -.Sh SEE ALSO -.Xr filter_api 3 , -.Xr regex 3 , -.Xr filter-regex.conf 5 , -.Xr smtpd.conf 5 , -.Xr re_format 7 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Nm -was written in 2015. -.Sh AUTHORS -.An -nosplit -.Nm -was intially written by -.An Armin Wolfermann Aq Mt armin@wolfermann.org -and further improved by -.An Joerg Jung Aq Mt jung@openbsd.org . diff --git a/extras/filters/filter-regex/filter-regex.conf b/extras/filters/filter-regex/filter-regex.conf deleted file mode 100644 index c449d73..0000000 --- a/extras/filters/filter-regex/filter-regex.conf +++ /dev/null @@ -1,26 +0,0 @@ -# opensmptd-extras filter-regex configuration - -# reject a host -#connect ^host\.example\.com$ - -# allow a specific hosts while rejecting the rest of the domain -#connect ! ^allow\.example\.net$ -#connect ^.*\.example\.net$ - -# reject helo with leading or trailing dot, and without dots (non-FQDN) -# skipping address literals -#helo ! ^\[ -#helo ^\. -#helo \.$ -#helo ^[^\.]*$ - -# reject some senders -#mail ^.*@example\.com$ -#mail ^.*@example\.net$ - -# reject some recipients -#rcpt ^.*@example\.org$ - -# reject some content -#dataline ^Content-Type: application/x-msdownload; name="[a-z]*\.[a-z]*" -#dataline (Viagra|Cialis) diff --git a/extras/filters/filter-regex/filter-regex.conf.5.in b/extras/filters/filter-regex/filter-regex.conf.5.in deleted file mode 100644 index fabd928..0000000 --- a/extras/filters/filter-regex/filter-regex.conf.5.in +++ /dev/null @@ -1,126 +0,0 @@ -.\" -.\" Copyright (c) 2015 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 15 2015 $ -.Dt FILTER-REGEX.CONF 5 -.Os -.Sh NAME -.Nm filter-regex.conf -.Nd filter-regex configuration file -.Sh DESCRIPTION -.Nm -is the configuration file for -.Xr filter-regex 8 . -.Pp -The file consists of rules that, when matched, cause -.Xr filter-regex 8 -to reject mails. -.Pp -Comments can be put anywhere in the file using a hash mark -.Pq Sq # , -and extend to the end of the current line. -Emtpy lines and lines starting with -.Sq # -are ignored, as well as leading whitespaces. -.Pp -The syntax of -.Nm -is described below. -.Bl -tag -width Ds -.It Xo -.Ic connect -.Op Ic \&! -.Pf < Ar hostname Ns > -.Xc -Reject the connection if the connection sender's -.Ar hostname -matches the specified regular expressions. -.It Xo -.Ic helo -.Op Ic \&! -.Pf < Ar name Ns > -.Xc -Reject the connection if the sender supplied HELO -.Ar name -matches the specified regular expression. -.It Xo -.Ic mail -.Op Ic \&! -.Pf < Ar address Ns > -.Xc -Reject the mail if the sender supplied MAIL FROM -.Ar address -matches the specified regular expression. -.It Xo -.Ic rcpt -.Op Ic \&! -.Pf < Ar address Ns > -.Xc -Reject the mail if the sender supplied RCPT TO -.Ar address -matches the specified regular expression. -.It Xo -.Ic dataline -.Op Ic \&! -.Pf < Ar line Ns > -.Xc -Reject the mail if a data (header or body) -.Ar line -matches the specified regular expression. -.El -.Sh REGULAR EXPRESSIONS -The regular expressions used in the configuration rules do not need further -escaping. -.Pp -The optional -.Sq \&! -character in front of the regular expression (separated by a whitespace) -reverses the matching result and causes the rule, when matched, to be accepted. -This is considered a negotiation and break operation, thus allows exceptions to -the actual rejection rules. -.Pp -All subsequent argument characters up to the end of the line are taken -literally as the regular expression. -.Pp -See -.Xr re_format 7 -for a detailed description of basic and extended regular expressions. -.Sh EXAMPLES -The default filter-regex.conf file which ships with OpenSMTPD-extras contains -commented examples. -.Sh FILES -.Bl -tag -width "@SYSCONFDIR@/filter-regex.conf" -compact -.It Pa @SYSCONFDIR@/filter-regex.conf -Default -.Xr filter-regex 8 -configuration file. -.El -.Sh SEE ALSO -.Xr filter_api 3 , -.Xr regex 3 , -.Xr smtpd.conf 5 , -.Xr re_format 7 , -.Xr filter-regex 8 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Xr filter-regex 8 -was written in 2015. -.Sh AUTHORS -.Xr filter-regex 8 -was intially written by -.An Armin Wolfermann Aq Mt armin@wolfermann.org -and further improved by -.An Joerg Jung Aq Mt jung@openbsd.org . diff --git a/extras/filters/filter-regex/filter_regex.c b/extras/filters/filter-regex/filter_regex.c deleted file mode 100644 index 02fd36e..0000000 --- a/extras/filters/filter-regex/filter_regex.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2015, Armin Wolfermann <armin@wolfermann.org> - * Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/queue.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <ctype.h> -#include <regex.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#define REGEX_CONF SMTPD_CONFDIR "/filter-regex.conf" - -struct regex { - SIMPLEQ_ENTRY(regex) el; - char *s, n; - regex_t p; -}; - -static SIMPLEQ_HEAD(regex_q, regex) - regex_connect = SIMPLEQ_HEAD_INITIALIZER(regex_connect), - regex_helo = SIMPLEQ_HEAD_INITIALIZER(regex_helo), - regex_mail = SIMPLEQ_HEAD_INITIALIZER(regex_mail), - regex_rcpt = SIMPLEQ_HEAD_INITIALIZER(regex_rcpt), - regex_dataline = SIMPLEQ_HEAD_INITIALIZER(regex_dataline); -static struct { const char *s; struct regex_q *rq; } regex_s[] = { - { "connect", ®ex_connect }, { "helo", ®ex_helo }, - { "mail", ®ex_mail }, { "rcpt", ®ex_rcpt }, - { "dataline", ®ex_dataline }, { NULL, NULL } }; -static size_t regex_limit; - -static int -regex_parse(char *l, size_t no) -{ - struct regex_q *rq = NULL; - struct regex *re; - char *k, buf[BUFSIZ]; - int i, r; - - l = strip(l); - if ((k = strsep(&l, " \t")) == NULL || strlen(k) == 0 || *k == '#') - return 0; /* skip empty or commented line */ - for (i = 0; regex_s[i].s != NULL && rq == NULL; i++) - if (strcmp(k, regex_s[i].s) == 0) - rq = regex_s[i].rq; - if (rq == NULL) { - log_warnx("warn: parse: unknown keyword %s line %lu", k, no); - return -1; - } - if (strlen((l = strip(l))) == 0 || *l == '#') { - log_warnx("warn: parse: missing value line %lu", no); - return -1; - } - re = xcalloc(1, sizeof(struct regex), "parse"); - re->s = xstrdup(l, "parse"); - if ((re->n = (l[0] == '!' && isspace((unsigned char)l[1])))) - l = strip(++l); - if ((r = regcomp(&re->p, l, REG_EXTENDED|REG_NOSUB)) != 0) { - regerror(r, &re->p, buf, sizeof(buf)); - log_warnx("warn: parse: regcomp %s line %lu", buf, no); - free(re->s); - free(re); - return -1; - } - SIMPLEQ_INSERT_TAIL(rq, re, el); - log_debug("debug: parse: %s %s line %lu", k, re->s, no); - return 0; -} - -static int -regex_load(const char *c) -{ - FILE *f; - char *l = NULL; - size_t sz = 0, no = 0; - ssize_t len; - - if ((f = fopen(c, "r")) == NULL) { - log_warn("warn: load: fopen %s", c); - return -1; - } - while ((len = getline(&l, &sz, f)) != -1) { - if (l[len - 1] == '\n') - l[len - 1] = '\0'; - if (regex_parse(l, ++no) == -1) { - free(l); - fclose(f); - return -1; - } - } - if (ferror(f)) { - log_warn("warn: load: getline"); - free(l); - fclose(f); - return -1; - } - free(l); - fclose(f); - return 0; -} - -static int -regex_match(struct regex_q *rq, const char *s) -{ - struct regex *re; - char buf[BUFSIZ]; - int r; - - SIMPLEQ_FOREACH(re, rq, el) { - if ((r = regexec(&re->p, s, 0, NULL, 0)) != 0) { - if (r != REG_NOMATCH) { - regerror(r, &re->p, buf, sizeof(buf)); - log_warnx("warn: match: regexec %s", buf); - } - continue; - } - log_info("info: match: %s to %s", re->s, s); - return (re->n == 0); - } - return 0; -} - -static void -regex_clear(void) -{ - struct regex *re; - int i; - - for (i = 0; regex_s[i].rq != NULL; i++) { - while((re = SIMPLEQ_FIRST(regex_s[i].rq)) != NULL) { - SIMPLEQ_REMOVE_HEAD(regex_s[i].rq, el); - regfree(&re->p); - free(re->s); - free(re); - } - } -} - -static int -regex_on_connect(uint64_t id, struct filter_connect *c) -{ - if (regex_match(®ex_connect, c->hostname)) { - log_warnx("warn: session %016"PRIx64": on_connect: REJECT connect hostname", id); - return filter_api_reject_code(id, FILTER_FAIL, 554, "5.7.1 Hostname rejected"); - } - return filter_api_accept(id); -} - -static int -regex_on_helo(uint64_t id, const char *h) -{ - if (regex_match(®ex_helo, h)) { - log_warnx("warn: session %016"PRIx64": on_helo: REJECT helo hostname", id); - return filter_api_reject_code(id, FILTER_FAIL, 554, "5.7.1 Helo rejected"); - } - return filter_api_accept(id); -} - -static int -regex_on_mail(uint64_t id, struct mailaddr *m) -{ - if (regex_match(®ex_mail, filter_api_mailaddr_to_text(m))) { - log_warnx("warn: session %016"PRIx64": on_mail: REJECT mail from", id); - return filter_api_reject_code(id, FILTER_FAIL, 554, "5.7.1 Sender rejected"); - } - return filter_api_accept(id); -} - -static int -regex_on_rcpt(uint64_t id, struct mailaddr *r) -{ - if (regex_match(®ex_rcpt, filter_api_mailaddr_to_text(r))) { - log_warnx("warn: session %016"PRIx64": on_rcpt: REJECT rcpt to", id); - return filter_api_reject_code(id, FILTER_FAIL, 554, "5.7.1 Recipient rejected"); - } - return filter_api_accept(id); -} - -static void -regex_on_dataline(uint64_t id, const char *l) -{ - struct { int m; size_t l; } *u; - - filter_api_writeln(id, l); - if ((u = filter_api_get_udata(id)) == NULL) { - u = xcalloc(1, sizeof(*u), "on_dataline"); - filter_api_set_udata(id, u); - } - u->l += strlen(l); - if (u->m || (regex_limit && u->l >= regex_limit)) - return; - u->m = regex_match(®ex_dataline, l); -} - -static int -regex_on_eom(uint64_t id, size_t size) -{ - int *m; - - if ((m = filter_api_get_udata(id)) == NULL) - return filter_api_accept(id); - if (*m) { - log_warnx("warn: session %016"PRIx64": on_eom: REJECT dataline", id); - return filter_api_reject_code(id, FILTER_CLOSE, 554, "5.7.1 Message content rejected"); - } - return filter_api_accept(id); -} - -static void -regex_on_tx_commit(uint64_t id) -{ - free(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -static void -regex_on_tx_rollback(uint64_t id) -{ - free(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - const char *errstr, *l = NULL; - - log_init(1); - - while ((ch = getopt(argc, argv, "dl:v")) != -1) { - switch (ch) { - case 'd': - d = 1; - break; - case 'l': - l = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - if (argc > 1) - fatalx("bogus argument(s)"); - - if (l) { - regex_limit = strtonum(l, 1, UINT_MAX, &errstr); /* todo: SIZE_MAX here? */ - if (errstr) - fatalx("limit option is %s: %s", errstr, l); - } - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - if (regex_load((argc == 1) ? argv[0] : REGEX_CONF) == -1) - fatalx("configuration failed"); - - filter_api_on_connect(regex_on_connect); - filter_api_on_helo(regex_on_helo); - filter_api_on_mail(regex_on_mail); - filter_api_on_rcpt(regex_on_rcpt); - filter_api_on_dataline(regex_on_dataline); - filter_api_on_eom(regex_on_eom); - filter_api_on_tx_commit(regex_on_tx_commit); - filter_api_on_tx_rollback(regex_on_tx_rollback); - - filter_api_loop(); - regex_clear(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-rspamd/Makefile.am b/extras/filters/filter-rspamd/Makefile.am deleted file mode 100644 index a01d3b6..0000000 --- a/extras/filters/filter-rspamd/Makefile.am +++ /dev/null @@ -1,13 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-rspamd - -filter_rspamd_SOURCES = $(SRCS) -filter_rspamd_SOURCES += filter_rspamd.c -filter_rspamd_SOURCES += rspamd.c -filter_rspamd_SOURCES += json.c -filter_rspamd_SOURCES += fixme.c - -LDFLAGS += -lm diff --git a/extras/filters/filter-rspamd/filter_rspamd.c b/extras/filters/filter-rspamd/filter_rspamd.c deleted file mode 100644 index f4c3bbd..0000000 --- a/extras/filters/filter-rspamd/filter_rspamd.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2016 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <limits.h> -#include <stdlib.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#include "rspamd.h" - - -static int -on_connect(uint64_t id, struct filter_connect *conn) -{ - struct session *rs = filter_api_session(id); - const char *ip; - - ip = filter_api_sockaddr_to_text((struct sockaddr *)&conn->local); - if (! session_set_ip(rs, ip ? ip : "127.0.0.1")) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - if (! session_set_hostname(rs, conn->hostname)) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - return filter_api_accept(id); -} - -static int -on_helo(uint64_t id, const char *helo) -{ - struct session *rs = filter_api_session(id); - - if (! session_set_helo(rs, helo)) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - return filter_api_accept(id); -} - -static int -on_mail(uint64_t id, struct mailaddr *mail) -{ - struct transaction *tx = filter_api_transaction(id); - const char *address; - - address = filter_api_mailaddr_to_text(mail); - if (! transaction_set_from(tx, address)) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - return filter_api_accept(id); -} - -static int -on_rcpt(uint64_t id, struct mailaddr *rcpt) -{ - struct transaction *tx = filter_api_transaction(id); - const char *address; - - address = filter_api_mailaddr_to_text(rcpt); - if (! transaction_add_rcpt(tx, address)) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - return filter_api_accept(id); -} - -static int -on_data(uint64_t id) -{ - struct transaction *tx = filter_api_transaction(id); - - if (! rspamd_connect(tx)) - return filter_api_reject_code(id, FILTER_FAIL, 421, - "temporary failure"); - - /* accept/reject is called from rspamd.c */ - return 1; -} - -static void -on_dataline(uint64_t id, const char *line) -{ - struct transaction *tx = filter_api_transaction(id); - - rspamd_send_chunk(tx, line); -} - -static int -on_eom(uint64_t id, size_t size) -{ - struct transaction *tx = filter_api_transaction(id); - - rspamd_send_chunk(tx, NULL); - - /* accept/reject is called from rspamd.c */ - return 1; -} - -int -main(int argc, char **argv) -{ - int ch, C = 0, d = 0, v = 0; - const char *l = NULL; - char *c = NULL, *h = RSPAMD_HOST, *p = RSPAMD_PORT, *s = NULL; - - log_init(1); - - while ((ch = getopt(argc, argv, "dh:l:p:s:v")) != -1) { - switch (ch) { - case 'C': - C = 1; - break; - case 'c': - c = optarg; - break; - case 'd': - d = 1; - break; - case 'h': - h = optarg; - break; - case 'l': - l = optarg; - break; - case 'p': - p = optarg; - break; - case 's': - s = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (c) - c = strip(c); - if (h) - h = strip(h); - if (p) - p = strip(p); - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - - rspamd_resolve(h, p); - - filter_api_on_connect(on_connect); - filter_api_on_helo(on_helo); - filter_api_on_mail(on_mail); - filter_api_on_rcpt(on_rcpt); - filter_api_on_data(on_data); - filter_api_on_dataline(on_dataline); - filter_api_on_eom(on_eom); - - filter_api_session_allocator(session_allocator); - filter_api_session_destructor(session_destructor); - - filter_api_transaction_allocator(transaction_allocator); - filter_api_transaction_destructor(transaction_destructor); - - filter_api_data_buffered(); - - /* - if (c) - filter_api_set_chroot(c); - if (C) - filter_api_no_chroot(); - */ - filter_api_no_chroot(); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} diff --git a/extras/filters/filter-rspamd/fixme.c b/extras/filters/filter-rspamd/fixme.c deleted file mode 100644 index 74c5a55..0000000 --- a/extras/filters/filter-rspamd/fixme.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2016 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <limits.h> -#include <stdlib.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#include "rspamd.h" - -struct sockaddr_storage ss; - - -/* XXX - * this needs to be handled differently, but lets focus on the filter for now - */ -void -rspamd_resolve(const char *h, const char *p) -{ - struct addrinfo hints, *addresses, *ai; - int fd, r; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - if ((r = getaddrinfo(h, p, &hints, &addresses))) - fatalx("resolve: getaddrinfo %s", gai_strerror(r)); - for (ai = addresses; ai; ai = ai->ai_next) { - if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) - continue; - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) { - close(fd); - continue; - } - close(fd); - memmove(&ss, ai->ai_addr, ai->ai_addrlen); - break; - } - freeaddrinfo(addresses); - if (!ai) - fatalx("resolve: failed"); -} diff --git a/extras/filters/filter-rspamd/json.c b/extras/filters/filter-rspamd/json.c deleted file mode 100644 index ea975e8..0000000 --- a/extras/filters/filter-rspamd/json.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "json.h" - -#ifdef _MSC_VER - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif -#endif - -const struct _json_value json_value_none; - -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <math.h> - -typedef unsigned int json_uchar; - -static unsigned char hex_value (json_char c) -{ - if (isdigit(c)) - return c - '0'; - - switch (c) { - case 'a': case 'A': return 0x0A; - case 'b': case 'B': return 0x0B; - case 'c': case 'C': return 0x0C; - case 'd': case 'D': return 0x0D; - case 'e': case 'E': return 0x0E; - case 'f': case 'F': return 0x0F; - default: return 0xFF; - } -} - -typedef struct -{ - unsigned long used_memory; - - unsigned int uint_max; - unsigned long ulong_max; - - json_settings settings; - int first_pass; - - const json_char * ptr; - unsigned int cur_line, cur_col; - -} json_state; - -static void * default_alloc (size_t size, int zero, void * user_data) -{ - return zero ? calloc (1, size) : malloc (size); -} - -static void default_free (void * ptr, void * user_data) -{ - free (ptr); -} - -static void * json_alloc (json_state * state, unsigned long size, int zero) -{ - if ((state->ulong_max - state->used_memory) < size) - return 0; - - if (state->settings.max_memory - && (state->used_memory += size) > state->settings.max_memory) - { - return 0; - } - - return state->settings.mem_alloc (size, zero, state->settings.user_data); -} - -static int new_value (json_state * state, - json_value ** top, json_value ** root, json_value ** alloc, - json_type type) -{ - json_value * value; - int values_size; - - if (!state->first_pass) - { - value = *top = *alloc; - *alloc = (*alloc)->_reserved.next_alloc; - - if (!*root) - *root = value; - - switch (value->type) - { - case json_array: - - if (value->u.array.length == 0) - break; - - if (! (value->u.array.values = (json_value **) json_alloc - (state, value->u.array.length * sizeof (json_value *), 0)) ) - { - return 0; - } - - value->u.array.length = 0; - break; - - case json_object: - - if (value->u.object.length == 0) - break; - - values_size = sizeof (*value->u.object.values) * value->u.object.length; - - if (! (value->u.object.values = (json_object_entry *) json_alloc - (state, values_size + ((unsigned long) value->u.object.values), 0)) ) - { - return 0; - } - - value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; - - value->u.object.length = 0; - break; - - case json_string: - - if (! (value->u.string.ptr = (json_char *) json_alloc - (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) - { - return 0; - } - - value->u.string.length = 0; - break; - - default: - break; - }; - - return 1; - } - - if (! (value = (json_value *) json_alloc - (state, sizeof (json_value) + state->settings.value_extra, 1))) - { - return 0; - } - - if (!*root) - *root = value; - - value->type = type; - value->parent = *top; - - #ifdef JSON_TRACK_SOURCE - value->line = state->cur_line; - value->col = state->cur_col; - #endif - - if (*alloc) - (*alloc)->_reserved.next_alloc = value; - - *alloc = *top = value; - - return 1; -} - -#define whitespace \ - case '\n': ++ state.cur_line; state.cur_col = 0; \ - case ' ': case '\t': case '\r' - -#define string_add(b) \ - do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); - -#define line_and_col \ - state.cur_line, state.cur_col - -static const long - flag_next = 1 << 0, - flag_reproc = 1 << 1, - flag_need_comma = 1 << 2, - flag_seek_value = 1 << 3, - flag_escaped = 1 << 4, - flag_string = 1 << 5, - flag_need_colon = 1 << 6, - flag_done = 1 << 7, - flag_num_negative = 1 << 8, - flag_num_zero = 1 << 9, - flag_num_e = 1 << 10, - flag_num_e_got_sign = 1 << 11, - flag_num_e_negative = 1 << 12, - flag_line_comment = 1 << 13, - flag_block_comment = 1 << 14; - -json_value * json_parse_ex (json_settings * settings, - const json_char * json, - size_t length, - char * error_buf) -{ - json_char error [json_error_max]; - const json_char * end; - json_value * top, * root, * alloc = 0; - json_state state = { 0 }; - long flags; - long num_digits = 0, num_e = 0; - json_int_t num_fraction = 0; - - /* Skip UTF-8 BOM - */ - if (length >= 3 && ((unsigned char) json [0]) == 0xEF - && ((unsigned char) json [1]) == 0xBB - && ((unsigned char) json [2]) == 0xBF) - { - json += 3; - length -= 3; - } - - error[0] = '\0'; - end = (json + length); - - memcpy (&state.settings, settings, sizeof (json_settings)); - - if (!state.settings.mem_alloc) - state.settings.mem_alloc = default_alloc; - - if (!state.settings.mem_free) - state.settings.mem_free = default_free; - - memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); - memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); - - state.uint_max -= 8; /* limit of how much can be added before next check */ - state.ulong_max -= 8; - - for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) - { - json_uchar uchar; - unsigned char uc_b1, uc_b2, uc_b3, uc_b4; - json_char * string = 0; - unsigned int string_length = 0; - - top = root = 0; - flags = flag_seek_value; - - state.cur_line = 1; - - for (state.ptr = json ;; ++ state.ptr) - { - json_char b = (state.ptr == end ? 0 : *state.ptr); - - if (flags & flag_string) - { - if (!b) - { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col); - goto e_failed; - } - - if (string_length > state.uint_max) - goto e_overflow; - - if (flags & flag_escaped) - { - flags &= ~ flag_escaped; - - switch (b) - { - case 'b': string_add ('\b'); break; - case 'f': string_add ('\f'); break; - case 'n': string_add ('\n'); break; - case 'r': string_add ('\r'); break; - case 't': string_add ('\t'); break; - case 'u': - - if (end - state.ptr < 4 || - (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) - { - sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar = (uc_b1 << 8) | uc_b2; - - if ((uchar & 0xF800) == 0xD800) { - json_uchar uchar2; - - if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || - (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || - (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) - { - sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar2 = (uc_b1 << 8) | uc_b2; - - uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); - } - - if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) - { - string_add ((json_char) uchar); - break; - } - - if (uchar <= 0x7FF) - { - if (state.first_pass) - string_length += 2; - else - { string [string_length ++] = 0xC0 | (uchar >> 6); - string [string_length ++] = 0x80 | (uchar & 0x3F); - } - - break; - } - - if (uchar <= 0xFFFF) { - if (state.first_pass) - string_length += 3; - else - { string [string_length ++] = 0xE0 | (uchar >> 12); - string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); - string [string_length ++] = 0x80 | (uchar & 0x3F); - } - - break; - } - - if (state.first_pass) - string_length += 4; - else - { string [string_length ++] = 0xF0 | (uchar >> 18); - string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); - string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); - string [string_length ++] = 0x80 | (uchar & 0x3F); - } - - break; - - default: - string_add (b); - }; - - continue; - } - - if (b == '\\') - { - flags |= flag_escaped; - continue; - } - - if (b == '"') - { - if (!state.first_pass) - string [string_length] = 0; - - flags &= ~ flag_string; - string = 0; - - switch (top->type) - { - case json_string: - - top->u.string.length = string_length; - flags |= flag_next; - - break; - - case json_object: - - if (state.first_pass) - (*(json_char **) &top->u.object.values) += string_length + 1; - else - { - top->u.object.values [top->u.object.length].name - = (json_char *) top->_reserved.object_mem; - - top->u.object.values [top->u.object.length].name_length - = string_length; - - (*(json_char **) &top->_reserved.object_mem) += string_length + 1; - } - - flags |= flag_seek_value | flag_need_colon; - continue; - - default: - break; - }; - } - else - { - string_add (b); - continue; - } - } - - if (state.settings.settings & json_enable_comments) - { - if (flags & (flag_line_comment | flag_block_comment)) - { - if (flags & flag_line_comment) - { - if (b == '\r' || b == '\n' || !b) - { - flags &= ~ flag_line_comment; - -- state.ptr; /* so null can be reproc'd */ - } - - continue; - } - - if (flags & flag_block_comment) - { - if (!b) - { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col); - goto e_failed; - } - - if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') - { - flags &= ~ flag_block_comment; - ++ state.ptr; /* skip closing sequence */ - } - - continue; - } - } - else if (b == '/') - { - if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) - { sprintf (error, "%d:%d: Comment not allowed here", line_and_col); - goto e_failed; - } - - if (++ state.ptr == end) - { sprintf (error, "%d:%d: EOF unexpected", line_and_col); - goto e_failed; - } - - switch (b = *state.ptr) - { - case '/': - flags |= flag_line_comment; - continue; - - case '*': - flags |= flag_block_comment; - continue; - - default: - sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b); - goto e_failed; - }; - } - } - - if (flags & flag_done) - { - if (!b) - break; - - switch (b) - { - whitespace: - continue; - - default: - - sprintf (error, "%d:%d: Trailing garbage: `%c`", - state.cur_line, state.cur_col, b); - - goto e_failed; - }; - } - - if (flags & flag_seek_value) - { - switch (b) - { - whitespace: - continue; - - case ']': - - if (top && top->type == json_array) - flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; - else - { sprintf (error, "%d:%d: Unexpected ]", line_and_col); - goto e_failed; - } - - break; - - default: - - if (flags & flag_need_comma) - { - if (b == ',') - { flags &= ~ flag_need_comma; - continue; - } - else - { - sprintf (error, "%d:%d: Expected , before %c", - state.cur_line, state.cur_col, b); - - goto e_failed; - } - } - - if (flags & flag_need_colon) - { - if (b == ':') - { flags &= ~ flag_need_colon; - continue; - } - else - { - sprintf (error, "%d:%d: Expected : before %c", - state.cur_line, state.cur_col, b); - - goto e_failed; - } - } - - flags &= ~ flag_seek_value; - - switch (b) - { - case '{': - - if (!new_value (&state, &top, &root, &alloc, json_object)) - goto e_alloc_failure; - - continue; - - case '[': - - if (!new_value (&state, &top, &root, &alloc, json_array)) - goto e_alloc_failure; - - flags |= flag_seek_value; - continue; - - case '"': - - if (!new_value (&state, &top, &root, &alloc, json_string)) - goto e_alloc_failure; - - flags |= flag_string; - - string = top->u.string.ptr; - string_length = 0; - - continue; - - case 't': - - if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || - *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') - { - goto e_unknown_value; - } - - if (!new_value (&state, &top, &root, &alloc, json_boolean)) - goto e_alloc_failure; - - top->u.boolean = 1; - - flags |= flag_next; - break; - - case 'f': - - if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || - *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || - *(++ state.ptr) != 'e') - { - goto e_unknown_value; - } - - if (!new_value (&state, &top, &root, &alloc, json_boolean)) - goto e_alloc_failure; - - flags |= flag_next; - break; - - case 'n': - - if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || - *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') - { - goto e_unknown_value; - } - - if (!new_value (&state, &top, &root, &alloc, json_null)) - goto e_alloc_failure; - - flags |= flag_next; - break; - - default: - - if (isdigit (b) || b == '-') - { - if (!new_value (&state, &top, &root, &alloc, json_integer)) - goto e_alloc_failure; - - if (!state.first_pass) - { - while (isdigit (b) || b == '+' || b == '-' - || b == 'e' || b == 'E' || b == '.') - { - if ( (++ state.ptr) == end) - { - b = 0; - break; - } - - b = *state.ptr; - } - - flags |= flag_next | flag_reproc; - break; - } - - flags &= ~ (flag_num_negative | flag_num_e | - flag_num_e_got_sign | flag_num_e_negative | - flag_num_zero); - - num_digits = 0; - num_fraction = 0; - num_e = 0; - - if (b != '-') - { - flags |= flag_reproc; - break; - } - - flags |= flag_num_negative; - continue; - } - else - { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b); - goto e_failed; - } - }; - }; - } - else - { - switch (top->type) - { - case json_object: - - switch (b) - { - whitespace: - continue; - - case '"': - - if (flags & flag_need_comma) - { sprintf (error, "%d:%d: Expected , before \"", line_and_col); - goto e_failed; - } - - flags |= flag_string; - - string = (json_char *) top->_reserved.object_mem; - string_length = 0; - - break; - - case '}': - - flags = (flags & ~ flag_need_comma) | flag_next; - break; - - case ',': - - if (flags & flag_need_comma) - { - flags &= ~ flag_need_comma; - break; - } - - default: - sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b); - goto e_failed; - }; - - break; - - case json_integer: - case json_double: - - if (isdigit (b)) - { - ++ num_digits; - - if (top->type == json_integer || flags & flag_num_e) - { - if (! (flags & flag_num_e)) - { - if (flags & flag_num_zero) - { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b); - goto e_failed; - } - - if (num_digits == 1 && b == '0') - flags |= flag_num_zero; - } - else - { - flags |= flag_num_e_got_sign; - num_e = (num_e * 10) + (b - '0'); - continue; - } - - top->u.integer = (top->u.integer * 10) + (b - '0'); - continue; - } - - num_fraction = (num_fraction * 10) + (b - '0'); - continue; - } - - if (b == '+' || b == '-') - { - if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) - { - flags |= flag_num_e_got_sign; - - if (b == '-') - flags |= flag_num_e_negative; - - continue; - } - } - else if (b == '.' && top->type == json_integer) - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col); - goto e_failed; - } - - top->type = json_double; - top->u.dbl = (double) top->u.integer; - - num_digits = 0; - continue; - } - - if (! (flags & flag_num_e)) - { - if (top->type == json_double) - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col); - goto e_failed; - } - - top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits)); - } - - if (b == 'e' || b == 'E') - { - flags |= flag_num_e; - - if (top->type == json_integer) - { - top->type = json_double; - top->u.dbl = (double) top->u.integer; - } - - num_digits = 0; - flags &= ~ flag_num_zero; - - continue; - } - } - else - { - if (!num_digits) - { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col); - goto e_failed; - } - - top->u.dbl *= pow (10.0, (double) - (flags & flag_num_e_negative ? - num_e : num_e)); - } - - if (flags & flag_num_negative) - { - if (top->type == json_integer) - top->u.integer = - top->u.integer; - else - top->u.dbl = - top->u.dbl; - } - - flags |= flag_next | flag_reproc; - break; - - default: - break; - }; - } - - if (flags & flag_reproc) - { - flags &= ~ flag_reproc; - -- state.ptr; - } - - if (flags & flag_next) - { - flags = (flags & ~ flag_next) | flag_need_comma; - - if (!top->parent) - { - /* root value done */ - - flags |= flag_done; - continue; - } - - if (top->parent->type == json_array) - flags |= flag_seek_value; - - if (!state.first_pass) - { - json_value * parent = top->parent; - - switch (parent->type) - { - case json_object: - - parent->u.object.values - [parent->u.object.length].value = top; - - break; - - case json_array: - - parent->u.array.values - [parent->u.array.length] = top; - - break; - - default: - break; - }; - } - - if ( (++ top->parent->u.array.length) > state.uint_max) - goto e_overflow; - - top = top->parent; - - continue; - } - } - - alloc = root; - } - - return root; - -e_unknown_value: - - sprintf (error, "%d:%d: Unknown value", line_and_col); - goto e_failed; - -e_alloc_failure: - - strlcpy (error, "Memory allocation failure", sizeof error); - goto e_failed; - -e_overflow: - - sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col); - goto e_failed; - -e_failed: - - if (error_buf) - { - if (*error) - strcpy (error_buf, error); - else - strcpy (error_buf, "Unknown error"); - } - - if (state.first_pass) - alloc = root; - - while (alloc) - { - top = alloc->_reserved.next_alloc; - state.settings.mem_free (alloc, state.settings.user_data); - alloc = top; - } - - if (!state.first_pass) - json_value_free_ex (&state.settings, root); - - return 0; -} - -json_value * json_parse (const json_char * json, size_t length) -{ - json_settings settings = { 0 }; - return json_parse_ex (&settings, json, length, 0); -} - -void json_value_free_ex (json_settings * settings, json_value * value) -{ - json_value * cur_value; - - if (!value) - return; - - value->parent = 0; - - while (value) - { - switch (value->type) - { - case json_array: - - if (!value->u.array.length) - { - settings->mem_free (value->u.array.values, settings->user_data); - break; - } - - value = value->u.array.values [-- value->u.array.length]; - continue; - - case json_object: - - if (!value->u.object.length) - { - settings->mem_free (value->u.object.values, settings->user_data); - break; - } - - value = value->u.object.values [-- value->u.object.length].value; - continue; - - case json_string: - - settings->mem_free (value->u.string.ptr, settings->user_data); - break; - - default: - break; - }; - - cur_value = value; - value = value->parent; - settings->mem_free (cur_value, settings->user_data); - } -} - -void json_value_free (json_value * value) -{ - json_settings settings = { 0 }; - settings.mem_free = default_free; - json_value_free_ex (&settings, value); -} - diff --git a/extras/filters/filter-rspamd/json.h b/extras/filters/filter-rspamd/json.h deleted file mode 100644 index f6549ec..0000000 --- a/extras/filters/filter-rspamd/json.h +++ /dev/null @@ -1,283 +0,0 @@ - -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. - * https://github.com/udp/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _JSON_H -#define _JSON_H - -#ifndef json_char - #define json_char char -#endif - -#ifndef json_int_t - #ifndef _MSC_VER - #include <inttypes.h> - #define json_int_t int64_t - #else - #define json_int_t __int64 - #endif -#endif - -#include <stdlib.h> - -#ifdef __cplusplus - - #include <string.h> - - extern "C" - { - -#endif - -typedef struct -{ - unsigned long max_memory; - int settings; - - /* Custom allocator support (leave null to use malloc/free) - */ - - void * (* mem_alloc) (size_t, int zero, void * user_data); - void (* mem_free) (void *, void * user_data); - - void * user_data; /* will be passed to mem_alloc and mem_free */ - - size_t value_extra; /* how much extra space to allocate for values? */ - -} json_settings; - -#define json_enable_comments 0x01 - -typedef enum -{ - json_none, - json_object, - json_array, - json_integer, - json_double, - json_string, - json_boolean, - json_null - -} json_type; - -extern const struct _json_value json_value_none; - -typedef struct _json_object_entry -{ - json_char * name; - unsigned int name_length; - - struct _json_value * value; - -} json_object_entry; - -typedef struct _json_value -{ - struct _json_value * parent; - - json_type type; - - union - { - int boolean; - json_int_t integer; - double dbl; - - struct - { - unsigned int length; - json_char * ptr; /* null terminated */ - - } string; - - struct - { - unsigned int length; - - json_object_entry * values; - - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const - { return values; - } - decltype(values) end () const - { return values + length; - } - #endif - - } object; - - struct - { - unsigned int length; - struct _json_value ** values; - - #if defined(__cplusplus) && __cplusplus >= 201103L - decltype(values) begin () const - { return values; - } - decltype(values) end () const - { return values + length; - } - #endif - - } array; - - } u; - - union - { - struct _json_value * next_alloc; - void * object_mem; - - } _reserved; - - #ifdef JSON_TRACK_SOURCE - - /* Location of the value in the source JSON - */ - unsigned int line, col; - - #endif - - - /* Some C++ operator sugar */ - - #ifdef __cplusplus - - public: - - inline _json_value () - { memset (this, 0, sizeof (_json_value)); - } - - inline const struct _json_value &operator [] (int index) const - { - if (type != json_array || index < 0 - || ((unsigned int) index) >= u.array.length) - { - return json_value_none; - } - - return *u.array.values [index]; - } - - inline const struct _json_value &operator [] (const char * index) const - { - if (type != json_object) - return json_value_none; - - for (unsigned int i = 0; i < u.object.length; ++ i) - if (!strcmp (u.object.values [i].name, index)) - return *u.object.values [i].value; - - return json_value_none; - } - - inline operator const char * () const - { - switch (type) - { - case json_string: - return u.string.ptr; - - default: - return ""; - }; - } - - inline operator json_int_t () const - { - switch (type) - { - case json_integer: - return u.integer; - - case json_double: - return (json_int_t) u.dbl; - - default: - return 0; - }; - } - - inline operator bool () const - { - if (type != json_boolean) - return false; - - return u.boolean != 0; - } - - inline operator double () const - { - switch (type) - { - case json_integer: - return (double) u.integer; - - case json_double: - return u.dbl; - - default: - return 0; - }; - } - - #endif - -} json_value; - -json_value * json_parse (const json_char * json, - size_t length); - -#define json_error_max 128 -json_value * json_parse_ex (json_settings * settings, - const json_char * json, - size_t length, - char * error); - -void json_value_free (json_value *); - - -/* Not usually necessary, unless you used a custom mem_alloc and now want to - * use a custom mem_free. - */ -void json_value_free_ex (json_settings * settings, - json_value *); - - -#ifdef __cplusplus - } /* extern "C" */ -#endif - -#endif - - diff --git a/extras/filters/filter-rspamd/rspamd.c b/extras/filters/filter-rspamd/rspamd.c deleted file mode 100644 index 76cbbbe..0000000 --- a/extras/filters/filter-rspamd/rspamd.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (c) 2016 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <limits.h> -#include <stdlib.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#include "rspamd.h" -#include "json.h" - -extern struct sockaddr_storage ss; - -void * -session_allocator(uint64_t id) -{ - return xcalloc(1, sizeof (struct session), "on_connect"); -} - -void -session_destructor(void *ctx) -{ - struct session *rs = ctx; - - free(rs->ip); - free(rs->hostname); - free(rs->helo); - free(rs); -} - -void * -transaction_allocator(uint64_t id) -{ - struct transaction *tx; - - tx = xcalloc(1, sizeof *tx, "transaction_allocator"); - tx->id = id; - - iobuf_xinit(&tx->iobuf, LINE_MAX, LINE_MAX, "on_eom"); - io_init(&tx->io, -1, tx, rspamd_io, &tx->iobuf); - - dict_init(&tx->rcpts); - - return tx; -} - -void -transaction_destructor(void *ctx) -{ - struct transaction *tx = ctx; - void *data; - - iobuf_clear(&tx->iobuf); - io_clear(&tx->io); - - if (tx->from) - free(tx->from); - if (tx->rspamd.body) - free(tx->rspamd.body); - if (tx->rspamd.subject) - free(tx->rspamd.subject); - - tx->eom = 0; - tx->from = NULL; - tx->rspamd.body = NULL; - tx->rspamd.subject = NULL; - - while (dict_poproot(&tx->rcpts, &data)) - ; - - free(tx); -} - - -int -session_set_helo(struct session *s, const char *helo) -{ - return ((s->helo = strdup(helo)) != NULL); -} - -int -session_set_ip(struct session *s, const char *ip) -{ - return ((s->ip = strdup(ip)) != NULL); -} - -int -session_set_hostname(struct session *s, const char *hostname) -{ - return ((s->hostname = strdup(hostname)) != NULL); -} - -int -transaction_set_from(struct transaction *t, const char *from) -{ - return ((t->from = strdup(from)) != NULL); -} - -int -transaction_add_rcpt(struct transaction *t, const char *rcpt) -{ - /* XXX - not the best data structure */ - dict_set(&t->rcpts, rcpt, NULL); - return 1; -} - - -int -rspamd_connect(struct transaction *tx) -{ - return (io_connect(&tx->io, (struct sockaddr *)&ss, NULL) != -1); -} - -void -rspamd_disconnect(struct transaction *tx) -{ - iobuf_clear(&tx->iobuf); - io_clear(&tx->io); -} - -void -rspamd_connected(struct transaction *tx) -{ - /* answer to DATA phase */ - filter_api_accept(tx->id); -} - -void -rspamd_error(struct transaction *tx) -{ - filter_api_reject_code(tx->id, FILTER_FAIL, 421, "temporary failure"); -} - -void -rspamd_send_query(struct transaction *tx) -{ - struct session *rs = filter_api_session(tx->id); - void *iter; - const char *key; - - iobuf_xfqueue(&tx->iobuf, "io", - "POST /check HTTP/1.0\r\n" - "Transfer-Encoding: chunked\r\n" - "Pass: all\r\n" - "IP: %s\r\n" - "Helo: %s\r\n" - "Hostname: %s\r\n" - "From: %s\r\n", - rs->ip, - rs->helo, - rs->hostname, - tx->from); - - iter = NULL; - while (dict_iter(&tx->rcpts, &iter, &key, NULL)) - iobuf_xfqueue(&tx->iobuf, "io", "Rcpt: %s\r\n", key); - iobuf_xfqueue(&tx->iobuf, "io", "\r\n"); - io_reload(&tx->io); -} - -void -rspamd_send_chunk(struct transaction *tx, const char *line) -{ - if (line) - iobuf_xfqueue(&tx->iobuf, "io", "%x\r\n%s\r\n\r\n", - strlen(line)+2, line); - else { - iobuf_xfqueue(&tx->iobuf, "io", "0\r\n\r\n"); - tx->eom = 1; - } - - io_reload(&tx->io); -} - -void -rspamd_read_response(struct transaction *tx) -{ - char *line; - - while ((line = iobuf_getline(&tx->iobuf, NULL))) - if (strlen(line) == 0) - tx->rspamd.eoh = 1; - - if (tx->rspamd.eoh) - if (iobuf_len(&tx->iobuf) != 0) { - tx->rspamd.body = xmemdup(iobuf_data(&tx->iobuf), - iobuf_len(&tx->iobuf) + 1, "rspamd_read_response"); - tx->rspamd.body[iobuf_len(&tx->iobuf)] = 0; - } - - iobuf_normalize(&tx->iobuf); -} - -/* XXX this can certainly be cleaned up */ -int -rspamd_parse_response(struct transaction *tx) -{ - json_value *jv = NULL; - json_value *def = NULL; - char *name; - json_value *val; - size_t i; - - if (tx->rspamd.body == NULL) - goto fail; - - jv = json_parse(tx->rspamd.body, strlen(tx->rspamd.body)); - if (jv == NULL || jv->type != json_object) - goto fail; - - for (i = 0; i < jv->u.object.length; ++i) - if (strcmp(jv->u.object.values[i].name, "default") == 0) { - def = jv->u.object.values[i].value; - break; - } - if (def == NULL) - goto fail; - - for (i = 0; i < def->u.object.length; ++i) { - name = def->u.object.values[i].name; - - if (strcmp(name, "is_spam") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_boolean) - goto fail; - tx->rspamd.is_spam = val->u.boolean; - } - else if (strcmp(name, "is_skipped") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_boolean) - goto fail; - tx->rspamd.is_skipped = val->u.boolean; - } - else if (strcmp(name, "score") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_double) - goto fail; - tx->rspamd.score = val->u.dbl; - } - else if (strcmp(name, "required_score") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_double) - goto fail; - tx->rspamd.required_score = val->u.dbl; - } - else if (strcmp(name, "action") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_string) - goto fail; - if (strncmp(val->u.string.ptr, "no action", - val->u.string.length) == 0) - tx->rspamd.action = NO_ACTION; - else if (strncmp(val->u.string.ptr, "greylist", - val->u.string.length) == 0) - tx->rspamd.action = GREYLIST; - else if (strncmp(val->u.string.ptr, "add header", - val->u.string.length) == 0) - tx->rspamd.action = ADD_HEADER; - else if (strncmp(val->u.string.ptr, "rewrite subject", - val->u.string.length) == 0) - tx->rspamd.action = REWRITE_SUBJECT; - else if (strncmp(val->u.string.ptr, "soft reject", - val->u.string.length) == 0) - tx->rspamd.action = SOFT_REJECT; - else if (strncmp(val->u.string.ptr, "reject", - val->u.string.length) == 0) - tx->rspamd.action = REJECT; - } - else if (strcmp(name, "subject") == 0) { - val = def->u.object.values[i].value; - if (val->type != json_string) - goto fail; - tx->rspamd.subject = xmemdup(val->u.string.ptr, - val->u.string.length, "rspamd_parse_result"); - } - } - - json_value_free(jv); - return 1; - -fail: - if (jv) - json_value_free(jv); - return 0; -} - -void -rspamd_spam_headers(struct transaction *tx) -{ - filter_api_header_add(tx->id, "X-Spam-Flag", "%s", - tx->rspamd.is_spam ? "Yes" : "No"); - filter_api_header_add(tx->id, "X-Spam-Score", "%.2f", - tx->rspamd.score); -} - -int -rspamd_proceed(struct transaction *tx) -{ - if (! rspamd_parse_response(tx)) - return 0; - - switch (tx->rspamd.action) { - case NO_ACTION: - return 1; - - case SOFT_REJECT: - filter_api_reject_code(tx->id, FILTER_FAIL, 421, - "message content rejected"); - return 0; - - case GREYLIST: - /* XXX - don't greylist until filter is finished */ - /* - filter_api_reject_code(tx->id, FILTER_FAIL, 421, - "greylisted"); - return 0; - */ - return 1; - - case REJECT: - filter_api_reject_code(tx->id, FILTER_FAIL, 550, - "message content rejected"); - return 0; - - case ADD_HEADER: - /* insert header */ - rspamd_spam_headers(tx); - return 1; - - case REWRITE_SUBJECT: - /* rewrite subject */ - return 1; - } - - filter_api_reject_code(tx->id, FILTER_FAIL, 550, - "server internal error"); - return 0; -} - - -void -rspamd_io(struct io *io, int evt) -{ - struct transaction *tx = io->arg; - - switch (evt) { - case IO_CONNECTED: - rspamd_connected(tx); - rspamd_send_query(tx); - io_set_write(io); - return; - - case IO_LOWAT: - /* we've hit EOM and no more data, toggle to read */ - if (tx->eom) - io_set_read(io); - return; - - case IO_DATAIN: - rspamd_read_response(tx); - return; - - case IO_DISCONNECTED: - rspamd_disconnect(tx); - - /* we're done with rspamd, if there was a local error - * during transaction, reject now, else move forward. - */ - if (! rspamd_proceed(tx)) - goto fail; - - filter_api_data_buffered_stream(tx->id); - return; - - case IO_TIMEOUT: - case IO_ERROR: - default: - break; - } - -fail: - rspamd_error(tx); - return; -} diff --git a/extras/filters/filter-rspamd/rspamd.h b/extras/filters/filter-rspamd/rspamd.h deleted file mode 100644 index 02774db..0000000 --- a/extras/filters/filter-rspamd/rspamd.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2016 Gilles Chehade <gilles@poolp.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#define RSPAMD_HOST "127.0.0.1" -#define RSPAMD_PORT "11333" - -struct session { - char *ip; - char *hostname; - char *helo; -}; - -struct transaction { - uint64_t id; - - struct iobuf iobuf; - struct io io; - - char *from; - int eom; - struct dict rcpts; - - struct rspamd_response { - int eoh; - char *body; - - int is_spam; - int is_skipped; - double score; - double required_score; - enum { - NO_ACTION, - GREYLIST, - ADD_HEADER, - REWRITE_SUBJECT, - SOFT_REJECT, - REJECT - } action; - char *subject; - } rspamd; - - char *line; -}; - -void *session_allocator(uint64_t); -void session_destructor(void *); -int session_set_helo(struct session *, const char *); -int session_set_ip(struct session *, const char *); -int session_set_hostname(struct session *, const char *); - -void *transaction_allocator(uint64_t); -void transaction_destructor(void *); -int transaction_set_from(struct transaction *, const char *); -int transaction_add_rcpt(struct transaction *, const char *); - -int rspamd_connect(struct transaction *); -void rspamd_connected(struct transaction *); -void rspamd_send_query(struct transaction *); -void rspamd_send_chunk(struct transaction *, const char *); -void rspamd_read_response(struct transaction *); -int rspamd_parse_response(struct transaction *); -void rspamd_error(struct transaction *); - -void rspamd_io(struct io *, int); - - - - - - diff --git a/extras/filters/filter-spamassassin/Makefile.am b/extras/filters/filter-spamassassin/Makefile.am deleted file mode 100644 index 7a456de..0000000 --- a/extras/filters/filter-spamassassin/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -include $(top_srcdir)/mk/paths.mk -include $(top_srcdir)/mk/filter.mk -include $(top_srcdir)/mk/experimental.mk - -pkglibexec_PROGRAMS = filter-spamassassin - -filter_spamassassin_SOURCES = $(SRCS) -filter_spamassassin_SOURCES += filter_spamassassin.c - -man_MANS = filter-spamassassin.8 diff --git a/extras/filters/filter-spamassassin/filter-spamassassin.8 b/extras/filters/filter-spamassassin/filter-spamassassin.8 deleted file mode 100644 index 9ebff45..0000000 --- a/extras/filters/filter-spamassassin/filter-spamassassin.8 +++ /dev/null @@ -1,130 +0,0 @@ -.\" -.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. -.\" -.Dd $Mdocdate: May 16 2016 $ -.Dt FILTER-SPAMASSASSIN 8 -.Os -.Sh NAME -.Nm filter-spamassassin -.Nd smtpd filter for SpamAssassin spamd -.Sh SYNOPSIS -.Nm -.Op Fl dv -.Op Fl h Ar host -.Op Fl l Ar limit -.Op Fl p Ar port -.Op Fl s Ar strategy -.Sh DESCRIPTION -.Nm -is a filter for -.Xr smtpd 8 -which can be used to filter mails based on decisions from SpamAssassin's -.Xr spamd 1 -daemon. -Mails are piped to the daemon, which decides whether a mail is spam or not, -according to its own configuration. -.Pp -The options are as follows: -.Bl -tag -width "-s strategy" -.It Fl d -Debug mode, if this option is specified, -.Nm -will run in the foreground and log to -.Em stderr . -.It Fl h Ar host -Set the -.Ar host -that runs SpamAssassin's -.Xr spamd 1 . -.Pp -The default -.Ar host -value is 127.0.0.1. -.It Fl l Ar limit -Set the number of bytes -.Ar limit -passed to -.Xr spamd 1 -after which the scanning is stopped and the mail is accepted. -The accepted values are within the range of 1 and SIZE_MAX. -.Pp -The default -.Ar limit -value is 0 (unlimited). -.It Fl p Ar port -Set the -.Ar port -that SpamAssassin's -.Xr spamd 1 -listens on. -.Pp -The default -.Ar port -value is 783. -.It Fl s Ar strategy -Set the -.Ar strategy -of -.Nm -to either accept or reject spam mails. -The accepted values are: -.Pp -.Bl -tag -width "accept" -compact -.It accept -Spam mails are accepted. -.It reject -Spam mails are rejected. -.El -.Pp -The default -.Ar strategy -value is accept. -.It Fl v -Produce more verbose output. -.El -.Pp -.Nm -runs by default in a chroot. -.Pp -The debug and verbose options given with the -.Xr smtpd 8 -invocation are intially passed to -.Nm . -.Pp -Depending on the chosen -.Ar strategy -spam mails are either accepted or rejected with a SMTP 554 reply. -Non-spam mails are always accepted. -.\"Accepted messages are marked with a -.\".Dq X-Filter-SpamAssassin -.\"header. -.Sh SPAMASSASSIN CONFIGURATION -The default -.Nm -configuration expects SpamAssassin's -.Xr spamd 1 -to listen on 127.0.0.1 port 783 for incoming requests. -This matches to the default configuration of the daemon. -.Sh SEE ALSO -.Xr spamd 1 , -.Xr filter_api 3 , -.Xr smtpd.conf 5 , -.Xr smtpd 8 -.Sh HISTORY -The first version of -.Nm -was written in 2015. -.Sh AUTHORS -.An Joerg Jung Aq Mt jung@openbsd.org diff --git a/extras/filters/filter-spamassassin/filter_spamassassin.c b/extras/filters/filter-spamassassin/filter_spamassassin.c deleted file mode 100644 index 264aa20..0000000 --- a/extras/filters/filter-spamassassin/filter_spamassassin.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. - */ - -#include "includes.h" - -#include <sys/types.h> - -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <limits.h> -#include <unistd.h> - -#include <smtpd-api.h> - -#define SPAMASSASSIN_HOST "127.0.0.1" -#define SPAMASSASSIN_PORT "783" - -struct spamassassin { - uint64_t id; - struct iobuf iobuf; - struct io io; - size_t l; - int r; - enum { SA_DATA, SA_EOM, SA_STA, SA_HDR, SA_MSG } s; -}; - -static struct sockaddr_storage spamassassin_ss; -static size_t spamassassin_limit; -static enum { SPAMASSASSIN_ACCEPT, SPAMASSASSIN_REJECT } spamassassin_strategy; - -static void -spamassassin_clear(struct spamassassin *sa) -{ - if (sa == NULL) - return; - io_clear(&sa->io); - iobuf_clear(&sa->iobuf); - free(sa); -} - -static int -spamassassin_result(struct spamassassin *sa) -{ - if (sa->r == INT_MIN) { - log_warnx("warn: result: failed"); - return -1; - } - if (sa->r) { - if (spamassassin_strategy == SPAMASSASSIN_ACCEPT) { - log_warnx("warn: session %016"PRIx64": result: ACCEPT spam", sa->id); - filter_api_accept(sa->id); - } - if (spamassassin_strategy == SPAMASSASSIN_REJECT) { - log_warnx("warn: session %016"PRIx64": result: REJECT spam", sa->id); - filter_api_reject_code(sa->id, FILTER_CLOSE, 554, "5.7.1 Message considered spam"); - } - } - return filter_api_accept(sa->id); -} - -#define SPAMASSASSIN_EXPAND(tok) #tok -#define SPAMASSASSIN_QUOTE(tok) SPAMASSASSIN_EXPAND(tok) -#define SPAMASSASSIN_EX_MAX 16 /* longest spamd response e.g. strlen("EX_UNAVAILABLE") */ - -static int -spamassassin_status(struct spamassassin *sa, const char *l) -{ - char s[SPAMASSASSIN_EX_MAX + 1]; - int r; - - if (sscanf(l, "SPAMD/%*d.%*d %d %"SPAMASSASSIN_QUOTE(SPAMASSASSIN_EX_MAX)"s", &r, s) != 2) { - (errno ? log_warn : log_warnx)("warn: status: sscanf"); - return -1; - } - if (r != 0 || strcmp(s, "EX_OK") != 0) { - log_warnx("warn: status: r=%d, s=%s", r, s); - return -1; - } - return sa->s++; -} - -static int -spamassassin_header(struct spamassassin *sa, const char *l) -{ - char s[SPAMASSASSIN_EX_MAX + 1]; - - if (strlen(l) == 0) - return sa->s++; /* end of spamd response headers */ - if (strncmp(l, "Spam: ", 6) == 0) { - if (sscanf(l, "Spam: %"SPAMASSASSIN_QUOTE(SPAMASSASSIN_EX_MAX)"s ; %*f / %*f", s) != 1) { - (errno ? log_warn : log_warnx)("warn: result: sscanf"); - return -1; - } - log_info("info: result: %s", l); - sa->r = (strcmp(s, "True") == 0); - } - return 0; -} - -static int -spamassassin_response(struct spamassassin *sa, const char *l) -{ - switch (sa->s) { - case SA_STA: - if (spamassassin_status(sa, l) == -1) - return -1; - break; - case SA_HDR: - if (spamassassin_header(sa, l) == -1) - return -1; - break; - case SA_MSG: - filter_api_writeln(sa->id, l); - break; - default: - fatalx("response: bad state"); - } - return 0; -} - -static void -spamassassin_io(struct io *io, int evt) -{ - struct spamassassin *sa = io->arg; - char *l; - - switch (evt) { - case IO_CONNECTED: - io_set_write(io); - break; - case IO_LOWAT: - if (sa->s == SA_EOM) { - if (shutdown(sa->io.sock, SHUT_WR) == -1) { - log_warn("warn: io: shutdown"); - goto fail; - } - sa->s++; - io_set_read(io); - } - break; - case IO_DATAIN: - while ((l = iobuf_getline(&sa->iobuf, NULL))) { - if (iobuf_len(&sa->iobuf) >= LINE_MAX) { - log_warnx("warn: io: iobuf_getline"); - goto fail; - } - if (spamassassin_response(sa, l) == -1) - goto fail; - } - iobuf_normalize(&sa->iobuf); - break; - case IO_DISCONNECTED: - if (sa->s == SA_MSG) { - if (iobuf_len(&sa->iobuf)) { - log_warnx("warn: io: incomplete"); - goto fail; - } - if (spamassassin_result(sa) == -1) - goto fail; - io_clear(io); - break; - } /* FALLTHROUGH */ - case IO_TIMEOUT: - case IO_ERROR: - log_warnx("warn: io: %s %s", io_strevent(evt), sa->io.error); - goto fail; - default: - fatalx("io: bad event"); - } - return; -fail: - if (sa->s > SA_DATA) - filter_api_reject_code(sa->id, FILTER_FAIL, 451, "4.7.1 Spam filter failed"); - filter_api_set_udata(sa->id, NULL); - spamassassin_clear(sa); -} - -static void -spamassassin_init(struct spamassassin *sa, uint64_t id) -{ - iobuf_xinit(&sa->iobuf, LINE_MAX, LINE_MAX, "init"); - io_init(&sa->io, -1, sa, spamassassin_io, &sa->iobuf); - sa->id = id; - sa->r = INT_MIN; -} - -static int -spamassassin_on_data(uint64_t id) -{ - struct spamassassin *sa; - - spamassassin_init((sa = xcalloc(1, sizeof(struct spamassassin), "on_data")), id); - if (io_connect(&sa->io, (struct sockaddr *)&spamassassin_ss, NULL) == -1) { - log_warnx("warn: on_data: io_connect %s", sa->io.error); - spamassassin_clear(sa); - return filter_api_accept(id); - } - iobuf_xfqueue(&sa->iobuf, "on_data", "PROCESS SPAMC/1.5\r\n\r\n"); /* spamd.raw source: content length header is optional */ - filter_api_set_udata(id, sa); - return filter_api_accept(id); -} - -static void -spamassassin_on_dataline(uint64_t id, const char *l) -{ - struct spamassassin *sa; - - if ((sa = filter_api_get_udata(id)) == NULL) { - filter_api_writeln(id, l); - return; - } - sa->l += strlen(l); - if (spamassassin_limit && sa->l >= spamassassin_limit) { - log_info("info: on_dataline: limit reached"); - log_warnx("warn: on_dataline: limit option not implemented"); - } - iobuf_xfqueue(&sa->iobuf, "on_dataline", "%s\n", l); - io_reload(&sa->io); -} - -static int -spamassassin_on_eom(uint64_t id, size_t size) -{ - struct spamassassin *sa; - - if ((sa = filter_api_get_udata(id)) == NULL) - return filter_api_accept(id); - sa->s++; - if (iobuf_queued(&sa->iobuf) == 0) - spamassassin_io(&sa->io, IO_LOWAT); - return 1; /* defer accept or reject */ -} - -static void -spamassassin_on_tx_commit(uint64_t id) -{ - spamassassin_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -static void -spamassassin_on_tx_rollback(uint64_t id) -{ - spamassassin_clear(filter_api_get_udata(id)); - filter_api_set_udata(id, NULL); -} - -static void -spamassassin_resolve(const char *h, const char *p) -{ - struct addrinfo hints, *addresses, *ai; - int fd, r; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - if ((r = getaddrinfo(h, p, &hints, &addresses))) - fatalx("resolve: getaddrinfo %s", gai_strerror(r)); - for (ai = addresses; ai; ai = ai->ai_next) { - if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) - continue; - if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) { - close(fd); - continue; - } - write(fd, "PING SPAMC/1.5\r\n\r\n", 18); /* avoid warning in log */ - close(fd); - memmove(&spamassassin_ss, ai->ai_addr, ai->ai_addrlen); - break; - } - freeaddrinfo(addresses); - if (!ai) - fatalx("resolve: failed"); -} - -int -main(int argc, char **argv) -{ - int ch, d = 0, v = 0; - const char *errstr, *l = NULL; - char *h = SPAMASSASSIN_HOST, *p = SPAMASSASSIN_PORT, *s = NULL; - - log_init(1); - - while ((ch = getopt(argc, argv, "dh:l:p:s:v")) != -1) { - switch (ch) { - case 'd': - d = 1; - break; - case 'h': - h = optarg; - break; - case 'l': - l = optarg; - break; - case 'p': - p = optarg; - break; - case 's': - s = optarg; - break; - case 'v': - v |= TRACE_DEBUG; - break; - default: - log_warnx("warn: bad option"); - return 1; - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (h) - h = strip(h); - if (p) - p = strip(p); - if (l) { - spamassassin_limit = strtonum(l, 1, UINT_MAX, &errstr); /* todo: SIZE_MAX here? */ - if (errstr) - fatalx("limit option is %s: %s", errstr, l); - } - if (s) { - s = strip(s); - if (strncmp(s, "accept", 6) == 0) - spamassassin_strategy = SPAMASSASSIN_ACCEPT; - else if (strncmp(s, "reject", 6) == 0) - spamassassin_strategy = SPAMASSASSIN_REJECT; - else - fatalx("bad strategy"); - } - - log_init(d); - log_verbose(v); - - log_debug("debug: starting..."); - spamassassin_resolve(h, p); - - filter_api_on_data(spamassassin_on_data); - filter_api_on_dataline(spamassassin_on_dataline); - filter_api_on_eom(spamassassin_on_eom); - filter_api_on_tx_commit(spamassassin_on_tx_commit); - filter_api_on_tx_rollback(spamassassin_on_tx_rollback); - - filter_api_loop(); - log_debug("debug: exiting"); - - return 1; -} |