commit 5e62db7b77a24bda90360684fe44325fde4ddac6 from: Martijn van Duren date: Thu Aug 22 10:27:58 2019 UTC Welcome filter-dnsbl into the libopensmtpd world commit - 0a17996036b08cae5fa25ef79c6fbcf2874a45c7 commit + 5e62db7b77a24bda90360684fe44325fde4ddac6 blob - ac8369da1e85debdce73e9a24fd086307973d538 blob + 0f4c09a9e75ac42285cecd8c8bee6b30d485c74c --- Makefile +++ Makefile @@ -2,10 +2,14 @@ PROG= filter-dnsbl BINDIR= /usr/libexec/smtpd/ -SRCS+= main.c smtp_proc.c +SRCS+= main.c -CFLAGS+= -g3 -O0 -LDADD+= -levent +CFLAGS+=-Wall -I${.CURDIR} +CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes +CFLAGS+=-Wmissing-declarations +CFLAGS+=-Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+=-Wsign-compare +LDADD+= -levent -lopensmtpd DPADD= ${LIBEVENT} .include blob - d1ae5a278784c61b80310851f4d7149fa3e89e58 blob + af961f8f9e2a252fb98df5ea263c1ee6f036d856 --- main.c +++ main.c @@ -13,7 +13,6 @@ * 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 @@ -30,12 +29,11 @@ #include #include -#include "smtp_proc.h" +#include "opensmtpd.h" struct dnsbl_session; struct dnsbl_query { - struct asr_query *query; struct event_asr *event; int resolved; int blacklist; @@ -43,42 +41,32 @@ struct dnsbl_query { }; struct dnsbl_session { - uint64_t reqid; - uint64_t token; - char addr[INET6_ADDRSTRLEN]; int listed; int set_header; int logged_mark; struct dnsbl_query *query; - RB_ENTRY(dnsbl_session) entry; + struct osmtpd_ctx *ctx; }; -RB_HEAD(dnsbl_sessions, dnsbl_session) dnsbl_sessions = RB_INITIALIZER(NULL); -RB_PROTOTYPE(dnsbl_sessions, dnsbl_session, entry, dnsbl_session_cmp); - static char **blacklists = NULL; static size_t nblacklists = 0; static int markspam = 0; void usage(void); -void dnsbl_connect(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t, char *, struct inx_addr *); -void dnsbl_data(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t); -void dnsbl_dataline(char *, int, struct timespec *, char *, char *, uint64_t, - uint64_t, char *); -void dnsbl_disconnect(char *, int, struct timespec *, char *, char *, uint64_t); +void dnsbl_connect(struct osmtpd_ctx *, const char *, + struct sockaddr_storage *); +void dnsbl_begin(struct osmtpd_ctx *, uint32_t); +void dnsbl_dataline(struct osmtpd_ctx *, const char *); void dnsbl_resolve(struct asr_result *, void *); void dnsbl_session_query_done(struct dnsbl_session *); -void dnsbl_session_free(struct dnsbl_session *); -int dnsbl_session_cmp(struct dnsbl_session *, struct dnsbl_session *); +void *dnsbl_session_new(struct osmtpd_ctx *); +void dnsbl_session_free(struct osmtpd_ctx *, void *); int main(int argc, char *argv[]) { int ch; - int i; - int debug = 0; + size_t i; while ((ch = getopt(argc, argv, "m")) != -1) { switch (ch) { @@ -101,55 +89,38 @@ main(int argc, char *argv[]) for (i = 0; i < nblacklists; i++) blacklists[i] = argv[optind + i]; - smtp_register_filter_connect(dnsbl_connect); + osmtpd_register_filter_connect(dnsbl_connect); + osmtpd_local_session(dnsbl_session_new, dnsbl_session_free); if (markspam) { - smtp_register_filter_data(dnsbl_data); - smtp_register_filter_dataline(dnsbl_dataline); + osmtpd_register_report_begin(1, dnsbl_begin); + osmtpd_register_filter_dataline(dnsbl_dataline); } - smtp_in_register_report_disconnect(dnsbl_disconnect); - smtp_run(debug); + osmtpd_run(); return 0; } void -dnsbl_connect(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid, uint64_t token, char *hostname, - struct inx_addr *xaddr) +dnsbl_connect(struct osmtpd_ctx *ctx, const char *hostname, + struct sockaddr_storage *ss) { - struct dnsbl_session *session; + struct dnsbl_session *session = ctx->local_session; + struct asr_query *aq; char query[255]; u_char *addr; - int i, try; + size_t i; - if ((session = calloc(1, sizeof(*session))) == NULL) - err(1, NULL); - if ((session->query = calloc(nblacklists, sizeof(*(session->query)))) - == NULL) - err(1, NULL); - session->reqid = reqid; - session->token = token; - session->listed = -1; - session->set_header = 0; - session->logged_mark = 0; - if (inet_ntop(xaddr->af, xaddr->af == AF_INET ? - (void *)&(xaddr->addr) : (void *)&(xaddr->addr6), session->addr, - sizeof(session->addr)) == NULL) - err(1, "inet_ntop"); - - RB_INSERT(dnsbl_sessions, &dnsbl_sessions, session); - - if (xaddr->af == AF_INET) - addr = (u_char *)&(xaddr->addr); + if (ss->ss_family == AF_INET) + addr = (u_char *)(&(((struct sockaddr_in *)ss)->sin_addr)); else - addr = (u_char *)&(xaddr->addr6); + addr = (u_char *)(&(((struct sockaddr_in6 *)ss)->sin6_addr)); for (i = 0; i < nblacklists; i++) { - if (xaddr->af == AF_INET) { + if (ss->ss_family == AF_INET) { if (snprintf(query, sizeof(query), "%u.%u.%u.%u.%s", addr[3], addr[2], addr[1], addr[0], - blacklists[i]) >= sizeof(query)) + blacklists[i]) >= (int) sizeof(query)) errx(1, "Can't create query, domain too long"); - } else if (xaddr->af == AF_INET6) { + } else if (ss->ss_family == AF_INET6) { if (snprintf(query, sizeof(query), "%hhx.%hhx.%hhx.%hhx" ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx" ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx" @@ -170,14 +141,14 @@ dnsbl_connect(char *type, int version, struct timespec (u_char) (addr[2] & 0xf), (u_char) (addr[2] >> 4), (u_char) (addr[1] & 0xf), (u_char) (addr[1] >> 4), (u_char) (addr[0] & 0xf), (u_char) (addr[0] >> 4), - blacklists[i]) >= sizeof(query)) + blacklists[i]) >= (int) sizeof(query)) errx(1, "Can't create query, domain too long"); } else errx(1, "Invalid address family received"); - session->query[i].query = gethostbyname_async(query, NULL); - session->query[i].event = event_asr_run(session->query[i].query, - dnsbl_resolve, &(session->query[i])); + aq = gethostbyname_async(query, NULL); + session->query[i].event = event_asr_run(aq, dnsbl_resolve, + &(session->query[i])); session->query[i].blacklist = i; session->query[i].session = session; } @@ -188,30 +159,27 @@ dnsbl_resolve(struct asr_result *result, void *arg) { struct dnsbl_query *query = arg; struct dnsbl_session *session = query->session; - int i, blacklist; + size_t i; query->resolved = 1; query->event = NULL; - query->query = NULL; if (result->ar_hostent != NULL) { if (!markspam) { - smtp_filter_disconnect(session->reqid, session->token, - "Listed at %s", blacklists[query->blacklist]); + osmtpd_filter_disconnect(session->ctx, "Listed at %s", + blacklists[query->blacklist]); warnx("%016"PRIx64" listed at %s: rejected", - session->reqid, blacklists[query->blacklist]); - dnsbl_session_free(session); + session->ctx->reqid, blacklists[query->blacklist]); } else { dnsbl_session_query_done(session); session->listed = query->blacklist; - smtp_filter_proceed(session->reqid, session->token); + osmtpd_filter_proceed(session->ctx); /* Delay logging until we have a message */ } return; } if (result->ar_h_errno != HOST_NOT_FOUND) { - smtp_filter_disconnect(session->reqid, session->token, - "DNS error on %s", blacklists[query->blacklist]); - dnsbl_session_free(session); + osmtpd_filter_disconnect(session->ctx, "DNS error on %s", + blacklists[query->blacklist]); return; } @@ -219,64 +187,44 @@ dnsbl_resolve(struct asr_result *result, void *arg) if (!session->query[i].resolved) return; } - smtp_filter_proceed(session->reqid, session->token); - warnx("%016"PRIx64" not listed", session->reqid); + osmtpd_filter_proceed(session->ctx); + warnx("%016"PRIx64" not listed", session->ctx->reqid); } void -dnsbl_disconnect(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid) +dnsbl_begin(struct osmtpd_ctx *ctx, uint32_t msgid) { - struct dnsbl_session *session, search; + struct dnsbl_session *session = ctx->local_session; - search.reqid = reqid; - if ((session = RB_FIND(dnsbl_sessions, &dnsbl_sessions, &search)) != NULL) - dnsbl_session_free(session); -} - -void -dnsbl_data(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid, uint64_t token) -{ - struct dnsbl_session *session, search; - - search.reqid = reqid; - session = RB_FIND(dnsbl_sessions, &dnsbl_sessions, &search); - if (session->listed != -1) { if (!session->logged_mark) { warnx("%016"PRIx64" listed at %s: Marking as spam", - session->reqid, blacklists[session->listed]); + ctx->reqid, blacklists[session->listed]); session->logged_mark = 1; } session->set_header = 1; } - smtp_filter_proceed(reqid, token); } void -dnsbl_dataline(char *type, int version, struct timespec *tm, char *direction, - char *phase, uint64_t reqid, uint64_t token, char *line) +dnsbl_dataline(struct osmtpd_ctx *ctx, const char *line) { - struct dnsbl_session *session, search; + struct dnsbl_session *session = ctx->local_session; - search.reqid = reqid; - session = RB_FIND(dnsbl_sessions, &dnsbl_sessions, &search); - if (session->set_header) { - smtp_filter_dataline(reqid, token, "X-Spam: yes"); - smtp_filter_dataline(reqid, token, "X-Spam-DNSBL: Listed at %s", + osmtpd_filter_dataline(ctx, "X-Spam: yes"); + osmtpd_filter_dataline(ctx, "X-Spam-DNSBL: Listed at %s", blacklists[session->listed]); session->set_header = 0; } - smtp_filter_dataline(reqid, token, "%s", line); + osmtpd_filter_dataline(ctx, "%s", line); } void dnsbl_session_query_done(struct dnsbl_session *session) { - int i; + size_t i; for (i = 0; i < nblacklists; i++) { if (!session->query[i].resolved) { @@ -286,21 +234,34 @@ dnsbl_session_query_done(struct dnsbl_session *session } } +void * +dnsbl_session_new(struct osmtpd_ctx *ctx) +{ + struct dnsbl_session *session; + + if ((session = calloc(1, sizeof(*session))) == NULL) + err(1, NULL); + if ((session->query = calloc(nblacklists, sizeof(*(session->query)))) + == NULL) + err(1, NULL); + session->listed = -1; + session->set_header = 0; + session->logged_mark = 0; + session->ctx = ctx; + + return session; +} + void -dnsbl_session_free(struct dnsbl_session *session) +dnsbl_session_free(struct osmtpd_ctx *ctx, void *data) { - RB_REMOVE(dnsbl_sessions, &dnsbl_sessions, session); + struct dnsbl_session *session = data; + dnsbl_session_query_done(session); free(session->query); free(session); } -int -dnsbl_session_cmp(struct dnsbl_session *s1, struct dnsbl_session *s2) -{ - return (s1->reqid < s2->reqid ? -1 : s1->reqid > s2->reqid); -} - __dead void usage(void) { @@ -308,5 +269,3 @@ usage(void) getprogname()); exit(1); } - -RB_GENERATE(dnsbl_sessions, dnsbl_session, entry, dnsbl_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);