From 1a38b68745758c147b41cadeb213ee5f431b005f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Apr 2010 15:24:31 +0200 Subject: update version --- version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sh b/version.sh index 2cbdde6..cae4b64 100755 --- a/version.sh +++ b/version.sh @@ -1,6 +1,6 @@ #!/bin/sh -VERSION=1.2 +VERSION=1.3 if head=$(git rev-parse --verify HEAD 2>/dev/null); then git update-index --refresh --unmerged > /dev/null -- cgit v1.2.3 From 04453737f2a63720b020fe8d4d73f3b81d9a5db0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Apr 2010 15:33:15 +0200 Subject: avoid warnings for dovecot <= 1.1 --- antispam-plugin.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/antispam-plugin.h b/antispam-plugin.h index 38a3be6..fd8783a 100644 --- a/antispam-plugin.h +++ b/antispam-plugin.h @@ -84,6 +84,10 @@ extern bool need_folder_hook; /* * Dovecot version compat code */ +#if DOVECOT_VERSION <= DOVECOT_VERSION_CODE(1, 1, 0) +#define mailbox_get_storage(s) mailbox_get_storage((struct mailbox *)s) +#define mailbox_get_name(s) mailbox_get_name((struct mailbox *)s) +#endif #if DOVECOT_VERSION_CODE(1, 1, 0) == DOVECOT_VERSION || DOVECOT_VERSION_CODE(1, 2, 0) == DOVECOT_VERSION #define __attr_unused__ ATTR_UNUSED -- cgit v1.2.3 From fe3ee5123602ac2b8af8d1209087c2c61274c8c5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 10:49:15 +0100 Subject: mailtrain: redirect stdout/stderr to /dev/null for execv This fixes a bug where sa-learn and similar tools fail because they cannot write to stdout or stderr at all, and propagate the error (EBADF or such). --- mailtrain.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mailtrain.c b/mailtrain.c index 41071bc..5529f03 100644 --- a/mailtrain.c +++ b/mailtrain.c @@ -71,7 +71,7 @@ static int run_sendmail(int mailfd, enum classification wanted) } else { char **argv; int sz = sizeof(char *) * (2 + extra_args_num + 1); - int i; + int i, fd; argv = i_malloc(sz); memset(argv, 0, sz); @@ -84,8 +84,10 @@ static int run_sendmail(int mailfd, enum classification wanted) argv[i + 1] = (char *) dest; dup2(mailfd, 0); - close(1); - close(2); + fd = open("/dev/null", O_WRONLY); + dup2(fd, 1); + dup2(fd, 2); + close(fd); execv(sendmail_binary, argv); _exit(1); /* not reached */ -- cgit v1.2.3 From cd30f319ca69e59db68632a131c6f36a2aee96ff Mon Sep 17 00:00:00 2001 From: Ron Date: Sat, 26 Feb 2011 21:32:50 +1030 Subject: Greater happiness through superior .gitignorance --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 96bcc17..1e3eccc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ dovecot-version.h antispam-version.h dovecot-version *-stamp +*.sw[lmnop] -- cgit v1.2.3 From 3c7327cf1d56ffd8580c4de8cdadba1fcf131422 Mon Sep 17 00:00:00 2001 From: Ron Date: Sun, 27 Feb 2011 04:46:57 +1030 Subject: Document the alternate names for the other backends --- antispam.7 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/antispam.7 b/antispam.7 index 141ef5c..e3e59bc 100644 --- a/antispam.7 +++ b/antispam.7 @@ -54,7 +54,13 @@ and add the antispam plugin to the imap protocol section: .nf protocol imap { + # Use the default mailtrain backend mail_plugins = antispam + + # mail_plugins = dspam # Or the dspam backend + # mail_plugins = crm114 # Or the crm114 backend + # mail_plugins = spool2dir # Or the spool2dir backend + # mail_plugin_dir = /usr/lib/dovecot/modules/imap } .fi -- cgit v1.2.3 From a7ae8df4a1611a18203bc29783e7fbaaf957fd54 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 27 Feb 2011 02:27:45 +0100 Subject: fix pointer argument --- signature-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signature-log.c b/signature-log.c index 5b7b306..85617f1 100644 --- a/signature-log.c +++ b/signature-log.c @@ -128,7 +128,7 @@ int backend_handle_mail(struct mailbox_transaction_context *t, ast->dict_ctx = dict_transaction_begin(ast->dict); signature = t_strconcat("priv/", signature, NULL); dict_atomic_inc(ast->dict_ctx, signature, inc); - ret = dict_transaction_commit(ast->dict_ctx); + ret = dict_transaction_commit(&ast->dict_ctx); if (ret) mail_storage_set_error(t->box->storage, ME(NOTPOSSIBLE) -- cgit v1.2.3 From 57cfc0aac9f8cc5d00fa1155367dfd055da27761 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 27 Feb 2011 01:49:00 +0100 Subject: make backend selection at runtime --- Makefile | 40 +++++++++++++++++++--------------------- antispam-plugin.c | 29 +++++++++++++++++++++++++++-- antispam-plugin.h | 40 ++++++++++++++++++++++------------------ antispam-storage-1.0.c | 14 +++++++------- antispam-storage-1.1.c | 16 ++++++++-------- antispam-storage-1.2.c | 16 ++++++++-------- crm114-exec.c | 25 +++++++++++++++++-------- dspam-exec.c | 27 ++++++++++++++++++--------- mailtrain.c | 27 ++++++++++++++++++--------- signature-log.c | 25 +++++++++++++++++-------- spool2dir.c | 27 ++++++++++++++++++--------- 11 files changed, 179 insertions(+), 107 deletions(-) diff --git a/Makefile b/Makefile index b833a3f..f405d3d 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,9 @@ INSTALLDIR ?= $(moduledir)/imap # Kill CFLAGS from dovecot-config CFLAGS := $(CFLAGSORIG) +backenddir := /usr/lib/dovecot-antispam +CFLAGS += '-DBACKENDDIR="$(backenddir)"' + # includes/flags we need for building a dovecot plugin INCS += -DHAVE_CONFIG_H INCS += -I$(DOVECOT)/ @@ -21,6 +24,7 @@ INCS += -I$(DOVECOT)/src/imap/ # output name LIBRARY_NAME ?= lib90_$(PLUGINNAME)_plugin.so +objs = antispam-storage.o antispam-plugin.o # debug rules ifeq ("$(DEBUG)", "stderr") @@ -37,32 +41,14 @@ ifeq ("$(DEBUG_VERBOSE)", "1") CFLAGS += -DCONFIG_DEBUG_VERBOSE endif -# backend error check -ifeq ("$(BACKEND)", "") -error: verify_config - @echo "Error! no backend configured" - @false -endif - -# per-backend rules -ifeq ("$(BACKEND)", "dspam-exec") -objs += signature.o -endif -ifeq ("$(BACKEND)", "signature-log") -objs += signature.o -endif -ifeq ("$(BACKEND)", "crm114-exec") -objs += signature.o -endif +BACKENDS = dspam-exec.so signature-log.so crm114-exec.so mailtrain.so spool2dir.so # main make rules CFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) CC ?= cc HOSTCC ?= cc -objs += antispam-plugin.o antispam-storage.o $(BACKEND).o - -all: verify_config $(LIBRARY_NAME) +all: verify_config $(LIBRARY_NAME) $(BACKENDS) antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-plugin.h dovecot-version.h $(CC) -c $(CFLAGS) $(INCS) -o $@ $< @@ -71,7 +57,7 @@ antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-p $(CC) -c $(CFLAGS) $(INCS) -o $@ $< $(LIBRARY_NAME): $(objs) - $(CC) $(CFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) + $(CC) $(CFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) -ldl dovecot-version: dovecot-version.c $(CONFIG) $(HOSTCC) $(INCS) -o dovecot-version dovecot-version.c @@ -82,11 +68,23 @@ dovecot-version.h: dovecot-version antispam-version.h: version.sh ./version.sh > antispam-version.h +dspam-exec.so: dspam-exec.o signature.o +signature-log.so: signature-log.o signature.o +crm114-exec.so: crm114-exec.o signature.o +mailtrain.so: mailtrain.o +spool2dir.so: spool2dir.o + +$(BACKENDS): + $(CC) $(CFLAGS) $(INCS) $(LDFLAGS) -shared -o $@ $^ + + clean: rm -f *.so *.o *~ dovecot-version dovecot-version.h antispam-version.h install: all install -o $(USER) -g $(GROUP) -m 0755 $(LIBRARY_NAME) $(DESTDIR)$(INSTALLDIR)/ + mkdir -p $(DESTDIR)$(backenddir) + install -o $(USER) -g $(GROUP) -m 0755 $(BACKENDS) $(DESTDIR)$(backenddir)/ verify_config: @if [ ! -r $(CONFIG) ]; then \ diff --git a/antispam-plugin.c b/antispam-plugin.c index 455668d..8a6fb65 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -27,6 +27,7 @@ #include #include +#include /* dovecot headers we need */ #include "lib.h" @@ -73,12 +74,15 @@ static char **trash_folders[] = { NULL, NULL, NULL }; static char **spam_folders[] = { default_spam_folders,NULL, NULL }; static char **unsure_folders[] = { NULL, NULL, NULL }; +void (*antispam_next_hook_mail_storage_created)(struct mail_storage *storage); bool antispam_can_append_to_spam = FALSE; static char **spam_keywords = NULL; bool need_keyword_hook; bool need_folder_hook; +struct backend *backend = NULL; + /* lower-case string, but keep modified UTF7 unchanged */ void lowercase_string(const char *in, char *out) { @@ -323,11 +327,32 @@ void PLUGIN_FUNCTION(init)(void) } } + tmp = get_setting("BACKEND"); + if (tmp) { + void *lib; + if (*tmp != '/') + tmp = t_strconcat(BACKENDDIR, tmp, ".so", NULL); + lib = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); + if (!lib) { + debug("backend failed to load: %s\n", strerror(errno)); + exit(3); + } + backend = dlsym(lib, "antispam_backend"); + if (!backend) { + debug("invalid backend!\n"); + exit(5); + } + } + else { + debug("no backend selected!\n"); + exit(2); + } + /* set spam_folders to empty to only allow keywords */ need_folder_hook = spam_folder_count > 0; need_keyword_hook = !!spam_keywords; - backend_init(global_pool); + backend->init(global_pool); antispam_next_hook_mail_storage_created = hook_mail_storage_created; hook_mail_storage_created = antispam_mail_storage_created; @@ -336,7 +361,7 @@ void PLUGIN_FUNCTION(init)(void) void PLUGIN_FUNCTION(deinit)(void) { hook_mail_storage_created = antispam_next_hook_mail_storage_created; - backend_exit(); + backend->exit(); mempool_unref(&global_pool); } diff --git a/antispam-plugin.h b/antispam-plugin.h index fd8783a..4b95f63 100644 --- a/antispam-plugin.h +++ b/antispam-plugin.h @@ -29,22 +29,26 @@ enum classification { CLASS_SPAM, }; -void backend_init(pool_t pool); -void backend_exit(void); -/* - * Handle mail; parameters are - * - t: transaction context - * - ast: transaction context from backend_start() - * - mail: the message - * - wanted: the wanted classification determined by the user - */ -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification wanted); -struct antispam_transaction_context *backend_start(struct mailbox *box); -void backend_rollback(struct antispam_transaction_context *ast); -int backend_commit(struct mailbox_transaction_context *ctx, - struct antispam_transaction_context *ast); +struct backend { + void (*init)(pool_t pool); + void (*exit)(void); + /* + * Handle mail; parameters are + * - t: transaction context + * - ast: transaction context from backend_start() + * - mail: the message + * - wanted: the wanted classification determined by the user + */ + int (*handle_mail)(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification wanted); + struct antispam_transaction_context *(*start)(struct mailbox *box); + void (*rollback)(struct antispam_transaction_context *ast); + int (*commit)(struct mailbox_transaction_context *ctx, + struct antispam_transaction_context *ast); +}; + +extern struct backend *backend; #ifdef CONFIG_DEBUG void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); @@ -70,12 +74,12 @@ static inline void debug_verbose(const char *fmt __attribute__((unused)), ...) #endif void antispam_mail_storage_created(struct mail_storage *storage); -void (*antispam_next_hook_mail_storage_created)(struct mail_storage *storage); +extern void (*antispam_next_hook_mail_storage_created)(struct mail_storage *storage); bool mailbox_is_spam(struct mailbox *box); bool mailbox_is_trash(struct mailbox *box); bool mailbox_is_unsure(struct mailbox *box); const char *get_setting(const char *name); -bool antispam_can_append_to_spam; +extern bool antispam_can_append_to_spam; bool keyword_is_spam(const char *keyword); extern bool need_keyword_hook; diff --git a/antispam-storage-1.0.c b/antispam-storage-1.0.c index 1651281..3112a22 100644 --- a/antispam-storage-1.0.c +++ b/antispam-storage-1.0.c @@ -119,8 +119,8 @@ antispam_copy(struct mailbox_transaction_context *t, struct mail *mail, if (asbox->save_hack || asbox->movetype == MMT_UNINTERESTING) ret = 0; else - ret = backend_handle_mail(t, ast, copy_dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(t, ast, copy_dest_mail, + move_to_class(asbox->movetype)); /* * Both save_hack and movetype are only valid within a copy operation, @@ -231,8 +231,8 @@ static int antispam_save_finish(struct mail_save_context *ctx, } /* fall through */ default: - ret = backend_handle_mail(ctx->transaction, ast, save_dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(ctx->transaction, ast, save_dest_mail, + move_to_class(asbox->movetype)); } if (save_dest_mail != dest_mail) @@ -245,7 +245,7 @@ antispam_transaction_begin(struct mailbox *box) { struct antispam_transaction_context *ast; - ast = backend_start(box); + ast = backend->start(box); i_assert(ast != NULL); return ast; @@ -256,7 +256,7 @@ antispam_transaction_rollback(struct antispam_transaction_context **_ast) { struct antispam_transaction_context *ast = *_ast; - backend_rollback(ast); + backend->rollback(ast); *_ast = NULL; } @@ -267,7 +267,7 @@ antispam_transaction_commit(struct mailbox_transaction_context *ctx, struct antispam_transaction_context *ast = *_ast; int ret; - ret = backend_commit(ctx, ast); + ret = backend->commit(ctx, ast); *_ast = NULL; return ret; } diff --git a/antispam-storage-1.1.c b/antispam-storage-1.1.c index 80c80e3..e21ac82 100644 --- a/antispam-storage-1.1.c +++ b/antispam-storage-1.1.c @@ -127,8 +127,8 @@ antispam_copy(struct mailbox_transaction_context *t, struct mail *mail, if (asbox->save_hack || asbox->movetype == MMT_UNINTERESTING) ret = 0; else - ret = backend_handle_mail(t, ast->backendctx, dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(t, ast->backendctx, dest_mail, + move_to_class(asbox->movetype)); /* * Both save_hack and movetype are only valid within a copy operation, @@ -247,9 +247,9 @@ static int antispam_save_finish(struct mail_save_context *ctx) } /* fall through */ default: - ret = backend_handle_mail(ctx->transaction, ast->backendctx, - dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(ctx->transaction, ast->backendctx, + dest_mail, + move_to_class(asbox->movetype)); } return ret; @@ -260,7 +260,7 @@ antispam_transaction_begin(struct mailbox *box) { struct antispam_transaction_context *ast; - ast = backend_start(box); + ast = backend->start(box); i_assert(ast != NULL); return ast; @@ -271,7 +271,7 @@ antispam_transaction_rollback(struct antispam_transaction_context **_ast) { struct antispam_transaction_context *ast = *_ast; - backend_rollback(ast); + backend->rollback(ast); *_ast = NULL; } @@ -282,7 +282,7 @@ antispam_transaction_commit(struct mailbox_transaction_context *ctx, struct antispam_transaction_context *ast = *_ast; int ret; - ret = backend_commit(ctx, ast); + ret = backend->commit(ctx, ast); *_ast = NULL; return ret; } diff --git a/antispam-storage-1.2.c b/antispam-storage-1.2.c index 54b8f7b..2c11ce7 100644 --- a/antispam-storage-1.2.c +++ b/antispam-storage-1.2.c @@ -126,8 +126,8 @@ antispam_copy(struct mail_save_context *ctx, struct mail *mail) if (asbox->save_hack || asbox->movetype == MMT_UNINTERESTING) ret = 0; else - ret = backend_handle_mail(t, ast->backendctx, ctx->dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(t, ast->backendctx, ctx->dest_mail, + move_to_class(asbox->movetype)); /* * Both save_hack and movetype are only valid within a copy operation, @@ -237,9 +237,9 @@ static int antispam_save_finish(struct mail_save_context *ctx) } /* fall through */ default: - ret = backend_handle_mail(ctx->transaction, ast->backendctx, - dest_mail, - move_to_class(asbox->movetype)); + ret = backend->handle_mail(ctx->transaction, ast->backendctx, + dest_mail, + move_to_class(asbox->movetype)); } return ret; @@ -250,7 +250,7 @@ antispam_transaction_begin(struct mailbox *box) { struct antispam_transaction_context *ast; - ast = backend_start(box); + ast = backend->start(box); i_assert(ast != NULL); return ast; @@ -261,7 +261,7 @@ antispam_transaction_rollback(struct antispam_transaction_context **_ast) { struct antispam_transaction_context *ast = *_ast; - backend_rollback(ast); + backend->rollback(ast); *_ast = NULL; } @@ -272,7 +272,7 @@ antispam_transaction_commit(struct mailbox_transaction_context *ctx, struct antispam_transaction_context *ast = *_ast; int ret; - ret = backend_commit(ctx, ast); + ret = backend->commit(ctx, ast); *_ast = NULL; return ret; } diff --git a/crm114-exec.c b/crm114-exec.c index 7727409..f4245dd 100644 --- a/crm114-exec.c +++ b/crm114-exec.c @@ -129,7 +129,7 @@ struct antispam_transaction_context { struct siglist *siglist; }; -struct antispam_transaction_context * +static struct antispam_transaction_context * backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; @@ -139,13 +139,13 @@ backend_start(struct mailbox *box __attr_unused__) return ast; } -void backend_rollback(struct antispam_transaction_context *ast) +static void backend_rollback(struct antispam_transaction_context *ast) { signature_list_free(&ast->siglist); i_free(ast); } -int backend_commit(struct mailbox_transaction_context *ctx, +static int backend_commit(struct mailbox_transaction_context *ctx, struct antispam_transaction_context *ast) { struct siglist *item = ast->siglist; @@ -167,14 +167,14 @@ int backend_commit(struct mailbox_transaction_context *ctx, return ret; } -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification want) +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification want) { return signature_extract_to_list(t, mail, &ast->siglist, want); } -void backend_init(pool_t pool) +static void backend_init(pool_t pool) { const char *tmp; int i; @@ -198,6 +198,15 @@ void backend_init(pool_t pool) signature_init(); } -void backend_exit(void) +static void backend_exit(void) { } + +struct backend antispam_backend = { + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; diff --git a/dspam-exec.c b/dspam-exec.c index ecfb9f1..ed706d7 100644 --- a/dspam-exec.c +++ b/dspam-exec.c @@ -163,7 +163,7 @@ struct antispam_transaction_context { struct siglist *siglist; }; -struct antispam_transaction_context * +static struct antispam_transaction_context * backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; @@ -173,14 +173,14 @@ backend_start(struct mailbox *box __attr_unused__) return ast; } -void backend_rollback(struct antispam_transaction_context *ast) +static void backend_rollback(struct antispam_transaction_context *ast) { signature_list_free(&ast->siglist); i_free(ast); } -int backend_commit(struct mailbox_transaction_context *ctx, - struct antispam_transaction_context *ast) +static int backend_commit(struct mailbox_transaction_context *ctx, + struct antispam_transaction_context *ast) { struct siglist *item = ast->siglist; int ret = 0; @@ -201,9 +201,9 @@ int backend_commit(struct mailbox_transaction_context *ctx, return ret; } -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification want) +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification want) { const char *const *result = NULL; int i; @@ -224,7 +224,7 @@ int backend_handle_mail(struct mailbox_transaction_context *t, return signature_extract_to_list(t, mail, &ast->siglist, want); } -void backend_init(pool_t pool) +static void backend_init(pool_t pool) { const char *tmp; int i; @@ -263,6 +263,15 @@ void backend_init(pool_t pool) signature_init(); } -void backend_exit(void) +static void backend_exit(void) { } + +struct backend antispam_backend = { + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; diff --git a/mailtrain.c b/mailtrain.c index 5529f03..276eb4a 100644 --- a/mailtrain.c +++ b/mailtrain.c @@ -101,7 +101,7 @@ struct antispam_transaction_context { int tmplen; }; -struct antispam_transaction_context * +static struct antispam_transaction_context * backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; @@ -178,7 +178,7 @@ static void clear_tmpdir(struct antispam_transaction_context *ast) t_pop(); } -void backend_rollback(struct antispam_transaction_context *ast) +static void backend_rollback(struct antispam_transaction_context *ast) { if (ast->tmpdir) { /* clear it! */ @@ -189,8 +189,8 @@ void backend_rollback(struct antispam_transaction_context *ast) i_free(ast); } -int backend_commit(struct mailbox_transaction_context *ctx, - struct antispam_transaction_context *ast) +static int backend_commit(struct mailbox_transaction_context *ctx, + struct antispam_transaction_context *ast) { int ret; @@ -209,9 +209,9 @@ int backend_commit(struct mailbox_transaction_context *ctx, return ret; } -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification wanted) +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification wanted) { struct istream *mailstream; struct ostream *outstream; @@ -310,7 +310,7 @@ int backend_handle_mail(struct mailbox_transaction_context *t, return ret; } -void backend_init(pool_t pool __attr_unused__) +static void backend_init(pool_t pool __attr_unused__) { const char *tmp; int i; @@ -349,6 +349,15 @@ void backend_init(pool_t pool __attr_unused__) debug("mail backend tmpdir %s\n", tmpdir); } -void backend_exit(void) +static void backend_exit(void) { } + +struct backend antispam_backend = { + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; diff --git a/signature-log.c b/signature-log.c index 85617f1..1cfc956 100644 --- a/signature-log.c +++ b/signature-log.c @@ -44,7 +44,7 @@ struct antispam_transaction_context { struct dict_transaction_context *dict_ctx; }; -struct antispam_transaction_context * +static struct antispam_transaction_context * backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; @@ -59,7 +59,7 @@ backend_start(struct mailbox *box __attr_unused__) return ast; } -void backend_rollback(struct antispam_transaction_context *ast) +static void backend_rollback(struct antispam_transaction_context *ast) { if (ast->dict) { // dict_transaction_rollback(ast->dict_ctx); @@ -69,7 +69,7 @@ void backend_rollback(struct antispam_transaction_context *ast) i_free(ast); } -int backend_commit(struct mailbox_transaction_context *ctx __attr_unused__, +static int backend_commit(struct mailbox_transaction_context *ctx __attr_unused__, struct antispam_transaction_context *ast) { int ret = 0; @@ -84,9 +84,9 @@ int backend_commit(struct mailbox_transaction_context *ctx __attr_unused__, return ret; } -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification wanted) +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification wanted) { const char *signature; int ret; @@ -137,7 +137,7 @@ int backend_handle_mail(struct mailbox_transaction_context *t, return ret; } -void backend_init(pool_t pool __attr_unused__) +static void backend_init(pool_t pool __attr_unused__) { const char *tmp; @@ -156,6 +156,15 @@ void backend_init(pool_t pool __attr_unused__) signature_init(); } -void backend_exit(void) +static void backend_exit(void) { } + +struct backend antispam_backend = { + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; diff --git a/spool2dir.c b/spool2dir.c index aa53e71..2c4b547 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -112,22 +112,22 @@ struct antispam_transaction_context { }; -void backend_rollback(struct antispam_transaction_context *ast) +static void backend_rollback(struct antispam_transaction_context *ast) { i_free(ast); } -int backend_commit(struct mailbox_transaction_context *ctx __attr_unused__, - struct antispam_transaction_context *ast) +static int backend_commit(struct mailbox_transaction_context *ctx __attr_unused__, + struct antispam_transaction_context *ast) { i_free(ast); return 0; } -int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification wanted) +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification wanted) { struct istream *mailstream; struct ostream *outstream; @@ -232,7 +232,7 @@ int backend_handle_mail(struct mailbox_transaction_context *t, return ret; } -void backend_init(pool_t pool __attr_unused__) +static void backend_init(pool_t pool __attr_unused__) { if((spamspool = get_setting("SPOOL2DIR_SPAM"))) debug("spool2dir spamspool %s\n", spamspool); @@ -241,7 +241,7 @@ void backend_init(pool_t pool __attr_unused__) debug("spool2dir hamspool %s\n", hamspool); } -struct antispam_transaction_context * +static struct antispam_transaction_context * backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; @@ -254,6 +254,15 @@ struct antispam_transaction_context * } -void backend_exit(void) +static void backend_exit(void) { } + +struct backend antispam_backend = { + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; -- cgit v1.2.3 From 1e00dcf27da691bc645965a2c40bfd1b5329456e Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Sun, 27 Feb 2011 02:02:34 +0100 Subject: be packaging friendly --- Makefile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index f405d3d..b7e446a 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ INSTALLDIR ?= $(moduledir)/imap CFLAGS := $(CFLAGSORIG) backenddir := /usr/lib/dovecot-antispam -CFLAGS += '-DBACKENDDIR="$(backenddir)"' +LOCALCFLAGS += '-DBACKENDDIR="$(backenddir)"' # includes/flags we need for building a dovecot plugin INCS += -DHAVE_CONFIG_H @@ -28,36 +28,36 @@ objs = antispam-storage.o antispam-plugin.o # debug rules ifeq ("$(DEBUG)", "stderr") -CFLAGS += -DCONFIG_DEBUG -DDEBUG_STDERR +LOCALCFLAGS += -DCONFIG_DEBUG -DDEBUG_STDERR objs += debug.o else ifeq ("$(DEBUG)", "syslog") -CFLAGS += -DCONFIG_DEBUG -DDEBUG_SYSLOG +LOCALCFLAGS += -DCONFIG_DEBUG -DDEBUG_SYSLOG objs += debug.o endif endif ifeq ("$(DEBUG_VERBOSE)", "1") -CFLAGS += -DCONFIG_DEBUG_VERBOSE +LOCALCFLAGS += -DCONFIG_DEBUG_VERBOSE endif BACKENDS = dspam-exec.so signature-log.so crm114-exec.so mailtrain.so spool2dir.so # main make rules -CFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) +LOCALCFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) CC ?= cc HOSTCC ?= cc all: verify_config $(LIBRARY_NAME) $(BACKENDS) antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-plugin.h dovecot-version.h - $(CC) -c $(CFLAGS) $(INCS) -o $@ $< + $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< %.o: %.c $(CONFIG) antispam-plugin.h dovecot-version.h antispam-version.h - $(CC) -c $(CFLAGS) $(INCS) -o $@ $< + $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< $(LIBRARY_NAME): $(objs) - $(CC) $(CFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) -ldl + $(CC) $(CFLAGS) $(LOCALCFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) -ldl dovecot-version: dovecot-version.c $(CONFIG) $(HOSTCC) $(INCS) -o dovecot-version dovecot-version.c @@ -75,16 +75,16 @@ mailtrain.so: mailtrain.o spool2dir.so: spool2dir.o $(BACKENDS): - $(CC) $(CFLAGS) $(INCS) $(LDFLAGS) -shared -o $@ $^ + $(CC) $(CFLAGS) $(INCS) $(LOCALCFLAGS) $(LDFLAGS) -o $@ $^ clean: rm -f *.so *.o *~ dovecot-version dovecot-version.h antispam-version.h install: all - install -o $(USER) -g $(GROUP) -m 0755 $(LIBRARY_NAME) $(DESTDIR)$(INSTALLDIR)/ + install -p -m 0755 $(LIBRARY_NAME) $(DESTDIR)$(INSTALLDIR)/ mkdir -p $(DESTDIR)$(backenddir) - install -o $(USER) -g $(GROUP) -m 0755 $(BACKENDS) $(DESTDIR)$(backenddir)/ + install -p -m 0755 $(BACKENDS) $(DESTDIR)$(backenddir)/ verify_config: @if [ ! -r $(CONFIG) ]; then \ -- cgit v1.2.3 From ca91e1366a57ff45597168592781cdaf35af48a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:09:49 +0100 Subject: add an API version to the backend struct Just to make sure nobody loads a backend plugin that isn't suitable for the version of antispam itself. --- antispam-plugin.c | 11 +++++++++-- antispam-plugin.h | 7 +++++++ crm114-exec.c | 13 +++++++------ dspam-exec.c | 13 +++++++------ mailtrain.c | 13 +++++++------ signature-log.c | 13 +++++++------ spool2dir.c | 13 +++++++------ 7 files changed, 51 insertions(+), 32 deletions(-) diff --git a/antispam-plugin.c b/antispam-plugin.c index 8a6fb65..b94481b 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -330,20 +330,27 @@ void PLUGIN_FUNCTION(init)(void) tmp = get_setting("BACKEND"); if (tmp) { void *lib; + if (*tmp != '/') tmp = t_strconcat(BACKENDDIR, tmp, ".so", NULL); + lib = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); if (!lib) { debug("backend failed to load: %s\n", strerror(errno)); exit(3); } + backend = dlsym(lib, "antispam_backend"); if (!backend) { debug("invalid backend!\n"); exit(5); } - } - else { + + if (backend->api_version != BACKEND_API_VERSION) { + debug("backend API version mismatch"); + exit(7); + } + } else { debug("no backend selected!\n"); exit(2); } diff --git a/antispam-plugin.h b/antispam-plugin.h index 4b95f63..2caf5a3 100644 --- a/antispam-plugin.h +++ b/antispam-plugin.h @@ -29,7 +29,14 @@ enum classification { CLASS_SPAM, }; +/* Update whenever the struct below needs to change */ +#define API_CODE 1 +#define BACKEND_API_VERSION ((DOVECOT_VERSION << 8) | API_CODE) + struct backend { + /* Set to BACKEND_API_VERSION */ + unsigned int api_version; + void (*init)(pool_t pool); void (*exit)(void); /* diff --git a/crm114-exec.c b/crm114-exec.c index f4245dd..3947dbc 100644 --- a/crm114-exec.c +++ b/crm114-exec.c @@ -203,10 +203,11 @@ static void backend_exit(void) } struct backend antispam_backend = { - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, }; diff --git a/dspam-exec.c b/dspam-exec.c index ed706d7..4be4af4 100644 --- a/dspam-exec.c +++ b/dspam-exec.c @@ -268,10 +268,11 @@ static void backend_exit(void) } struct backend antispam_backend = { - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, }; diff --git a/mailtrain.c b/mailtrain.c index 276eb4a..e1c7bab 100644 --- a/mailtrain.c +++ b/mailtrain.c @@ -354,10 +354,11 @@ static void backend_exit(void) } struct backend antispam_backend = { - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, }; diff --git a/signature-log.c b/signature-log.c index 1cfc956..d0ab332 100644 --- a/signature-log.c +++ b/signature-log.c @@ -161,10 +161,11 @@ static void backend_exit(void) } struct backend antispam_backend = { - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, }; diff --git a/spool2dir.c b/spool2dir.c index 2c4b547..26fcd3e 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -259,10 +259,11 @@ static void backend_exit(void) } struct backend antispam_backend = { - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, }; -- cgit v1.2.3 From b10c78cde4afcdc9fbd1be25bd7750e1a9cb69a7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:12:21 +0100 Subject: remove BACKEND from defconfig --- defconfig | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/defconfig b/defconfig index 3bbda18..f6de237 100644 --- a/defconfig +++ b/defconfig @@ -9,18 +9,6 @@ # be modified from here. In most cases, these lines should use += in order not # to override previous values of the variables. -# backend (select exactly one) -# dspam-exec - direct dspam training by calling dspam executable -# signature-log - signature logging using dovecot's dict API -# mailtrain - send mail to special addresses for training -# crm114-exec - direct crm114 training by calling mailreaver.crm -# spool2dir - spool trained emails to a directory -#BACKEND=dspam-exec -#BACKEND=signature-log -#BACKEND=mailtrain -#BACKEND=crm114-exec -#BACKEND=spool2dir - # Dovecot build/header directory # Building the plugin requires configured dovecot sources or having # configured it with --enable-header-install in which case you can -- cgit v1.2.3 From 8ed65ea1566b8479536181c2520f8309ba14364e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:12:50 +0100 Subject: Revert "Document the alternate names for the other backends" This reverts commit 3c7327cf1d56ffd8580c4de8cdadba1fcf131422. Now that the backend selection is dynamic it no longer makes sense to document this -- need to document the selection instead. --- antispam.7 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/antispam.7 b/antispam.7 index e3e59bc..141ef5c 100644 --- a/antispam.7 +++ b/antispam.7 @@ -54,13 +54,7 @@ and add the antispam plugin to the imap protocol section: .nf protocol imap { - # Use the default mailtrain backend mail_plugins = antispam - - # mail_plugins = dspam # Or the dspam backend - # mail_plugins = crm114 # Or the crm114 backend - # mail_plugins = spool2dir # Or the spool2dir backend - # mail_plugin_dir = /usr/lib/dovecot/modules/imap } .fi -- cgit v1.2.3 From d52daf7e31928c1b52bef6e57ec316f5f057d85a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:35:01 +0100 Subject: rename mailtrain to pipe --- Makefile | 4 +- NOTES | 2 +- antispam.7 | 41 ++++--- mailtrain.c | 364 ---------------------------------------------------------- pipe.c | 374 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 401 insertions(+), 384 deletions(-) delete mode 100644 mailtrain.c create mode 100644 pipe.c diff --git a/Makefile b/Makefile index b7e446a..0516a6f 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ ifeq ("$(DEBUG_VERBOSE)", "1") LOCALCFLAGS += -DCONFIG_DEBUG_VERBOSE endif -BACKENDS = dspam-exec.so signature-log.so crm114-exec.so mailtrain.so spool2dir.so +BACKENDS = dspam-exec.so signature-log.so crm114-exec.so pipe.so spool2dir.so # main make rules LOCALCFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) @@ -71,7 +71,7 @@ antispam-version.h: version.sh dspam-exec.so: dspam-exec.o signature.o signature-log.so: signature-log.o signature.o crm114-exec.so: crm114-exec.o signature.o -mailtrain.so: mailtrain.o +pipe.so: pipe.o spool2dir.so: spool2dir.o $(BACKENDS): diff --git a/NOTES b/NOTES index 0eaf63c..70c4fb5 100644 --- a/NOTES +++ b/NOTES @@ -7,4 +7,4 @@ Full-message availability Pristine retraining or SpamAssassin retraining might need the full message available. This can easily be implemented since the backend is passed each -struct mail *mail that is moved. For an example see the mailtrain backend. +struct mail *mail that is moved. For an example see the pipe backend. diff --git a/antispam.7 b/antispam.7 index 141ef5c..5544ca3 100644 --- a/antispam.7 +++ b/antispam.7 @@ -189,31 +189,38 @@ plugin { # antispam_dspam_result_blacklist = Virus #===================== - # mail sending plugin + # pipe plugin + # + # This plug can be used to train via an arbitrary program that + # receives the message on standard input. Since sendmail can be + # such a program, it can be used to send the message to another + # email address for training there. # - # Because of the way this plugin works, you can also use it - # to train via an arbitrary program that receives the message - # on standard input, in that case you can use the config - # options antispam_mail_spam and antispam_mail_notspam for - # the argument that distinguishes between ham and spam. # For example: - # antispam_mail_sendmail = /path/to/mailtrain - # antispam_mail_sendmail_args = --for;%u - # antispam_mail_spam = --spam - # antispam_mail_notspam = --ham + # antispam_pipe_program = /path/to/mailtrain + # (defaults to /usr/sbin/sendmail) + # antispam_pipe_program_args = --for;%u + # antispam_pipe_program_spam_arg = --spam + # antispam_pipe_program_notspam_arg = --ham + # antispam_pipe_tmpdir = /tmp # will call it, for example, like this: # /path/to/mailtrain --for jberg --spam + # + # The old configuration options from when this plugin was called + # "mailtrain" are still valid, these are, in the same order as + # above: antispam_mail_sendmail, antispam_mail_sendmail_args, + # antispam_mail_spam, antispam_mail_notspam and antispam_mail_tmpdir. # temporary directory - antispam_mail_tmpdir = /tmp + antispam_pipe_tmpdir = /tmp - # spam/not-spam addresses (default unset which will give errors) - # antispam_mail_spam = - # antispam_mail_notspam = + # spam/not-spam argument (default unset which will is not what you want) + # antispam_pipe_program_spam_arg = + # antispam_pipe_program_notspam_arg = - # sendmail binary - antispam_mail_sendmail = /usr/sbin/sendmail - #antispam_mail_sendmail_args = -f;%u@example.com # % expansion done by dovecot + # binary to pipe mail to + antispam_pipe_program = /usr/sbin/sendmail + #antispam_pipe_program_args = -f;%u@example.com # % expansion done by dovecot #=================== # crm114-exec plugin diff --git a/mailtrain.c b/mailtrain.c deleted file mode 100644 index e1c7bab..0000000 --- a/mailtrain.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * mailing backend for dovecot antispam plugin - * - * Copyright (C) 2007 Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include -#include - -#include "lib.h" -#include "dict.h" -#include "mail-storage-private.h" -#include "ostream.h" -#include "istream.h" - -#include "antispam-plugin.h" - -static const char *spamaddr = NULL; -static const char *hamaddr = NULL; -static const char *sendmail_binary = "/usr/sbin/sendmail"; -static const char *tmpdir = "/tmp"; -static char **extra_args = NULL; -static int extra_args_num = 0; - -static int run_sendmail(int mailfd, enum classification wanted) -{ - const char *dest; - pid_t pid; - int status; - - switch (wanted) { - case CLASS_SPAM: - dest = spamaddr; - break; - case CLASS_NOTSPAM: - dest = hamaddr; - break; - } - - if (!dest) - return -1; - - pid = fork(); - - if (pid == -1) - return -1; - - debug("running mailtrain backend program %s", sendmail_binary); - - if (pid) { - if (waitpid(pid, &status, 0) == -1) - return -1; - if (!WIFEXITED(status)) - return -1; - return WEXITSTATUS(status); - } else { - char **argv; - int sz = sizeof(char *) * (2 + extra_args_num + 1); - int i, fd; - - argv = i_malloc(sz); - memset(argv, 0, sz); - - argv[0] = (char *) sendmail_binary; - - for (i = 0; i < extra_args_num; i++) - argv[i + 1] = (char *) extra_args[i]; - - argv[i + 1] = (char *) dest; - - dup2(mailfd, 0); - fd = open("/dev/null", O_WRONLY); - dup2(fd, 1); - dup2(fd, 2); - close(fd); - execv(sendmail_binary, argv); - _exit(1); - /* not reached */ - return -1; - } -} - -struct antispam_transaction_context { - char *tmpdir; - int count; - int tmplen; -}; - -static struct antispam_transaction_context * -backend_start(struct mailbox *box __attr_unused__) -{ - struct antispam_transaction_context *ast; - char *tmp; - - ast = i_new(struct antispam_transaction_context, 1); - - ast->count = 0; - - tmp = i_strconcat(tmpdir, "/antispam-mail-XXXXXX", NULL); - - ast->tmpdir = mkdtemp(tmp); - if (!ast->tmpdir) - i_free(tmp); - else - ast->tmplen = strlen(ast->tmpdir); - - return ast; -} - -static int process_tmpdir(struct mailbox_transaction_context *ctx, - struct antispam_transaction_context *ast) -{ - int cnt = ast->count; - int fd; - char *buf; - enum classification wanted; - int rc = 0; - - t_push(); - - buf = t_malloc(20 + ast->tmplen); - - while (rc == 0 && cnt > 0) { - cnt--; - i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", - ast->tmpdir, cnt); - - fd = open(buf, O_RDONLY); - read(fd, &wanted, sizeof(wanted)); - - if ((rc = run_sendmail(fd, wanted))) { - mail_storage_set_error(ctx->box->storage, - ME(TEMP) - "failed to send mail"); - debug("run program failed with exit code %d\n", rc); - rc = -1; - } - - close(fd); - } - - t_pop(); - - return rc; -} - -static void clear_tmpdir(struct antispam_transaction_context *ast) -{ - char *buf; - - t_push(); - - buf = t_malloc(20 + ast->tmplen); - - while (ast->count > 0) { - ast->count--; - i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", - ast->tmpdir, ast->count); - unlink(buf); - } - rmdir(ast->tmpdir); - - t_pop(); -} - -static void backend_rollback(struct antispam_transaction_context *ast) -{ - if (ast->tmpdir) { - /* clear it! */ - clear_tmpdir(ast); - i_free(ast->tmpdir); - } - - i_free(ast); -} - -static int backend_commit(struct mailbox_transaction_context *ctx, - struct antispam_transaction_context *ast) -{ - int ret; - - if (!ast->tmpdir) { - i_free(ast); - return 0; - } - - ret = process_tmpdir(ctx, ast); - - clear_tmpdir(ast); - - i_free(ast->tmpdir); - i_free(ast); - - return ret; -} - -static int backend_handle_mail(struct mailbox_transaction_context *t, - struct antispam_transaction_context *ast, - struct mail *mail, enum classification wanted) -{ - struct istream *mailstream; - struct ostream *outstream; - int ret; - char *buf; - const unsigned char *beginning; - size_t size; - int fd; - - if (!ast->tmpdir) { - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to initialise temporary dir"); - return -1; - } - - if (!hamaddr || !spamaddr) { - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "antispam plugin not configured"); - return -1; - } - - mailstream = get_mail_stream(mail); - if (!mailstream) { - mail_storage_set_error(t->box->storage, - ME(EXPUNGED) - "Failed to get mail contents"); - return -1; - } - - t_push(); - - buf = t_malloc(20 + ast->tmplen); - i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", ast->tmpdir, ast->count); - - fd = creat(buf, 0600); - if (fd < 0) { - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to create temporary file"); - ret = -1; - goto out; - } - - ast->count++; - - outstream = o_stream_create_from_fd(fd, t->box->pool); - if (!outstream) { - ret = -1; - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to stream temporary file"); - goto out_close; - } - - if (o_stream_send(outstream, &wanted, sizeof(wanted)) - != sizeof(wanted)) { - ret = -1; - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to write marker to temp file"); - goto failed_to_copy; - } - - if (i_stream_read_data(mailstream, &beginning, &size, 5) < 0 || - size < 5) { - ret = -1; - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to read mail beginning"); - goto failed_to_copy; - } - - /* "From "? skip line */ - if (memcmp("From ", beginning, 5) == 0) - i_stream_read_next_line(mailstream); - - if (o_stream_send_istream(outstream, mailstream) < 0) { - ret = -1; - mail_storage_set_error(t->box->storage, - ME(NOTPOSSIBLE) - "Failed to copy to temporary file"); - goto failed_to_copy; - } - - ret = 0; - - failed_to_copy: - o_stream_destroy(&outstream); - out_close: - close(fd); - out: - t_pop(); - - return ret; -} - -static void backend_init(pool_t pool __attr_unused__) -{ - const char *tmp; - int i; - - tmp = get_setting("MAIL_SPAM"); - if (tmp) { - spamaddr = tmp; - debug("mail backend spam address %s\n", tmp); - } - - tmp = get_setting("MAIL_NOTSPAM"); - if (tmp) { - hamaddr = tmp; - debug("mail backend not-spam address %s\n", tmp); - } - - tmp = get_setting("MAIL_SENDMAIL"); - if (tmp) { - sendmail_binary = tmp; - debug("mail backend sendmail %s\n", tmp); - } - - tmp = get_setting("MAIL_SENDMAIL_ARGS"); - if (tmp) { - extra_args = p_strsplit(pool, tmp, ";"); - extra_args_num = str_array_length( - (const char *const *)extra_args); - for (i = 0; i < extra_args_num; i++) - debug("mail backend sendmail arg %s\n", - extra_args[i]); - } - - tmp = get_setting("MAIL_TMPDIR"); - if (tmp) - tmpdir = tmp; - debug("mail backend tmpdir %s\n", tmpdir); -} - -static void backend_exit(void) -{ -} - -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, - .init = backend_init, - .exit = backend_exit, - .handle_mail = backend_handle_mail, - .start = backend_start, - .rollback = backend_rollback, - .commit = backend_commit, -}; diff --git a/pipe.c b/pipe.c new file mode 100644 index 0000000..309f8d9 --- /dev/null +++ b/pipe.c @@ -0,0 +1,374 @@ +/* + * mailing backend for dovecot antispam plugin + * + * Copyright (C) 2007 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "lib.h" +#include "dict.h" +#include "mail-storage-private.h" +#include "ostream.h" +#include "istream.h" + +#include "antispam-plugin.h" + +static const char *spam_arg = NULL; +static const char *ham_arg = NULL; +static const char *pipe_binary = "/usr/sbin/sendmail"; +static const char *tmpdir = "/tmp"; +static char **extra_args = NULL; +static int extra_args_num = 0; + +static int run_pipe(int mailfd, enum classification wanted) +{ + const char *dest; + pid_t pid; + int status; + + switch (wanted) { + case CLASS_SPAM: + dest = spam_arg; + break; + case CLASS_NOTSPAM: + dest = ham_arg; + break; + } + + if (!dest) + return -1; + + pid = fork(); + + if (pid == -1) + return -1; + + debug("running mailtrain backend program %s", pipe_binary); + + if (pid) { + if (waitpid(pid, &status, 0) == -1) + return -1; + if (!WIFEXITED(status)) + return -1; + return WEXITSTATUS(status); + } else { + char **argv; + int sz = sizeof(char *) * (2 + extra_args_num + 1); + int i, fd; + + argv = i_malloc(sz); + memset(argv, 0, sz); + + argv[0] = (char *) pipe_binary; + + for (i = 0; i < extra_args_num; i++) + argv[i + 1] = (char *) extra_args[i]; + + argv[i + 1] = (char *) dest; + + dup2(mailfd, 0); + fd = open("/dev/null", O_WRONLY); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + execv(pipe_binary, argv); + _exit(1); + /* not reached */ + return -1; + } +} + +struct antispam_transaction_context { + char *tmpdir; + int count; + int tmplen; +}; + +static struct antispam_transaction_context * +backend_start(struct mailbox *box __attr_unused__) +{ + struct antispam_transaction_context *ast; + char *tmp; + + ast = i_new(struct antispam_transaction_context, 1); + + ast->count = 0; + + tmp = i_strconcat(tmpdir, "/antispam-mail-XXXXXX", NULL); + + ast->tmpdir = mkdtemp(tmp); + if (!ast->tmpdir) + i_free(tmp); + else + ast->tmplen = strlen(ast->tmpdir); + + return ast; +} + +static int process_tmpdir(struct mailbox_transaction_context *ctx, + struct antispam_transaction_context *ast) +{ + int cnt = ast->count; + int fd; + char *buf; + enum classification wanted; + int rc = 0; + + t_push(); + + buf = t_malloc(20 + ast->tmplen); + + while (rc == 0 && cnt > 0) { + cnt--; + i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", + ast->tmpdir, cnt); + + fd = open(buf, O_RDONLY); + read(fd, &wanted, sizeof(wanted)); + + if ((rc = run_pipe(fd, wanted))) { + mail_storage_set_error(ctx->box->storage, + ME(TEMP) + "failed to send mail"); + debug("run program failed with exit code %d\n", rc); + rc = -1; + } + + close(fd); + } + + t_pop(); + + return rc; +} + +static void clear_tmpdir(struct antispam_transaction_context *ast) +{ + char *buf; + + t_push(); + + buf = t_malloc(20 + ast->tmplen); + + while (ast->count > 0) { + ast->count--; + i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", + ast->tmpdir, ast->count); + unlink(buf); + } + rmdir(ast->tmpdir); + + t_pop(); +} + +static void backend_rollback(struct antispam_transaction_context *ast) +{ + if (ast->tmpdir) { + /* clear it! */ + clear_tmpdir(ast); + i_free(ast->tmpdir); + } + + i_free(ast); +} + +static int backend_commit(struct mailbox_transaction_context *ctx, + struct antispam_transaction_context *ast) +{ + int ret; + + if (!ast->tmpdir) { + i_free(ast); + return 0; + } + + ret = process_tmpdir(ctx, ast); + + clear_tmpdir(ast); + + i_free(ast->tmpdir); + i_free(ast); + + return ret; +} + +static int backend_handle_mail(struct mailbox_transaction_context *t, + struct antispam_transaction_context *ast, + struct mail *mail, enum classification wanted) +{ + struct istream *mailstream; + struct ostream *outstream; + int ret; + char *buf; + const unsigned char *beginning; + size_t size; + int fd; + + if (!ast->tmpdir) { + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to initialise temporary dir"); + return -1; + } + + if (!ham_arg || !spam_arg) { + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "antispam plugin not configured"); + return -1; + } + + mailstream = get_mail_stream(mail); + if (!mailstream) { + mail_storage_set_error(t->box->storage, + ME(EXPUNGED) + "Failed to get mail contents"); + return -1; + } + + t_push(); + + buf = t_malloc(20 + ast->tmplen); + i_snprintf(buf, 20 + ast->tmplen - 1, "%s/%d", ast->tmpdir, ast->count); + + fd = creat(buf, 0600); + if (fd < 0) { + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to create temporary file"); + ret = -1; + goto out; + } + + ast->count++; + + outstream = o_stream_create_from_fd(fd, t->box->pool); + if (!outstream) { + ret = -1; + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to stream temporary file"); + goto out_close; + } + + if (o_stream_send(outstream, &wanted, sizeof(wanted)) + != sizeof(wanted)) { + ret = -1; + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to write marker to temp file"); + goto failed_to_copy; + } + + if (i_stream_read_data(mailstream, &beginning, &size, 5) < 0 || + size < 5) { + ret = -1; + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to read mail beginning"); + goto failed_to_copy; + } + + /* "From "? skip line */ + if (memcmp("From ", beginning, 5) == 0) + i_stream_read_next_line(mailstream); + + if (o_stream_send_istream(outstream, mailstream) < 0) { + ret = -1; + mail_storage_set_error(t->box->storage, + ME(NOTPOSSIBLE) + "Failed to copy to temporary file"); + goto failed_to_copy; + } + + ret = 0; + + failed_to_copy: + o_stream_destroy(&outstream); + out_close: + close(fd); + out: + t_pop(); + + return ret; +} + +static void backend_init(pool_t pool __attr_unused__) +{ + const char *tmp; + int i; + + tmp = get_setting("PIPE_PROGRAM_SPAM_ARG"); + if (!tmp) + tmp = get_setting("MAIL_SPAM"); + if (tmp) { + spam_arg = tmp; + debug("pipe backend spam argument = %s\n", tmp); + } + + tmp = get_setting("PIPE_PROGRAM_NOTSPAM_ARG"); + if (!tmp) + tmp = get_setting("MAIL_NOTSPAM"); + if (tmp) { + ham_arg = tmp; + debug("pipe backend not-spam argument = %s\n", tmp); + } + + tmp = get_setting("PIPE_PROGRAM"); + if (!tmp) + tmp = get_setting("MAIL_SENDMAIL"); + if (tmp) { + pipe_binary = tmp; + debug("pipe backend program = %s\n", tmp); + } + + tmp = get_setting("PIPE_PROGRAM_ARGS"); + if (!tmp) + tmp = get_setting("MAIL_SENDMAIL_ARGS"); + if (tmp) { + extra_args = p_strsplit(pool, tmp, ";"); + extra_args_num = str_array_length( + (const char *const *)extra_args); + for (i = 0; i < extra_args_num; i++) + debug("pipe backend program arg[%d] = %s\n", + i, extra_args[i]); + } + + tmp = get_setting("PIPE_TMPDIR"); + if (!tmp) + tmp = get_setting("MAIL_TMPDIR"); + if (tmp) + tmpdir = tmp; + debug("pipe backend tmpdir %s\n", tmpdir); +} + +static void backend_exit(void) +{ +} + +struct backend antispam_backend = { + .api_version = BACKEND_API_VERSION, + .init = backend_init, + .exit = backend_exit, + .handle_mail = backend_handle_mail, + .start = backend_start, + .rollback = backend_rollback, + .commit = backend_commit, +}; -- cgit v1.2.3 From abaa5d6ecbb4546c51fa42937cc4048373647886 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:43:53 +0100 Subject: make two functions static --- antispam-plugin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/antispam-plugin.c b/antispam-plugin.c index b94481b..a620e4e 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -84,7 +84,7 @@ bool need_folder_hook; struct backend *backend = NULL; /* lower-case string, but keep modified UTF7 unchanged */ -void lowercase_string(const char *in, char *out) +static void lowercase_string(const char *in, char *out) { char ch; @@ -252,8 +252,8 @@ const char *get_setting(const char *name) return env; } -int parse_folder_setting(const char *setting, char ***strings, - const char *display_name) +static int parse_folder_setting(const char *setting, char ***strings, + const char *display_name) { const char *tmp; int cnt = 0; -- cgit v1.2.3 From 9dd56d967ce2eb31d8fadec5db637d55b03dc58a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:44:47 +0100 Subject: document backend selection --- antispam.7 | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/antispam.7 b/antispam.7 index 5544ca3..c08af34 100644 --- a/antispam.7 +++ b/antispam.7 @@ -61,7 +61,7 @@ protocol imap { .SH BACKENDS -The plugin supports multiple backends, there are currently two working +The plugin supports multiple backends, there are currently a few working backends included in the distribution: .SS dspam executable backend (dspam specific) @@ -71,12 +71,13 @@ problems with this approach including (1) it can take a long time during which the IMAP session is blocked (2) when many users retrain many messages at once server load may spike -.SS email sender backend (spam filter agnostic) +.SS pipe backend (spam filter agnostic) -This backend sends mail to ham@example.com or spam@example.com -(actual addresses are configurable) for retraining. This backend can -be very fast to set up if you already have a working setup that uses -training addresses as recommended by many spam filter setups. +This backend simply pipes the mail to train to a process it executes. +This can for example be used to send it as email to mail aliases for +retraining. This backend can be very easy to set up if you already +have a working setup that uses training addresses as recommended by +many spam filter setups. Since this backend simply pipes the message to a program (by default sendmail) it can also be used for all kinds of other spam filters, @@ -111,6 +112,14 @@ plugin { ################## # GENERIC OPTIONS + # backend selection, MUST be configured first, + # there's no default so you need to set one of + # these options: + # antispam_backend = crm114-exec + # antispam_backend = dspam-exec + # antispam_backend = pipe + # antispam_backend = spool2dir + # mail signature (used with any backend requiring a signature) antispam_signature = X-DSPAM-Signature -- cgit v1.2.3 From dab81fb66f30a46c341ebb237e7aa5a6c1fb983b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 11:47:27 +0100 Subject: prepare version 1.4 --- version.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.sh b/version.sh index cae4b64..7849cd8 100755 --- a/version.sh +++ b/version.sh @@ -1,6 +1,6 @@ #!/bin/sh -VERSION=1.3 +VERSION=1.4 if head=$(git rev-parse --verify HEAD 2>/dev/null); then git update-index --refresh --unmerged > /dev/null -- cgit v1.2.3 From 50e2cd6a909000111136cbec1e7a2affd457b31d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 13:01:41 +0100 Subject: bugfix: add / when generating plugin path name --- antispam-plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/antispam-plugin.c b/antispam-plugin.c index a620e4e..23a61c0 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -332,7 +332,7 @@ void PLUGIN_FUNCTION(init)(void) void *lib; if (*tmp != '/') - tmp = t_strconcat(BACKENDDIR, tmp, ".so", NULL); + tmp = t_strconcat(BACKENDDIR, "/", tmp, ".so", NULL); lib = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); if (!lib) { -- cgit v1.2.3 From 7a13a04dc0ef562e53097f614e887285965d4659 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 15:40:03 +0100 Subject: build in all backend plugins --- Makefile | 18 ++---------------- antispam-plugin.c | 31 ++++++++++++------------------- antispam-plugin.h | 15 ++++++++------- crm114-exec.c | 3 +-- dspam-exec.c | 3 +-- pipe.c | 3 +-- signature-log.c | 3 +-- spool2dir.c | 3 +-- 8 files changed, 27 insertions(+), 52 deletions(-) diff --git a/Makefile b/Makefile index 0516a6f..b7a5653 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,6 @@ INSTALLDIR ?= $(moduledir)/imap # Kill CFLAGS from dovecot-config CFLAGS := $(CFLAGSORIG) -backenddir := /usr/lib/dovecot-antispam -LOCALCFLAGS += '-DBACKENDDIR="$(backenddir)"' - # includes/flags we need for building a dovecot plugin INCS += -DHAVE_CONFIG_H INCS += -I$(DOVECOT)/ @@ -41,14 +38,14 @@ ifeq ("$(DEBUG_VERBOSE)", "1") LOCALCFLAGS += -DCONFIG_DEBUG_VERBOSE endif -BACKENDS = dspam-exec.so signature-log.so crm114-exec.so pipe.so spool2dir.so +objs += dspam-exec.o signature-log.o crm114-exec.o pipe.o spool2dir.o # main make rules LOCALCFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) CC ?= cc HOSTCC ?= cc -all: verify_config $(LIBRARY_NAME) $(BACKENDS) +all: verify_config $(LIBRARY_NAME) antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-plugin.h dovecot-version.h $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< @@ -68,23 +65,12 @@ dovecot-version.h: dovecot-version antispam-version.h: version.sh ./version.sh > antispam-version.h -dspam-exec.so: dspam-exec.o signature.o -signature-log.so: signature-log.o signature.o -crm114-exec.so: crm114-exec.o signature.o -pipe.so: pipe.o -spool2dir.so: spool2dir.o - -$(BACKENDS): - $(CC) $(CFLAGS) $(INCS) $(LOCALCFLAGS) $(LDFLAGS) -o $@ $^ - clean: rm -f *.so *.o *~ dovecot-version dovecot-version.h antispam-version.h install: all install -p -m 0755 $(LIBRARY_NAME) $(DESTDIR)$(INSTALLDIR)/ - mkdir -p $(DESTDIR)$(backenddir) - install -p -m 0755 $(BACKENDS) $(DESTDIR)$(backenddir)/ verify_config: @if [ ! -r $(CONFIG) ]; then \ diff --git a/antispam-plugin.c b/antispam-plugin.c index 23a61c0..2b4ff93 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -329,27 +329,20 @@ void PLUGIN_FUNCTION(init)(void) tmp = get_setting("BACKEND"); if (tmp) { - void *lib; - - if (*tmp != '/') - tmp = t_strconcat(BACKENDDIR, "/", tmp, ".so", NULL); - - lib = dlopen(tmp, RTLD_NOW | RTLD_LOCAL); - if (!lib) { - debug("backend failed to load: %s\n", strerror(errno)); + if (strcmp(tmp, "crm114") == 0) + backend = &crm114_backend; + else if (strcmp(tmp, "dspam") == 0) + backend = &dspam_backend; + else if (strcmp(tmp, "pipe") == 0) + backend = &pipe_backend; + else if (strcmp(tmp, "signature") == 0) + backend = &signature_backend; + else if (strcmp(tmp, "spool2dir") == 0) + backend = &spool2dir_backend; + else { + debug("selected invalid backend!\n"); exit(3); } - - backend = dlsym(lib, "antispam_backend"); - if (!backend) { - debug("invalid backend!\n"); - exit(5); - } - - if (backend->api_version != BACKEND_API_VERSION) { - debug("backend API version mismatch"); - exit(7); - } } else { debug("no backend selected!\n"); exit(2); diff --git a/antispam-plugin.h b/antispam-plugin.h index 2caf5a3..728ec1e 100644 --- a/antispam-plugin.h +++ b/antispam-plugin.h @@ -29,14 +29,7 @@ enum classification { CLASS_SPAM, }; -/* Update whenever the struct below needs to change */ -#define API_CODE 1 -#define BACKEND_API_VERSION ((DOVECOT_VERSION << 8) | API_CODE) - struct backend { - /* Set to BACKEND_API_VERSION */ - unsigned int api_version; - void (*init)(pool_t pool); void (*exit)(void); /* @@ -55,8 +48,16 @@ struct backend { struct antispam_transaction_context *ast); }; +/* the selected backend */ extern struct backend *backend; +/* possible backends */ +extern struct backend crm114_backend; +extern struct backend dspam_backend; +extern struct backend pipe_backend; +extern struct backend signature_backend; +extern struct backend spool2dir_backend; + #ifdef CONFIG_DEBUG void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void debugv(char **args); diff --git a/crm114-exec.c b/crm114-exec.c index 3947dbc..ea0babc 100644 --- a/crm114-exec.c +++ b/crm114-exec.c @@ -202,8 +202,7 @@ static void backend_exit(void) { } -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, +struct backend crm114_backend = { .init = backend_init, .exit = backend_exit, .handle_mail = backend_handle_mail, diff --git a/dspam-exec.c b/dspam-exec.c index 4be4af4..a9e0c1d 100644 --- a/dspam-exec.c +++ b/dspam-exec.c @@ -267,8 +267,7 @@ static void backend_exit(void) { } -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, +struct backend dspam_backend = { .init = backend_init, .exit = backend_exit, .handle_mail = backend_handle_mail, diff --git a/pipe.c b/pipe.c index 309f8d9..c0853d6 100644 --- a/pipe.c +++ b/pipe.c @@ -363,8 +363,7 @@ static void backend_exit(void) { } -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, +struct backend pipe_backend = { .init = backend_init, .exit = backend_exit, .handle_mail = backend_handle_mail, diff --git a/signature-log.c b/signature-log.c index d0ab332..7a9b422 100644 --- a/signature-log.c +++ b/signature-log.c @@ -160,8 +160,7 @@ static void backend_exit(void) { } -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, +struct backend signature_backend = { .init = backend_init, .exit = backend_exit, .handle_mail = backend_handle_mail, diff --git a/spool2dir.c b/spool2dir.c index 26fcd3e..2d9691b 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -258,8 +258,7 @@ static void backend_exit(void) { } -struct backend antispam_backend = { - .api_version = BACKEND_API_VERSION, +struct backend spool2dir_backend = { .init = backend_init, .exit = backend_exit, .handle_mail = backend_handle_mail, -- cgit v1.2.3 From 17fd064d36e1e6962305d78844605dd8f22c4837 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 27 Feb 2011 15:59:49 +0100 Subject: remove -ldl --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b7a5653..de754bf 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-p $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< $(LIBRARY_NAME): $(objs) - $(CC) $(CFLAGS) $(LOCALCFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) -ldl + $(CC) $(CFLAGS) $(LOCALCFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) dovecot-version: dovecot-version.c $(CONFIG) $(HOSTCC) $(INCS) -o dovecot-version dovecot-version.c -- cgit v1.2.3 From b3d7e7bce03946102ff79aeef225106316b23edc Mon Sep 17 00:00:00 2001 From: Ron Date: Sun, 6 Mar 2011 10:51:42 +1030 Subject: Drop dlfcn.h again now the plugins are builtin --- antispam-plugin.c | 1 - 1 file changed, 1 deletion(-) diff --git a/antispam-plugin.c b/antispam-plugin.c index 2b4ff93..5260948 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -27,7 +27,6 @@ #include #include -#include /* dovecot headers we need */ #include "lib.h" -- cgit v1.2.3 From 65d997f8fe4c3786044dc79047dce5fc56facde5 Mon Sep 17 00:00:00 2001 From: Ron Date: Sun, 6 Mar 2011 11:24:29 +1030 Subject: Add signature.o back to the build And drop a stray tab in the prerequisites. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index de754bf..9e56245 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ ifeq ("$(DEBUG_VERBOSE)", "1") LOCALCFLAGS += -DCONFIG_DEBUG_VERBOSE endif -objs += dspam-exec.o signature-log.o crm114-exec.o pipe.o spool2dir.o +objs += dspam-exec.o signature-log.o crm114-exec.o pipe.o spool2dir.o signature.o # main make rules LOCALCFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) @@ -50,7 +50,7 @@ all: verify_config $(LIBRARY_NAME) antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-plugin.h dovecot-version.h $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< -%.o: %.c $(CONFIG) antispam-plugin.h dovecot-version.h antispam-version.h +%.o: %.c $(CONFIG) antispam-plugin.h dovecot-version.h antispam-version.h $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< $(LIBRARY_NAME): $(objs) -- cgit v1.2.3 From 4e74951f612263f40c07459e8a9304904c4421f2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 6 Mar 2011 10:24:51 +0100 Subject: fix spool2dir error handling bug pointed out by Ron, thanks. --- spool2dir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spool2dir.c b/spool2dir.c index 2d9691b..59293d8 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -131,7 +131,7 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, { struct istream *mailstream; struct ostream *outstream; - int ret; + int ret = -1; const char *dest, *buf; const unsigned char *beginning; size_t size; @@ -198,7 +198,6 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, if (i_stream_read_data(mailstream, &beginning, &size, 5) < 0 || size < 5) { - ret = -1; mail_storage_set_error(t->box->storage, ME(NOTPOSSIBLE) "Failed to read mail beginning"); @@ -210,7 +209,6 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, i_stream_read_next_line(mailstream); if (o_stream_send_istream(outstream, mailstream) < 0) { - ret = -1; mail_storage_set_error(t->box->storage, ME(NOTPOSSIBLE) "Failed to copy to spool file"); -- cgit v1.2.3 From 9ad6e48571bc99f5b629cdd2ecbf29ffe335ca7b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Mar 2011 15:55:48 +0100 Subject: spool2dir: fix destination file loop --- spool2dir.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/spool2dir.c b/spool2dir.c index 59293d8..da17c5b 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -135,7 +135,7 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, const char *dest, *buf; const unsigned char *beginning; size_t size; - int fd; + int fd = -1; i_assert(ast); @@ -171,13 +171,14 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, while (ast->count <= 9999) { buf = t_strdup_printf(dest, (long)time(0), (long)++ast->count); fd = open(buf, O_CREAT | O_EXCL | O_WRONLY, 0600); - if(fd >= 0 || errno != EEXIST) + if (fd >= 0 || errno != EEXIST) break; /* current filename in buf already exists, zap it */ t_pop(); t_push(); - /* buf is invalid now ! */ + /* buf is invalid now! */ } + if (fd < 0) { debug("spool2dir backend: Failed to create spool file %s: %s\n", dest, strerror(errno)); @@ -188,6 +189,7 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, } /* buf still points to allocated memory, because fd >= 0 */ + outstream = o_stream_create_from_fd(fd, t->box->pool); if (!outstream) { mail_storage_set_error(t->box->storage, @@ -221,10 +223,9 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, o_stream_destroy(&outstream); out_close: close(fd); - out: if (ret) unlink(buf); - + out: t_pop(); return ret; -- cgit v1.2.3 From 056f20bb29213d7ec32376124f5598f3d4e8b85e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Mar 2011 15:58:10 +0100 Subject: spool2dir: fix some codestyle issues --- spool2dir.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spool2dir.c b/spool2dir.c index da17c5b..edd5bd3 100644 --- a/spool2dir.c +++ b/spool2dir.c @@ -233,15 +233,17 @@ static int backend_handle_mail(struct mailbox_transaction_context *t, static void backend_init(pool_t pool __attr_unused__) { - if((spamspool = get_setting("SPOOL2DIR_SPAM"))) + spamspool = get_setting("SPOOL2DIR_SPAM"); + if (spamspool) debug("spool2dir spamspool %s\n", spamspool); - if((hamspool = get_setting("SPOOL2DIR_NOTSPAM"))) + hamspool = get_setting("SPOOL2DIR_NOTSPAM"); + if (hamspool) debug("spool2dir hamspool %s\n", hamspool); } static struct antispam_transaction_context * - backend_start(struct mailbox *box __attr_unused__) +backend_start(struct mailbox *box __attr_unused__) { struct antispam_transaction_context *ast; -- cgit v1.2.3 From 2e82b97c5411b2b9d2c5d9615260cb7724153e96 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Mar 2011 15:59:35 +0100 Subject: more no-plugin cleanup --- defconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/defconfig b/defconfig index f6de237..361c0c5 100644 --- a/defconfig +++ b/defconfig @@ -20,9 +20,6 @@ DOVECOT=/usr/include/dovecot # install directory for 'make install' # NB no need for a final '/' INSTALLDIR=/usr/lib/dovecot/modules/imap -# The user and group for the installed plugin -USER=root -GROUP=root # enable debugging to syslog or stderr #DEBUG=stderr -- cgit v1.2.3 From 5ee29e4f74209bb8c5a85ae8c10763d0f7a50963 Mon Sep 17 00:00:00 2001 From: Ron Date: Sat, 12 Mar 2011 15:54:03 +1030 Subject: Tweak the antispam_backend option docs With the backends built in, it's now crm114 or dspam, without the -exec. --- antispam.7 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/antispam.7 b/antispam.7 index c08af34..48f5a01 100644 --- a/antispam.7 +++ b/antispam.7 @@ -93,7 +93,7 @@ You need to use the unsure folder option (see below) together with this plugin and deliver unsure mail into an unsure folder, spam mail into a spam folder and other mail regularly. -Has the same drawbacks as the dspam-exec approach. +Has the same drawbacks as the dspam approach. .SS spool2dir backend (general) @@ -115,8 +115,8 @@ plugin { # backend selection, MUST be configured first, # there's no default so you need to set one of # these options: - # antispam_backend = crm114-exec - # antispam_backend = dspam-exec + # antispam_backend = crm114 + # antispam_backend = dspam # antispam_backend = pipe # antispam_backend = spool2dir @@ -179,7 +179,7 @@ plugin { # #=================== - # dspam-exec plugin + # dspam plugin # dspam binary antispam_dspam_binary = /usr/bin/dspam @@ -232,7 +232,7 @@ plugin { #antispam_pipe_program_args = -f;%u@example.com # % expansion done by dovecot #=================== - # crm114-exec plugin + # crm114 plugin # mailreaver binary antispam_crm_binary = /bin/false -- cgit v1.2.3 From 27d016eeb4536fdebd89882133fc5daa614ecf17 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Mar 2011 12:27:23 +0100 Subject: make debugging dynamic --- Makefile | 18 +----------------- antispam-plugin.c | 25 +++++++++++++++++++++++++ antispam-plugin.h | 31 +++++++++++-------------------- antispam.7 | 9 +++++++++ debug.c | 46 ++++++++++++++++++++++++++++++++++++++-------- defconfig | 7 ------- dspam-exec.c | 4 +--- 7 files changed, 85 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index 9e56245..68c30a3 100644 --- a/Makefile +++ b/Makefile @@ -21,23 +21,7 @@ INCS += -I$(DOVECOT)/src/imap/ # output name LIBRARY_NAME ?= lib90_$(PLUGINNAME)_plugin.so -objs = antispam-storage.o antispam-plugin.o - -# debug rules -ifeq ("$(DEBUG)", "stderr") -LOCALCFLAGS += -DCONFIG_DEBUG -DDEBUG_STDERR -objs += debug.o -else -ifeq ("$(DEBUG)", "syslog") -LOCALCFLAGS += -DCONFIG_DEBUG -DDEBUG_SYSLOG -objs += debug.o -endif -endif - -ifeq ("$(DEBUG_VERBOSE)", "1") -LOCALCFLAGS += -DCONFIG_DEBUG_VERBOSE -endif - +objs = antispam-storage.o antispam-plugin.o debug.o objs += dspam-exec.o signature-log.o crm114-exec.o pipe.o spool2dir.o signature.o # main make rules diff --git a/antispam-plugin.c b/antispam-plugin.c index 5260948..bbcc0e6 100644 --- a/antispam-plugin.c +++ b/antispam-plugin.c @@ -300,8 +300,33 @@ void PLUGIN_FUNCTION(init)(void) char * const *iter; int spam_folder_count; + debug_target = ADT_NONE; + verbose_debug = 0; + + tmp = get_setting("DEBUG_TARGET"); + if (tmp) { + if (strcmp(tmp, "syslog") == 0) + debug_target = ADT_SYSLOG; + else if (strcmp(tmp, "stderr") == 0) + debug_target = ADT_STDERR; + else + exit(4); + } + debug("plugin initialising (%s)\n", ANTISPAM_VERSION); + tmp = get_setting("VERBOSE_DEBUG"); + if (tmp) { + char *endp; + unsigned long val = strtoul(tmp, &endp, 10); + if (*endp || val >= 2) { + debug("Invalid verbose_debug setting"); + exit(5); + } + verbose_debug = val; + debug_verbose("verbose debug enabled"); + } + global_pool = pool_alloconly_create("antispam-pool", 1024); parse_folder_setting("TRASH", trash_folders, "trash"); diff --git a/antispam-plugin.h b/antispam-plugin.h index 728ec1e..a06a1e9 100644 --- a/antispam-plugin.h +++ b/antispam-plugin.h @@ -58,28 +58,19 @@ extern struct backend pipe_backend; extern struct backend signature_backend; extern struct backend spool2dir_backend; -#ifdef CONFIG_DEBUG +enum antispam_debug_target { + ADT_NONE, + ADT_STDERR, + ADT_SYSLOG, +}; + +extern enum antispam_debug_target debug_target; +extern int verbose_debug; + void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void debugv(char **args); -#else -static void debug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -static inline void debug(const char *fmt __attribute__((unused)), ...) -{ -} -static inline void debugv(char **args __attribute__((unused))) -{ -} -#endif - -#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_VERBOSE) -/* bit of an ugly short-cut */ -#define debug_verbose debug -#else -static void debug_verbose(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -static inline void debug_verbose(const char *fmt __attribute__((unused)), ...) -{ -} -#endif +void debugv_not_stderr(char **args); +void debug_verbose(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void antispam_mail_storage_created(struct mail_storage *storage); extern void (*antispam_next_hook_mail_storage_created)(struct mail_storage *storage); diff --git a/antispam.7 b/antispam.7 index 48f5a01..b506ce9 100644 --- a/antispam.7 +++ b/antispam.7 @@ -112,6 +112,15 @@ plugin { ################## # GENERIC OPTIONS + # Debugging options + # Uncomment to get the desired debugging behaviour. + # Note that in some cases stderr debugging will not be as + # verbose as syslog debugging due to internal limitations. + # + # antispam_debug_target = syslog + # antispam_debug_target = stderr + # antispam_verbose_debug = 1 + # backend selection, MUST be configured first, # there's no default so you need to set one of # these options: diff --git a/debug.c b/debug.c index 7f3e407..a3e0fc4 100644 --- a/debug.c +++ b/debug.c @@ -4,22 +4,32 @@ #include #include "antispam-plugin.h" +enum antispam_debug_target debug_target; +int verbose_debug; + static void _debug(const char *format, va_list ap) { const char *fmt; + if (debug_target == ADT_NONE) + return; + t_push(); fmt = t_strconcat(stringify(PLUGINNAME), ": ", format, NULL); -#if defined(DEBUG_SYSLOG) - vsyslog(LOG_DEBUG, fmt, ap); -#elif defined(DEBUG_STDERR) - vfprintf(stderr, fmt, ap); - fflush(stderr); -#else -#error no logging method -#endif + switch (debug_target) { + case ADT_NONE: + break; + case ADT_SYSLOG: + vsyslog(LOG_DEBUG, fmt, ap); + break; + case ADT_STDERR: + vfprintf(stderr, fmt, ap); + fflush(stderr); + break; + } + t_pop(); } @@ -64,3 +74,23 @@ void debugv(char **args) debug("%s", buf); t_pop(); } + +void debugv_not_stderr(char **args) +{ + if (debug_target == ADT_STDERR) + return; + + debugv(args); +} + +void debug_verbose(const char *fmt, ...) +{ + va_list args; + + if (!verbose_debug) + return; + + va_start(args, fmt); + _debug(fmt, args); + va_end(args); +} diff --git a/defconfig b/defconfig index 361c0c5..0eb1db3 100644 --- a/defconfig +++ b/defconfig @@ -21,13 +21,6 @@ DOVECOT=/usr/include/dovecot # NB no need for a final '/' INSTALLDIR=/usr/lib/dovecot/modules/imap -# enable debugging to syslog or stderr -#DEBUG=stderr -#DEBUG=syslog - -# verbose debugging (lots of output!) -#DEBUG_VERBOSE=1 - # plugin name, change only if you need to rename the plugin # (because, for example, you need two instances for different # spam filters installed) diff --git a/dspam-exec.c b/dspam-exec.c index a9e0c1d..c4a49b4 100644 --- a/dspam-exec.c +++ b/dspam-exec.c @@ -141,13 +141,11 @@ static int call_dspam(const char *signature, enum classification wanted) for (i = 0; i < extra_args_num; i++) argv[i + 4] = (char *)extra_args[i]; -#ifdef DEBUG_SYSLOG /* * not good with stderr debuggin since we then write to * stderr which our parent takes as a bug */ - debugv(argv); -#endif + debugv_not_stderr(argv); execv(dspam_binary, argv); debug("executing %s failed: %d (uid=%d, gid=%d)", -- cgit v1.2.3 From 808eaa49efe2dc2438ef98ddf4bac4cfd2898a3d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 12 Mar 2011 13:03:45 +0100 Subject: remove need for .config file --- Makefile | 25 +++++++++++++------------ defconfig | 11 +++++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 68c30a3..5b4b00a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ -# include config file +# include config file if present CONFIG ?= .config -include $(CONFIG) CFLAGSORIG := $(CFLAGS) +DOVECOT ?= /usr/include/dovecot +PLUGINNAME ?= antispam -include $(DOVECOT)/dovecot-config INSTALLDIR ?= $(moduledir)/imap # Kill CFLAGS from dovecot-config @@ -29,18 +31,18 @@ LOCALCFLAGS += -fPIC -shared -Wall -Wextra -DPLUGINNAME=$(PLUGINNAME) CC ?= cc HOSTCC ?= cc -all: verify_config $(LIBRARY_NAME) +all: $(LIBRARY_NAME) -antispam-storage.o: antispam-storage.c antispam-storage-*.c $(CONFIG) antispam-plugin.h dovecot-version.h +antispam-storage.o: antispam-storage.c antispam-storage-*.c antispam-plugin.h dovecot-version.h $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< -%.o: %.c $(CONFIG) antispam-plugin.h dovecot-version.h antispam-version.h +%.o: %.c antispam-plugin.h dovecot-version.h antispam-version.h $(CC) -c $(CFLAGS) $(LOCALCFLAGS) $(INCS) -o $@ $< $(LIBRARY_NAME): $(objs) $(CC) $(CFLAGS) $(LOCALCFLAGS) $(INCS) $(objs) -o $(LIBRARY_NAME) $(LDFLAGS) -dovecot-version: dovecot-version.c $(CONFIG) +dovecot-version: dovecot-version.c $(HOSTCC) $(INCS) -o dovecot-version dovecot-version.c dovecot-version.h: dovecot-version @@ -53,13 +55,12 @@ antispam-version.h: version.sh clean: rm -f *.so *.o *~ dovecot-version dovecot-version.h antispam-version.h -install: all +install: all checkinstalldir install -p -m 0755 $(LIBRARY_NAME) $(DESTDIR)$(INSTALLDIR)/ -verify_config: - @if [ ! -r $(CONFIG) ]; then \ - echo -e "\nBuilding the plugin requires a configuration file"; \ - echo -e $(CONFIG)'. Copy defconfig ("cp defconfig' $(CONFIG)'")' ; \ - echo -e "to create an example configuration.\n"; \ - exit 1; \ +checkinstalldir: + @if [ ! -d "$(DESTDIR)$(INSTALLDIR)/" ] ; then \ + echo "Installation directory $(DESTDIR)$(INSTALLDIR)/ doesn't exist," ; \ + echo "run make install INSTALLDIR=..." ; \ + exit 2 ; \ fi diff --git a/defconfig b/defconfig index 0eb1db3..34a1633 100644 --- a/defconfig +++ b/defconfig @@ -13,18 +13,21 @@ # Building the plugin requires configured dovecot sources or having # configured it with --enable-header-install in which case you can # point DOVECOT= to the installed headers too. +# If unset, it defaults to /usr/include/dovecot which typically is the +# right place so you don't have to worry about it. #DOVECOT=../dovecot-1.0.5 #DOVECOT=../dovecot-1.1 -DOVECOT=/usr/include/dovecot +#DOVECOT=/usr/include/dovecot # install directory for 'make install' # NB no need for a final '/' INSTALLDIR=/usr/lib/dovecot/modules/imap # plugin name, change only if you need to rename the plugin -# (because, for example, you need two instances for different -# spam filters installed) -PLUGINNAME=antispam +# (for backward compatibility reasons, there no longer is a +# need for this since backends can be configured dynamically). +# If unset, defaults to "antispam" which is what you want. +# PLUGINNAME=antispam # extra CFLAGS # CFLAGS += -g3 -- cgit v1.2.3