commit 6840f1a1324e44cbaa373c963504b7b0eedeb569 from: Martijn van Duren date: Thu Aug 22 13:05:43 2019 UTC Drag filter-dkim into the libopensmtpd world commit - 27541da87a2e82efb16eaac56bb5c10e12859b29 commit + 6840f1a1324e44cbaa373c963504b7b0eedeb569 blob - e621fb18c804aeddd0113a789eeeb8e34d0e7423 blob + 162410079b5787f759025db694c5a456932a50f6 --- Makefile +++ Makefile @@ -2,10 +2,14 @@ PROG= filter-dkim BINDIR= /usr/libexec/smtpd/ -SRCS+= main.c smtp_proc.c +SRCS+= main.c -CFLAGS+= -g3 -O0 -LDADD+= -levent -lcrypto +CFLAGS+=-Wall -I${.CURDIR} +CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes +CFLAGS+=-Wmissing-declarations +CFLAGS+=-Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+=-Wsign-compare +LDADD+= -levent -lcrypto -lopensmtpd DPADD= ${LIBEVENT} ${LIBCRYPTO} .include blob - 114ca8bc90f950566cfe35bb43c14ae1b58834c9 blob + 18fee80d2299c7e4fff8667e6aba71006f622039 --- filter-dkim.1 +++ filter-dkim.1 @@ -22,13 +22,11 @@ .Nd add dkim signature to messages .Sh SYNOPSIS .Nm +.Op Fl tz .Op Fl a Ar algorithm .Op Fl c Ar canonicalization .Op Fl h Ar headers -.Op Fl t .Op Fl x Ar seconds -.Op Fl z -.Op Fl Z .Fl d Ar domain .Fl k Ar file .Fl s Ar selector @@ -71,10 +69,10 @@ Add the amount of the signature is valid to the dkim header. .It Fl z Add the mail headers used in the dkim signature to the dkim header. +If a second +.Fl z +is specified all headers will be included in the dkim header. Useful for debugging purposes. -.It Fl Z -Add all the mail headers to the dkim header. -Useful for debugging purposes. .El .Sh SEE ALSO .Xr smtpd 8 blob - 0d1c69f72c27f74d37a5e6d2083227dea8b7cf05 blob + 5a258366c31fcf1c07bdb19fc046fa0d549a4eea --- main.c +++ main.c @@ -13,14 +13,11 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include - #include #include #include #include -#include #include #include #include @@ -30,7 +27,7 @@ #include #include -#include "smtp_proc.h" +#include "opensmtpd.h" struct dkim_signature { char *signature; @@ -38,9 +35,7 @@ struct dkim_signature { size_t len; }; -struct dkim_session { - uint64_t reqid; - uint64_t token; +struct dkim_message { FILE *origf; int parsing_headers; char **headers; @@ -51,12 +46,8 @@ struct dkim_session { int err; EVP_MD_CTX *b; EVP_MD_CTX *bh; - RB_ENTRY(dkim_session) entry; }; -RB_HEAD(dkim_sessions, dkim_session) dkim_sessions = RB_INITIALIZER(NULL); -RB_PROTOTYPE(dkim_sessions, dkim_session, entry, dkim_session_cmp); - /* RFC 6376 section 5.4.1 */ static char *dsign_headers[] = { "from", @@ -103,41 +94,35 @@ static const EVP_MD *hash_md; #define DKIM_SIGNATURE_LINELEN 78 void usage(void); -void dkim_err(struct dkim_session *, char *); -void dkim_errx(struct dkim_session *, char *); +void dkim_err(struct dkim_message *, char *); +void dkim_errx(struct dkim_message *, char *); void dkim_headers_set(char *); -void dkim_dataline(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t, char *); -void dkim_commit(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t); -void dkim_disconnect(char *, int, struct timespec *, char *, char *, uint64_t); -struct dkim_session *dkim_session_new(uint64_t); -void dkim_session_free(struct dkim_session *); -int dkim_session_cmp(struct dkim_session *, struct dkim_session *); -void dkim_parse_header(struct dkim_session *, char *, int); -void dkim_parse_body(struct dkim_session *, char *); -void dkim_sign(struct dkim_session *); -int dkim_signature_printheader(struct dkim_session *, char *); -int dkim_signature_printf(struct dkim_session *, char *, ...) +void dkim_dataline(struct osmtpd_ctx *, const char *); +void dkim_commit(struct osmtpd_ctx *); +void *dkim_message_new(struct osmtpd_ctx *); +void dkim_message_free(struct osmtpd_ctx *, void *); +void dkim_parse_header(struct dkim_message *, char *, int); +void dkim_parse_body(struct dkim_message *, char *); +void dkim_sign(struct osmtpd_ctx *); +int dkim_signature_printheader(struct dkim_message *, const char *); +int dkim_signature_printf(struct dkim_message *, char *, ...) __attribute__((__format__ (printf, 2, 3))); -int dkim_signature_normalize(struct dkim_session *); -int dkim_signature_need(struct dkim_session *, size_t); -int dkim_sign_init(struct dkim_session *); +int dkim_signature_normalize(struct dkim_message *); +int dkim_signature_need(struct dkim_message *, size_t); +int dkim_sign_init(struct dkim_message *); int main(int argc, char *argv[]) { int ch; - int i; - int debug = 0; FILE *keyfile; const char *errstr; - while ((ch = getopt(argc, argv, "a:c:Dd:h:k:s:tx:zZ")) != -1) { + while ((ch = getopt(argc, argv, "a:c:d:h:k:s:tx:z")) != -1) { switch (ch) { case 'a': if (strncmp(optarg, "rsa-", 4) != 0) - err(1, "invalid algorithm"); + osmtpd_err(1, "invalid algorithm"); hashalg = optarg + 4; break; case 'c': @@ -148,18 +133,19 @@ main(int argc, char *argv[]) canonheader = CANON_RELAXED; optarg += 7; } else - err(1, "Invalid canonicalization"); + osmtpd_err(1, "Invalid canonicalization"); if (optarg[0] == '/') { if (strcmp(optarg + 1, "simple") == 0) canonbody = CANON_SIMPLE; else if (strcmp(optarg + 1, "relaxed") == 0) canonbody = CANON_RELAXED; else - err(1, "Invalid canonicalization"); + osmtpd_err(1, + "Invalid canonicalization"); } else if (optarg[0] == '\0') canonbody = CANON_SIMPLE; else - err(1, "Invalid canonicalization"); + osmtpd_err(1, "Invalid canonicalization"); break; case 'd': domain = optarg; @@ -169,12 +155,13 @@ main(int argc, char *argv[]) break; case 'k': if ((keyfile = fopen(optarg, "r")) == NULL) - err(1, "Can't open key file"); + osmtpd_err(1, "Can't open key file (%s)", + optarg); pkey = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL); if (pkey == NULL) - errx(1, "Can't read key file"); + osmtpd_errx(1, "Can't read key file"); if (EVP_PKEY_get0_RSA(pkey) == NULL) - err(1, "Key is not of type rsa"); + osmtpd_err(1, "Key is not of type rsa"); fclose(keyfile); break; case 's': @@ -186,17 +173,11 @@ main(int argc, char *argv[]) case 'x': addexpire = strtonum(optarg, 1, INT64_MAX, &errstr); if (addexpire == 0) - errx(1, "Expire offset is %s", errstr); + osmtpd_errx(1, "Expire offset is %s", errstr); break; case 'z': - addheaders = 1; + addheaders++; break; - case 'Z': - addheaders = 2; - break; - case 'D': - debug = 1; - break; default: usage(); } @@ -204,170 +185,135 @@ main(int argc, char *argv[]) OpenSSL_add_all_digests(); if ((hash_md = EVP_get_digestbyname(hashalg)) == NULL) - errx(1, "Can't find hash: %s", hashalg); + osmtpd_errx(1, "Can't find hash: %s", hashalg); - /* - * fattr required for tmpfile. - * Can hopefully be removed in the future - */ - if (pledge("fattr tmppath stdio", NULL) == -1) - err(1, "pledge"); + if (pledge("tmppath stdio", NULL) == -1) + osmtpd_err(1, "pledge"); if (domain == NULL || selector == NULL || pkey == NULL) usage(); - smtp_register_filter_dataline(dkim_dataline); - smtp_register_filter_commit(dkim_commit); - smtp_in_register_report_disconnect(dkim_disconnect); - smtp_run(debug); + osmtpd_register_filter_dataline(dkim_dataline); + osmtpd_register_filter_commit(dkim_commit); + osmtpd_local_message(dkim_message_new, dkim_message_free); + osmtpd_run(); return 0; } void -dkim_disconnect(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid) +dkim_dataline(struct osmtpd_ctx *ctx, const char *line) { - struct dkim_session *session, search; - - search.reqid = reqid; - if ((session = RB_FIND(dkim_sessions, &dkim_sessions, &search)) != NULL) - dkim_session_free(session); -} - -void -dkim_dataline(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid, uint64_t token, char *line) -{ - struct dkim_session *session, search; + struct dkim_message *message = ctx->local_message; + char *linedup; size_t linelen; - search.reqid = reqid; - session = RB_FIND(dkim_sessions, &dkim_sessions, &search); - if (session == NULL) { - if ((session = dkim_session_new(reqid)) == NULL) - return; - session->token = token; - } else if (session->token != token) - errx(1, "Token incorrect"); - if (session->err) + if (message->err) return; linelen = strlen(line); - if (fprintf(session->origf, "%s\n", line) < linelen) - dkim_err(session, "Couldn't write to tempfile"); + if (fprintf(message->origf, "%s\n", line) < (int) linelen) + dkim_err(message, "Couldn't write to tempfile"); if (line[0] == '.' && line[1] =='\0') { - dkim_sign(session); - } else if (linelen != 0 && session->parsing_headers) { + dkim_sign(ctx); + } else if (linelen != 0 && message->parsing_headers) { if (line[0] == '.') line++; - dkim_parse_header(session, line, 0); - } else if (linelen == 0 && session->parsing_headers) { - if (addheaders > 0 && !dkim_signature_printf(session, "; ")) + if ((linedup = strdup(line)) == NULL) + osmtpd_err(1, "strdup"); + dkim_parse_header(message, linedup, 0); + free(linedup); + } else if (linelen == 0 && message->parsing_headers) { + if (addheaders > 0 && !dkim_signature_printf(message, "; ")) return; - session->parsing_headers = 0; + message->parsing_headers = 0; } else { if (line[0] == '.') line++; - dkim_parse_body(session, line); + if ((linedup = strdup(line)) == NULL) + osmtpd_err(1, "strdup"); + dkim_parse_body(message, linedup); + free(linedup); } } void -dkim_commit(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid, uint64_t token) +dkim_commit(struct osmtpd_ctx *ctx) { - struct dkim_session *session, search; + struct dkim_message *message = ctx->local_message; - search.reqid = reqid; - if ((session = RB_FIND(dkim_sessions, &dkim_sessions, &search)) == NULL) - errx(1, "Commit on undefined session"); - - if (session->err) - smtp_filter_disconnect(session->reqid, session->token, - "Internal server error"); + if (message->err) + osmtpd_filter_disconnect(ctx, "Internal server error"); else - smtp_filter_proceed(reqid, token); - - dkim_session_free(session); + osmtpd_filter_proceed(ctx); } -struct dkim_session * -dkim_session_new(uint64_t reqid) +void * +dkim_message_new(struct osmtpd_ctx *ctx) { - struct dkim_session *session; - struct dkim_signature *signature; + struct dkim_message *message; - if ((session = calloc(1, sizeof(*session))) == NULL) - err(1, NULL); + if ((message = calloc(1, sizeof(*message))) == NULL) + osmtpd_err(1, NULL); - session->reqid = reqid; - if ((session->origf = tmpfile()) == NULL) { - dkim_err(session, "Can't open tempfile"); + if ((message->origf = tmpfile()) == NULL) { + dkim_err(message, "Can't open tempfile"); return NULL; } - session->parsing_headers = 1; + message->parsing_headers = 1; - session->body_whitelines = 0; - session->headers = calloc(1, sizeof(*(session->headers))); - if (session->headers == NULL) { - dkim_err(session, "Can't save headers"); + message->body_whitelines = 0; + message->headers = calloc(1, sizeof(*(message->headers))); + if (message->headers == NULL) { + dkim_err(message, "Can't save headers"); return NULL; } - session->lastheader = 0; - session->signature.signature = NULL; - session->signature.size = 0; - session->signature.len = 0; - session->err = 0; + message->lastheader = 0; + message->signature.signature = NULL; + message->signature.size = 0; + message->signature.len = 0; + message->err = 0; - if (!dkim_signature_printf(session, + if (!dkim_signature_printf(message, "DKIM-signature: v=%s; a=%s-%s; c=%s/%s; d=%s; s=%s; ", "1", cryptalg, hashalg, canonheader == CANON_SIMPLE ? "simple" : "relaxed", canonbody == CANON_SIMPLE ? "simple" : "relaxed", domain, selector)) return NULL; - if (addheaders > 0 && !dkim_signature_printf(session, "z=")) + if (addheaders > 0 && !dkim_signature_printf(message, "z=")) return NULL; - if ((session->b = EVP_MD_CTX_new()) == NULL || - (session->bh = EVP_MD_CTX_new()) == NULL) { - dkim_errx(session, "Can't create hash context"); + if ((message->b = EVP_MD_CTX_new()) == NULL || + (message->bh = EVP_MD_CTX_new()) == NULL) { + dkim_errx(message, "Can't create hash context"); return NULL; } - if (EVP_DigestSignInit(session->b, NULL, hash_md, NULL, pkey) <= 0 || - EVP_DigestInit_ex(session->bh, hash_md, NULL) == 0) { - dkim_errx(session, "Failed to initialize hash context"); + if (EVP_DigestSignInit(message->b, NULL, hash_md, NULL, pkey) <= 0 || + EVP_DigestInit_ex(message->bh, hash_md, NULL) == 0) { + dkim_errx(message, "Failed to initialize hash context"); return NULL; } - if (RB_INSERT(dkim_sessions, &dkim_sessions, session) != NULL) - errx(1, "session already registered"); - return session; + return message; } void -dkim_session_free(struct dkim_session *session) +dkim_message_free(struct osmtpd_ctx *ctx, void *data) { + struct dkim_message *message = data; size_t i; - RB_REMOVE(dkim_sessions, &dkim_sessions, session); - fclose(session->origf); - EVP_MD_CTX_free(session->b); - EVP_MD_CTX_free(session->bh); - free(session->signature.signature); - for (i = 0; session->headers[i] != NULL; i++) - free(session->headers[i]); - free(session->headers); - free(session); + fclose(message->origf); + EVP_MD_CTX_free(message->b); + EVP_MD_CTX_free(message->bh); + free(message->signature.signature); + for (i = 0; message->headers[i] != NULL; i++) + free(message->headers[i]); + free(message->headers); + free(message); } -int -dkim_session_cmp(struct dkim_session *s1, struct dkim_session *s2) -{ - return (s1->reqid < s2->reqid ? -1 : s1->reqid > s2->reqid); -} - void dkim_headers_set(char *headers) { @@ -379,21 +325,21 @@ dkim_headers_set(char *headers) for (i = 0; headers[i] != '\0'; i++) { /* RFC 5322 field-name */ if (!(headers[i] >= 33 && headers[i] <= 126)) - errx(1, "-h: invalid character"); + osmtpd_errx(1, "-h: invalid character"); if (headers[i] == ':') { /* Test for empty headers */ if (i == 0 || headers[i - 1] == ':') - errx(1, "-h: header can't be empty"); + osmtpd_errx(1, "-h: header can't be empty"); nsign_headers++; } headers[i] = tolower(headers[i]); } if (headers[i - 1] == ':') - errx(1, "-h: header can't be empty"); + osmtpd_errx(1, "-h: header can't be empty"); - sign_headers = reallocarray(NULL, nsign_headers + 1, sizeof(*sign_headers)); - if (sign_headers == NULL) - errx(1, NULL); + if ((sign_headers = reallocarray(NULL, nsign_headers + 1, + sizeof(*sign_headers))) == NULL) + osmtpd_errx(1, NULL); for (i = 0; i < nsign_headers; i++) { sign_headers[i] = headers; @@ -405,25 +351,25 @@ dkim_headers_set(char *headers) has_from = 1; } if (!has_from) - errx(1, "From header must be included"); + osmtpd_errx(1, "From header must be included"); } void -dkim_err(struct dkim_session *session, char *msg) +dkim_err(struct dkim_message *message, char *msg) { - session->err = 1; - warn("%s", msg); + message->err = 1; + fprintf(stderr, "%s\n", msg); } void -dkim_errx(struct dkim_session *session, char *msg) +dkim_errx(struct dkim_message *message, char *msg) { - session->err = 1; - warnx("%s", msg); + message->err = 1; + fprintf(stderr, "%s\n", msg); } void -dkim_parse_header(struct dkim_session *session, char *line, int force) +dkim_parse_header(struct dkim_message *message, char *line, int force) { size_t i; size_t r, w; @@ -436,13 +382,13 @@ dkim_parse_header(struct dkim_session *session, char * char *tmp; if (addheaders == 2 && !force && - !dkim_signature_printheader(session, line)) + !dkim_signature_printheader(message, line)) return; - if ((line[0] == ' ' || line[0] == '\t') && !session->lastheader) + if ((line[0] == ' ' || line[0] == '\t') && !message->lastheader) return; if ((line[0] != ' ' && line[0] != '\t')) { - session->lastheader = 0; + message->lastheader = 0; for (i = 0; i < nsign_headers; i++) { hlen = strlen(sign_headers[i]); if (strncasecmp(line, sign_headers[i], hlen) == 0) { @@ -458,11 +404,11 @@ dkim_parse_header(struct dkim_session *session, char * } if (addheaders == 1 && !force && - !dkim_signature_printheader(session, line)) + !dkim_signature_printheader(message, line)) return; if (canonheader == CANON_RELAXED) { - if (!session->lastheader) + if (!message->lastheader) fieldname = 1; for (r = w = 0; line[r] != '\0'; r++) { if (line[r] == ':' && fieldname) { @@ -493,48 +439,48 @@ dkim_parse_header(struct dkim_session *session, char * } else linelen = strlen(line); - for (lastheader = 0; session->headers[lastheader] != NULL; lastheader++) + for (lastheader = 0; message->headers[lastheader] != NULL; lastheader++) continue; - if (!session->lastheader) { - mtmp = recallocarray(session->headers, lastheader + 1, + if (!message->lastheader) { + mtmp = recallocarray(message->headers, lastheader + 1, lastheader + 2, sizeof(*mtmp)); if (mtmp == NULL) { - dkim_err(session, "Can't store header"); + dkim_err(message, "Can't store header"); return; } - session->headers = mtmp; - - session->headers[lastheader] = strdup(line); - session->headers[lastheader + 1 ] = NULL; - session->lastheader = 1; + message->headers = mtmp; + + message->headers[lastheader] = strdup(line); + message->headers[lastheader + 1 ] = NULL; + message->lastheader = 1; } else { lastheader--; - linelen += strlen(session->headers[lastheader]); + linelen += strlen(message->headers[lastheader]); if (canonheader == CANON_SIMPLE) linelen += 2; linelen++; - htmp = reallocarray(session->headers[lastheader], linelen, + htmp = reallocarray(message->headers[lastheader], linelen, sizeof(*htmp)); if (htmp == NULL) { - dkim_err(session, "Can't store header"); + dkim_err(message, "Can't store header"); return; } - session->headers[lastheader] = htmp; + message->headers[lastheader] = htmp; if (canonheader == CANON_SIMPLE) { if (strlcat(htmp, "\r\n", linelen) >= linelen) - errx(1, "Missized header"); + osmtpd_errx(1, "Missized header"); } else if (canonheader == CANON_RELAXED && - (tmp = strchr(session->headers[lastheader], ':')) != NULL && + (tmp = strchr(message->headers[lastheader], ':')) != NULL && tmp[1] == '\0') line++; if (strlcat(htmp, line, linelen) >= linelen) - errx(1, "Missized header"); + osmtpd_errx(1, "Missized header"); } } void -dkim_parse_body(struct dkim_session *session, char *line) +dkim_parse_body(struct dkim_message *message, char *line) { size_t r, w; size_t linelen; @@ -555,145 +501,143 @@ dkim_parse_body(struct dkim_session *session, char *li linelen = strlen(line); if (line[0] == '\0') { - session->body_whitelines++; + message->body_whitelines++; return; } - while (session->body_whitelines--) { - if (EVP_DigestUpdate(session->bh, "\r\n", 2) == 0) { - dkim_err(session, "Can't update hash context"); + while (message->body_whitelines--) { + if (EVP_DigestUpdate(message->bh, "\r\n", 2) == 0) { + dkim_err(message, "Can't update hash context"); return; } } - session->body_whitelines = 0; - session->has_body = 1; + message->body_whitelines = 0; + message->has_body = 1; - if (EVP_DigestUpdate(session->bh, line, linelen) == 0 || - EVP_DigestUpdate(session->bh, "\r\n", 2) == 0) { - dkim_err(session, "Can't update hash context"); + if (EVP_DigestUpdate(message->bh, line, linelen) == 0 || + EVP_DigestUpdate(message->bh, "\r\n", 2) == 0) { + dkim_err(message, "Can't update hash context"); return; } } void -dkim_sign(struct dkim_session *session) +dkim_sign(struct osmtpd_ctx *ctx) { + struct dkim_message *message = ctx->local_message; /* Use largest hash size here */ char bbh[EVP_MAX_MD_SIZE]; char bh[(((sizeof(bbh) + 2) / 3) * 4) + 1]; char *b; time_t now; - ssize_t i, j; + ssize_t i; size_t linelen; char *tmp, *tmp2; - char tmpchar; if (addtime || addexpire) now = time(NULL); - if (addtime && !dkim_signature_printf(session, "t=%lld; ", now)) + if (addtime && !dkim_signature_printf(message, "t=%lld; ", now)) return; - if (addexpire != 0 && !dkim_signature_printf(session, "x=%lld; ", + if (addexpire != 0 && !dkim_signature_printf(message, "x=%lld; ", now + addexpire < now ? INT64_MAX : now + addexpire)) return; - if (canonbody == CANON_SIMPLE && !session->has_body) { - if (EVP_DigestUpdate(session->bh, "\r\n", 2) <= 0) { - dkim_err(session, "Can't update hash context"); + if (canonbody == CANON_SIMPLE && !message->has_body) { + if (EVP_DigestUpdate(message->bh, "\r\n", 2) <= 0) { + dkim_err(message, "Can't update hash context"); return; } } - if (EVP_DigestFinal_ex(session->bh, bbh, NULL) == 0) { - dkim_err(session, "Can't finalize hash context"); + if (EVP_DigestFinal_ex(message->bh, bbh, NULL) == 0) { + dkim_err(message, "Can't finalize hash context"); return; } - EVP_EncodeBlock(bh, bbh, EVP_MD_CTX_size(session->bh)); - if (!dkim_signature_printf(session, "bh=%s; h=", bh)) + EVP_EncodeBlock(bh, bbh, EVP_MD_CTX_size(message->bh)); + if (!dkim_signature_printf(message, "bh=%s; h=", bh)) return; /* Reverse order for ease of use of RFC6367 section 5.4.2 */ - for (i = 0; session->headers[i] != NULL; i++) + for (i = 0; message->headers[i] != NULL; i++) continue; for (i--; i >= 0; i--) { - if (EVP_DigestSignUpdate(session->b, - session->headers[i], - strlen(session->headers[i])) <= 0 || - EVP_DigestSignUpdate(session->b, "\r\n", 2) <= 0) { - dkim_errx(session, "Failed to update digest context"); + if (EVP_DigestSignUpdate(message->b, + message->headers[i], + strlen(message->headers[i])) <= 0 || + EVP_DigestSignUpdate(message->b, "\r\n", 2) <= 0) { + dkim_errx(message, "Failed to update digest context"); return; } /* We're done with the cached header after hashing */ - for (tmp = session->headers[i]; tmp[0] != ':'; tmp++) { + for (tmp = message->headers[i]; tmp[0] != ':'; tmp++) { if (tmp[0] == ' ' || tmp[0] == '\t') break; tmp[0] = tolower(tmp[0]); } tmp[0] = '\0'; - if (!dkim_signature_printf(session, "%s%s", - session->headers[i + 1] == NULL ? "" : ":", - session->headers[i])) + if (!dkim_signature_printf(message, "%s%s", + message->headers[i + 1] == NULL ? "" : ":", + message->headers[i])) return; - tmp[0] = tmpchar; } - dkim_signature_printf(session, "; b="); - if (!dkim_signature_normalize(session)) + dkim_signature_printf(message, "; b="); + if (!dkim_signature_normalize(message)) return; - if ((tmp = strdup(session->signature.signature)) == NULL) { - dkim_err(session, "Can't create DKIM signature"); + if ((tmp = strdup(message->signature.signature)) == NULL) { + dkim_err(message, "Can't create DKIM signature"); return; } - dkim_parse_header(session, tmp, 1); - if (EVP_DigestSignUpdate(session->b, tmp, strlen(tmp)) <= 0) { - dkim_err(session, "Failed to update digest context"); + dkim_parse_header(message, tmp, 1); + if (EVP_DigestSignUpdate(message->b, tmp, strlen(tmp)) <= 0) { + dkim_err(message, "Failed to update digest context"); return; } free(tmp); - if (EVP_DigestSignFinal(session->b, NULL, &linelen) <= 0) { - dkim_err(session, "Failed to finalize digest"); + if (EVP_DigestSignFinal(message->b, NULL, &linelen) <= 0) { + dkim_err(message, "Failed to finalize digest"); return; } if ((tmp = malloc(linelen)) == NULL) { - dkim_err(session, "Can't allocate space for digest"); + dkim_err(message, "Can't allocate space for digest"); return; } - if (EVP_DigestSignFinal(session->b, tmp, &linelen) <= 0) { - dkim_err(session, "Failed to finalize digest"); + if (EVP_DigestSignFinal(message->b, tmp, &linelen) <= 0) { + dkim_err(message, "Failed to finalize digest"); return; } if ((b = malloc((((linelen + 2) / 3) * 4) + 1)) == NULL) { - dkim_err(session, "Can't create DKIM signature"); + dkim_err(message, "Can't create DKIM signature"); return; } EVP_EncodeBlock(b, tmp, linelen); free(tmp); - dkim_signature_printf(session, "%s\r\n", b); + dkim_signature_printf(message, "%s\r\n", b); free(b); - dkim_signature_normalize(session); - tmp = session->signature.signature; + dkim_signature_normalize(message); + tmp = message->signature.signature; while ((tmp2 = strchr(tmp, '\r')) != NULL) { tmp2[0] = '\0'; - smtp_filter_dataline(session->reqid, session->token, - "%s", tmp); + osmtpd_filter_dataline(ctx, "%s", tmp); tmp = tmp2 + 2; } tmp = NULL; linelen = 0; - rewind(session->origf); - while ((i = getline(&tmp, &linelen, session->origf)) != -1) { + rewind(message->origf); + while ((i = getline(&tmp, &linelen, message->origf)) != -1) { tmp[i - 1] = '\0'; - smtp_filter_dataline(session->reqid, session->token, "%s", tmp); + osmtpd_filter_dataline(ctx, "%s", tmp); } } int -dkim_signature_normalize(struct dkim_session *session) +dkim_signature_normalize(struct dkim_message *message) { size_t i; size_t linelen; size_t checkpoint; size_t skip; - size_t *headerlen = &(session->signature.len); + size_t *headerlen = &(message->signature.len); int headername = 1; char tag = '\0'; - char *sig = session->signature.signature; + char *sig = message->signature.signature; for (linelen = i = 0; sig[i] != '\0'; i++) { if (sig[i] == '\r' && sig[i + 1] == '\n') { @@ -719,11 +663,11 @@ dkim_signature_normalize(struct dkim_session *session) skip++) continue; skip -= checkpoint + 1; - if (!dkim_signature_need(session, + if (!dkim_signature_need(message, skip > 3 ? 0 : 3 - skip + 1)) return 0; - sig = session->signature.signature; - + sig = message->signature.signature; + memmove(sig + checkpoint + 3, sig + checkpoint + skip, *headerlen - skip - checkpoint + 1); @@ -765,7 +709,7 @@ dkim_signature_normalize(struct dkim_session *session) } int -dkim_signature_printheader(struct dkim_session *session, char *header) +dkim_signature_printheader(struct dkim_message *message, const char *header) { size_t i, j, len; static char *fmtheader = NULL; @@ -776,24 +720,24 @@ dkim_signature_printheader(struct dkim_session *sessio len = strlen(header); if ((len + 3) * 3 < len) { errno = EOVERFLOW; - dkim_err(session, "Can't add z-component to header"); + dkim_err(message, "Can't add z-component to header"); return 0; } if ((len + 3) * 3 > size) { if ((tmp = reallocarray(fmtheader, 3, len + 3)) == NULL) { - dkim_err(session, "Can't add z-component to header"); + dkim_err(message, "Can't add z-component to header"); return 0; } fmtheader = tmp; size = (len + 1) * 3; } - first = session->signature.signature[session->signature.len - 1] == '='; + first = message->signature.signature[message->signature.len - 1] == '='; for (j = i = 0; header[i] != '\0'; i++, j++) { if (i == 0 && header[i] != ' ' && header[i] != '\t' && !first) fmtheader[j++] = '|'; if ((header[i] >= 0x21 && header[i] <= 0x3A) || - header[i] == 0x3C || + (header[i] == 0x3C) || (header[i] >= 0x3E && header[i] <= 0x7B) || (header[i] >= 0x7D && header[i] <= 0x7E)) fmtheader[j] = header[i]; @@ -806,28 +750,26 @@ dkim_signature_printheader(struct dkim_session *sessio (void) sprintf(fmtheader + j, "=%02hhX=%02hhX", (unsigned char) '\r', (unsigned char) '\n'); - return dkim_signature_printf(session, "%s", fmtheader); + return dkim_signature_printf(message, "%s", fmtheader); } int -dkim_signature_printf(struct dkim_session *session, char *fmt, ...) +dkim_signature_printf(struct dkim_message *message, char *fmt, ...) { - struct dkim_signature *sig = &(session->signature); + struct dkim_signature *sig = &(message->signature); va_list ap; - size_t newlen; - char *tmp; size_t len; va_start(ap, fmt); if ((len = vsnprintf(sig->signature + sig->len, sig->size - sig->len, fmt, ap)) >= sig->size - sig->len) { va_end(ap); - if (!dkim_signature_need(session, len + 1)) + if (!dkim_signature_need(message, len + 1)) return 0; va_start(ap, fmt); - if ((len = vsnprintf(sig->signature + sig->len, sig->size - sig->len, - fmt, ap)) >= sig->size - sig->len) - errx(1, "Miscalculated header size"); + if ((len = vsnprintf(sig->signature + sig->len, + sig->size - sig->len, fmt, ap)) >= sig->size - sig->len) + osmtpd_errx(1, "Miscalculated header size"); } sig->len += len; va_end(ap); @@ -835,16 +777,16 @@ dkim_signature_printf(struct dkim_session *session, ch } int -dkim_signature_need(struct dkim_session *session, size_t len) +dkim_signature_need(struct dkim_message *message, size_t len) { - struct dkim_signature *sig = &(session->signature); + struct dkim_signature *sig = &(message->signature); char *tmp; if (sig->len + len < sig->size) return 1; sig->size = (((len + sig->len) / 512) + 1) * 512; if ((tmp = realloc(sig->signature, sig->size)) == NULL) { - dkim_err(session, "No room for signature"); + dkim_err(message, "No room for signature"); return 0; } sig->signature = tmp; @@ -854,9 +796,8 @@ dkim_signature_need(struct dkim_session *session, size __dead void usage(void) { - fprintf(stderr, "usage: %s [-a signalg] [-c canonicalization] [-h headerfields] -d domain -k keyfile " - "-s selector\n", getprogname()); + fprintf(stderr, "usage: filter-dkim [-tz] [-a signalg] " + "[-c canonicalization] [-h headerfields]\n " + "[-x seconds] -d domain -k keyfile -s selector\n"); exit(1); } - -RB_GENERATE(dkim_sessions, dkim_session, entry, dkim_session_cmp); blob - e6708b1ce7cb46802b1c4c47df2df0f9dc92c4a7 (mode 644) blob + /dev/null --- smtp_proc.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Copyright (c) 2019 Martijn van Duren - * - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "smtp_proc.h" - -#define NITEMS(x) (sizeof(x) / sizeof(*x)) - -struct smtp_callback; -struct smtp_request; - -extern struct event_base *current_base; - -static int smtp_register(char *, char *, char *, void *); -static ssize_t smtp_getline(char ** restrict, size_t * restrict); -static void smtp_newline(int, short, void *); -static void smtp_connect(struct smtp_callback *, int, struct timespec *, - uint64_t, uint64_t, char *); -static void smtp_noargs(struct smtp_callback *, int, struct timespec *, - uint64_t, uint64_t, char *); -static void smtp_dataline(struct smtp_callback *, int, struct timespec *, - uint64_t, uint64_t, char *); -static void smtp_in_link_disconnect(struct smtp_callback *, int, struct timespec *, - uint64_t, char *); -static void smtp_printf(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -static void smtp_vprintf(const char *, va_list); -static void smtp_write(int, short, void *); - -struct smtp_writebuf { - char *buf; - size_t bufsize; - size_t buflen; -}; - -struct smtp_callback { - char *type; - char *phase; - char *direction; - union { - void (*smtp_filter)(struct smtp_callback *, int, - struct timespec *, uint64_t, uint64_t, char *); - void (*smtp_report)(struct smtp_callback *, int, - struct timespec *, uint64_t, char *); - }; - void *cb; -} smtp_callbacks[] = { - {"filter", "connect", "smtp-in", .smtp_filter = smtp_connect, NULL}, - {"filter", "data", "smtp-in", .smtp_filter = smtp_noargs, NULL}, - {"filter", "data-line", "smtp-in", .smtp_filter = smtp_dataline, NULL}, - {"filter", "commit", "smtp-in", .smtp_filter = smtp_noargs, NULL}, - {"report", "link-disconnect", "smtp-in", - .smtp_report = smtp_in_link_disconnect, NULL} -}; - -static int ready = 0; - -int -smtp_register_filter_connect(void (*cb)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t, char *, struct inx_addr *)) -{ - return smtp_register("filter", "connect", "smtp-in", (void *)cb); -} - -int -smtp_register_filter_data(void (*cb)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t)) -{ - return smtp_register("filter", "data", "smtp-in", (void *)cb); -} - -int -smtp_register_filter_dataline(void (*cb)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t, char *)) -{ - return smtp_register("filter", "data-line", "smtp-in", (void *)cb); -} - -int -smtp_register_filter_commit(void (*cb)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t)) -{ - return smtp_register("filter", "commit", "smtp-in", (void *)cb); -} - -int -smtp_in_register_report_disconnect(void (*cb)(char *, int, struct timespec *, - char *, char *, uint64_t)) -{ - return smtp_register("report", "link-disconnect", "smtp-in", (void *)cb); -} - -void -smtp_run(int debug) -{ - struct event stdinev; - - smtp_printf("register|ready\n"); - ready = 1; - - event_set(&stdinev, STDIN_FILENO, EV_READ | EV_PERSIST, smtp_newline, - &stdinev); - event_add(&stdinev, NULL); - - if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) - err(1, "fcntl"); - event_dispatch(); -} - -static ssize_t -smtp_getline(char ** restrict buf, size_t * restrict size) -{ - static char *rbuf = NULL; - static size_t rsoff = 0, reoff = 0; - static size_t rbsize = 0; - char *sep; - size_t sepoff; - ssize_t strlen, nread; - - do { - if (rsoff != reoff) { - if ((sep = memchr(rbuf + rsoff, '\n', reoff - rsoff)) - != NULL) { - sepoff = sep - rbuf; - if (*buf == NULL) - *size = 0; - if (*size < (sepoff - rsoff + 1)) { - *size = sepoff - rsoff + 1; - *buf = realloc(*buf, sepoff - rsoff + 1); - if (*buf == NULL) - err(1, NULL); - } - sep[0] = '\0'; - strlen = strlcpy(*buf, rbuf + rsoff, *size); - if (strlen >= *size) - errx(1, "copy buffer too small"); - rsoff = sepoff + 1; - return strlen; - } - } - /* If we can't fill at the end, move everything back. */ - if (rbsize - reoff < 1500 && rsoff != 0) { - memmove(rbuf, rbuf + rsoff, reoff - rsoff); - reoff -= rsoff; - rsoff = 0; - } - /* If we still can't fill alloc some new memory. */ - if (rbsize - reoff < 1500) { - if ((rbuf = realloc(rbuf, rbsize + 4096)) == NULL) - err(1, NULL); - rbsize += 4096; - } - nread = read(STDIN_FILENO, rbuf + reoff, rbsize - reoff); - if (nread <= 0) - return nread; - reoff += nread; - } while (1); -} - -static void -smtp_newline(int fd, short event, void *arg) -{ - struct event *stdinev = (struct event *)arg; - static char *line = NULL, *linedup = NULL; - static size_t linesize = 0; - static size_t dupsize = 0; - ssize_t linelen; - char *start, *end, *type, *direction, *phase, *params; - int version; - struct timespec tm; - uint64_t reqid, token; - int i; - - while ((linelen = smtp_getline(&line, &linesize)) > 0) { - if (dupsize < linesize) { - if ((linedup = realloc(linedup, linesize)) == NULL) - err(1, NULL); - dupsize = linesize; - } - strlcpy(linedup, line, dupsize); - type = line; - if ((start = strchr(type, '|')) == NULL) - errx(1, "Invalid line received: missing version: %s", linedup); - start++[0] = '\0'; - if ((end = strchr(start, '|')) == NULL) - errx(1, "Invalid line received: missing time: %s", linedup); - end++[0] = '\0'; - if (strcmp(start, "1") != 0) - errx(1, "Unsupported protocol received: %s: %s", start, linedup); - version = 1; - start = end; - if ((direction = strchr(start, '|')) == NULL) - errx(1, "Invalid line received: missing direction: %s", linedup); - direction++[0] = '\0'; - tm.tv_sec = (time_t) strtoull(start, &end, 10); - tm.tv_nsec = 0; - if (start[0] == '\0' || (end[0] != '\0' && end[0] != '.')) - errx(1, "Invalid line received: invalid timestamp: %s", linedup); - if (end[0] == '.') { - start = end + 1; - tm.tv_nsec = strtol(start, &end, 10); - if (start[0] == '\0' || end[0] != '\0') - errx(1, "Invalid line received: invalid " - "timestamp: %s", linedup); - for (i = 9 - (end - start); i > 0; i--) - tm.tv_nsec *= 10; - } - if ((phase = strchr(direction, '|')) == NULL) - errx(1, "Invalid line receieved: missing phase: %s", linedup); - phase++[0] = '\0'; - if ((start = strchr(phase, '|')) == NULL) - errx(1, "Invalid line received: missing reqid: %s", linedup); - start++[0] = '\0'; - reqid = strtoull(start, ¶ms, 16); - if (start[0] == '|' || (params[0] != '|' & params[0] != '\0')) - errx(1, "Invalid line received: invalid reqid: %s", linedup); - params++; - - for (i = 0; i < NITEMS(smtp_callbacks); i++) { - if (strcmp(type, smtp_callbacks[i].type) == 0 && - strcmp(phase, smtp_callbacks[i].phase) == 0 && - strcmp(direction, smtp_callbacks[i].direction) == 0) - break; - } - if (i == NITEMS(smtp_callbacks)) { - errx(1, "Invalid line received: received unregistered " - "%s: %s: %s", type, phase, linedup); - } - if (strcmp(type, "filter") == 0) { - start = params; - token = strtoull(start, ¶ms, 16); - if (start[0] == '|' || params[0] != '|') - errx(1, "Invalid line received: invalid token: %s", linedup); - params++; - smtp_callbacks[i].smtp_filter(&(smtp_callbacks[i]), - version, &tm, reqid, token, params); - } else - smtp_callbacks[i].smtp_report(&(smtp_callbacks[i]), - version, &tm, reqid, params); - } - if (linelen == 0 || errno != EAGAIN) - event_del(stdinev); -} - -static void -smtp_connect(struct smtp_callback *cb, int version, struct timespec *tm, - uint64_t reqid, uint64_t token, char *params) -{ - struct inx_addr addrx; - char *hostname; - char *address; - int ret; - void (*f)(char *, int, struct timespec *,char *, char *, uint64_t, - uint64_t, char *, struct inx_addr *); - - hostname = params; - if ((address = strchr(params, '|')) == NULL) - errx(1, "Invalid line received: missing address: %s", params); - address++[0] = '\0'; - - addrx.af = AF_INET; - if (strncasecmp(address, "ipv6:", 5) == 0) { - addrx.af = AF_INET6; - address += 5; - } - - ret = inet_pton(addrx.af, address, addrx.af == AF_INET ? - (void *)&(addrx.addr) : (void *)&(addrx.addr6)); - if (ret == 0) - errx(1, "Invalid line received: Couldn't parse address: %s", params); - if (ret == -1) - err(1, "Couldn't convert address: %s", params); - - f = cb->cb; - f(cb->type, version, tm, cb->direction, cb->phase, reqid, token, - hostname, &addrx); -} - -static void -smtp_noargs(struct smtp_callback *cb, int version, struct timespec *tm, - uint64_t reqid, uint64_t token, char *params) -{ - void (*f)(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t); - - f = cb->cb; - f(cb->type, version, tm, cb->direction, cb->phase, reqid, token); -} - -static void -smtp_dataline(struct smtp_callback *cb, int version, struct timespec *tm, - uint64_t reqid, uint64_t token, char *line) -{ - void (*f)(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t, char *); - - f = cb->cb; - f(cb->type, version, tm, cb->direction, cb->phase, reqid, token, - line); -} - -static void -smtp_in_link_disconnect(struct smtp_callback *cb, int version, - struct timespec *tm, uint64_t reqid, char *params) -{ - void (*f)(char *, int, struct timespec *, char *, char *, uint64_t); - - f = cb->cb; - f(cb->type, version, tm, cb->direction, cb->phase, reqid); -} - -void -smtp_filter_proceed(uint64_t reqid, uint64_t token) -{ - smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n", token, - reqid); -} - -static void -smtp_printf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - smtp_vprintf(fmt, ap); - va_end(ap); -} - -static void -smtp_vprintf(const char *fmt, va_list ap) -{ - va_list cap; - static struct smtp_writebuf buf = {NULL, 0, 0}; - int fmtlen; - - va_copy(cap, ap); - fmtlen = vsnprintf(buf.buf + buf.buflen, buf.bufsize - buf.buflen, fmt, - ap); - if (fmtlen == -1) - err(1, "vsnprintf"); - if (fmtlen >= buf.bufsize - buf.buflen) { - buf.bufsize = buf.buflen + fmtlen + 1; - buf.buf = reallocarray(buf.buf, buf.bufsize, - sizeof(*(buf.buf))); - if (buf.buf == NULL) - err(1, NULL); - fmtlen = vsnprintf(buf.buf + buf.buflen, - buf.bufsize - buf.buflen, fmt, cap); - if (fmtlen == -1) - err(1, "vsnprintf"); - } - va_end(cap); - buf.buflen += fmtlen; - - if (strchr(buf.buf, '\n') != NULL) - smtp_write(STDOUT_FILENO, EV_WRITE, &buf); -} - -static void -smtp_write(int fd, short event, void *arg) -{ - struct smtp_writebuf *buf = arg; - static struct event stdoutev; - static int evset = 0; - ssize_t wlen; - - if (buf->buflen == 0) - return; - if (!evset) { - event_set(&stdoutev, fd, EV_WRITE, smtp_write, buf); - evset = 1; - } - wlen = write(fd, buf->buf, buf->buflen); - if (wlen == -1) { - if (errno != EAGAIN && errno != EINTR) - err(1, "Failed to write to smtpd"); - event_add(&stdoutev, NULL); - return; - } - if (wlen < buf->buflen) { - memmove(buf->buf, buf->buf + wlen, buf->buflen - wlen); - event_add(&stdoutev, NULL); - } - buf->buflen -= wlen; - if (buf->buflen == 0 && event_pending(&stdoutev, EV_WRITE, NULL)) - event_del(&stdoutev); -} - -void -smtp_filter_reject(uint64_t reqid, uint64_t token, int code, - const char *reason, ...) -{ - va_list ap; - - if (code < 200 || code > 599) - errx(1, "Invalid reject code"); - - smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%d ", token, - reqid, code); - va_start(ap, reason); - smtp_vprintf(reason, ap); - va_end(ap); - smtp_printf("\n"); -} - -void -smtp_filter_disconnect(uint64_t reqid, uint64_t token, const char *reason, ...) -{ - va_list ap; - - smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|421 ", - token, reqid); - va_start(ap, reason); - smtp_vprintf(reason, ap); - va_end(ap); - smtp_printf("\n"); -} - -void -smtp_filter_dataline(uint64_t reqid, uint64_t token, const char *line, ...) -{ - va_list ap; - - smtp_printf("filter-dataline|%016"PRIx64"|%016"PRIx64"|", token, reqid); - va_start(ap, line); - smtp_vprintf(line, ap); - va_end(ap); - smtp_printf("\n"); -} - -static int -smtp_register(char *type, char *phase, char *direction, void *cb) -{ - int i; - static int evinit = 0; - - if (ready) - errx(1, "Can't register when proc is running"); - - if (!evinit) { - event_init(); - evinit = 1; - } - - for (i = 0; i < NITEMS(smtp_callbacks); i++) { - if (strcmp(type, smtp_callbacks[i].type) == 0 && - strcmp(phase, smtp_callbacks[i].phase) == 0 && - strcmp(direction, smtp_callbacks[i].direction) == 0) { - if (smtp_callbacks[i].cb != NULL) { - errno = EALREADY; - return -1; - } - smtp_callbacks[i].cb = cb; - smtp_printf("register|%s|%s|%s\n", type, direction, - phase); - return 0; - } - } - errno = EINVAL; - return -1; -} blob - ca27bcad53dea8412d4a2739f4b25ef203fe4d4f (mode 644) blob + /dev/null --- smtp_proc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019 Martijn van Duren - * - * 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 - -#include - -struct inx_addr { - int af; - union { - struct in_addr addr; - struct in6_addr addr6; - }; -}; - -int smtp_register_filter_connect(void (*)(char *, int, struct timespec *, - char *, char *, uint64_t, uint64_t, char *, struct inx_addr *)); -int smtp_register_filter_data(void (*)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t)); -int smtp_register_filter_dataline(void (*)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t, char *)); -int smtp_register_filter_commit(void (*)(char *, int, struct timespec *, char *, - char *, uint64_t, uint64_t)); -int smtp_in_register_report_disconnect(void (*)(char *, int, struct timespec *, - char *, char *, uint64_t)); -void smtp_filter_proceed(uint64_t, uint64_t); -void smtp_filter_reject(uint64_t, uint64_t, int, const char *, ...) - __attribute__((__format__ (printf, 4, 5))); -void smtp_filter_disconnect(uint64_t, uint64_t, const char *, ...) - __attribute__((__format__ (printf, 3, 4))); -void smtp_filter_dataline(uint64_t, uint64_t, const char *, ...) - __attribute__((__format__ (printf, 3, 4))); -void smtp_run(int);