diff options
73 files changed, 2760 insertions, 2022 deletions
diff --git a/usr.sbin/smtpd/Makefile b/usr.sbin/smtpd/Makefile index 98cb2c8c839..06920b9248e 100644 --- a/usr.sbin/smtpd/Makefile +++ b/usr.sbin/smtpd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.9 2009/03/18 01:56:52 jacekm Exp $ +# $OpenBSD: Makefile,v 1.10 2013/05/24 17:03:14 eric Exp $ .include <bsd.own.mk> diff --git a/usr.sbin/smtpd/aldap.c b/usr.sbin/smtpd/aldap.c index bf470853b9b..796aebd26df 100644 --- a/usr.sbin/smtpd/aldap.c +++ b/usr.sbin/smtpd/aldap.c @@ -1,5 +1,5 @@ -/* $Id: aldap.c,v 1.4 2013/01/31 18:34:43 eric Exp $ */ -/* $OpenBSD: aldap.c,v 1.4 2013/01/31 18:34:43 eric Exp $ */ +/* $Id: aldap.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ +/* $OpenBSD: aldap.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org> @@ -29,7 +29,7 @@ #if 0 #define DEBUG #endif -#define VERSION 3 +#define ALDAP_VERSION 3 static struct ber_element *ldap_parse_search_filter(struct ber_element *, char *); @@ -92,7 +92,7 @@ aldap_bind(struct aldap *ldap, char *binddn, char *bindcred) goto fail; elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP, - (unsigned long)LDAP_REQ_BIND, VERSION, binddn, bindcred, + (unsigned long)LDAP_REQ_BIND, ALDAP_VERSION, binddn, bindcred, BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE); if (elm == NULL) goto fail; diff --git a/usr.sbin/smtpd/aliases.c b/usr.sbin/smtpd/aliases.c index 8056487ed45..899540289a3 100644 --- a/usr.sbin/smtpd/aliases.c +++ b/usr.sbin/smtpd/aliases.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aliases.c,v 1.63 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: aliases.c,v 1.64 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -40,10 +39,10 @@ int aliases_get(struct expand *expand, const char *username) { struct expandnode *xn; - char buf[MAX_LOCALPART_SIZE]; + char buf[SMTPD_MAXLOCALPARTSIZE]; size_t nbaliases; int ret; - struct expand *xp = NULL; + union lookup lk; struct table *mapping = NULL; struct table *userbase = NULL; @@ -51,13 +50,13 @@ aliases_get(struct expand *expand, const char *username) userbase = expand->rule->r_userbase; xlowercase(buf, username, sizeof(buf)); - ret = table_lookup(mapping, buf, K_ALIAS, (void **)&xp); + ret = table_lookup(mapping, buf, K_ALIAS, &lk); if (ret <= 0) return ret; /* foreach node in table_alias expandtree, we merge */ nbaliases = 0; - RB_FOREACH(xn, expandtree, &xp->tree) { + RB_FOREACH(xn, expandtree, &lk.expand->tree) { if (xn->type == EXPAND_INCLUDE) nbaliases += aliases_expand_include(expand, xn->u.buffer); @@ -69,7 +68,7 @@ aliases_get(struct expand *expand, const char *username) } } - expand_free(xp); + expand_free(lk.expand); log_debug("debug: aliases_get: returned %zd aliases", nbaliases); return nbaliases; @@ -123,7 +122,7 @@ int aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr) { struct expandnode *xn; - struct expand *xp; + union lookup lk; char buf[SMTPD_MAXLINESIZE]; char *pbuf; int nbaliases; @@ -140,7 +139,7 @@ aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr) xlowercase(buf, buf, sizeof(buf)); /* First, we lookup for full entry: user@domain */ - ret = table_lookup(mapping, buf, K_ALIAS, (void **)&xp); + ret = table_lookup(mapping, buf, K_ALIAS, &lk); if (ret < 0) return (-1); if (ret) @@ -149,7 +148,7 @@ aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr) /* Failed ? We lookup for username only */ pbuf = strchr(buf, '@'); *pbuf = '\0'; - ret = table_lookup(mapping, buf, K_ALIAS, (void **)&xp); + ret = table_lookup(mapping, buf, K_ALIAS, &lk); if (ret < 0) return (-1); if (ret) @@ -157,21 +156,21 @@ aliases_virtual_get(struct expand *expand, const struct mailaddr *maddr) *pbuf = '@'; /* Failed ? We lookup for catch all for virtual domain */ - ret = table_lookup(mapping, pbuf, K_ALIAS, (void **)&xp); + ret = table_lookup(mapping, pbuf, K_ALIAS, &lk); if (ret < 0) return (-1); if (ret) goto expand; /* Failed ? We lookup for a *global* catch all */ - ret = table_lookup(mapping, "@", K_ALIAS, (void **)&xp); + ret = table_lookup(mapping, "@", K_ALIAS, &lk); if (ret <= 0) return (ret); expand: /* foreach node in table_virtual expand, we merge */ nbaliases = 0; - RB_FOREACH(xn, expandtree, &xp->tree) { + RB_FOREACH(xn, expandtree, &lk.expand->tree) { if (xn->type == EXPAND_INCLUDE) nbaliases += aliases_expand_include(expand, xn->u.buffer); @@ -183,7 +182,7 @@ expand: } } - expand_free(xp); + expand_free(lk.expand); log_debug("debug: aliases_virtual_get: '%s' resolved to %d nodes", buf, nbaliases); @@ -197,7 +196,7 @@ aliases_expand_include(struct expand *expand, const char *filename) FILE *fp; char *line; size_t len, lineno = 0; - char delim[3] = { '\\', '\0', '#' }; + char delim[3] = { '\\', '#', '\0' }; fp = fopen(filename, "r"); if (fp == NULL) { diff --git a/usr.sbin/smtpd/bounce.c b/usr.sbin/smtpd/bounce.c index d09cd7604fd..0d02897feef 100644 --- a/usr.sbin/smtpd/bounce.c +++ b/usr.sbin/smtpd/bounce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bounce.c,v 1.55 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: bounce.c,v 1.56 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <err.h> @@ -128,7 +127,7 @@ bounce_add(uint64_t evpid) bounce_init(); if (queue_envelope_load(evpid, &evp) == 0) { - m_create(p_scheduler, IMSG_DELIVERY_PERMFAIL, 0, 0, -1, 9); + m_create(p_scheduler, IMSG_DELIVERY_PERMFAIL, 0, 0, -1); m_add_evpid(p_scheduler, evpid); m_close(p_scheduler); return; @@ -440,7 +439,7 @@ bounce_next(struct bounce_session *s) n = iobuf_queued(&s->iobuf); - while (iobuf_len(&s->iobuf) < BOUNCE_HIWAT) { + while (iobuf_queued(&s->iobuf) < BOUNCE_HIWAT) { line = fgetln(s->msgfp, &len); if (line == NULL) break; @@ -505,12 +504,11 @@ bounce_delivery(struct bounce_message *msg, int delivery, const char *status) evp.lasttry = msg->timeout; envelope_set_errormsg(&evp, "%s", status); queue_envelope_update(&evp); - m_create(p_scheduler, delivery, 0, 0, -1, MSZ_EVP); + m_create(p_scheduler, delivery, 0, 0, -1); m_add_envelope(p_scheduler, &evp); m_close(p_scheduler); } else { - m_create(p_scheduler, delivery, 0, 0, -1, - sizeof(be->id) + 1); + m_create(p_scheduler, delivery, 0, 0, -1); m_add_evpid(p_scheduler, be->id); m_close(p_scheduler); queue_envelope_delete(be->id); diff --git a/usr.sbin/smtpd/compress_backend.c b/usr.sbin/smtpd/compress_backend.c index b7a957671c1..08ac9665a32 100644 --- a/usr.sbin/smtpd/compress_backend.c +++ b/usr.sbin/smtpd/compress_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: compress_backend.c,v 1.7 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: compress_backend.c,v 1.8 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Charles Longeau <chl@openbsd.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -32,71 +31,39 @@ #include "smtpd.h" -extern struct compress_backend compress_gzip; +#define BUFFER_SIZE 16364 -static struct compress_backend *backend = NULL; +extern struct compress_backend compress_gzip; -int -compress_backend_init(const char *name) +struct compress_backend * +compress_backend_lookup(const char *name) { if (!strcmp(name, "gzip")) - backend = &compress_gzip; - - if (backend) - return (1); - return (0); -} - -void * -compress_new(void) -{ - return (backend->compress_new()); -} - -size_t -compress_chunk(void *hdl, void *ib, size_t ibsz, void *ob, size_t obsz) -{ - return (backend->compress_chunk(hdl, ib, ibsz, ob, obsz)); -} + return &compress_gzip; -size_t -compress_finalize(void *hdl, void *ob, size_t obsz) -{ - return (backend->compress_finalize(hdl, ob, obsz)); -} - -void * -uncompress_new(void) -{ - return (backend->uncompress_new()); -} - -size_t -uncompress_chunk(void *hdl, void *ib, size_t ibsz, void *ob, size_t obsz) -{ - return (backend->uncompress_chunk(hdl, ib, ibsz, ob, obsz)); + return NULL; } size_t -uncompress_finalize(void *hdl, void *ob, size_t obsz) +compress_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) { - return (backend->uncompress_finalize(hdl, ob, obsz)); + return (env->sc_comp->compress_chunk(ib, ibsz, ob, obsz)); } size_t -compress_buffer(char *ib, size_t iblen, char *ob, size_t oblen) +uncompress_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) { - return (compress_chunk(NULL, ib, iblen, ob, oblen)); + return (env->sc_comp->uncompress_chunk(ib, ibsz, ob, obsz)); } -size_t -uncompress_buffer(char *ib, size_t iblen, char *ob, size_t oblen) +int +compress_file(FILE *ifile, FILE *ofile) { - return (uncompress_chunk(NULL, ib, iblen, ob, oblen)); + return (env->sc_comp->compress_file(ifile, ofile)); } int uncompress_file(FILE *ifile, FILE *ofile) { - return (0); -}; + return (env->sc_comp->uncompress_file(ifile, ofile)); +} diff --git a/usr.sbin/smtpd/compress_gzip.c b/usr.sbin/smtpd/compress_gzip.c index 32a31770fc3..e601137f1f2 100644 --- a/usr.sbin/smtpd/compress_gzip.c +++ b/usr.sbin/smtpd/compress_gzip.c @@ -1,4 +1,4 @@ -/* $OpenBSD: compress_gzip.c,v 1.6 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: compress_gzip.c,v 1.7 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -39,55 +38,146 @@ #include "smtpd.h" #include "log.h" -static void* compress_gzip_new(void); -static size_t compress_gzip_chunk(void *, void *, size_t, void *, size_t); -static size_t compress_gzip_finalize(void *, void *, size_t); -static void* uncompress_gzip_new(void); -static size_t uncompress_gzip_chunk(void *, void *, size_t, void *, size_t); -static size_t uncompress_gzip_finalize(void *, void *, size_t); + +#define GZIP_BUFFER_SIZE 16384 + + +static size_t compress_gzip_chunk(void *, size_t, void *, size_t); +static size_t uncompress_gzip_chunk(void *, size_t, void *, size_t); +static int compress_gzip_file(FILE *, FILE *); +static int uncompress_gzip_file(FILE *, FILE *); + struct compress_backend compress_gzip = { - compress_gzip_new, compress_gzip_chunk, - compress_gzip_finalize, - - uncompress_gzip_new, uncompress_gzip_chunk, - uncompress_gzip_finalize, -}; -static void * -compress_gzip_new(void) -{ - return (NULL); -} + compress_gzip_file, + uncompress_gzip_file, +}; static size_t -compress_gzip_chunk(void *hdl, void *ib, size_t ibsz, void *ob, size_t obsz) +compress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) { - return (-1); + z_stream *strm; + size_t ret = 0; + + if ((strm = calloc(1, sizeof *strm)) == NULL) + return 0; + + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + if (deflateInit2(strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) + goto end; + + strm->avail_in = ibsz; + strm->next_in = (unsigned char *)ib; + strm->avail_out = obsz; + strm->next_out = (unsigned char *)ob; + if (deflate(strm, Z_FINISH) != Z_STREAM_END) + goto end; + + ret = strm->total_out; + +end: + deflateEnd(strm); + free(strm); + return ret; } + static size_t -compress_gzip_finalize(void *hdl, void *ob, size_t obsz) +uncompress_gzip_chunk(void *ib, size_t ibsz, void *ob, size_t obsz) { - return (-1); -} + z_stream *strm; + size_t ret = 0; -static void * -uncompress_gzip_new(void) -{ - return (NULL); + if ((strm = calloc(1, sizeof *strm)) == NULL) + return 0; + + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + strm->avail_in = 0; + strm->next_in = Z_NULL; + + if (inflateInit2(strm, (15+16)) != Z_OK) + goto end; + + strm->avail_in = ibsz; + strm->next_in = (unsigned char *)ib; + strm->avail_out = obsz; + strm->next_out = (unsigned char *)ob; + + if (inflate(strm, Z_FINISH) != Z_STREAM_END) + goto end; + + ret = strm->total_out; + +end: + deflateEnd(strm); + free(strm); + return ret; } -static size_t -uncompress_gzip_chunk(void *hdl, void *ib, size_t ibsz, void *ob, size_t obsz) + +static int +compress_gzip_file(FILE *in, FILE *out) { - return (-1); + gzFile gzf; + char ibuf[GZIP_BUFFER_SIZE]; + int r, w; + int ret = 0; + + if (in == NULL || out == NULL) + return (0); + + gzf = gzdopen(fileno(out), "wb"); + if (gzf == NULL) + return (0); + + while ((r = fread(ibuf, 1, GZIP_BUFFER_SIZE, in)) != 0) { + if ((w = gzwrite(gzf, ibuf, r)) != r) + goto end; + } + if (! feof(in)) + goto end; + + ret = 1; + +end: + gzclose(gzf); + return (ret); } -static size_t -uncompress_gzip_finalize(void *hdl, void *ob, size_t obsz) + +static int +uncompress_gzip_file(FILE *in, FILE *out) { - return (-1); + gzFile gzf; + char obuf[GZIP_BUFFER_SIZE]; + int r, w; + int ret = 0; + + if (in == NULL || out == NULL) + return (0); + + gzf = gzdopen(fileno(in), "r"); + if (gzf == NULL) + return (0); + + while ((r = gzread(gzf, obuf, sizeof(obuf))) > 0) { + if ((w = fwrite(obuf, r, 1, out)) != 1) + goto end; + } + if (! gzeof(gzf)) + goto end; + + ret = 1; + +end: + gzclose(gzf); + return (ret); } diff --git a/usr.sbin/smtpd/config.c b/usr.sbin/smtpd/config.c index e553c5bef96..c647a479b69 100644 --- a/usr.sbin/smtpd/config.c +++ b/usr.sbin/smtpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.19 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: config.c,v 1.20 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <event.h> @@ -54,12 +53,10 @@ purge_config(uint8_t what) env->sc_listeners = NULL; } if (what & PURGE_TABLES) { - while (tree_root(env->sc_tables_tree, NULL, (void **)&t)) + while (dict_root(env->sc_tables_dict, NULL, (void **)&t)) table_destroy(t); free(env->sc_tables_dict); - free(env->sc_tables_tree); env->sc_tables_dict = NULL; - env->sc_tables_tree = NULL; } if (what & PURGE_RULES) { while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) { diff --git a/usr.sbin/smtpd/control.c b/usr.sbin/smtpd/control.c index e3267d6d6fd..8312bad41ca 100644 --- a/usr.sbin/smtpd/control.c +++ b/usr.sbin/smtpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.84 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: control.c,v 1.85 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/un.h> @@ -320,6 +319,7 @@ control_accept(int listenfd, short event, void *arg) if (getpeereid(connfd, &c->euid, &c->egid) == -1) fatal("getpeereid"); c->id = ++connid; + c->mproc.proc = PROC_CLIENT; c->mproc.handler = control_dispatch_ext; c->mproc.data = c; mproc_init(&c->mproc, connfd); @@ -413,6 +413,11 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) return; } + if (imsg->hdr.peerid != IMSG_VERSION) { + m_compose(p, IMSG_CTL_FAIL, IMSG_VERSION, 0, -1, NULL, 0); + return; + } + switch (imsg->hdr.type) { case IMSG_SMTP_ENQUEUE_FD: if (env->sc_flags & (SMTPD_SMTP_PAUSED | @@ -477,7 +482,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) verbose = v; log_verbose(verbose); - m_create(p_parent, IMSG_CTL_VERBOSE, 0, 0, -1, 9); + m_create(p_parent, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_parent, verbose); m_close(p_parent); @@ -495,7 +500,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) verbose |= v; log_verbose(verbose); - m_create(p_parent, IMSG_CTL_TRACE, 0, 0, -1, 9); + m_create(p_parent, IMSG_CTL_TRACE, 0, 0, -1); m_add_int(p_parent, v); m_close(p_parent); @@ -513,7 +518,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) verbose &= ~v; log_verbose(verbose); - m_create(p_parent, IMSG_CTL_UNTRACE, 0, 0, -1, 9); + m_create(p_parent, IMSG_CTL_UNTRACE, 0, 0, -1); m_add_int(p_parent, v); m_close(p_parent); @@ -530,7 +535,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) memcpy(&v, imsg->data, sizeof(v)); profiling |= v; - m_create(p_parent, IMSG_CTL_PROFILE, 0, 0, -1, 9); + m_create(p_parent, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_parent, v); m_close(p_parent); @@ -547,7 +552,7 @@ control_dispatch_ext(struct mproc *p, struct imsg *imsg) memcpy(&v, imsg->data, sizeof(v)); profiling &= ~v; - m_create(p_parent, IMSG_CTL_UNPROFILE, 0, 0, -1, 9); + m_create(p_parent, IMSG_CTL_UNPROFILE, 0, 0, -1); m_add_int(p_parent, v); m_close(p_parent); diff --git a/usr.sbin/smtpd/delivery.c b/usr.sbin/smtpd/delivery.c index c2d63484216..7e0519b953f 100644 --- a/usr.sbin/smtpd/delivery.c +++ b/usr.sbin/smtpd/delivery.c @@ -1,4 +1,4 @@ -/* $OpenBSD: delivery.c,v 1.3 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: delivery.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -38,6 +37,7 @@ extern struct delivery_backend delivery_backend_mbox; extern struct delivery_backend delivery_backend_mda; extern struct delivery_backend delivery_backend_maildir; extern struct delivery_backend delivery_backend_filename; +extern struct delivery_backend delivery_backend_lmtp; struct delivery_backend * delivery_backend_lookup(enum action_type type) @@ -51,6 +51,8 @@ delivery_backend_lookup(enum action_type type) return &delivery_backend_maildir; case A_FILENAME: return &delivery_backend_filename; + case A_LMTP: + return &delivery_backend_lmtp; default: fatal("unsupported delivery_backend type"); } diff --git a/usr.sbin/smtpd/delivery_filename.c b/usr.sbin/smtpd/delivery_filename.c index 097d68153ae..1ce62432834 100644 --- a/usr.sbin/smtpd/delivery_filename.c +++ b/usr.sbin/smtpd/delivery_filename.c @@ -1,4 +1,4 @@ -/* $OpenBSD: delivery_filename.c,v 1.8 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: delivery_filename.c,v 1.9 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> diff --git a/usr.sbin/smtpd/delivery_lmtp.c b/usr.sbin/smtpd/delivery_lmtp.c new file mode 100644 index 00000000000..53f8552ce28 --- /dev/null +++ b/usr.sbin/smtpd/delivery_lmtp.c @@ -0,0 +1,237 @@ +/* $OpenBSD: delivery_lmtp.c,v 1.1 2013/05/24 17:03:14 eric Exp $ */ + +/* + * Copyright (c) 2013 Ashish SHUKLA <ashish.is@lostca.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <ctype.h> +#include <err.h> +#include <event.h> +#include <fcntl.h> +#include <imsg.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd.h" +#include "log.h" + + +/* mda backend */ +static void delivery_lmtp_open(struct deliver *); + +static int inet_socket(char *); +static int unix_socket(char *); +static char* lmtp_getline(FILE *); + +struct delivery_backend delivery_backend_lmtp = { + 0, delivery_lmtp_open +}; + +enum lmtp_state { + LMTP_BANNER, + LMTP_LHLO, + LMTP_MAIL_FROM, + LMTP_RCPT_TO, + LMTP_DATA, + LMTP_QUIT, + LMTP_BYE +}; + +static int +inet_socket (char *address) +{ + int s, n; + char *hostname, *servname; + struct addrinfo hints; + struct addrinfo *result0, *result; + + servname = strchr(address, ':'); + *servname++ = '\0'; + hostname = address; + s = -1; + + bzero(&hints, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + + n = getaddrinfo(hostname, servname, &hints, &result0); + if (n) + errx(1, "%s", gai_strerror(n)); + + for (result = result0; s < 0 && result; result = result->ai_next) { + if ((s = socket(result->ai_family, result->ai_socktype, + result->ai_protocol)) == -1) { + warn("socket"); + continue; + } + if (connect(s, result->ai_addr, result->ai_addrlen) == -1) { + warn("connect"); + close(s); + s = -1; + continue; + } + break; + } + + freeaddrinfo(result0); + + return s; +} + +static int +unix_socket(char *path) { + struct sockaddr_un addr; + int s; + + bzero(&addr, sizeof(addr)); + + if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) { + warn("socket"); + return -1; + } + + addr.sun_family = AF_UNIX; + strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); + + if (connect(s, (struct sockaddr*) &addr, sizeof(addr)) == -1) { + warn("connect"); + close(s); + return -1; + } + + return s; +} + +static void +delivery_lmtp_open(struct deliver *deliver) +{ + char *buffer; + char *lbuf; + char lhloname[255]; + int s; + FILE *fp; + enum lmtp_state state = LMTP_BANNER; + size_t len; + + fp = NULL; + + if (deliver->to[0] == '/') + s = unix_socket(deliver->to); + else + s = inet_socket(deliver->to); + + if (s == -1 || (fp = fdopen(s, "r+")) == NULL) + err(1, "couldn't establish connection"); + + while (!feof(fp) && !ferror(fp) && state != LMTP_BYE) { + buffer = lmtp_getline(fp); + if (buffer == NULL) + err(1, "No input received"); + + switch (state) { + case LMTP_BANNER: + if (strncmp("220 ", buffer, 4) != 0) + errx(1, "Invalid LMTP greeting: %s\n", buffer); + gethostname(lhloname, sizeof lhloname ); + fprintf(fp, "LHLO %s\r\n", lhloname); + state = LMTP_LHLO; + break; + + case LMTP_LHLO: + if (buffer[0] != '2') + errx(1, "LHLO rejected: %s\n", buffer); + if (strlen(buffer) < 4) + errx(1, "Invalid LMTP LHLO answer: %s\n", buffer); + if (buffer[3] == '-') + continue; /* multi-line */ + fprintf(fp, "MAIL FROM:<%s>\r\n", deliver->from); + state = LMTP_MAIL_FROM; + break; + + case LMTP_MAIL_FROM: + if (buffer[0] != '2') + errx(1, "MAIL FROM rejected: %s\n", buffer); + fprintf(fp, "RCPT TO:<%s>\r\n", deliver->user); + state = LMTP_RCPT_TO; + break; + + case LMTP_RCPT_TO: + if (buffer[0] != '2') + errx(1, "RCPT TO rejected: %s\n", buffer); + fprintf(fp, "DATA\r\n"); + state = LMTP_DATA; + break; + + case LMTP_DATA: + if (buffer[0] != '3') + errx(1, "DATA rejected: %s\n", buffer); + lbuf = NULL; + while ((buffer = fgetln(stdin, &len))) { + if (buffer[len- 1] == '\n') + buffer[len - 1] = '\0'; + else { + if ((lbuf = malloc(len + 1)) == NULL) + err(1, NULL); + memcpy(lbuf, buffer, len); + lbuf[len] = '\0'; + buffer = lbuf; + } + fprintf(fp, "%s%s\r\n", + *buffer == '.' ? "." : "", buffer); + } + free(lbuf); + fprintf(fp, ".\r\n"); + state = LMTP_QUIT; + break; + + case LMTP_QUIT: + if (buffer[0] != '2') + errx(1, "Delivery error: %s\n", buffer); + fprintf(fp, "QUIT\r\n"); + state = LMTP_BYE; + break; + + case LMTP_BYE: + break; + } + } + + _exit(0); +} + +static char* +lmtp_getline(FILE *fp) +{ + char *buffer; + size_t len; + + if ((buffer = fgetln(fp, &len)) != NULL) { + if (len >= 2 && buffer[len-2] == '\r') + buffer[len-2] = '\0'; + buffer[len-1] = '\0'; + } + + return buffer; +} diff --git a/usr.sbin/smtpd/delivery_maildir.c b/usr.sbin/smtpd/delivery_maildir.c index 663bb1cb755..4f854e18526 100644 --- a/usr.sbin/smtpd/delivery_maildir.c +++ b/usr.sbin/smtpd/delivery_maildir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: delivery_maildir.c,v 1.11 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: delivery_maildir.c,v 1.12 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -52,7 +51,7 @@ struct delivery_backend delivery_backend_maildir = { static void delivery_maildir_open(struct deliver *deliver) { - char tmp[PATH_MAX], new[PATH_MAX]; + char tmp[SMTPD_MAXPATHLEN], new[SMTPD_MAXPATHLEN]; int ch, fd; FILE *fp; char *msg; diff --git a/usr.sbin/smtpd/delivery_mbox.c b/usr.sbin/smtpd/delivery_mbox.c index 34b9eb37ee8..13bb2178d86 100644 --- a/usr.sbin/smtpd/delivery_mbox.c +++ b/usr.sbin/smtpd/delivery_mbox.c @@ -1,4 +1,4 @@ -/* $OpenBSD: delivery_mbox.c,v 1.8 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: delivery_mbox.c,v 1.9 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -56,6 +55,9 @@ delivery_mbox_open(struct deliver *deliver) environ_new[0] = "PATH=" _PATH_DEFPATH; environ_new[1] = (char *)NULL; environ = environ_new; + + if (deliver->from[0] == '\0') + strlcpy(deliver->from, "MAILER-DAEMON", sizeof deliver->from); execle(PATH_MAILLOCAL, PATH_MAILLOCAL, "-f", deliver->from, deliver->to, (char *)NULL, environ_new); perror("execle"); diff --git a/usr.sbin/smtpd/delivery_mda.c b/usr.sbin/smtpd/delivery_mda.c index a087f5617a4..f374e702a88 100644 --- a/usr.sbin/smtpd/delivery_mda.c +++ b/usr.sbin/smtpd/delivery_mda.c @@ -1,4 +1,4 @@ -/* $OpenBSD: delivery_mda.c,v 1.7 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: delivery_mda.c,v 1.8 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> diff --git a/usr.sbin/smtpd/dict.c b/usr.sbin/smtpd/dict.c index b513413e7f7..07fdc771e7c 100644 --- a/usr.sbin/smtpd/dict.c +++ b/usr.sbin/smtpd/dict.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dict.c,v 1.1 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: dict.c,v 1.2 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -41,7 +41,7 @@ struct dictentry { static int dictentry_cmp(struct dictentry *, struct dictentry *); -SPLAY_PROTOTYPE(dict, dictentry, entry, dictentry_cmp); +SPLAY_PROTOTYPE(_dict, dictentry, entry, dictentry_cmp); int dict_check(struct dict *d, const char *k) @@ -51,7 +51,7 @@ dict_check(struct dict *d, const char *k) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_check(%p, %s): key too large", d, k); - return (SPLAY_FIND(dict, d, &key) != NULL); + return (SPLAY_FIND(_dict, &d->dict, &key) != NULL); } void * @@ -62,11 +62,13 @@ dict_set(struct dict *d, const char *k, void *data) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_set(%p, %s): key too large", d, k); - if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) { - entry = xmalloc(sizeof *entry, "dict_set"); + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) { + if ((entry = malloc(sizeof *entry)) == NULL) + err(1, "dict_set: malloc"); (void)strlcpy(entry->key, k, sizeof entry->key); - SPLAY_INSERT(dict, d, entry); + SPLAY_INSERT(_dict, &d->dict, entry); old = NULL; + d->count += 1; } else old = entry->data; @@ -80,12 +82,14 @@ dict_xset(struct dict *d, const char * k, void *data) { struct dictentry *entry; - entry = xmalloc(sizeof *entry, "dict_xset"); + if ((entry = malloc(sizeof *entry)) == NULL) + err(1, "dict_xset: malloc"); if (strlcpy(entry->key, k, sizeof entry->key) >= sizeof entry->key) errx(1, "dict_xset(%p, %s): key too large", d, k); entry->data = data; - if (SPLAY_INSERT(dict, d, entry)) + if (SPLAY_INSERT(_dict, &d->dict, entry)) errx(1, "dict_xset(%p, %s)", d, k); + d->count += 1; } void * @@ -95,7 +99,7 @@ dict_get(struct dict *d, const char *k) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_get(%p, %s): key too large", d, k); - if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) return (NULL); return (entry->data); @@ -108,7 +112,7 @@ dict_xget(struct dict *d, const char *k) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_xget(%p, %s): key too large", d, k); - if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) errx(1, "dict_xget(%p, %s)", d, k); return (entry->data); @@ -122,12 +126,13 @@ dict_pop(struct dict *d, const char *k) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_pop(%p, %s): key too large", d, k); - if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) return (NULL); data = entry->data; - SPLAY_REMOVE(dict, d, entry); + SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); + d->count -= 1; return (data); } @@ -140,12 +145,13 @@ dict_xpop(struct dict *d, const char *k) if (strlcpy(key.key, k, sizeof key.key) >= sizeof key.key) errx(1, "dict_xpop(%p, %s): key too large", d, k); - if ((entry = SPLAY_FIND(dict, d, &key)) == NULL) + if ((entry = SPLAY_FIND(_dict, &d->dict, &key)) == NULL) errx(1, "dict_xpop(%p, %s)", d, k); data = entry->data; - SPLAY_REMOVE(dict, d, entry); + SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); + d->count -= 1; return (data); } @@ -155,15 +161,17 @@ dict_poproot(struct dict *d, const char **k, void **data) { struct dictentry *entry; - entry = SPLAY_ROOT(d); + entry = SPLAY_ROOT(&d->dict); if (entry == NULL) return (0); if (k) *k = entry->key; if (data) *data = entry->data; - SPLAY_REMOVE(dict, d, entry); + SPLAY_REMOVE(_dict, &d->dict, entry); free(entry); + d->count -= 1; + return (1); } @@ -172,7 +180,7 @@ dict_root(struct dict *d, const char **k, void **data) { struct dictentry *entry; - entry = SPLAY_ROOT(d); + entry = SPLAY_ROOT(&d->dict); if (entry == NULL) return (0); if (k) @@ -188,9 +196,9 @@ dict_iter(struct dict *d, void **hdl, const char **k, void **data) struct dictentry *curr = *hdl; if (curr == NULL) - curr = SPLAY_MIN(dict, d); + curr = SPLAY_MIN(_dict, &d->dict); else - curr = SPLAY_NEXT(dict, d, curr); + curr = SPLAY_NEXT(_dict, &d->dict, curr); if (curr) { *hdl = curr; @@ -212,21 +220,21 @@ dict_iterfrom(struct dict *d, void **hdl, const char *kfrom, const char **k, if (curr == NULL) { if (kfrom == NULL) - curr = SPLAY_MIN(dict, d); + curr = SPLAY_MIN(_dict, &d->dict); else { if (strlcpy(key.key, kfrom, sizeof key.key) >= sizeof key.key) errx(1, "dict_iterfrom(%p, %s): key too large", d, kfrom); - curr = SPLAY_FIND(dict, d, &key); + curr = SPLAY_FIND(_dict, &d->dict, &key); if (curr == NULL) { - SPLAY_INSERT(dict, d, &key); - curr = SPLAY_NEXT(dict, d, &key); - SPLAY_REMOVE(dict, d, &key); + SPLAY_INSERT(_dict, &d->dict, &key); + curr = SPLAY_NEXT(_dict, &d->dict, &key); + SPLAY_REMOVE(_dict, &d->dict, &key); } } } else - curr = SPLAY_NEXT(dict, d, curr); + curr = SPLAY_NEXT(_dict, &d->dict, curr); if (curr) { *hdl = curr; @@ -245,12 +253,14 @@ dict_merge(struct dict *dst, struct dict *src) { struct dictentry *entry; - while (!SPLAY_EMPTY(src)) { - entry = SPLAY_ROOT(src); - SPLAY_REMOVE(dict, src, entry); - if (SPLAY_INSERT(dict, dst, entry)) + while (!SPLAY_EMPTY(&src->dict)) { + entry = SPLAY_ROOT(&src->dict); + SPLAY_REMOVE(_dict, &src->dict, entry); + if (SPLAY_INSERT(_dict, &dst->dict, entry)) errx(1, "dict_merge: duplicate"); } + dst->count += src->count; + src->count = 0; } static int @@ -259,4 +269,4 @@ dictentry_cmp(struct dictentry *a, struct dictentry *b) return strcmp(a->key, b->key); } -SPLAY_GENERATE(dict, dictentry, entry, dictentry_cmp); +SPLAY_GENERATE(_dict, dictentry, entry, dictentry_cmp); diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c index 33e0eb5fc40..506f82f027b 100644 --- a/usr.sbin/smtpd/dns.c +++ b/usr.sbin/smtpd/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.65 2013/04/30 12:07:21 eric Exp $ */ +/* $OpenBSD: dns.c,v 1.66 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -48,7 +48,7 @@ struct dns_session { struct mproc *p; uint64_t reqid; int type; - char name[MAXHOSTNAMELEN]; + char name[SMTPD_MAXHOSTNAMELEN]; size_t mxfound; int error; int refcount; @@ -69,7 +69,7 @@ static void dns_dispatch_mx_preference(int, struct async_res *, void *); void dns_query_host(uint64_t id, const char *host) { - m_create(p_lka, IMSG_DNS_HOST, 0, 0, -1, 128); + m_create(p_lka, IMSG_DNS_HOST, 0, 0, -1); m_add_id(p_lka, id); m_add_string(p_lka, host); m_close(p_lka); @@ -78,7 +78,7 @@ dns_query_host(uint64_t id, const char *host) void dns_query_ptr(uint64_t id, const struct sockaddr *sa) { - m_create(p_lka, IMSG_DNS_PTR, 0, 0, -1, 128); + m_create(p_lka, IMSG_DNS_PTR, 0, 0, -1); m_add_id(p_lka, id); m_add_sockaddr(p_lka, sa); m_close(p_lka); @@ -87,7 +87,7 @@ dns_query_ptr(uint64_t id, const struct sockaddr *sa) void dns_query_mx(uint64_t id, const char *domain) { - m_create(p_lka, IMSG_DNS_MX, 0, 0, -1, 128); + m_create(p_lka, IMSG_DNS_MX, 0, 0, -1); m_add_id(p_lka, id); m_add_string(p_lka, domain); m_close(p_lka); @@ -96,7 +96,7 @@ dns_query_mx(uint64_t id, const char *domain) void dns_query_mx_preference(uint64_t id, const char *domain, const char *mx) { - m_create(p_lka, IMSG_DNS_MX_PREFERENCE, 0, 0, -1, 128); + m_create(p_lka, IMSG_DNS_MX_PREFERENCE, 0, 0, -1); m_add_id(p_lka, id); m_add_string(p_lka, domain); m_add_string(p_lka, mx); @@ -171,7 +171,7 @@ dns_dispatch_host(int ev, struct async_res *ar, void *arg) for (ai = ar->ar_addrinfo; ai; ai = ai->ai_next) { s->mxfound++; - m_create(s->p, IMSG_DNS_HOST, 0, 0, -1, 128); + m_create(s->p, IMSG_DNS_HOST, 0, 0, -1); m_add_id(s->p, s->reqid); m_add_sockaddr(s->p, ai->ai_addr); m_add_int(s->p, lookup->preference); @@ -187,7 +187,7 @@ dns_dispatch_host(int ev, struct async_res *ar, void *arg) if (--s->refcount) return; - m_create(s->p, IMSG_DNS_HOST_END, 0, 0, -1, 24); + m_create(s->p, IMSG_DNS_HOST_END, 0, 0, -1); m_add_id(s->p, s->reqid); m_add_int(s->p, s->mxfound ? DNS_OK : DNS_ENOTFOUND); m_close(s->p); @@ -200,7 +200,7 @@ dns_dispatch_ptr(int ev, struct async_res *ar, void *arg) struct dns_session *s = arg; /* The error code could be more precise, but we don't currently care */ - m_create(s->p, IMSG_DNS_PTR, 0, 0, -1, 512); + m_create(s->p, IMSG_DNS_PTR, 0, 0, -1); m_add_id(s->p, s->reqid); m_add_int(s->p, ar->ar_gai_errno ? DNS_ENOTFOUND : DNS_OK); if (ar->ar_gai_errno == 0) @@ -222,7 +222,7 @@ dns_dispatch_mx(int ev, struct async_res *ar, void *arg) if (ar->ar_h_errno && ar->ar_h_errno != NO_DATA) { - m_create(s->p, IMSG_DNS_HOST_END, 0, 0, -1, 24); + m_create(s->p, IMSG_DNS_HOST_END, 0, 0, -1); m_add_id(s->p, s->reqid); if (ar->ar_rcode == NXDOMAIN) m_add_int(s->p, DNS_ENONAME); @@ -297,7 +297,7 @@ dns_dispatch_mx_preference(int ev, struct async_res *ar, void *arg) free(ar->ar_data); - m_create(s->p, IMSG_DNS_MX_PREFERENCE, 0, 0, -1, 36); + m_create(s->p, IMSG_DNS_MX_PREFERENCE, 0, 0, -1); m_add_id(s->p, s->reqid); m_add_int(s->p, error); if (error == DNS_OK) diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c index 0413d27927d..e51f4a220fa 100644 --- a/usr.sbin/smtpd/enqueue.c +++ b/usr.sbin/smtpd/enqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: enqueue.c,v 1.67 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: enqueue.c,v 1.68 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2005 Henning Brauer <henning@bulabula.org> @@ -18,11 +18,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/param.h> +#include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> #include <sys/tree.h> -#include <sys/types.h> #include <sys/stat.h> #include <ctype.h> @@ -96,7 +95,7 @@ struct { #define WSP(c) (c == ' ' || c == '\t') int verbose = 0; -char host[MAXHOSTNAMELEN]; +char host[SMTPD_MAXHOSTNAMELEN]; char *user = NULL; time_t timestamp; @@ -694,7 +693,7 @@ open_connection(void) int fd; int n; - imsg_compose(ibuf, IMSG_SMTP_ENQUEUE_FD, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_SMTP_ENQUEUE_FD, IMSG_VERSION, 0, -1, NULL, 0); while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) < 0) @@ -732,7 +731,7 @@ open_connection(void) int enqueue_offline(int argc, char *argv[]) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; FILE *fp; int i, fd, ch; mode_t omode; @@ -753,6 +752,11 @@ enqueue_offline(int argc, char *argv[]) } umask(omode); + if (fchmod(fd, 0600) == -1) { + unlink(path); + exit(1); + } + for (i = 1; i < argc; i++) { if (strchr(argv[i], '|') != NULL) { warnx("%s contains illegal character", argv[i]); diff --git a/usr.sbin/smtpd/envelope.c b/usr.sbin/smtpd/envelope.c index da8cdbfd3ac..03a966befed 100644 --- a/usr.sbin/smtpd/envelope.c +++ b/usr.sbin/smtpd/envelope.c @@ -1,4 +1,4 @@ -/* $OpenBSD: envelope.c,v 1.19 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: envelope.c,v 1.20 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -592,6 +591,8 @@ ascii_load_mda_method(enum action_type *dest, char *buf) *dest = A_FILENAME; else if (strcasecmp(buf, "mda") == 0) *dest = A_MDA; + else if (strcasecmp(buf, "lmtp") == 0) + *dest = A_LMTP; else return 0; return 1; @@ -697,6 +698,9 @@ ascii_dump_mda_method(enum action_type type, char *dest, size_t len) char *p = NULL; switch (type) { + case A_LMTP: + p = "lmtp"; + break; case A_MAILDIR: p = "maildir"; break; diff --git a/usr.sbin/smtpd/expand.c b/usr.sbin/smtpd/expand.c index 4e96cdf08fe..811ce093625 100644 --- a/usr.sbin/smtpd/expand.c +++ b/usr.sbin/smtpd/expand.c @@ -1,4 +1,4 @@ -/* $OpenBSD: expand.c,v 1.22 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: expand.c,v 1.23 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -41,6 +40,22 @@ expand_lookup(struct expand *expand, struct expandnode *key) return RB_FIND(expandtree, &expand->tree, key); } +int +expand_to_text(struct expand *expand, char *buf, size_t sz) +{ + struct expandnode *xn; + + buf[0] = '\0'; + + RB_FOREACH(xn, expandtree, &expand->tree) { + if (buf[0]) + strlcat(buf, ", ", sz); + strlcat(buf, expandnode_to_text(xn), sz); + } + + return 1; +} + void expand_insert(struct expand *expand, struct expandnode *node) { @@ -223,6 +238,9 @@ expandnode_info(struct expandnode *e) case EXPAND_ADDRESS: type = "address"; break; + case EXPAND_ERROR: + type = "error"; + break; case EXPAND_INVALID: default: return NULL; diff --git a/usr.sbin/smtpd/filter_api.c b/usr.sbin/smtpd/filter_api.c index ba7696f3d9d..1c97d6a5a96 100644 --- a/usr.sbin/smtpd/filter_api.c +++ b/usr.sbin/smtpd/filter_api.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filter_api.c,v 1.6 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: filter_api.c,v 1.7 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -39,6 +39,8 @@ struct query { }; static int register_done; +static const char *filter_name; + static struct filter_internals { struct mproc p; @@ -72,12 +74,6 @@ static void filter_dispatch_helo(uint64_t, uint64_t, const char *); static void filter_dispatch_mail(uint64_t, uint64_t, struct mailaddr *); static void filter_dispatch_rcpt(uint64_t, uint64_t, struct mailaddr *); -const char * -proc_to_str(int proc) -{ - return "PEER"; -} - void filter_api_on_notify(void(*cb)(uint64_t, enum filter_status)) { @@ -171,6 +167,10 @@ filter_api_loop(void) register_done = 1; + mproc_enable(&fi.p); + + usleep(1000000); + if (event_dispatch() < 0) errx(1, "event_dispatch"); } @@ -211,7 +211,7 @@ filter_api_reject_code(uint64_t id, enum filter_status status, uint32_t code, void filter_api_data(uint64_t id, const char *line) { - m_create(&fi.p, IMSG_FILTER_DATA, 0, 0, -1, 1024); + m_create(&fi.p, IMSG_FILTER_DATA, 0, 0, -1); m_add_id(&fi.p, id); m_add_string(&fi.p, line); m_close(&fi.p); @@ -225,7 +225,7 @@ filter_response(uint64_t qid, int status, int code, const char *line, int notify q = tree_xpop(&queries, qid); free(q); - m_create(&fi.p, IMSG_FILTER_RESPONSE, 0, 0, -1, 64); + m_create(&fi.p, IMSG_FILTER_RESPONSE, 0, 0, -1); m_add_id(&fi.p, qid); m_add_int(&fi.p, status); m_add_int(&fi.p, code); @@ -238,6 +238,7 @@ filter_response(uint64_t qid, int status, int code, const char *line, int notify static void filter_api_init(void) { + extern const char *__progname; static int init = 0; if (init) @@ -245,9 +246,17 @@ filter_api_init(void) init = 1; - bzero(&fi, sizeof(fi)); + smtpd_process = PROC_FILTER; + filter_name = __progname; + tree_init(&queries); event_init(); + + bzero(&fi, sizeof(fi)); + fi.p.proc = PROC_MFA; + fi.p.name = "filter"; + fi.p.handler = filter_dispatch; + mproc_init(&fi.p, 0); } @@ -262,6 +271,8 @@ filter_dispatch(struct mproc *p, struct imsg *imsg) uint64_t id, qid; int status, event, hook; + log_debug("debug: %s: imsg %i", filter_name, imsg->hdr.type); + switch (imsg->hdr.type) { case IMSG_FILTER_REGISTER: m_msg(&m, imsg); @@ -269,7 +280,7 @@ filter_dispatch(struct mproc *p, struct imsg *imsg) m_end(&m); if (v != FILTER_API_VERSION) errx(1, "API version mismatch"); - m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1, 18); + m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1); m_add_int(p, fi.hooks); m_add_int(p, fi.flags); m_close(p); @@ -396,3 +407,27 @@ filter_dispatch_eom(uint64_t id, uint64_t qid) { fi.cb.eom(id, qid); } + +/* + * These functions are called from mproc.c + */ + +enum smtp_proc_type smtpd_process; + +const char * +proc_name(enum smtp_proc_type proc) +{ + if (proc == PROC_FILTER) + return filter_name; + return "filter"; +} + +const char * +imsg_to_str(int imsg) +{ + static char buf[32]; + + snprintf(buf, sizeof(buf), "%i", imsg); + + return (buf); +} diff --git a/usr.sbin/smtpd/forward.c b/usr.sbin/smtpd/forward.c index b1a498597e8..151e8a3d977 100644 --- a/usr.sbin/smtpd/forward.c +++ b/usr.sbin/smtpd/forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: forward.c,v 1.34 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: forward.c,v 1.35 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -45,18 +44,22 @@ forwards_get(int fd, struct expand *expand) char *line = NULL; size_t len; size_t lineno; + size_t save; int ret; struct stat sb; - ret = 0; + ret = -1; if (fstat(fd, &sb) == -1) goto end; - /* empty or over MAX_FORWARD_SIZE, temporarily fail */ + /* if it's empty just pretend that no expansion took place */ if (sb.st_size == 0) { log_info("info: forward file is empty"); + ret = 0; goto end; } + + /* over MAX_FORWARD_SIZE, temporarily fail */ if (sb.st_size >= MAX_FORWARD_SIZE) { log_info("info: forward file exceeds max size"); goto end; @@ -68,6 +71,7 @@ forwards_get(int fd, struct expand *expand) } lineno = 0; + save = expand->nb_nodes; while ((line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL) { if (! expand_line(expand, line, 0)) { log_info("info: parse error in forward file"); @@ -80,7 +84,7 @@ forwards_get(int fd, struct expand *expand) free(line); } - ret = 1; + ret = expand->nb_nodes > save ? 1 : 0; end: if (line) diff --git a/usr.sbin/smtpd/iobuf.c b/usr.sbin/smtpd/iobuf.c index 0523302943e..8d3e6a54c00 100644 --- a/usr.sbin/smtpd/iobuf.c +++ b/usr.sbin/smtpd/iobuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iobuf.c,v 1.4 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: iobuf.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -15,11 +15,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/param.h> +#include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> #include <errno.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/usr.sbin/smtpd/ioev.c b/usr.sbin/smtpd/ioev.c index 8d9094a5b98..fdc9fa400ff 100644 --- a/usr.sbin/smtpd/ioev.c +++ b/usr.sbin/smtpd/ioev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ioev.c,v 1.11 2013/02/05 11:45:18 gilles Exp $ */ +/* $OpenBSD: ioev.c,v 1.12 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> * @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/param.h> +#include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -118,6 +118,7 @@ io_strevent(int evt) switch (evt) { CASE(IO_CONNECTED); CASE(IO_TLSREADY); + CASE(IO_TLSVERIFIED); CASE(IO_DATAIN); CASE(IO_LOWAT); CASE(IO_DISCONNECTED); @@ -622,6 +623,8 @@ void io_dispatch_connect(int fd, short ev, void *humppa) { struct io *io = humppa; + int r, e; + socklen_t sl; io_frame_enter("io_dispatch_connect", io, ev); @@ -630,8 +633,22 @@ io_dispatch_connect(int fd, short ev, void *humppa) io->sock = -1; io_callback(io, IO_TIMEOUT); } else { - io->state = IO_STATE_UP; - io_callback(io, IO_CONNECTED); + sl = sizeof(e); + r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &e, &sl); + if (r == -1) { + warn("io_dispatch_connect: getsockopt"); + e = errno; + } + if (e) { + close(fd); + io->sock = -1; + io->error = strerror(e); + io_callback(io, e == ETIMEDOUT ? IO_TIMEOUT : IO_ERROR); + } + else { + io->state = IO_STATE_UP; + io_callback(io, IO_CONNECTED); + } } io_frame_leave(io); @@ -675,11 +692,11 @@ io_start_tls(struct io *io, void *ssl) if (mode == IO_WRITE) { io->state = IO_STATE_CONNECT_SSL; SSL_set_connect_state(io->ssl); - io_reset(io, EV_READ | EV_WRITE, io_dispatch_connect_ssl); + io_reset(io, EV_WRITE, io_dispatch_connect_ssl); } else { io->state = IO_STATE_ACCEPT_SSL; SSL_set_accept_state(io->ssl); - io_reset(io, EV_READ | EV_WRITE, io_dispatch_accept_ssl); + io_reset(io, EV_READ, io_dispatch_accept_ssl); } return (0); @@ -853,29 +870,36 @@ io_dispatch_write_ssl(int fd, short event, void *humppa) void io_reload_ssl(struct io *io) { + short ev = 0; void (*dispatch)(int, short, void*) = NULL; switch (io->state) { case IO_STATE_CONNECT_SSL: + ev = EV_WRITE; dispatch = io_dispatch_connect_ssl; break; case IO_STATE_ACCEPT_SSL: + ev = EV_READ; dispatch = io_dispatch_accept_ssl; break; case IO_STATE_UP: - if ((io->flags & IO_RW) == IO_READ) + ev = 0; + if (IO_READING(io) && !(io->flags & IO_PAUSE_IN)) { + ev = EV_READ; dispatch = io_dispatch_read_ssl; - else { - if (io_queued(io) == 0) - return; /* nothing to write */ + } + else if (IO_WRITING(io) && !(io->flags & IO_PAUSE_OUT) && io_queued(io)) { + ev = EV_WRITE; dispatch = io_dispatch_write_ssl; } + if (! ev) + return; /* paused */ break; default: errx(1, "io_reload_ssl(): bad state"); } - io_reset(io, EV_READ | EV_WRITE, dispatch); + io_reset(io, ev, dispatch); } #endif /* IO_SSL */ diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c index eea6d30edd9..62494e3c0a7 100644 --- a/usr.sbin/smtpd/lka.c +++ b/usr.sbin/smtpd/lka.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lka.c,v 1.151 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: lka.c,v 1.152 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/uio.h> @@ -65,12 +64,10 @@ lka_imsg(struct mproc *p, struct imsg *imsg) void *tmp; int ret; const char *key, *val; - char *src; struct ssl *ssl; struct iovec iov[3]; static struct dict *ssl_dict; static struct dict *tables_dict; - static struct tree *tables_tree; static struct table *table_last; static struct ca_vrfy_req_msg *req_ca_vrfy_smtp = NULL; static struct ca_vrfy_req_msg *req_ca_vrfy_mta = NULL; @@ -79,15 +76,15 @@ lka_imsg(struct mproc *p, struct imsg *imsg) struct ca_cert_req_msg *req_ca_cert; struct ca_cert_resp_msg resp_ca_cert; struct sockaddr_storage ss; - struct addrinfo hints, *ai; struct userinfo userinfo; struct addrname addrname; struct envelope evp; struct msg m; + union lookup lk; char buf[SMTPD_MAXLINESIZE]; const char *tablename, *username, *password, *label; uint64_t reqid; - size_t i, len; + size_t i; int v; if (imsg->hdr.type == IMSG_DNS_HOST || @@ -159,7 +156,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) resp_ca_vrfy.reqid = req_ca_vrfy_smtp->reqid; - if (! lka_X509_verify(req_ca_vrfy_smtp, "/etc/ssl/cert.pem", NULL)) + if (! lka_X509_verify(req_ca_vrfy_smtp, CA_FILE, NULL)) resp_ca_vrfy.status = CA_FAIL; else resp_ca_vrfy.status = CA_OK; @@ -185,7 +182,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) if (!tablename[0]) { m_create(p_parent, IMSG_LKA_AUTHENTICATE, - 0, 0, -1, 128); + 0, 0, -1); m_add_id(p_parent, reqid); m_add_string(p_parent, username); m_add_string(p_parent, password); @@ -195,7 +192,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) ret = lka_authenticate(tablename, username, password); - m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1, 128); + m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1); m_add_id(p, reqid); m_add_int(p, ret); m_close(p); @@ -213,10 +210,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) ret = lka_userinfo(tablename, username, &userinfo); - len = 32 + strlen(tablename) + strlen(username); - if (ret == LKA_OK) - len += sizeof(userinfo); - m_create(p, IMSG_LKA_USERINFO, 0, 0, -1, len); + m_create(p, IMSG_LKA_USERINFO, 0, 0, -1); m_add_string(p, tablename); m_add_string(p, username); m_add_int(p, ret); @@ -282,7 +276,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) resp_ca_vrfy.reqid = req_ca_vrfy_mta->reqid; - if (! lka_X509_verify(req_ca_vrfy_mta, "/etc/ssl/cert.pem", NULL)) + if (! lka_X509_verify(req_ca_vrfy_mta, CA_FILE, NULL)) resp_ca_vrfy.status = CA_FAIL; else resp_ca_vrfy.status = CA_OK; @@ -307,7 +301,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) lka_credentials(tablename, label, buf, sizeof(buf)); - m_create(p, IMSG_LKA_SECRET, 0, 0, -1, 128); + m_create(p, IMSG_LKA_SECRET, 0, 0, -1); m_add_id(p, reqid); m_add_string(p, buf); m_close(p); @@ -318,34 +312,26 @@ lka_imsg(struct mproc *p, struct imsg *imsg) m_get_id(&m, &reqid); m_get_string(&m, &tablename); - table = table_findbyname(tablename); + table = table_find(tablename, NULL); - m_create(p, IMSG_LKA_SOURCE, 0, 0, -1, 64); + m_create(p, IMSG_LKA_SOURCE, 0, 0, -1); m_add_id(p, reqid); if (table == NULL) { log_warn("warn: source address table %s missing", tablename); m_add_int(p, LKA_TEMPFAIL); - } + } else { - ret = table_fetch(table, K_SOURCE, &src); + ret = table_fetch(table, K_SOURCE, &lk); if (ret == -1) m_add_int(p, LKA_TEMPFAIL); else if (ret == 0) m_add_int(p, LKA_PERMFAIL); else { - /* XXX find a nicer way? */ - bzero(&hints, sizeof hints); - hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(src, NULL, &hints, &ai) != 0) - m_add_int(p, LKA_TEMPFAIL); - else { - m_add_int(p, LKA_OK); - m_add_sockaddr(p, ai->ai_addr); - freeaddrinfo(ai); - } - free(src); + m_add_int(p, LKA_OK); + m_add_sockaddr(p, + (struct sockaddr *)&lk.source.addr); } } m_close(p); @@ -361,7 +347,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) ret = lka_addrname(tablename, (struct sockaddr*)&ss, &addrname); - m_create(p, IMSG_LKA_HELO, 0, 0, -1, 1024); + m_create(p, IMSG_LKA_HELO, 0, 0, -1); m_add_id(p, reqid); m_add_int(p, ret); if (ret == LKA_OK) @@ -379,15 +365,12 @@ lka_imsg(struct mproc *p, struct imsg *imsg) sizeof *env->sc_rules, "lka:sc_rules_reload"); tables_dict = xcalloc(1, sizeof *tables_dict, "lka:tables_dict"); - tables_tree = xcalloc(1, - sizeof *tables_tree, "lka:tables_tree"); ssl_dict = calloc(1, sizeof *ssl_dict); if (ssl_dict == NULL) fatal(NULL); dict_init(ssl_dict); dict_init(tables_dict); - tree_init(tables_tree); TAILQ_INIT(env->sc_rules_reload); return; @@ -425,14 +408,13 @@ lka_imsg(struct mproc *p, struct imsg *imsg) "lka:table"); dict_init(&table->t_dict); dict_set(tables_dict, table->t_name, table); - tree_set(tables_tree, table->t_id, table); return; case IMSG_CONF_RULE_SOURCE: rule = TAILQ_LAST(env->sc_rules_reload, rulelist); tmp = env->sc_tables_dict; env->sc_tables_dict = tables_dict; - rule->r_sources = table_findbyname(imsg->data); + rule->r_sources = table_find(imsg->data, NULL); if (rule->r_sources == NULL) fatalx("lka: tables inconsistency"); env->sc_tables_dict = tmp; @@ -442,7 +424,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) rule = TAILQ_LAST(env->sc_rules_reload, rulelist); tmp = env->sc_tables_dict; env->sc_tables_dict = tables_dict; - rule->r_senders = table_findbyname(imsg->data); + rule->r_senders = table_find(imsg->data, NULL); if (rule->r_senders == NULL) fatalx("lka: tables inconsistency"); env->sc_tables_dict = tmp; @@ -452,7 +434,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) rule = TAILQ_LAST(env->sc_rules_reload, rulelist); tmp = env->sc_tables_dict; env->sc_tables_dict = tables_dict; - rule->r_destination = table_findbyname(imsg->data); + rule->r_destination = table_find(imsg->data, NULL); if (rule->r_destination == NULL) fatalx("lka: tables inconsistency"); env->sc_tables_dict = tmp; @@ -462,7 +444,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) rule = TAILQ_LAST(env->sc_rules_reload, rulelist); tmp = env->sc_tables_dict; env->sc_tables_dict = tables_dict; - rule->r_mapping = table_findbyname(imsg->data); + rule->r_mapping = table_find(imsg->data, NULL); if (rule->r_mapping == NULL) fatalx("lka: tables inconsistency"); env->sc_tables_dict = tmp; @@ -472,7 +454,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) rule = TAILQ_LAST(env->sc_rules_reload, rulelist); tmp = env->sc_tables_dict; env->sc_tables_dict = tables_dict; - rule->r_userbase = table_findbyname(imsg->data); + rule->r_userbase = table_find(imsg->data, NULL); if (rule->r_userbase == NULL) fatalx("lka: tables inconsistency"); env->sc_tables_dict = tmp; @@ -497,20 +479,20 @@ lka_imsg(struct mproc *p, struct imsg *imsg) if (env->sc_rules) purge_config(PURGE_RULES); - if (env->sc_tables_tree) { + if (env->sc_tables_dict) { table_close_all(); purge_config(PURGE_TABLES); } env->sc_rules = env->sc_rules_reload; env->sc_ssl_dict = ssl_dict; env->sc_tables_dict = tables_dict; - env->sc_tables_tree = tables_tree; + if (verbose & TRACE_TABLES) + table_dump_all(); table_open_all(); ssl_dict = NULL; table_last = NULL; tables_dict = NULL; - tables_tree = NULL; /* Start fulfilling requests */ mproc_enable(p_mda); @@ -545,7 +527,7 @@ lka_imsg(struct mproc *p, struct imsg *imsg) if (p->proc == PROC_CONTROL) { switch (imsg->hdr.type) { case IMSG_LKA_UPDATE_TABLE: - table = table_findbyname(imsg->data); + table = table_find(imsg->data, NULL); if (table == NULL) { log_warnx("warn: Lookup table not found: " "\"%s\"", (char *)imsg->data); @@ -659,18 +641,17 @@ static int lka_authenticate(const char *tablename, const char *user, const char *password) { struct table *table; - struct credentials *creds; - int r; + union lookup lk; - log_trace(TRACE_LOOKUP, "lookup: authenticating for %s:%s", tablename, user); - table = table_findbyname(tablename); + log_debug("debug: lka: authenticating for %s:%s", tablename, user); + table = table_find(tablename, NULL); if (table == NULL) { log_warnx("warn: could not find table %s needed for authentication", tablename); return (LKA_TEMPFAIL); } - switch (table_lookup(table, user, K_CREDENTIALS, (void **)&creds)) { + switch (table_lookup(table, user, K_CREDENTIALS, &lk)) { case -1: log_warnx("warn: user credentials lookup fail for %s:%s", tablename, user); @@ -678,9 +659,7 @@ lka_authenticate(const char *tablename, const char *user, const char *password) case 0: return (LKA_PERMFAIL); default: - r = !strcmp(creds->password, crypt(password, creds->password)); - free(creds); - if (r) + if (!strcmp(lk.creds.password, crypt(password, lk.creds.password))) return (LKA_OK); return (LKA_PERMFAIL); } @@ -690,11 +669,11 @@ static int lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) { struct table *table; - struct credentials *creds; + union lookup lk; char *buf; int buflen, r; - table = table_findbyname(tablename); + table = table_find(tablename, NULL); if (table == NULL) { log_warnx("warn: credentials table %s missing", tablename); return (LKA_TEMPFAIL); @@ -702,7 +681,7 @@ lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) dst[0] = '\0'; - switch(table_lookup(table, label, K_CREDENTIALS, (void **)&creds)) { + switch(table_lookup(table, label, K_CREDENTIALS, &lk)) { case -1: log_warnx("warn: credentials lookup fail for %s:%s", tablename, label); @@ -713,12 +692,10 @@ lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) return (LKA_PERMFAIL); default: if ((buflen = asprintf(&buf, "%c%s%c%s", '\0', - creds->username, '\0', creds->password)) == -1) { - free(creds); + lk.creds.username, '\0', lk.creds.password)) == -1) { log_warn("warn"); return (LKA_TEMPFAIL); } - free(creds); r = __b64_ntop((unsigned char *)buf, buflen, dst, sz); free(buf); @@ -735,17 +712,17 @@ lka_credentials(const char *tablename, const char *label, char *dst, size_t sz) static int lka_userinfo(const char *tablename, const char *username, struct userinfo *res) { - struct userinfo *info; struct table *table; + union lookup lk; - log_trace(TRACE_LOOKUP, "lookup: userinfo %s:%s", tablename, username); - table = table_findbyname(tablename); + log_debug("debug: lka: userinfo %s:%s", tablename, username); + table = table_find(tablename, NULL); if (table == NULL) { log_warnx("warn: cannot find user table %s", tablename); return (LKA_TEMPFAIL); } - switch (table_lookup(table, username, K_USERINFO, (void **)&info)) { + switch (table_lookup(table, username, K_USERINFO, &lk)) { case -1: log_warnx("warn: failure during userinfo lookup %s:%s", tablename, username); @@ -753,8 +730,7 @@ lka_userinfo(const char *tablename, const char *username, struct userinfo *res) case 0: return (LKA_PERMFAIL); default: - *res = *info; - free(info); + *res = lk.userinfo; return (LKA_OK); } } @@ -763,20 +739,20 @@ static int lka_addrname(const char *tablename, const struct sockaddr *sa, struct addrname *res) { - struct addrname *addrname; struct table *table; + union lookup lk; const char *source; source = sa_to_text(sa); - log_trace(TRACE_LOOKUP, "lookup: helo %s:%s", tablename, source); - table = table_findbyname(tablename); + log_debug("debug: lka: helo %s:%s", tablename, source); + table = table_find(tablename, NULL); if (table == NULL) { log_warnx("warn: cannot find helo table %s", tablename); return (LKA_TEMPFAIL); } - switch (table_lookup(table, source, K_ADDRNAME, (void **)&addrname)) { + switch (table_lookup(table, source, K_ADDRNAME, &lk)) { case -1: log_warnx("warn: failure during helo lookup %s:%s", tablename, source); @@ -784,8 +760,7 @@ lka_addrname(const char *tablename, const struct sockaddr *sa, case 0: return (LKA_PERMFAIL); default: - *res = *addrname; - free(addrname); + *res = lk.addrname; return (LKA_OK); } } @@ -829,7 +804,7 @@ lka_X509_verify(struct ca_vrfy_req_msg *vrfy, } } if (! ca_X509_verify(x509, x509_chain, CAfile, NULL, &errstr)) - log_trace(TRACE_LOOKUP, "lookup: X509 verify: %s", errstr); + log_debug("debug: lka: X509 verify: %s", errstr); else ret = 1; diff --git a/usr.sbin/smtpd/lka_session.c b/usr.sbin/smtpd/lka_session.c index cfb1fc592cf..3d79254fc7c 100644 --- a/usr.sbin/smtpd/lka_session.c +++ b/usr.sbin/smtpd/lka_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lka_session.c,v 1.55 2013/02/14 12:30:49 gilles Exp $ */ +/* $OpenBSD: lka_session.c,v 1.56 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/wait.h> @@ -53,6 +52,7 @@ struct lka_session { int flags; int error; + const char *errormsg; struct envelope envelope; struct xnodes nodes; /* waiting for fwdrq */ @@ -70,7 +70,8 @@ static size_t lka_expand_format(char *, size_t, const struct envelope *, static void mailaddr_to_username(const struct mailaddr *, char *, size_t); static const char * mailaddr_tag(const struct mailaddr *); -static struct tree sessions = SPLAY_INITIALIZER(&sessions); +static int init; +static struct tree sessions; #define MAXTOKENLEN 128 @@ -80,6 +81,11 @@ lka_session(uint64_t id, struct envelope *envelope) struct lka_session *lks; struct expandnode xn; + if (init == 0) { + init = 1; + tree_init(&sessions); + } + lks = xcalloc(1, sizeof(*lks), "lka_session"); lks->id = id; RB_INIT(&lks->expand.tree); @@ -104,6 +110,7 @@ lka_session_forward_reply(struct forward_req *fwreq, int fd) struct lka_session *lks; struct rule *rule; struct expandnode *xn; + int ret; lks = tree_xget(&sessions, fwreq->id); xn = lks->node; @@ -132,11 +139,17 @@ lka_session_forward_reply(struct forward_req *fwreq, int fd) xn->mapping = rule->r_mapping; xn->userbase = rule->r_userbase; /* forwards_get() will close the descriptor no matter what */ - if (! forwards_get(fd, &lks->expand)) { + ret = forwards_get(fd, &lks->expand); + if (ret == -1) { log_trace(TRACE_EXPAND, "expand: temporary " "forward error for user %s", fwreq->user); lks->error = LKA_TEMPFAIL; } + else if (ret == 0) { + log_trace(TRACE_EXPAND, "expand: empty .forward " + "for user %s, just deliver", fwreq->user); + lka_submit(lks, rule, xn); + } } break; default: @@ -174,9 +187,19 @@ lka_resume(struct lka_session *lks) } error: if (lks->error) { - m_create(p_smtp, IMSG_LKA_EXPAND_RCPT, 0, 0, -1, 24); + m_create(p_smtp, IMSG_LKA_EXPAND_RCPT, 0, 0, -1); m_add_id(p_smtp, lks->id); m_add_int(p_smtp, lks->error); + + if (lks->errormsg) + m_add_string(p_smtp, lks->errormsg); + else { + if (lks->error == LKA_PERMFAIL) + m_add_string(p_smtp, "550 Invalid recipient"); + else if (lks->error == LKA_TEMPFAIL) + m_add_string(p_smtp, "451 Temporary failure"); + } + m_close(p_smtp); while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { TAILQ_REMOVE(&lks->deliverylist, ep, entry); @@ -187,15 +210,14 @@ lka_resume(struct lka_session *lks) /* Process the delivery list and submit envelopes to queue */ while ((ep = TAILQ_FIRST(&lks->deliverylist)) != NULL) { TAILQ_REMOVE(&lks->deliverylist, ep, entry); - m_create(p_queue, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, - MSZ_EVP); + m_create(p_queue, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1); m_add_id(p_queue, lks->id); m_add_envelope(p_queue, ep); m_close(p_queue); free(ep); } - m_create(p_queue, IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, 9); + m_create(p_queue, IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1); m_add_id(p_queue, lks->id); m_close(p_queue); } @@ -211,8 +233,9 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) struct forward_req fwreq; struct envelope ep; struct expandnode node; + struct mailaddr maddr; int r; - struct userinfo *tu = NULL; + union lookup lk; if (xn->depth >= EXPAND_DEPTH) { log_trace(TRACE_EXPAND, "expand: lka_expand: node too deep."); @@ -255,7 +278,15 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) lks->expand.rule = rule; lks->expand.parent = xn; lks->expand.alias = 1; - r = aliases_virtual_get(&lks->expand, &xn->u.mailaddr); + + /* temporary replace the mailaddr with a copy where + * we eventually strip the '+'-part before lookup. + */ + maddr = xn->u.mailaddr; + mailaddr_to_username(&xn->u.mailaddr, maddr.user, + sizeof maddr.user); + + r = aliases_virtual_get(&lks->expand, &maddr); if (r == -1) { lks->error = LKA_TEMPFAIL; log_trace(TRACE_EXPAND, "expand: lka_expand: " @@ -317,7 +348,7 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) break; } - r = table_lookup(rule->r_userbase, xn->u.user, K_USERINFO, (void **)&tu); + r = table_lookup(rule->r_userbase, xn->u.user, K_USERINFO, &lk); if (r == -1) { log_trace(TRACE_EXPAND, "expand: lka_expand: " "backend error while searching user"); @@ -335,14 +366,13 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) lks->rule = rule; lks->node = xn; fwreq.id = lks->id; - (void)strlcpy(fwreq.user, tu->username, sizeof(fwreq.user)); - (void)strlcpy(fwreq.directory, tu->directory, sizeof(fwreq.directory)); - fwreq.uid = tu->uid; - fwreq.gid = tu->gid; + (void)strlcpy(fwreq.user, lk.userinfo.username, sizeof(fwreq.user)); + (void)strlcpy(fwreq.directory, lk.userinfo.directory, sizeof(fwreq.directory)); + fwreq.uid = lk.userinfo.uid; + fwreq.gid = lk.userinfo.gid; m_compose(p_parent, IMSG_PARENT_FORWARD_OPEN, 0, 0, -1, &fwreq, sizeof(fwreq)); lks->flags |= F_WAITING; - free(tu); break; case EXPAND_FILENAME: @@ -351,6 +381,16 @@ lka_expand(struct lka_session *lks, struct rule *rule, struct expandnode *xn) lka_submit(lks, rule, xn); break; + case EXPAND_ERROR: + log_trace(TRACE_EXPAND, "expand: lka_expand: error: %s " + "[depth=%d]", xn->u.buffer, xn->depth); + if (xn->u.buffer[0] == '4') + lks->error = LKA_TEMPFAIL; + else if (xn->u.buffer[0] == '5') + lks->error = LKA_PERMFAIL; + lks->errormsg = xn->u.buffer; + break; + case EXPAND_FILTER: log_trace(TRACE_EXPAND, "expand: lka_expand: filter: %s " "[depth=%d]", xn->u.buffer, xn->depth); @@ -375,7 +415,7 @@ lka_find_ancestor(struct expandnode *xn, enum expand_type type) static void lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) { - struct userinfo *tu; + union lookup lk; struct envelope *ep; struct expandnode *xn2; const char *tag; @@ -392,10 +432,12 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) ep->type = D_MTA; ep->dest = xn->u.mailaddr; ep->agent.mta.relay = rule->r_value.relayhost; - if (rule->r_as && rule->r_as->user[0]) + + /* only rewrite if not a bounce */ + if (ep->sender.user[0] && rule->r_as && rule->r_as->user[0]) strlcpy(ep->sender.user, rule->r_as->user, sizeof ep->sender.user); - if (rule->r_as && rule->r_as->domain[0]) + if (ep->sender.user[0] && rule->r_as && rule->r_as->domain[0]) strlcpy(ep->sender.domain, rule->r_as->domain, sizeof ep->sender.domain); break; @@ -403,6 +445,7 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) case A_MAILDIR: case A_FILENAME: case A_MDA: + case A_LMTP: ep->type = D_MDA; ep->dest = lka_find_ancestor(xn, EXPAND_ADDRESS)->u.mailaddr; @@ -418,8 +461,8 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) sizeof(ep->agent.mda.username)); } - r = table_lookup(rule->r_userbase, ep->agent.mda.username, K_USERINFO, - (void **)&tu); + r = table_lookup(rule->r_userbase, ep->agent.mda.username, + K_USERINFO, &lk); if (r <= 0) { lks->error = (r == -1) ? LKA_TEMPFAIL : LKA_PERMFAIL; free(ep); @@ -427,7 +470,7 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) } strlcpy(ep->agent.mda.usertable, rule->r_userbase->t_name, sizeof ep->agent.mda.usertable); - strlcpy(ep->agent.mda.username, tu->username, + strlcpy(ep->agent.mda.username, lk.userinfo.username, sizeof ep->agent.mda.username); if (xn->type == EXPAND_FILENAME) { @@ -456,8 +499,7 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) fatalx("lka_deliver: bad node type"); r = lka_expand_format(ep->agent.mda.buffer, - sizeof(ep->agent.mda.buffer), ep, tu); - free(tu); + sizeof(ep->agent.mda.buffer), ep, &lk.userinfo); if (!r) { lks->error = LKA_TEMPFAIL; log_warnx("warn: format string error while" @@ -485,6 +527,7 @@ lka_expand_token(char *dest, size_t len, const char *token, ssize_t i; ssize_t begoff, endoff; const char *errstr = NULL; + int replace = 1; begoff = 0; endoff = EXPAND_BUFFER; @@ -545,8 +588,10 @@ lka_expand_token(char *dest, size_t len, const char *token, string = ep->sender.domain; else if (! strcasecmp("user.username", rtoken)) string = ui->username; - else if (! strcasecmp("user.directory", rtoken)) + else if (! strcasecmp("user.directory", rtoken)) { string = ui->directory; + replace = 0; + } else if (! strcasecmp("dest.user", rtoken)) string = ep->dest.user; else if (! strcasecmp("dest.domain", rtoken)) @@ -592,7 +637,7 @@ lka_expand_token(char *dest, size_t len, const char *token, string += begoff; for (; i; i--) { - *dest = (*string == '/') ? ':' : *string; + *dest = (replace && *string == '/') ? ':' : *string; dest++; string++; } diff --git a/usr.sbin/smtpd/log.c b/usr.sbin/smtpd/log.c index 637bf8e48d7..b553f2a5160 100644 --- a/usr.sbin/smtpd/log.c +++ b/usr.sbin/smtpd/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.14 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: log.c,v 1.15 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <errno.h> @@ -33,7 +32,9 @@ #include "log.h" -static int debug; +#define TRACE_DEBUG 0x1 + +static int foreground; static int verbose; void vlog(int, const char *, va_list); @@ -42,14 +43,12 @@ void logit(int, const char *, ...) void -log_init(int n_debug) +log_init(int n_foreground) { extern char *__progname; - debug = n_debug; - verbose = n_debug; - - if (!debug) + foreground = n_foreground; + if (! foreground) openlog(__progname, LOG_PID | LOG_NDELAY, LOG_MAIL); tzset(); @@ -76,7 +75,7 @@ vlog(int pri, const char *fmt, va_list ap) { char *nfmt; - if (debug) { + if (foreground) { /* best effort in out of mem situations */ if (asprintf(&nfmt, "%s\n", fmt) == -1) { vfprintf(stderr, fmt, ap); @@ -140,7 +139,7 @@ log_debug(const char *emsg, ...) { va_list ap; - if (verbose) { + if (verbose & TRACE_DEBUG) { va_start(ap, emsg); vlog(LOG_DEBUG, emsg, ap); va_end(ap); diff --git a/usr.sbin/smtpd/makemap.c b/usr.sbin/smtpd/makemap.c index bdae0d4d858..1df0e3b04d0 100644 --- a/usr.sbin/smtpd/makemap.c +++ b/usr.sbin/smtpd/makemap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: makemap.c,v 1.44 2013/03/29 12:56:19 tobias Exp $ */ +/* $OpenBSD: makemap.c,v 1.45 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/stat.h> #include <sys/tree.h> #include <sys/queue.h> -#include <sys/param.h> #include <sys/socket.h> #include <db.h> @@ -34,8 +33,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <util.h> #include <unistd.h> +#include <util.h> #include "smtpd.h" #include "log.h" @@ -45,7 +44,7 @@ extern char *__progname; __dead void usage(void); -static int parse_map(FILE *, char *); +static int parse_map(char *); static int parse_entry(char *, size_t, size_t); static int parse_mapentry(char *, size_t, size_t); static int parse_setentry(char *, size_t, size_t); @@ -85,13 +84,13 @@ int main(int argc, char *argv[]) { struct stat sb; - char dbname[MAXPATHLEN]; - FILE *fp; + char dbname[SMTPD_MAXPATHLEN]; char *opts; char *conf; int ch; DBTYPE dbtype = DB_HASH; char *p; + mode_t omode; log_init(1); @@ -173,40 +172,32 @@ main(int argc, char *argv[]) if (oflag == NULL && asprintf(&oflag, "%s.db", source) == -1) err(1, "asprintf"); + if (strcmp(source, "-") != 0) + if (stat(source, &sb) == -1) + err(1, "stat: %s", source); + if (! bsnprintf(dbname, sizeof(dbname), "%s.XXXXXXXXXXX", oflag)) errx(1, "path too long"); + omode = umask(7077); + if (mkstemp(dbname) == -1) + err(1, "mkstemp"); + umask(omode); - if (mktemp(dbname) == NULL) - err(1, "mktemp"); - - db = dbopen(dbname, O_EXCL|O_CREAT|O_EXLOCK|O_RDWR|O_SYNC, 0644, - dbtype, NULL); + db = dbopen(dbname, O_EXLOCK|O_RDWR|O_SYNC, 0644, dbtype, NULL); if (db == NULL) { warn("dbopen: %s", dbname); goto bad; } if (strcmp(source, "-") != 0) - fp = fopen(source, "r"); - else - fp = fdopen(STDIN_FILENO, "r"); - if (fp == NULL) { - warn("%s", source); - goto bad; - } - - if (strcmp(source, "-") != 0) { - if (fstat(fileno(fp), &sb) == -1) - err(1, "stat: %s", source); - if (fchown(db->fd(db), sb.st_uid, sb.st_gid) == -1 || - fchmod(db->fd(db), sb.st_mode) == -1) { + if (fchmod(db->fd(db), sb.st_mode) == -1 || + fchown(db->fd(db), sb.st_uid, sb.st_gid) == -1) { warn("couldn't carry ownership and perms to %s", dbname); goto bad; } - } - if (! parse_map(fp, source)) + if (! parse_map(source)) goto bad; if (db->close(db) == -1) { @@ -231,13 +222,23 @@ bad: } int -parse_map(FILE *fp, char *filename) +parse_map(char *filename) { + FILE *fp; char *line; size_t len; size_t lineno = 0; char delim[] = { '\\', 0, 0 }; + if (strcmp(filename, "-") == 0) + fp = fdopen(0, "r"); + else + fp = fopen(filename, "r"); + if (fp == NULL) { + warn("%s", filename); + return 0; + } + if (!isatty(fileno(fp)) && flock(fileno(fp), LOCK_SH|LOCK_NB) == -1) { if (errno == EWOULDBLOCK) warnx("%s is locked", filename); @@ -424,7 +425,7 @@ conf_aliases(char *cfgpath) if (parse_config(env, cfgpath, 0)) exit(1); - table = table_findbyname("aliases"); + table = table_find("aliases", NULL); if (table == NULL) return (PATH_ALIASES); diff --git a/usr.sbin/smtpd/makemap/Makefile b/usr.sbin/smtpd/makemap/Makefile index 04c4290e909..1ff588b799b 100644 --- a/usr.sbin/smtpd/makemap/Makefile +++ b/usr.sbin/smtpd/makemap/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.18 2013/01/31 14:17:48 eric Exp $ +# $OpenBSD: Makefile,v 1.19 2013/05/24 17:03:14 eric Exp $ .PATH: ${.CURDIR}/.. @@ -25,10 +25,11 @@ SRCS+= table_static.c SRCS+= table_db.c SRCS+= table_getpwnam.c SRCS+= table_ldap.c +SRCS+= table_sqlite.c + SRCS+= ber.c SRCS+= aldap.c -SRCS+= table_sqlite.c -DPADD+= ${LIBUTIL} ${LIBCRYPTO} ${LIBSQLITE3} -LDADD+= -lutil -lcrypto -lsqlite3 +DPADD+= ${LIBUTIL} ${LIBCRYPTO} ${LIBSQLITE3} ${LIBZ} +LDADD+= -lutil -lcrypto -lsqlite3 -lz .include <bsd.prog.mk> diff --git a/usr.sbin/smtpd/mda.c b/usr.sbin/smtpd/mda.c index 4b98b3937a4..f5a8fefbde9 100644 --- a/usr.sbin/smtpd/mda.c +++ b/usr.sbin/smtpd/mda.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mda.c,v 1.90 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: mda.c,v 1.91 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -68,8 +67,8 @@ struct mda_envelope { struct mda_user { TAILQ_ENTRY(mda_user) entry; TAILQ_ENTRY(mda_user) entry_runnable; - char name[MAXLOGNAME]; - char usertable[MAXPATHLEN]; + char name[SMTPD_MAXLOGNAME]; + char usertable[SMTPD_MAXPATHLEN]; size_t evpcount; TAILQ_HEAD(, mda_envelope) envelopes; int flags; @@ -218,8 +217,7 @@ mda_imsg(struct mproc *p, struct imsg *imsg) strlcpy(u->name, username, sizeof u->name); strlcpy(u->usertable, usertable, sizeof u->usertable); u->flags |= FLAG_USER_WAITINFO; - m_create(p_lka, IMSG_LKA_USERINFO, 0, 0, -1, - 32 + strlen(usertable) + strlen(username)); + m_create(p_lka, IMSG_LKA_USERINFO, 0, 0, -1); m_add_string(p_lka, usertable); m_add_string(p_lka, username); m_close(p_lka); @@ -358,6 +356,17 @@ mda_imsg(struct mproc *p, struct imsg *imsg) sizeof deliver.to); break; + case A_LMTP: + deliver.mode = A_LMTP; + deliver.userinfo = *userinfo; + strlcpy(deliver.user, userinfo->username, + sizeof(deliver.user)); + strlcpy(deliver.to, e->buffer, + sizeof(deliver.to)); + strlcpy(deliver.from, e->sender, + sizeof(deliver.from)); + break; + default: errx(1, "mda: unknown delivery method: %d", e->method); @@ -367,8 +376,7 @@ mda_imsg(struct mproc *p, struct imsg *imsg) "for session %016"PRIx64 " evpid %016"PRIx64, s->id, s->evp->id); - m_create(p_parent, IMSG_PARENT_FORK_MDA, 0, 0, -1, - 32 + sizeof(deliver)); + m_create(p_parent, IMSG_PARENT_FORK_MDA, 0, 0, -1); m_add_id(p_parent, reqid); m_add_data(p_parent, &deliver, sizeof(deliver)); m_close(p_parent); @@ -557,6 +565,7 @@ mda_io(struct io *io, int evt) case IO_LOWAT: /* done */ + done: if (s->datafp == NULL) { log_debug("debug: mda: all data sent for session" " %016"PRIx64 " evpid %016"PRIx64, @@ -570,7 +579,7 @@ mda_io(struct io *io, int evt) break; if (iobuf_queue(&s->iobuf, ln, len) == -1) { m_create(p_parent, IMSG_PARENT_KILL_MDA, - 0, 0, -1, 128); + 0, 0, -1); m_add_id(p_parent, s->id); m_add_string(p_parent, "Out of memory"); m_close(p_parent); @@ -587,7 +596,7 @@ mda_io(struct io *io, int evt) if (ferror(s->datafp)) { log_debug("debug: mda: ferror on session %016"PRIx64, s->id); - m_create(p_parent, IMSG_PARENT_KILL_MDA, 0, 0, -1, 128); + m_create(p_parent, IMSG_PARENT_KILL_MDA, 0, 0, -1); m_add_id(p_parent, s->id); m_add_string(p_parent, "Error reading body"); m_close(p_parent); @@ -601,6 +610,8 @@ mda_io(struct io *io, int evt) s->id, s->evp->id); fclose(s->datafp); s->datafp = NULL; + if (iobuf_queued(&s->iobuf) == 0) + goto done; } return; @@ -793,7 +804,7 @@ mda_drain(void) " for user \"%s\" evpid %016" PRIx64, s->id, u->name, s->evp->id); - m_create(p_queue, IMSG_QUEUE_MESSAGE_FD, 0, 0, -1, 18); + m_create(p_queue, IMSG_QUEUE_MESSAGE_FD, 0, 0, -1); m_add_id(p_queue, s->id); m_add_msgid(p_queue, evpid_to_msgid(s->evp->id)); m_close(p_queue); @@ -867,6 +878,8 @@ mda_log(const struct mda_envelope *evp, const char *prefix, const char *status) method = "file"; else if (evp->method == A_MDA) method = "mda"; + else if (evp->method == A_LMTP) + method = "lmtp"; else method = "???"; diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c index ad484c51d7f..c27b485937e 100644 --- a/usr.sbin/smtpd/mfa.c +++ b/usr.sbin/smtpd/mfa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mfa.c,v 1.75 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: mfa.c,v 1.76 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/wait.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <err.h> diff --git a/usr.sbin/smtpd/mfa_session.c b/usr.sbin/smtpd/mfa_session.c index ba14eb7e94a..6d808a254d2 100644 --- a/usr.sbin/smtpd/mfa_session.c +++ b/usr.sbin/smtpd/mfa_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mfa_session.c,v 1.16 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: mfa_session.c,v 1.17 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/wait.h> @@ -88,7 +87,7 @@ struct mfa_query { struct { struct sockaddr_storage local; struct sockaddr_storage remote; - char hostname[MAXHOSTNAMELEN]; + char hostname[SMTPD_MAXHOSTNAMELEN]; } connect; char line[SMTPD_MAXLINESIZE]; struct mailaddr maddr; @@ -142,12 +141,12 @@ mfa_filter_init(void) f = xcalloc(1, sizeof *f, "mfa_filter_init"); p = &f->mproc; p->handler = mfa_filter_imsg; - p->proc = -1; + p->proc = PROC_FILTER; p->name = xstrdup(filter->name, "mfa_filter_init"); p->data = f; if (mproc_fork(p, filter->path, filter->name) < 0) fatalx("mfa_filter_init"); - m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1, 5); + m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1); m_add_u32(p, FILTER_API_VERSION); m_close(p); mproc_enable(p); @@ -261,7 +260,7 @@ mfa_run_data(struct mfa_filter *f, uint64_t id, const char *line) while (f) { if (f->hooks & HOOK_DATALINE) { p = &f->mproc; - m_create(p, IMSG_FILTER_DATA, 0, 0, -1, len); + m_create(p, IMSG_FILTER_DATA, 0, 0, -1); m_add_id(p, id); m_add_string(p, line); m_close(p); @@ -285,7 +284,7 @@ mfa_run_data(struct mfa_filter *f, uint64_t id, const char *line) log_trace(TRACE_MFA, "mfa: sending final data to smtp for %016"PRIx64" on filter %p: %s", id, f, line); - m_create(p_smtp, IMSG_MFA_SMTP_DATA, 0, 0, -1, len); + m_create(p_smtp, IMSG_MFA_SMTP_DATA, 0, 0, -1); m_add_id(p_smtp, id); m_add_string(p_smtp, line); m_close(p_smtp); @@ -375,7 +374,7 @@ mfa_drain_query(struct mfa_query *q) /* Done, notify all listeners and return smtp response */ while (tree_poproot(&q->notify, NULL, (void**)&f)) { - m_create(&f->mproc, IMSG_FILTER_NOTIFY, 0, 0, -1, 16); + m_create(&f->mproc, IMSG_FILTER_NOTIFY, 0, 0, -1); m_add_id(&f->mproc, q->qid); m_add_int(&f->mproc, q->smtp.status); m_close(&f->mproc); @@ -384,7 +383,7 @@ mfa_drain_query(struct mfa_query *q) len = 48; if (q->smtp.response) len += strlen(q->smtp.response); - m_create(p_smtp, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1, len); + m_create(p_smtp, IMSG_MFA_SMTP_RESPONSE, 0, 0, -1); m_add_id(p_smtp, q->session->id); m_add_int(p_smtp, q->smtp.status); m_add_u32(p_smtp, q->smtp.code); @@ -419,7 +418,7 @@ mfa_run_query(struct mfa_filter *f, struct mfa_query *q) mfa_filter_to_text(f), mfa_query_to_text(q)); if (q->type == QT_QUERY) { - m_create(&f->mproc, IMSG_FILTER_QUERY, 0, 0, -1, 1024); + m_create(&f->mproc, IMSG_FILTER_QUERY, 0, 0, -1); m_add_id(&f->mproc, q->session->id); m_add_id(&f->mproc, q->qid); m_add_int(&f->mproc, q->hook); @@ -449,7 +448,7 @@ mfa_run_query(struct mfa_filter *f, struct mfa_query *q) q->state = QUERY_RUNNING; } else { - m_create(&f->mproc, IMSG_FILTER_EVENT, 0, 0, -1, 16); + m_create(&f->mproc, IMSG_FILTER_EVENT, 0, 0, -1); m_add_id(&f->mproc, q->session->id); m_add_int(&f->mproc, q->hook); m_close(&f->mproc); @@ -467,6 +466,13 @@ mfa_filter_imsg(struct mproc *p, struct imsg *imsg) int status, code, notify; f = p->data; + + if (imsg == NULL) { + log_warnx("warn: filter \"%s\" closed unexpectedly", + p->name); + fatalx("exiting"); + } + log_trace(TRACE_MFA, "mfa: imsg %s from filter %s", filterimsg_to_str(imsg->hdr.type), mfa_filter_to_text(f)); diff --git a/usr.sbin/smtpd/mproc.c b/usr.sbin/smtpd/mproc.c index 0ca56245c80..ba86405520e 100644 --- a/usr.sbin/smtpd/mproc.c +++ b/usr.sbin/smtpd/mproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mproc.c,v 1.2 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: mproc.c,v 1.3 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@faurot.net> @@ -43,9 +43,6 @@ static void mproc_dispatch(int, short, void *); static ssize_t msgbuf_write2(struct msgbuf *); -static uint32_t reqtype; -static size_t reqlen; - int mproc_fork(struct mproc *p, const char *path, const char *arg) { @@ -100,7 +97,8 @@ void mproc_enable(struct mproc *p) { if (p->enable == 0) { - log_debug("debug: enabling %s -> %s", proc_name(smtpd_process), + log_trace(TRACE_MPROC, "mproc: %s -> %s: enabled", + proc_name(smtpd_process), proc_name(p->proc)); p->enable = 1; } @@ -111,7 +109,8 @@ void mproc_disable(struct mproc *p) { if (p->enable == 1) { - log_debug("debug: disabling %s -> %s", proc_name(smtpd_process), + log_trace(TRACE_MPROC, "mproc: %s -> %s: disabled", + proc_name(smtpd_process), proc_name(p->proc)); p->enable = 0; } @@ -152,10 +151,17 @@ mproc_dispatch(int fd, short event, void *arg) if (event & EV_READ) { - if ((n = imsg_read(&p->imsgbuf)) == -1) - fatal("imsg_read"); + if ((n = imsg_read(&p->imsgbuf)) == -1) { + log_warn("warn: %s -> %s: imsg_read", + proc_name(smtpd_process), p->name); + fatal("exiting"); + } if (n == 0) { /* this pipe is dead, so remove the event handler */ + if (smtpd_process != PROC_CONTROL || + p->proc != PROC_CLIENT) + log_warnx("warn: %s -> %s: pipe closed", + proc_name(smtpd_process), p->name); p->handler(p, NULL); return; } @@ -268,6 +274,12 @@ m_forward(struct mproc *p, struct imsg *imsg) imsg->hdr.pid, imsg->fd, imsg->data, imsg->hdr.len - sizeof(imsg->hdr)); + log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (forward)", + proc_name(smtpd_process), + proc_name(p->proc), + imsg->hdr.len - sizeof(imsg->hdr), + imsg_to_str(imsg->hdr.type)); + p->msg_out += 1; p->bytes_queued += imsg->hdr.len; if (p->bytes_queued > p->bytes_queued_max) @@ -282,6 +294,12 @@ m_compose(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd, { imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, len); + log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", + proc_name(smtpd_process), + proc_name(p->proc), + len, + imsg_to_str(type)); + p->msg_out += 1; p->bytes_queued += len + IMSG_HEADER_SIZE; if (p->bytes_queued > p->bytes_queued_max) @@ -294,73 +312,99 @@ void m_composev(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd, const struct iovec *iov, int n) { + size_t len; int i; imsg_composev(&p->imsgbuf, type, peerid, pid, fd, iov, n); - p->msg_out += 1; - p->bytes_queued += IMSG_HEADER_SIZE; + len = 0; for (i = 0; i < n; i++) - p->bytes_queued += iov[i].iov_len; + len += iov[i].iov_len; + + p->msg_out += 1; + p->bytes_queued += IMSG_HEADER_SIZE + len; if (p->bytes_queued > p->bytes_queued_max) p->bytes_queued_max = p->bytes_queued; + log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", + proc_name(smtpd_process), + proc_name(p->proc), + len, + imsg_to_str(type)); + mproc_event_add(p); } void -m_create(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd, - size_t len) +m_create(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd) { - if (p->ibuf) - fatal("ibuf already rhere"); - - reqtype = type; - reqlen = len; - - p->ibuf = imsg_create(&p->imsgbuf, type, peerid, pid, len); - if (p->ibuf == NULL) - fatal("imsg_create"); + if (p->m_buf == NULL) { + p->m_alloc = 128; + log_trace(TRACE_MPROC, "mproc: %s -> %s: allocating %zu", + proc_name(smtpd_process), + proc_name(p->proc), + p->m_alloc); + p->m_buf = malloc(p->m_alloc); + if (p->m_buf == NULL) + fatal("warn: m_create: malloc"); + } - /* Is this a problem with imsg? */ - p->ibuf->fd = fd; + p->m_pos = 0; + p->m_type = type; + p->m_peerid = peerid; + p->m_pid = pid; + p->m_fd = fd; } void m_add(struct mproc *p, const void *data, size_t len) { - if (p->ibuferror) - return; + size_t alloc; + void *tmp; - if (ibuf_add(p->ibuf, data, len) == -1) - p->ibuferror = 1; + if (p->m_pos + len + IMSG_HEADER_SIZE > MAX_IMSGSIZE) { + log_warnx("warn: message to large"); + fatal(NULL); + } + + alloc = p->m_alloc; + while (p->m_pos + len > alloc) + alloc *= 2; + if (alloc != p->m_alloc) { + log_trace(TRACE_MPROC, "mproc: %s -> %s: realloc %zu -> %zu", + proc_name(smtpd_process), + proc_name(p->proc), + p->m_alloc, + alloc); + + tmp = realloc(p->m_buf, alloc); + if (tmp == NULL) + fatal("realloc"); + p->m_alloc = alloc; + p->m_buf = tmp; + } + + memmove(p->m_buf + p->m_pos, data, len); + p->m_pos += len; } void m_close(struct mproc *p) { - imsg_close(&p->imsgbuf, p->ibuf); + if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd, + p->m_buf, p->m_pos) == -1) + fatal("imsg_compose"); - if (verbose & TRACE_IMSGSIZE && - reqlen != p->ibuf->wpos - IMSG_HEADER_SIZE) - log_debug("msg-len: too %s %zu -> %zu : %s -> %s : %s", - (reqlen < p->ibuf->wpos - IMSG_HEADER_SIZE) ? "small" : "large", - reqlen, p->ibuf->wpos - IMSG_HEADER_SIZE, - proc_name(smtpd_process), - proc_name(p->proc), - imsg_to_str(reqtype)); - else if (verbose & TRACE_IMSGSIZE) - log_debug("msg-len: ok %zu : %s -> %s : %s", - p->ibuf->wpos - IMSG_HEADER_SIZE, + log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", proc_name(smtpd_process), proc_name(p->proc), - imsg_to_str(reqtype)); + p->m_pos, + imsg_to_str(p->m_type)); p->msg_out += 1; - p->bytes_queued += p->ibuf->wpos; + p->bytes_queued += p->m_pos + IMSG_HEADER_SIZE; if (p->bytes_queued > p->bytes_queued_max) p->bytes_queued_max = p->bytes_queued; - p->ibuf = NULL; mproc_event_add(p); } @@ -438,24 +482,16 @@ m_get_typed_sized(struct msg *m, uint8_t type, const void **dst, size_t *sz) static void m_add_typed(struct mproc *p, uint8_t type, const void *data, size_t len) { - if (p->ibuferror) - return; - - if (ibuf_add(p->ibuf, &type, 1) == -1 || - ibuf_add(p->ibuf, data, len) == -1) - p->ibuferror = 1; + m_add(p, &type, 1); + m_add(p, data, len); } static void m_add_typed_sized(struct mproc *p, uint8_t type, const void *data, size_t len) { - if (p->ibuferror) - return; - - if (ibuf_add(p->ibuf, &type, 1) == -1 || - ibuf_add(p->ibuf, &len, sizeof(len)) == -1 || - ibuf_add(p->ibuf, data, len) == -1) - p->ibuferror = 1; + m_add(p, &type, 1); + m_add(p, &len, sizeof(len)); + m_add(p, data, len); } enum { @@ -532,6 +568,7 @@ m_add_mailaddr(struct mproc *m, const struct mailaddr *maddr) m_add_typed(m, M_MAILADDR, maddr, sizeof(*maddr)); } +#ifndef BUILD_FILTER void m_add_envelope(struct mproc *m, const struct envelope *evp) { @@ -545,6 +582,7 @@ m_add_envelope(struct mproc *m, const struct envelope *evp) m_add_typed_sized(m, M_ENVELOPE, buf, strlen(buf) + 1); #endif } +#endif void m_get_int(struct msg *m, int *i) @@ -622,6 +660,7 @@ m_get_mailaddr(struct msg *m, struct mailaddr *maddr) m_get_typed(m, M_MAILADDR, maddr, sizeof(*maddr)); } +#ifndef BUILD_FILTER void m_get_envelope(struct msg *m, struct envelope *evp) { @@ -636,7 +675,8 @@ m_get_envelope(struct msg *m, struct envelope *evp) m_get_typed_sized(m, M_ENVELOPE, &d, &s); if (!envelope_load_buffer(evp, d, s - 1)) - fatalx("failed to load envelope"); + fatalx("failed to retreive envelope"); evp->id = evpid; #endif } +#endif diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c index 89e54d40efb..df79762fef5 100644 --- a/usr.sbin/smtpd/mta.c +++ b/usr.sbin/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.156 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: mta.c,v 1.157 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -72,7 +71,7 @@ static void mta_relay_timeout(int, short, void *); static void mta_flush(struct mta_relay *, int, const char *); static struct mta_route *mta_find_route(struct mta_connector *); static void mta_log(const struct mta_envelope *, const char *, const char *, - const char *); + const char *, const char *); SPLAY_HEAD(mta_relay_tree, mta_relay); static struct mta_relay *mta_relay(struct envelope *); @@ -577,23 +576,23 @@ mta_route_next_task(struct mta_relay *relay, struct mta_route *route) } void -mta_delivery(struct mta_envelope *e, const char *relay, int delivery, - const char *status) +mta_delivery(struct mta_envelope *e, const char *source, const char *relay, + int delivery, const char *status) { if (delivery == IMSG_DELIVERY_OK) { - mta_log(e, "Ok", relay, status); + mta_log(e, "Ok", source, relay, status); queue_ok(e->id); } else if (delivery == IMSG_DELIVERY_TEMPFAIL) { - mta_log(e, "TempFail", relay, status); + mta_log(e, "TempFail", source, relay, status); queue_tempfail(e->id, status); } else if (delivery == IMSG_DELIVERY_PERMFAIL) { - mta_log(e, "PermFail", relay, status); + mta_log(e, "PermFail", source, relay, status); queue_permfail(e->id, status); } else if (delivery == IMSG_DELIVERY_LOOP) { - mta_log(e, "PermFail", relay, "Loop detected"); + mta_log(e, "PermFail", source, relay, "Loop detected"); queue_loop(e->id); } else @@ -634,7 +633,7 @@ mta_query_secret(struct mta_relay *relay) tree_xset(&wait_secret, relay->id, relay); relay->status |= RELAY_WAIT_SECRET; - m_create(p_lka, IMSG_LKA_SECRET, 0, 0, -1, 128); + m_create(p_lka, IMSG_LKA_SECRET, 0, 0, -1); m_add_id(p_lka, relay->id); m_add_string(p_lka, relay->authtable); m_add_string(p_lka, relay->authlabel); @@ -663,7 +662,7 @@ mta_query_source(struct mta_relay *relay) { log_debug("debug: mta_query_source(%s)", mta_relay_to_text(relay)); - m_create(p_lka, IMSG_LKA_SOURCE, 0, 0, -1, 64); + m_create(p_lka, IMSG_LKA_SOURCE, 0, 0, -1); m_add_id(p_lka, relay->id); m_add_string(p_lka, relay->sourcetable); m_close(p_lka); @@ -980,17 +979,12 @@ mta_flush(struct mta_relay *relay, int fail, const char *error) { struct mta_envelope *e; struct mta_task *task; - const char *pfx; size_t n; log_debug("debug: mta_flush(%s, %i, \"%s\")", mta_relay_to_text(relay), fail, error); - if (fail == IMSG_DELIVERY_TEMPFAIL) - pfx = "TempFail"; - else if (fail == IMSG_DELIVERY_PERMFAIL) - pfx = "PermFail"; - else + if (fail != IMSG_DELIVERY_TEMPFAIL && fail != IMSG_DELIVERY_PERMFAIL) errx(1, "unexpected delivery status %i", fail); n = 0; @@ -998,7 +992,7 @@ mta_flush(struct mta_relay *relay, int fail, const char *error) TAILQ_REMOVE(&relay->tasks, task, entry); while ((e = TAILQ_FIRST(&task->envelopes))) { TAILQ_REMOVE(&task->envelopes, e, entry); - mta_delivery(e, relay->domain->name, fail, error); + mta_delivery(e, NULL, relay->domain->name, fail, error); free(e->dest); free(e->rcpt); free(e); @@ -1116,11 +1110,6 @@ mta_find_route(struct mta_connector *c) mta_connector_to_text(c)); c->flags |= CONNECTOR_MX_ERROR; } - else if (family_mismatch) { - log_info("smtp-out: Address family mismatch on connector %s", - mta_connector_to_text(c)); - c->flags |= CONNECTOR_FAMILY_ERROR; - } else if (limit_route) { log_debug("debug: mta: hit route limit on connector %s", mta_connector_to_text(c)); @@ -1131,26 +1120,45 @@ mta_find_route(struct mta_connector *c) mta_connector_to_text(c)); c->flags |= CONNECTOR_LIMIT_HOST; } + else if (family_mismatch) { + log_info("smtp-out: Address family mismatch on connector %s", + mta_connector_to_text(c)); + c->flags |= CONNECTOR_FAMILY_ERROR; + } return (NULL); } static void -mta_log(const struct mta_envelope *evp, const char *prefix, const char *relay, - const char *status) +mta_log(const struct mta_envelope *evp, const char *prefix, const char *source, + const char *relay, const char *status) { + char session[SMTPD_MAXLINESIZE]; char rcpt[SMTPD_MAXLINESIZE]; + char src[SMTPD_MAXLINESIZE]; + + session[0] = '\0'; + if (evp->session) + snprintf(session, sizeof session, "session=%016"PRIx64", ", + evp->session); rcpt[0] = '\0'; if (evp->rcpt) snprintf(rcpt, sizeof rcpt, "rcpt=<%s>, ", evp->rcpt); - log_info("relay: %s for %016" PRIx64 ": from=<%s>, to=<%s>, " - "%srelay=%s, delay=%s, stat=%s", + src[0] = '\0'; + if (source) + snprintf(src, sizeof src, "source=%s, ", source); + + + log_info("relay: %s for %016" PRIx64 ": %sfrom=<%s>, to=<%s>, " + "%s%srelay=%s, delay=%s, stat=%s", prefix, evp->id, + session, evp->task->sender, evp->dest, + src, rcpt, relay, duration_to_text(time(NULL) - evp->creation), diff --git a/usr.sbin/smtpd/mta_session.c b/usr.sbin/smtpd/mta_session.c index a0e9d5061c2..0615d691f24 100644 --- a/usr.sbin/smtpd/mta_session.c +++ b/usr.sbin/smtpd/mta_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta_session.c,v 1.35 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: mta_session.c,v 1.36 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/uio.h> @@ -235,12 +234,20 @@ mta_session_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_id(&m, &reqid); m_end(&m); - if (imsg->fd == -1) - fatalx("mta: cannot obtain msgfd"); s = mta_tree_pop(&wait_fd, reqid); if (s == NULL) { - close(imsg->fd); + if (imsg->fd != -1) + close(imsg->fd); + return; + } + + if (imsg->fd == -1) { + log_debug("debug: mta: failed to obtain msg fd"); + mta_flush_task(s, IMSG_DELIVERY_TEMPFAIL, + "Could not get message fd", 0); + mta_enter_state(s, MTA_READY); + io_reload(&s->io); return; } @@ -425,7 +432,7 @@ mta_connect(struct mta_session *s) if (s->helo == NULL) { if (s->relay->helotable && s->route->src->sa) { - m_create(p_lka, IMSG_LKA_HELO, 0, 0, -1, 64); + m_create(p_lka, IMSG_LKA_HELO, 0, 0, -1); m_add_id(p_lka, s->id); m_add_string(p_lka, s->relay->helotable); m_add_sockaddr(p_lka, s->route->src->sa); @@ -608,7 +615,7 @@ mta_enter_state(struct mta_session *s, int newstate) stat_increment("mta.task.running", 1); - m_create(p_queue, IMSG_QUEUE_MESSAGE_FD, 0, 0, -1, 18); + m_create(p_queue, IMSG_QUEUE_MESSAGE_FD, 0, 0, -1); m_add_id(p_queue, s->id); m_add_msgid(p_queue, s->task->msgid); m_close(p_queue); @@ -644,6 +651,10 @@ mta_enter_state(struct mta_session *s, int newstate) s->flags |= MTA_FREE; break; } + if (q == 0) { + mta_enter_state(s, MTA_BODY); + break; + } log_trace(TRACE_MTA, "mta: %p: >>> [...%zi bytes...]", s, q); break; @@ -684,6 +695,8 @@ mta_response(struct mta_session *s, char *line) struct mta_envelope *e; char buf[SMTPD_MAXLINESIZE]; int delivery; + struct sockaddr sa; + socklen_t sa_len; switch (s->state) { @@ -779,7 +792,21 @@ mta_response(struct mta_session *s, char *line) TAILQ_REMOVE(&s->task->envelopes, e, entry); snprintf(buf, sizeof(buf), "%s", mta_host_to_text(s->route->dst)); - mta_delivery(e, buf, delivery, line); + + /* we're about to log, associate session to envelope */ + e->session = s->id; + + /* XXX */ + /* + * getsockname() can only fail with ENOBUFS here + * best effort, don't log source ... + */ + sa_len = sizeof sa; + if (getsockname(s->io.sock, &sa, &sa_len) < 0) + mta_delivery(e, NULL, buf, delivery, line); + else + mta_delivery(e, sa_to_text(&sa), + buf, delivery, line); free(e->dest); free(e->rcpt); free(e); @@ -848,7 +875,6 @@ mta_io(struct io *io, int evt) size_t len; const char *error; int cont; - const char *schema; log_trace(TRACE_IO, "mta: %p: %s %s", s, io_strevent(evt), io_strio(io)); @@ -856,15 +882,6 @@ mta_io(struct io *io, int evt) switch (evt) { case IO_CONNECTED: - if (s->use_smtp_tls) - schema = "smtp+tls://"; - else if (s->use_starttls) - schema = "tls://"; - else if (s->use_smtps) - schema = "smtps://"; - else - schema = "smtp://"; - log_info("smtp-out: Connected on session %016"PRIx64, s->id); if (s->use_smtps) { @@ -1067,6 +1084,8 @@ mta_flush_task(struct mta_session *s, int delivery, const char *error, size_t co struct mta_envelope *e; char relay[SMTPD_MAXLINESIZE]; size_t n; + struct sockaddr sa; + socklen_t sa_len; snprintf(relay, sizeof relay, "%s", mta_host_to_text(s->route->dst)); @@ -1079,7 +1098,22 @@ mta_flush_task(struct mta_session *s, int delivery, const char *error, size_t co } TAILQ_REMOVE(&s->task->envelopes, e, entry); - mta_delivery(e, relay, delivery, error); + + /* we're about to log, associate session to envelope */ + e->session = s->id; + + /* XXX */ + /* + * getsockname() can only fail with ENOBUFS here + * best effort, don't log source ... + */ + sa_len = sizeof sa; + if (getsockname(s->io.sock, &sa, &sa_len) < 0) + mta_delivery(e, NULL, relay, delivery, error); + else + mta_delivery(e, sa_to_text(&sa), + relay, delivery, error); + free(e->dest); free(e->rcpt); free(e); diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y index b6d3e96f19e..bf51f6bb9e8 100644 --- a/usr.sbin/smtpd/parse.y +++ b/usr.sbin/smtpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.116 2013/03/06 21:42:40 sthen Exp $ */ +/* $OpenBSD: parse.y,v 1.117 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -25,7 +25,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/ioctl.h> @@ -108,7 +107,7 @@ int is_if_in_group(const char *, const char *); typedef struct { union { int64_t number; - objid_t object; + struct table *table; char *string; struct host *host; struct mailaddr *maddr; @@ -120,15 +119,15 @@ typedef struct { %token AS QUEUE COMPRESSION MAXMESSAGESIZE LISTEN ON ANY PORT EXPIRE %token TABLE SSL SMTPS CERTIFICATE DOMAIN BOUNCEWARN -%token RELAY BACKUP VIA DELIVER TO MAILDIR MBOX HOSTNAME HELO +%token RELAY BACKUP VIA DELIVER TO LMTP MAILDIR MBOX HOSTNAME HELO %token ACCEPT REJECT INCLUDE ERROR MDA FROM FOR SOURCE %token ARROW AUTH TLS LOCAL VIRTUAL TAG TAGGED ALIAS FILTER KEY %token AUTH_OPTIONAL TLS_REQUIRE USERBASE SENDER %token <v.string> STRING %token <v.number> NUMBER %type <v.table> table -%type <v.number> port from auth ssl size expire sender -%type <v.object> tables tablenew tableref destination alias virtual usermapping userbase credentials +%type <v.number> port auth ssl size expire +%type <v.table> tables tablenew tableref destination alias virtual usermapping userbase credentials from sender %type <v.maddr> relay_as %type <v.string> certificate tag tagged relay_source listen_helo relay_helo relay_backup %% @@ -247,11 +246,11 @@ auth : AUTH { $$ = F_AUTH; } | AUTH tables { - strlcpy(l.authtable, table_find($2)->t_name, sizeof l.authtable); + strlcpy(l.authtable, ($2)->t_name, sizeof l.authtable); $$ = F_AUTH|F_AUTH_REQUIRE; } | AUTH_OPTIONAL tables { - strlcpy(l.authtable, table_find($2)->t_name, sizeof l.authtable); + strlcpy(l.authtable, ($2)->t_name, sizeof l.authtable); $$ = F_AUTH; } | /* empty */ { $$ = 0; } @@ -317,7 +316,7 @@ bouncedelays : bouncedelays ',' bouncedelay ; credentials : AUTH tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_HASH, K_CREDENTIALS)) { yyerror("invalid use of table \"%s\" as AUTH parameter", @@ -325,7 +324,7 @@ credentials : AUTH tables { YYERROR; } - $$ = t->t_id; + $$ = t; } | /* empty */ { $$ = 0; } ; @@ -336,6 +335,9 @@ listen_helo : HOSTNAME STRING { $$ = $2; } main : BOUNCEWARN { bzero(conf->sc_bounce_warn, sizeof conf->sc_bounce_warn); } bouncedelays + | QUEUE COMPRESSION { + conf->sc_queue_flags |= QUEUE_COMPRESSION; + } | EXPIRE STRING { conf->sc_qexpire = delaytonum($2); if (conf->sc_qexpire == -1) { @@ -487,8 +489,8 @@ table : TABLE STRING STRING { free($3); YYERROR; } - table = table_create(backend, $2, config); - if (! table->t_backend->config(table, config)) { + table = table_create(backend, $2, NULL, config); + if (!table_config(table)) { yyerror("invalid backend configuration for table %s", table->t_name); free($2); @@ -499,7 +501,7 @@ table : TABLE STRING STRING { free($3); } | TABLE STRING { - table = table_create("static", $2, NULL); + table = table_create("static", $2, NULL, NULL); free($2); } '{' tableval_list '}' { table = NULL; @@ -538,30 +540,29 @@ tableval_list : string_list { } tablenew : STRING { struct table *t; - t = table_create("static", NULL, NULL); + t = table_create("static", NULL, NULL, NULL); t->t_type = T_LIST; table_add(t, $1, NULL); free($1); - $$ = t->t_id; - table = table_create("static", NULL, NULL); + $$ = t; } | '{' { - table = table_create("static", NULL, NULL); + table = table_create("static", NULL, NULL, NULL); } tableval_list '}' { - $$ = table->t_id; + $$ = table; } ; tableref : '<' STRING '>' { struct table *t; - if ((t = table_findbyname($2)) == NULL) { + if ((t = table_find($2, NULL)) == NULL) { yyerror("no such table: %s", $2); free($2); YYERROR; } free($2); - $$ = t->t_id; + $$ = t; } ; @@ -570,7 +571,7 @@ tables : tablenew { $$ = $1; } ; alias : ALIAS tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ALIAS)) { yyerror("invalid use of table \"%s\" as ALIAS parameter", @@ -578,12 +579,12 @@ alias : ALIAS tables { YYERROR; } - $$ = t->t_id; + $$ = t; } ; virtual : VIRTUAL tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_service(t, K_ALIAS)) { yyerror("invalid use of table \"%s\" as VIRTUAL parameter", @@ -591,7 +592,7 @@ virtual : VIRTUAL tables { YYERROR; } - $$ = t->t_id; + $$ = t; } ; @@ -610,7 +611,7 @@ usermapping : alias { ; userbase : USERBASE tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_HASH, K_USERINFO)) { yyerror("invalid use of table \"%s\" as USERBASE parameter", @@ -618,16 +619,16 @@ userbase : USERBASE tables { YYERROR; } - $$ = t->t_id; + $$ = t; } - | /**/ { $$ = table_findbyname("<getpwnam>")->t_id; } + | /**/ { $$ = table_find("<getpwnam>", NULL); } ; destination : DOMAIN tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_LIST, K_DOMAIN)) { yyerror("invalid use of table \"%s\" as DOMAIN parameter", @@ -635,14 +636,14 @@ destination : DOMAIN tables { YYERROR; } - $$ = t->t_id; + $$ = t; } - | LOCAL { $$ = table_findbyname("<localnames>")->t_id; } + | LOCAL { $$ = table_find("<localnames>", NULL); } | ANY { $$ = 0; } ; relay_source : SOURCE tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_LIST, K_SOURCE)) { yyerror("invalid use of table \"%s\" as " "SOURCE parameter", t->t_name); @@ -654,7 +655,7 @@ relay_source : SOURCE tables { ; relay_helo : HELO tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_HASH, K_ADDRNAME)) { yyerror("invalid use of table \"%s\" as " "HELO parameter", t->t_name); @@ -698,7 +699,7 @@ relay_as : AS STRING { ; action : userbase DELIVER TO MAILDIR { - rule->r_userbase = table_find($1); + rule->r_userbase = $1; rule->r_action = A_MAILDIR; if (strlcpy(rule->r_value.buffer, "~/Maildir", sizeof(rule->r_value.buffer)) >= @@ -706,7 +707,7 @@ action : userbase DELIVER TO MAILDIR { fatal("pathname too long"); } | userbase DELIVER TO MAILDIR STRING { - rule->r_userbase = table_find($1); + rule->r_userbase = $1; rule->r_action = A_MAILDIR; if (strlcpy(rule->r_value.buffer, $5, sizeof(rule->r_value.buffer)) >= @@ -714,8 +715,20 @@ action : userbase DELIVER TO MAILDIR { fatal("pathname too long"); free($5); } + | userbase DELIVER TO LMTP STRING { + rule->r_userbase = $1; + rule->r_action = A_LMTP; + if (strchr($5, ':') || $5[0] == '/') { + if (strlcpy(rule->r_value.buffer, $5, + sizeof(rule->r_value.buffer)) + >= sizeof(rule->r_value.buffer)) + fatal("lmtp destination too long"); + } else + fatal("invalid lmtp destination"); + free($5); + } | userbase DELIVER TO MBOX { - rule->r_userbase = table_find($1); + rule->r_userbase = $1; rule->r_action = A_MBOX; if (strlcpy(rule->r_value.buffer, _PATH_MAILDIR "/%u", sizeof(rule->r_value.buffer)) @@ -723,7 +736,7 @@ action : userbase DELIVER TO MAILDIR { fatal("pathname too long"); } | userbase DELIVER TO MDA STRING { - rule->r_userbase = table_find($1); + rule->r_userbase = $1; rule->r_action = A_MDA; if (strlcpy(rule->r_value.buffer, $5, sizeof(rule->r_value.buffer)) @@ -734,10 +747,6 @@ action : userbase DELIVER TO MAILDIR { | RELAY relay_as relay_source relay_helo { rule->r_action = A_RELAY; rule->r_as = $2; - if ($4 != NULL && $3 == NULL) { - yyerror("HELO can only be used with SOURCE"); - YYERROR; - } if ($3) strlcpy(rule->r_value.relayhost.sourcetable, $3, sizeof rule->r_value.relayhost.sourcetable); @@ -754,14 +763,11 @@ action : userbase DELIVER TO MAILDIR { strlcpy(rule->r_value.relayhost.hostname, $2, sizeof (rule->r_value.relayhost.hostname)); else - strlcpy(rule->r_value.relayhost.hostname, env->sc_hostname, + strlcpy(rule->r_value.relayhost.hostname, + env->sc_hostname, sizeof (rule->r_value.relayhost.hostname)); free($2); - if ($5 != NULL && $4 == NULL) { - yyerror("HELO can only be used with SOURCE"); - YYERROR; - } if ($4) strlcpy(rule->r_value.relayhost.sourcetable, $4, sizeof rule->r_value.relayhost.sourcetable); @@ -792,7 +798,7 @@ action : userbase DELIVER TO MAILDIR { free($6); YYERROR; } - t = table_find($5); + t = $5; strlcpy(rule->r_value.relayhost.authtable, t->t_name, sizeof(rule->r_value.relayhost.authtable)); } @@ -804,10 +810,7 @@ action : userbase DELIVER TO MAILDIR { fatal("certificate path too long"); } free($4); - if ($8 != NULL && $7 == NULL) { - yyerror("HELO can only be used with SOURCE"); - YYERROR; - } + if ($7) strlcpy(rule->r_value.relayhost.sourcetable, $7, sizeof rule->r_value.relayhost.sourcetable); @@ -818,7 +821,7 @@ action : userbase DELIVER TO MAILDIR { ; from : FROM tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_LIST, K_NETADDR)) { yyerror("invalid use of table \"%s\" as FROM parameter", @@ -826,21 +829,21 @@ from : FROM tables { YYERROR; } - $$ = t->t_id; + $$ = t; } | FROM ANY { - $$ = table_findbyname("<anyhost>")->t_id; + $$ = table_find("<anyhost>", NULL); } | FROM LOCAL { - $$ = table_findbyname("<localhost>")->t_id; + $$ = table_find("<localhost>", NULL); } | /* empty */ { - $$ = table_findbyname("<localhost>")->t_id; + $$ = table_find("<localhost>", NULL); } ; sender : SENDER tables { - struct table *t = table_find($2); + struct table *t = $2; if (! table_check_use(t, T_DYNAMIC|T_LIST, K_MAILADDR)) { yyerror("invalid use of table \"%s\" as SENDER parameter", @@ -848,9 +851,9 @@ sender : SENDER tables { YYERROR; } - $$ = t->t_id; + $$ = t; } - | /* empty */ { $$ = 0; } + | /* empty */ { $$ = NULL; } ; rule : ACCEPT { @@ -858,10 +861,10 @@ rule : ACCEPT { } tagged from sender FOR destination usermapping action expire { rule->r_decision = R_ACCEPT; - rule->r_sources = table_find($4); - rule->r_senders = table_find($5); - rule->r_destination = table_find($7); - rule->r_mapping = table_find($8); + rule->r_sources = $4; + rule->r_senders = $5; + rule->r_destination = $7; + rule->r_mapping = $8; if ($3) { if (strlcpy(rule->r_tag, $3, sizeof rule->r_tag) >= sizeof rule->r_tag) { @@ -901,10 +904,10 @@ rule : ACCEPT { rule = xcalloc(1, sizeof(*rule), "parse rule: REJECT"); } tagged from sender FOR destination usermapping { rule->r_decision = R_REJECT; - rule->r_sources = table_find($4); - rule->r_sources = table_find($5); - rule->r_destination = table_find($7); - rule->r_mapping = table_find($8); + rule->r_sources = $4; + rule->r_senders = $5; + rule->r_destination = $7; + rule->r_mapping = $8; if ($3) { if (strlcpy(rule->r_tag, $3, sizeof rule->r_tag) >= sizeof rule->r_tag) { @@ -961,6 +964,7 @@ lookup(char *s) { "backup", BACKUP }, { "bounce-warn", BOUNCEWARN }, { "certificate", CERTIFICATE }, + { "compression", COMPRESSION }, { "deliver", DELIVER }, { "domain", DOMAIN }, { "expire", EXPIRE }, @@ -972,6 +976,7 @@ lookup(char *s) { "include", INCLUDE }, { "key", KEY }, { "listen", LISTEN }, + { "lmtp", LMTP }, { "local", LOCAL }, { "maildir", MAILDIR }, { "max-message-size", MAXMESSAGESIZE }, @@ -1324,7 +1329,7 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) { struct sym *sym, *next; struct table *t; - char hostname[MAXHOSTNAMELEN]; + char hostname[SMTPD_MAXHOSTNAMELEN]; if (gethostname(hostname, sizeof hostname) == -1) { fprintf(stderr, "invalid hostname: gethostname() failed\n"); @@ -1337,7 +1342,6 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) conf->sc_maxsize = DEFAULT_MAX_BODY_SIZE; conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict)); - conf->sc_tables_tree = calloc(1, sizeof(*conf->sc_tables_tree)); conf->sc_rules = calloc(1, sizeof(*conf->sc_rules)); conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners)); conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict)); @@ -1346,13 +1350,11 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) conf->sc_bounce_warn[0] = 3600 * 4; if (conf->sc_tables_dict == NULL || - conf->sc_tables_tree == NULL || conf->sc_rules == NULL || conf->sc_listeners == NULL || conf->sc_ssl_dict == NULL) { log_warn("warn: cannot allocate memory"); free(conf->sc_tables_dict); - free(conf->sc_tables_tree); free(conf->sc_rules); free(conf->sc_listeners); free(conf->sc_ssl_dict); @@ -1368,7 +1370,6 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) dict_init(conf->sc_ssl_dict); dict_init(conf->sc_tables_dict); - tree_init(conf->sc_tables_tree); TAILQ_INIT(conf->sc_listeners); TAILQ_INIT(conf->sc_rules); @@ -1387,12 +1388,12 @@ parse_config(struct smtpd *x_conf, const char *filename, int opts) */ set_localaddrs(); - t = table_create("static", "<localnames>", NULL); + t = table_create("static", "<localnames>", NULL, NULL); t->t_type = T_LIST; table_add(t, "localhost", NULL); table_add(t, hostname, NULL); - table_create("getpwnam", "<getpwnam>", NULL); + table_create("getpwnam", "<getpwnam>", NULL, NULL); /* * parse configuration @@ -1735,7 +1736,7 @@ set_localaddrs(void) struct sockaddr_in6 *sin6; struct table *t; - t = table_create("static", "<anyhost>", NULL); + t = table_create("static", "<anyhost>", NULL, NULL); table_add(t, "local", NULL); table_add(t, "0.0.0.0/0", NULL); table_add(t, "::/0", NULL); @@ -1743,7 +1744,7 @@ set_localaddrs(void) if (getifaddrs(&ifap) == -1) fatal("getifaddrs"); - t = table_create("static", "<localhost>", NULL); + t = table_create("static", "<localhost>", NULL, NULL); table_add(t, "local", NULL); for (p = ifap; p != NULL; p = p->ifa_next) { diff --git a/usr.sbin/smtpd/parser.c b/usr.sbin/smtpd/parser.c index 0e1922c251d..a0e75473210 100644 --- a/usr.sbin/smtpd/parser.c +++ b/usr.sbin/smtpd/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.33 2013/02/14 12:30:49 gilles Exp $ */ +/* $OpenBSD: parser.c,v 1.34 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -22,7 +22,6 @@ #include <sys/socket.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <event.h> #include <imsg.h> @@ -149,7 +148,7 @@ static const struct token t_trace[] = { {KEYWORD, "lookup", LOG_TRACE_LOOKUP, NULL}, {KEYWORD, "stat", LOG_TRACE_STAT, NULL}, {KEYWORD, "rules", LOG_TRACE_RULES, NULL}, - {KEYWORD, "msg-size", LOG_TRACE_IMSG_SIZE, NULL}, + {KEYWORD, "mproc", LOG_TRACE_MPROC, NULL}, {KEYWORD, "expand", LOG_TRACE_EXPAND, NULL}, {KEYWORD, "all", LOG_TRACE_ALL, NULL}, {ENDTOKEN, "", NONE, NULL} @@ -166,7 +165,7 @@ static const struct token t_untrace[] = { {KEYWORD, "lookup", LOG_UNTRACE_LOOKUP, NULL}, {KEYWORD, "stat", LOG_UNTRACE_STAT, NULL}, {KEYWORD, "rules", LOG_UNTRACE_RULES, NULL}, - {KEYWORD, "msg-size", LOG_UNTRACE_IMSG_SIZE, NULL}, + {KEYWORD, "mproc", LOG_UNTRACE_MPROC, NULL}, {KEYWORD, "expand", LOG_UNTRACE_EXPAND, NULL}, {KEYWORD, "all", LOG_UNTRACE_ALL, NULL}, {ENDTOKEN, "", NONE, NULL} diff --git a/usr.sbin/smtpd/parser.h b/usr.sbin/smtpd/parser.h index a6d5ad00385..ffdcc49c08a 100644 --- a/usr.sbin/smtpd/parser.h +++ b/usr.sbin/smtpd/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.26 2013/02/14 12:30:49 gilles Exp $ */ +/* $OpenBSD: parser.h,v 1.27 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -46,7 +46,7 @@ enum actions { LOG_TRACE_LOOKUP, LOG_TRACE_STAT, LOG_TRACE_RULES, - LOG_TRACE_IMSG_SIZE, + LOG_TRACE_MPROC, LOG_TRACE_EXPAND, LOG_TRACE_ALL, LOG_UNTRACE_IMSG, @@ -59,7 +59,7 @@ enum actions { LOG_UNTRACE_LOOKUP, LOG_UNTRACE_STAT, LOG_UNTRACE_RULES, - LOG_UNTRACE_IMSG_SIZE, + LOG_UNTRACE_MPROC, LOG_UNTRACE_EXPAND, LOG_UNTRACE_ALL, LOG_PROFILE_IMSG, @@ -69,7 +69,7 @@ enum actions { }; struct ctl_id { - objid_t id; + uint32_t id; char name[MAX_NAME_SIZE]; }; diff --git a/usr.sbin/smtpd/queue.c b/usr.sbin/smtpd/queue.c index ffb956e1766..e2517fdac2a 100644 --- a/usr.sbin/smtpd/queue.c +++ b/usr.sbin/smtpd/queue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: queue.c,v 1.147 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: queue.c,v 1.148 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -82,7 +81,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) ret = queue_message_create(&msgid); - m_create(p, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, 24); + m_create(p, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1); m_add_id(p, reqid); if (ret == 0) m_add_int(p, 0); @@ -101,7 +100,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) queue_message_delete(msgid); m_create(p_scheduler, IMSG_QUEUE_REMOVE_MESSAGE, - 0, 0, -1, 5); + 0, 0, -1); m_add_msgid(p_scheduler, msgid); m_close(p_scheduler); return; @@ -114,14 +113,14 @@ queue_imsg(struct mproc *p, struct imsg *imsg) ret = queue_message_commit(msgid); - m_create(p, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, 16); + m_create(p, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1); m_add_id(p, reqid); m_add_int(p, (ret == 0) ? 0 : 1); m_close(p); if (ret) { m_create(p_scheduler, IMSG_QUEUE_COMMIT_MESSAGE, - 0, 0, -1, 5); + 0, 0, -1); m_add_msgid(p_scheduler, msgid); m_close(p_scheduler); } @@ -135,7 +134,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) fd = queue_message_fd_rw(msgid); - m_create(p, IMSG_QUEUE_MESSAGE_FILE, 0, 0, fd, 16); + m_create(p, IMSG_QUEUE_MESSAGE_FILE, 0, 0, fd); m_add_id(p, reqid); m_add_int(p, (fd == -1) ? 0 : 1); m_close(p); @@ -156,13 +155,12 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_end(&m); if (evp.id == 0) - log_warn("warn: imsg_queue_submit_envelope: evpid=0"); + log_warnx("warn: imsg_queue_submit_envelope: evpid=0"); if (evpid_to_msgid(evp.id) == 0) - log_warn("warn: imsg_queue_submit_envelope: msgid=0, " + log_warnx("warn: imsg_queue_submit_envelope: msgid=0, " "evpid=%016"PRIx64, evp.id); ret = queue_envelope_create(&evp); - m_create(p_smtp, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, - 24); + m_create(p_smtp, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1); m_add_id(p_smtp, reqid); if (ret == 0) m_add_int(p_smtp, 0); @@ -173,8 +171,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_close(p_smtp); if (ret) { m_create(p_scheduler, - IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, - MSZ_EVP); + IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1); m_add_envelope(p_scheduler, &evp); m_close(p_scheduler); @@ -185,8 +182,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_id(&m, &reqid); m_end(&m); - m_create(p_smtp, IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1, - 16); + m_create(p_smtp, IMSG_QUEUE_COMMIT_ENVELOPES, 0, 0, -1); m_add_id(p_smtp, reqid); m_add_int(p_smtp, 1); m_close(p_smtp); @@ -200,8 +196,10 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_evpid(&m, &evpid); m_end(&m); + + /* already removed by scheduler */ if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + return; queue_log(&evp, "Remove", "Removed by administrator"); queue_envelope_delete(evpid); return; @@ -210,8 +208,11 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_evpid(&m, &evpid); m_end(&m); + + /* already removed by scheduler*/ if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + return; + bounce.type = B_ERROR; bounce.delay = 0; bounce.expire = 0; @@ -224,8 +225,15 @@ queue_imsg(struct mproc *p, struct imsg *imsg) case IMSG_QUEUE_BOUNCE: req_bounce = imsg->data; evpid = req_bounce->evpid; - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: bounce: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 0); /* not in-flight */ + m_close(p_scheduler); + return; + } queue_bounce(&evp, &req_bounce->bounce); evp.lastbounce = req_bounce->timestamp; queue_envelope_update(&evp); @@ -235,10 +243,16 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_evpid(&m, &evpid); m_end(&m); - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: deliver: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 1); /* in-flight */ + m_close(p_scheduler); + return; + } evp.lasttry = time(NULL); - m_create(p_mda, IMSG_MDA_DELIVER, 0, 0, -1, MSZ_EVP); + m_create(p_mda, IMSG_MDA_DELIVER, 0, 0, -1); m_add_envelope(p_mda, &evp); m_close(p_mda); return; @@ -252,7 +266,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) case IMSG_MTA_BATCH: batch_id = generate_uid(); - m_create(p_mta, IMSG_MTA_BATCH, 0, 0, -1, 9); + m_create(p_mta, IMSG_MTA_BATCH, 0, 0, -1); m_add_id(p_mta, batch_id); m_close(p_mta); return; @@ -261,17 +275,23 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_evpid(&m, &evpid); m_end(&m); - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: batch: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 1); /* in-flight */ + m_close(p_scheduler); + return; + } evp.lasttry = time(NULL); - m_create(p_mta, IMSG_MTA_BATCH_ADD, 0, 0, -1, MSZ_EVP); + m_create(p_mta, IMSG_MTA_BATCH_ADD, 0, 0, -1); m_add_id(p_mta, batch_id); m_add_envelope(p_mta, &evp); m_close(p_mta); return; case IMSG_MTA_BATCH_END: - m_create(p_mta, IMSG_MTA_BATCH_END, 0, 0, -1, 9); + m_create(p_mta, IMSG_MTA_BATCH_END, 0, 0, -1); m_add_id(p_mta, batch_id); m_close(p_mta); return; @@ -321,7 +341,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_get_msgid(&m, &msgid); m_end(&m); fd = queue_message_fd_r(msgid); - m_create(p, IMSG_QUEUE_MESSAGE_FD, 0, 0, fd, 25); + m_create(p, IMSG_QUEUE_MESSAGE_FD, 0, 0, fd); m_add_id(p, reqid); m_close(p); return; @@ -331,7 +351,7 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_get_evpid(&m, &evpid); m_end(&m); queue_envelope_delete(evpid); - m_create(p_scheduler, IMSG_DELIVERY_OK, 0, 0, -1, 9); + m_create(p_scheduler, IMSG_DELIVERY_OK, 0, 0, -1); m_add_evpid(p_scheduler, evpid); m_close(p_scheduler); return; @@ -341,13 +361,18 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_get_evpid(&m, &evpid); m_get_string(&m, &reason); m_end(&m); - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: tempfail: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 1); /* in-flight */ + m_close(p_scheduler); + return; + } envelope_set_errormsg(&evp, "%s", reason); evp.retry++; queue_envelope_update(&evp); - m_create(p_scheduler, IMSG_DELIVERY_TEMPFAIL, 0, 0, -1, - MSZ_EVP); + m_create(p_scheduler, IMSG_DELIVERY_TEMPFAIL, 0, 0, -1); m_add_envelope(p_scheduler, &evp); m_close(p_scheduler); return; @@ -357,16 +382,21 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_get_evpid(&m, &evpid); m_get_string(&m, &reason); m_end(&m); - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: permfail: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 1); /* in-flight */ + m_close(p_scheduler); + return; + } bounce.type = B_ERROR; bounce.delay = 0; bounce.expire = 0; envelope_set_errormsg(&evp, "%s", reason); queue_bounce(&evp, &bounce); queue_envelope_delete(evpid); - m_create(p_scheduler, IMSG_DELIVERY_PERMFAIL, 0, 0, -1, - 9); + m_create(p_scheduler, IMSG_DELIVERY_PERMFAIL, 0, 0, -1); m_add_evpid(p_scheduler, evpid); m_close(p_scheduler); return; @@ -375,15 +405,21 @@ queue_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_evpid(&m, &evpid); m_end(&m); - if (queue_envelope_load(evpid, &evp) == 0) - errx(1, "cannot load evp:%016" PRIx64, evpid); + if (queue_envelope_load(evpid, &evp) == 0) { + log_warnx("queue: loop: failed to load envelope"); + m_create(p_scheduler, IMSG_QUEUE_REMOVE, 0, 0, -1); + m_add_evpid(p_scheduler, evpid); + m_add_u32(p_scheduler, 1); /* in-flight */ + m_close(p_scheduler); + return; + } envelope_set_errormsg(&evp, "%s", "Loop detected"); bounce.type = B_ERROR; bounce.delay = 0; bounce.expire = 0; queue_bounce(&evp, &bounce); queue_envelope_delete(evp.id); - m_create(p_scheduler, IMSG_DELIVERY_LOOP, 0, 0, -1, 9); + m_create(p_scheduler, IMSG_DELIVERY_LOOP, 0, 0, -1); m_add_evpid(p_scheduler, evp.id); m_close(p_scheduler); return; @@ -438,9 +474,9 @@ queue_bounce(struct envelope *e, struct delivery_bounce *d) b.expire = 3600 * 24 * 7; if (b.id == 0) - log_warn("warn: queue_bounce: evpid=0"); + log_warnx("warn: queue_bounce: evpid=0"); if (evpid_to_msgid(b.id) == 0) - log_warn("warn: queue_bounce: msgid=0, evpid=%016"PRIx64, + log_warnx("warn: queue_bounce: msgid=0, evpid=%016"PRIx64, b.id); if (e->type == D_BOUNCE) { log_warnx("warn: queue: double bounce!"); @@ -452,12 +488,11 @@ queue_bounce(struct envelope *e, struct delivery_bounce *d) log_debug("debug: queue: bouncing evp:%016" PRIx64 " as evp:%016" PRIx64, e->id, b.id); - m_create(p_scheduler, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, - MSZ_EVP); + m_create(p_scheduler, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1); m_add_envelope(p_scheduler, &b); m_close(p_scheduler); - m_create(p_scheduler, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, 5); + m_create(p_scheduler, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1); m_add_msgid(p_scheduler, evpid_to_msgid(b.id)); m_close(p_scheduler); @@ -571,7 +606,7 @@ queue_timeout(int fd, short event, void *p) if (r == -1) { if (msgid) { m_create(p_scheduler, IMSG_QUEUE_COMMIT_MESSAGE, - 0, 0, -1, 5); + 0, 0, -1); m_add_msgid(p_scheduler, msgid); m_close(p_scheduler); } @@ -582,13 +617,12 @@ queue_timeout(int fd, short event, void *p) if (r) { if (msgid && evpid_to_msgid(evp.id) != msgid) { m_create(p_scheduler, IMSG_QUEUE_COMMIT_MESSAGE, - 0, 0, -1, 5); + 0, 0, -1); m_add_msgid(p_scheduler, msgid); m_close(p_scheduler); } msgid = evpid_to_msgid(evp.id); - m_create(p_scheduler, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1, - MSZ_EVP); + m_create(p_scheduler, IMSG_QUEUE_SUBMIT_ENVELOPE, 0, 0, -1); m_add_envelope(p_scheduler, &evp); m_close(p_scheduler); } @@ -601,7 +635,7 @@ queue_timeout(int fd, short event, void *p) void queue_ok(uint64_t evpid) { - m_create(p_queue, IMSG_DELIVERY_OK, 0, 0, -1, sizeof(evpid) + 1); + m_create(p_queue, IMSG_DELIVERY_OK, 0, 0, -1); m_add_evpid(p_queue, evpid); m_close(p_queue); } @@ -609,8 +643,7 @@ queue_ok(uint64_t evpid) void queue_tempfail(uint64_t evpid, const char *reason) { - m_create(p_queue, IMSG_DELIVERY_TEMPFAIL, 0, 0, -1, - sizeof(evpid) + strlen(reason) + 2); + m_create(p_queue, IMSG_DELIVERY_TEMPFAIL, 0, 0, -1); m_add_evpid(p_queue, evpid); m_add_string(p_queue, reason); m_close(p_queue); @@ -619,8 +652,7 @@ queue_tempfail(uint64_t evpid, const char *reason) void queue_permfail(uint64_t evpid, const char *reason) { - m_create(p_queue, IMSG_DELIVERY_PERMFAIL, 0, 0, -1, - sizeof(evpid) + strlen(reason) + 2); + m_create(p_queue, IMSG_DELIVERY_PERMFAIL, 0, 0, -1); m_add_evpid(p_queue, evpid); m_add_string(p_queue, reason); m_close(p_queue); @@ -629,7 +661,7 @@ queue_permfail(uint64_t evpid, const char *reason) void queue_loop(uint64_t evpid) { - m_create(p_queue, IMSG_DELIVERY_LOOP, 0, 0, -1, sizeof(evpid) + 1); + m_create(p_queue, IMSG_DELIVERY_LOOP, 0, 0, -1); m_add_evpid(p_queue, evpid); m_close(p_queue); } diff --git a/usr.sbin/smtpd/queue_backend.c b/usr.sbin/smtpd/queue_backend.c index 9eb9693e0e6..5fc1cd1994d 100644 --- a/usr.sbin/smtpd/queue_backend.c +++ b/usr.sbin/smtpd/queue_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: queue_backend.c,v 1.43 2013/04/17 15:02:38 deraadt Exp $ */ +/* $OpenBSD: queue_backend.c,v 1.44 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -73,8 +72,8 @@ static inline void profile_leave(void) clock_gettime(CLOCK_MONOTONIC, &t1); timespecsub(&t1, &profile.t0, &dt); - log_debug("profile-queue: %s %lld.%06li", profile.name, - (long long)dt.tv_sec * 1000000 + dt.tv_nsec / 1000000, + log_debug("profile-queue: %s %li.%06li", profile.name, + dt.tv_sec * 1000000 + dt.tv_nsec / 1000000, dt.tv_nsec % 1000000); } #else @@ -93,6 +92,8 @@ queue_message_incoming_path(uint32_t msgid, char *buf, size_t len) int queue_init(const char *name, int server) { + int r; + if (!strcmp(name, "fs")) backend = &queue_backend_fs; if (!strcmp(name, "null")) @@ -105,7 +106,11 @@ queue_init(const char *name, int server) return (0); } - return backend->init(server); + r = backend->init(server); + + log_trace(TRACE_QUEUE, "queue-backend: queue_init(%i) -> %i", server, r); + + return (r); } int @@ -117,6 +122,10 @@ queue_message_create(uint32_t *msgid) r = backend->message(QOP_CREATE, msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_create() -> %i (%08"PRIx32")", + r, *msgid); + return (r); } @@ -129,6 +138,9 @@ queue_message_delete(uint32_t msgid) r = backend->message(QOP_DELETE, &msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_delete(%08"PRIx32") -> %i", msgid, r); + return (r); } @@ -136,12 +148,51 @@ int queue_message_commit(uint32_t msgid) { int r; + char msgpath[MAXPATHLEN]; + char tmppath[MAXPATHLEN]; + FILE *ifp = NULL; + FILE *ofp = NULL; profile_enter("queue_message_commit"); + queue_message_incoming_path(msgid, msgpath, sizeof msgpath); + strlcat(msgpath, PATH_MESSAGE, sizeof(msgpath)); + + if (env->sc_queue_flags & QUEUE_COMPRESSION) { + + bsnprintf(tmppath, sizeof tmppath, "%s.comp", msgpath); + ifp = fopen(msgpath, "r"); + ofp = fopen(tmppath, "w+"); + if (ifp == NULL || ofp == NULL) + goto err; + if (! compress_file(ifp, ofp)) + goto err; + fclose(ifp); + fclose(ofp); + ifp = NULL; + ofp = NULL; + + if (rename(tmppath, msgpath) == -1) { + if (errno == ENOSPC) + return (0); + fatal("queue_message_commit: rename"); + } + } + r = backend->message(QOP_COMMIT, &msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_commit(%08"PRIx32") -> %i", + msgid, r); + return (r); + +err: + if (ifp) + fclose(ifp); + if (ofp) + fclose(ofp); + return 0; } int @@ -153,6 +204,9 @@ queue_message_corrupt(uint32_t msgid) r = backend->message(QOP_CORRUPT, &msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_corrupt(%08"PRIx32") -> %i", msgid, r); + return (r); } @@ -167,10 +221,13 @@ queue_message_fd_r(uint32_t msgid) fdin = backend->message(QOP_FD_R, &msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_fd_r(%08"PRIx32") -> %i", msgid, fdin); + if (fdin == -1) return (-1); - if (env->sc_queue_flags & QUEUE_COMPRESS) { + if (env->sc_queue_flags & QUEUE_COMPRESSION) { if ((fdout = mktmpfile()) == -1) goto err; if ((fd = dup(fdout)) == -1) @@ -181,8 +238,10 @@ queue_message_fd_r(uint32_t msgid) fd = -1; if ((ofp = fdopen(fdout, "w+")) == NULL) goto err; + if (! uncompress_file(ifp, ofp)) goto err; + fclose(ifp); fclose(ofp); lseek(fdin, SEEK_SET, 0); @@ -213,27 +272,31 @@ queue_message_fd_rw(uint32_t msgid) r = backend->message(QOP_FD_RW, &msgid); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_message_fd_rw(%08"PRIx32") -> %i", msgid, r); + return (r); } static int queue_envelope_dump_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize) { - char evpbufcom[sizeof(struct envelope)]; - char *evp; - size_t evplen; + char *evp; + size_t evplen; + size_t complen; + char compbuf[sizeof(struct envelope)]; evp = evpbuf; evplen = envelope_dump_buffer(ep, evpbuf, evpbufsize); if (evplen == 0) return (0); - if (env->sc_queue_flags & QUEUE_COMPRESS) { - evplen = compress_buffer(evp, evplen, evpbufcom, - sizeof evpbufcom); - if (evplen == 0) + if (env->sc_queue_flags & QUEUE_COMPRESSION) { + complen = compress_chunk(evp, evplen, compbuf, sizeof compbuf); + if (complen == 0) return (0); - evp = evpbufcom; + evp = compbuf; + evplen = complen; } memmove(evpbuf, evp, evplen); @@ -244,19 +307,20 @@ queue_envelope_dump_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize) static int queue_envelope_load_buffer(struct envelope *ep, char *evpbuf, size_t evpbufsize) { - char evpbufcom[sizeof(struct envelope)]; char *evp; size_t evplen; + char compbuf[sizeof(struct envelope)]; + size_t complen; evp = evpbuf; evplen = evpbufsize; - if (env->sc_queue_flags & QUEUE_COMPRESS) { - evplen = uncompress_buffer(evp, evplen, evpbufcom, - sizeof evpbufcom); - if (evplen == 0) + if (env->sc_queue_flags & QUEUE_COMPRESSION) { + complen = uncompress_chunk(evp, evplen, compbuf, sizeof compbuf); + if (complen == 0) return (0); - evp = evpbufcom; + evp = compbuf; + evplen = complen; } return (envelope_load_buffer(ep, evp, evplen)); @@ -268,19 +332,28 @@ queue_envelope_create(struct envelope *ep) int r; char evpbuf[sizeof(struct envelope)]; size_t evplen; + uint64_t evpid; ep->creation = time(NULL); evplen = queue_envelope_dump_buffer(ep, evpbuf, sizeof evpbuf); if (evplen == 0) return (0); + evpid = ep->id; + profile_enter("queue_envelope_create"); r = backend->envelope(QOP_CREATE, &ep->id, evpbuf, evplen); profile_leave(); + + log_trace(TRACE_QUEUE, + "queue-backend: queue_envelope_create(%016"PRIx64", %zu) -> %i (%016"PRIx64")", + evpid, evplen, r, ep->id); + if (!r) { ep->creation = 0; ep->id = 0; } + return (r); } @@ -293,6 +366,10 @@ queue_envelope_delete(uint64_t evpid) r = backend->envelope(QOP_DELETE, &evpid, NULL, 0); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_envelope_delete(%016"PRIx64") -> %i", + evpid, r); + return (r); } @@ -307,6 +384,11 @@ queue_envelope_load(uint64_t evpid, struct envelope *ep) profile_enter("queue_envelope_load"); evplen = backend->envelope(QOP_LOAD, &ep->id, evpbuf, sizeof evpbuf); profile_leave(); + + log_trace(TRACE_QUEUE, + "queue-backend: queue_envelope_load(%016"PRIx64") -> %zu", + evpid, evplen); + if (evplen == 0) return (0); @@ -318,6 +400,8 @@ queue_envelope_load(uint64_t evpid, struct envelope *ep) log_debug("debug: invalid envelope %016" PRIx64 ": %s", ep->id, e); } + + (void)queue_message_corrupt(evpid_to_msgid(evpid)); return (0); } @@ -336,6 +420,10 @@ queue_envelope_update(struct envelope *ep) r = backend->envelope(QOP_UPDATE, &ep->id, evpbuf, evplen); profile_leave(); + log_trace(TRACE_QUEUE, + "queue-backend: queue_envelope_update(%016"PRIx64") -> %i", + ep->id, r); + return (r); } @@ -350,10 +438,15 @@ queue_envelope_walk(struct envelope *ep) profile_enter("queue_envelope_walk"); r = backend->envelope(QOP_WALK, &evpid, evpbuf, sizeof evpbuf); profile_leave(); - if (r == -1 || r == 0) + + log_trace(TRACE_QUEUE, + "queue-backend: queue_envelope_walk() -> %i (%016"PRIx64")", + r, evpid); + + if (r == -1) return (r); - if (queue_envelope_load_buffer(ep, evpbuf, (size_t)r)) { + if (r && queue_envelope_load_buffer(ep, evpbuf, (size_t)r)) { if ((e = envelope_validate(ep)) == NULL) { ep->id = evpid; return (1); @@ -361,6 +454,8 @@ queue_envelope_walk(struct envelope *ep) log_debug("debug: invalid envelope %016" PRIx64 ": %s", ep->id, e); } + + (void)queue_message_corrupt(evpid_to_msgid(evpid)); return (0); } diff --git a/usr.sbin/smtpd/queue_fsqueue.c b/usr.sbin/smtpd/queue_fsqueue.c index 2c27f426d60..85e6e233c2e 100644 --- a/usr.sbin/smtpd/queue_fsqueue.c +++ b/usr.sbin/smtpd/queue_fsqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: queue_fsqueue.c,v 1.61 2013/04/02 09:17:14 gilles Exp $ */ +/* $OpenBSD: queue_fsqueue.c,v 1.62 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/param.h> @@ -79,8 +78,8 @@ struct tree evpcount; #define PATH_EVPTMP PATH_INCOMING "/envelope.tmp" /* percentage of remaining space / inodes required to accept new messages */ -#define MINSPACE 10 -#define MININODES 10 +#define MINSPACE 5 +#define MININODES 5 struct queue_backend queue_backend_fs = { fsqueue_init, @@ -110,6 +109,7 @@ fsqueue_check_space(void) used = 100; if (100 - used < MINSPACE) { log_warnx("warn: not enough disk space: %llu%% left", 100 - used); + log_warnx("warn: temporarily rejecting messages"); return 0; } @@ -121,6 +121,7 @@ fsqueue_check_space(void) used = 100; if (100 - used < MININODES) { log_warnx("warn: not enough inodes: %llu%% left", 100 - used); + log_warnx("warn: temporarily rejecting messages"); return 0; } @@ -227,7 +228,7 @@ tempfail: static int fsqueue_envelope_create(uint64_t *evpid, char *buf, size_t len) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; uint32_t msgid; int queued = 0, i, r = 0; struct stat sb; @@ -271,7 +272,7 @@ done: static int fsqueue_envelope_load(uint64_t evpid, char *buf, size_t len) { - char pathname[MAXPATHLEN]; + char pathname[SMTPD_MAXPATHLEN]; FILE *fp; size_t r; @@ -301,7 +302,7 @@ fsqueue_envelope_load(uint64_t evpid, char *buf, size_t len) static int fsqueue_envelope_update(uint64_t evpid, char *buf, size_t len) { - char dest[MAXPATHLEN]; + char dest[SMTPD_MAXPATHLEN]; fsqueue_envelope_path(evpid, dest, sizeof(dest)); @@ -311,7 +312,7 @@ fsqueue_envelope_update(uint64_t evpid, char *buf, size_t len) static int fsqueue_envelope_delete(uint64_t evpid) { - char pathname[MAXPATHLEN]; + char pathname[SMTPD_MAXPATHLEN]; uint32_t msgid; uintptr_t *n; @@ -339,7 +340,6 @@ fsqueue_envelope_walk(uint64_t *evpid, char *buf, size_t len) uintptr_t *n; int r; uint32_t msgid; - struct envelope ep; if (done) return (-1); @@ -352,13 +352,9 @@ fsqueue_envelope_walk(uint64_t *evpid, char *buf, size_t len) r = fsqueue_envelope_load(*evpid, buf, len); if (r) { msgid = evpid_to_msgid(*evpid); - if (! envelope_load_buffer(&ep, buf, r)) - (void)fsqueue_message_corrupt(msgid); - else { - n = tree_pop(&evpcount, msgid); - n += 1; - tree_xset(&evpcount, msgid, n); - } + n = tree_pop(&evpcount, msgid); + n += 1; + tree_xset(&evpcount, msgid, n); } return (r); } @@ -371,8 +367,8 @@ fsqueue_envelope_walk(uint64_t *evpid, char *buf, size_t len) static int fsqueue_message_create(uint32_t *msgid) { - char rootdir[MAXPATHLEN]; - struct stat sb; + char rootdir[SMTPD_MAXPATHLEN]; + struct stat sb; if (! fsqueue_check_space()) return 0; @@ -382,9 +378,15 @@ again: /* prevent possible collision later when moving to Q_QUEUE */ fsqueue_message_path(*msgid, rootdir, sizeof(rootdir)); - if (stat(rootdir, &sb) != -1 || errno != ENOENT) + if (stat(rootdir, &sb) != -1) goto again; + /* we hit an unexpected error, temporarily fail */ + if (errno != ENOENT) { + *msgid = 0; + return 0; + } + queue_message_incoming_path(*msgid, rootdir, sizeof(rootdir)); if (mkdir(rootdir, 0700) == -1) { if (errno == EEXIST) @@ -406,9 +408,9 @@ again: static int fsqueue_message_commit(uint32_t msgid) { - char incomingdir[MAXPATHLEN]; - char queuedir[MAXPATHLEN]; - char msgdir[MAXPATHLEN]; + char incomingdir[SMTPD_MAXPATHLEN]; + char queuedir[SMTPD_MAXPATHLEN]; + char msgdir[SMTPD_MAXPATHLEN]; queue_message_incoming_path(msgid, incomingdir, sizeof(incomingdir)); fsqueue_message_path(msgid, msgdir, sizeof(msgdir)); @@ -450,7 +452,7 @@ static int fsqueue_message_fd_r(uint32_t msgid) { int fd; - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; fsqueue_message_path(msgid, path, sizeof(path)); strlcat(path, PATH_MESSAGE, sizeof(path)); @@ -466,7 +468,7 @@ fsqueue_message_fd_r(uint32_t msgid) static int fsqueue_message_fd_rw(uint32_t msgid) { - char msgpath[MAXPATHLEN]; + char msgpath[SMTPD_MAXPATHLEN]; queue_message_incoming_path(msgid, msgpath, sizeof msgpath); strlcat(msgpath, PATH_MESSAGE, sizeof(msgpath)); @@ -477,7 +479,7 @@ fsqueue_message_fd_rw(uint32_t msgid) static int fsqueue_message_delete(uint32_t msgid) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; struct stat sb; queue_message_incoming_path(msgid, path, sizeof(path)); @@ -496,8 +498,8 @@ static int fsqueue_message_corrupt(uint32_t msgid) { struct stat sb; - char rootdir[MAXPATHLEN]; - char corruptdir[MAXPATHLEN]; + char rootdir[SMTPD_MAXPATHLEN]; + char corruptdir[SMTPD_MAXPATHLEN]; char buf[64]; int retry = 0; @@ -519,6 +521,8 @@ again: return 0; } + tree_pop(&evpcount, msgid); + return 1; } @@ -527,7 +531,7 @@ fsqueue_init(int server) { unsigned int n; char *paths[] = { PATH_QUEUE, PATH_CORRUPT }; - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; int ret; struct timeval tv; @@ -602,7 +606,7 @@ struct qwalk { static void * fsqueue_qwalk_new(void) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; char * const path_argv[] = { path, NULL }; struct qwalk *q; diff --git a/usr.sbin/smtpd/queue_null.c b/usr.sbin/smtpd/queue_null.c index 770111239dc..e6f1ed279e9 100644 --- a/usr.sbin/smtpd/queue_null.c +++ b/usr.sbin/smtpd/queue_null.c @@ -1,4 +1,4 @@ -/* $OpenBSD: queue_null.c,v 1.1 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: queue_null.c,v 1.2 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> diff --git a/usr.sbin/smtpd/queue_ram.c b/usr.sbin/smtpd/queue_ram.c index ab80811435e..55b3c3fd08d 100644 --- a/usr.sbin/smtpd/queue_ram.c +++ b/usr.sbin/smtpd/queue_ram.c @@ -1,4 +1,4 @@ -/* $OpenBSD: queue_ram.c,v 1.2 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: queue_ram.c,v 1.3 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -76,7 +75,7 @@ queue_ram_init(int server) static int queue_ram_message(enum queue_op qop, uint32_t *msgid) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; uint64_t evpid; struct qr_envelope *evp; struct qr_message *msg; diff --git a/usr.sbin/smtpd/ruleset.c b/usr.sbin/smtpd/ruleset.c index 04ffe2cdfe5..7042ee090ca 100644 --- a/usr.sbin/smtpd/ruleset.c +++ b/usr.sbin/smtpd/ruleset.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ruleset.c,v 1.27 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: ruleset.c,v 1.28 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> diff --git a/usr.sbin/smtpd/scheduler.c b/usr.sbin/smtpd/scheduler.c index 1d114b457a4..6c2d8da476f 100644 --- a/usr.sbin/smtpd/scheduler.c +++ b/usr.sbin/smtpd/scheduler.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler.c,v 1.27 2013/02/10 15:01:16 eric Exp $ */ +/* $OpenBSD: scheduler.c,v 1.28 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -57,6 +56,7 @@ static void scheduler_process_mda(struct scheduler_batch *); static void scheduler_process_mta(struct scheduler_batch *); static struct scheduler_backend *backend = NULL; +static struct event ev; extern const char *backend_scheduler; @@ -75,6 +75,7 @@ scheduler_imsg(struct mproc *p, struct imsg *imsg) struct msg m; uint64_t evpid, id; uint32_t msgid, msgids[MSGBATCHSIZE]; + uint32_t inflight; size_t n, i; time_t timestamp; int v; @@ -115,6 +116,23 @@ scheduler_imsg(struct mproc *p, struct imsg *imsg) scheduler_reset_events(); return; + case IMSG_QUEUE_REMOVE: + m_msg(&m, imsg); + m_get_evpid(&m, &evpid); + m_get_u32(&m, &inflight); + m_end(&m); + log_trace(TRACE_SCHEDULER, + "scheduler: queue requested removal of evp:%016" PRIx64, + evpid); + stat_decrement("scheduler.envelope", 1); + if (! inflight) + backend->remove(evpid); + else + backend->delete(evpid); + + scheduler_reset_events(); + return; + case IMSG_DELIVERY_OK: m_msg(&m, imsg); m_get_evpid(&m, &evpid); @@ -225,7 +243,7 @@ scheduler_imsg(struct mproc *p, struct imsg *imsg) n = backend->envelopes(id, state, EVPBATCHSIZE); for (i = 0; i < n; i++) { m_create(p_queue, IMSG_CTL_LIST_ENVELOPES, - imsg->hdr.peerid, 0, -1, 32); + imsg->hdr.peerid, 0, -1); m_add_evpid(p_queue, state[i].evpid); m_add_int(p_queue, state[i].flags); m_add_time(p_queue, state[i].time); @@ -289,10 +307,10 @@ scheduler_reset_events(void) { struct timeval tv; - evtimer_del(&env->sc_ev); + evtimer_del(&ev); tv.tv_sec = 0; tv.tv_usec = 0; - evtimer_add(&env->sc_ev, &tv); + evtimer_add(&ev, &tv); } pid_t @@ -303,6 +321,11 @@ scheduler(void) struct event ev_sigint; struct event ev_sigterm; + backend = scheduler_backend_lookup(backend_scheduler); + if (backend == NULL) + errx(1, "cannot find scheduler backend \"%s\"", + backend_scheduler); + switch (pid = fork()) { case -1: fatal("scheduler: cannot fork"); @@ -315,29 +338,23 @@ scheduler(void) purge_config(PURGE_EVERYTHING); + config_process(PROC_SCHEDULER); + + fdlimit(1.0); + + backend->init(); + pw = env->sc_pw; if (chroot(pw->pw_dir) == -1) fatal("scheduler: chroot"); if (chdir("/") == -1) fatal("scheduler: chdir(\"/\")"); - config_process(PROC_SCHEDULER); - if (setgroups(1, &pw->pw_gid) || setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("scheduler: cannot drop privileges"); - fdlimit(1.0); - - env->sc_scheduler = scheduler_backend_lookup(backend_scheduler); - if (env->sc_scheduler == NULL) - errx(1, "cannot find scheduler backend \"%s\"", - backend_scheduler); - backend = env->sc_scheduler; - - backend->init(); - imsg_callback = scheduler_imsg; event_init(); @@ -352,7 +369,7 @@ scheduler(void) config_peer(PROC_QUEUE); config_done(); - evtimer_set(&env->sc_ev, scheduler_timeout, NULL); + evtimer_set(&ev, scheduler_timeout, NULL); scheduler_reset_events(); if (event_dispatch() < 0) fatal("event_dispatch"); @@ -431,7 +448,7 @@ scheduler_timeout(int fd, short event, void *p) fatalx("scheduler_timeout: unknown batch type"); } - evtimer_add(&env->sc_ev, &tv); + evtimer_add(&ev, &tv); } static void @@ -442,7 +459,7 @@ scheduler_process_remove(struct scheduler_batch *batch) for (i = 0; i < batch->evpcount; i++) { log_debug("debug: scheduler: evp:%016" PRIx64 " removed", batch->evpids[i]); - m_create(p_queue, IMSG_QUEUE_REMOVE, 0, 0, -1, 9); + m_create(p_queue, IMSG_QUEUE_REMOVE, 0, 0, -1); m_add_evpid(p_queue, batch->evpids[i]); m_close(p_queue); } @@ -459,7 +476,7 @@ scheduler_process_expire(struct scheduler_batch *batch) for (i = 0; i < batch->evpcount; i++) { log_debug("debug: scheduler: evp:%016" PRIx64 " expired", batch->evpids[i]); - m_create(p_queue, IMSG_QUEUE_EXPIRE, 0, 0, -1, 9); + m_create(p_queue, IMSG_QUEUE_EXPIRE, 0, 0, -1); m_add_evpid(p_queue, batch->evpids[i]); m_close(p_queue); } @@ -476,7 +493,7 @@ scheduler_process_bounce(struct scheduler_batch *batch) for (i = 0; i < batch->evpcount; i++) { log_debug("debug: scheduler: evp:%016" PRIx64 " scheduled (bounce)", batch->evpids[i]); - m_create(p_queue, IMSG_BOUNCE_INJECT, 0, 0, -1, 9); + m_create(p_queue, IMSG_BOUNCE_INJECT, 0, 0, -1); m_add_evpid(p_queue, batch->evpids[i]); m_close(p_queue); } @@ -492,7 +509,7 @@ scheduler_process_mda(struct scheduler_batch *batch) for (i = 0; i < batch->evpcount; i++) { log_debug("debug: scheduler: evp:%016" PRIx64 " scheduled (mda)", batch->evpids[i]); - m_create(p_queue, IMSG_MDA_DELIVER, 0, 0, -1, 9); + m_create(p_queue, IMSG_MDA_DELIVER, 0, 0, -1); m_add_evpid(p_queue, batch->evpids[i]); m_close(p_queue); } @@ -510,7 +527,7 @@ scheduler_process_mta(struct scheduler_batch *batch) for (i = 0; i < batch->evpcount; i++) { log_debug("debug: scheduler: evp:%016" PRIx64 " scheduled (mta)", batch->evpids[i]); - m_create(p_queue, IMSG_MTA_BATCH_ADD, 0, 0, -1, 9); + m_create(p_queue, IMSG_MTA_BATCH_ADD, 0, 0, -1); m_add_evpid(p_queue, batch->evpids[i]); m_close(p_queue); } diff --git a/usr.sbin/smtpd/scheduler_backend.c b/usr.sbin/smtpd/scheduler_backend.c index 2c0a83c8e56..fbe4cb9197d 100644 --- a/usr.sbin/smtpd/scheduler_backend.c +++ b/usr.sbin/smtpd/scheduler_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler_backend.c,v 1.8 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: scheduler_backend.c,v 1.9 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> diff --git a/usr.sbin/smtpd/scheduler_null.c b/usr.sbin/smtpd/scheduler_null.c index f9e6e272704..6cd7a70e2e7 100644 --- a/usr.sbin/smtpd/scheduler_null.c +++ b/usr.sbin/smtpd/scheduler_null.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler_null.c,v 1.1 2013/01/26 09:37:23 gilles Exp $ */ +/* $OpenBSD: scheduler_null.c,v 1.2 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -31,17 +30,17 @@ #include "smtpd.h" -static void scheduler_null_init(void); -static void scheduler_null_insert(struct scheduler_info *); +static int scheduler_null_init(void); +static int scheduler_null_insert(struct scheduler_info *); static size_t scheduler_null_commit(uint32_t); static size_t scheduler_null_rollback(uint32_t); -static void scheduler_null_update(struct scheduler_info *); -static void scheduler_null_delete(uint64_t); -static void scheduler_null_batch(int, struct scheduler_batch *); +static int scheduler_null_update(struct scheduler_info *); +static int scheduler_null_delete(uint64_t); +static int scheduler_null_batch(int, struct scheduler_batch *); static size_t scheduler_null_messages(uint32_t, uint32_t *, size_t); static size_t scheduler_null_envelopes(uint64_t, struct evpstate *, size_t); -static void scheduler_null_schedule(uint64_t); -static void scheduler_null_remove(uint64_t); +static int scheduler_null_schedule(uint64_t); +static int scheduler_null_remove(uint64_t); struct scheduler_backend scheduler_backend_null = { scheduler_null_init, @@ -61,14 +60,16 @@ struct scheduler_backend scheduler_backend_null = { scheduler_null_remove, }; -static void +static int scheduler_null_init(void) { + return (1); } -static void +static int scheduler_null_insert(struct scheduler_info *si) { + return (0); } static size_t @@ -83,30 +84,37 @@ scheduler_null_rollback(uint32_t msgid) return (0); } -static void +static int scheduler_null_update(struct scheduler_info *si) { + return (0); } -static void +static int scheduler_null_delete(uint64_t evpid) { + return (0); } -static void +static int scheduler_null_batch(int typemask, struct scheduler_batch *ret) { ret->type = SCHED_NONE; + ret->evpcount = 0; + + return (0); } -static void +static int scheduler_null_schedule(uint64_t evpid) { + return (0); } -static void +static int scheduler_null_remove(uint64_t evpid) { + return (0); } static size_t diff --git a/usr.sbin/smtpd/scheduler_ramqueue.c b/usr.sbin/smtpd/scheduler_ramqueue.c index 7ee0a4a341b..f8a896b2540 100644 --- a/usr.sbin/smtpd/scheduler_ramqueue.c +++ b/usr.sbin/smtpd/scheduler_ramqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler_ramqueue.c,v 1.27 2013/02/10 15:01:16 eric Exp $ */ +/* $OpenBSD: scheduler_ramqueue.c,v 1.28 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -82,17 +81,17 @@ struct rq_queue { struct evplist q_removed; }; -static void scheduler_ramqueue_init(void); -static void scheduler_ramqueue_insert(struct scheduler_info *); -static size_t scheduler_ramqueue_commit(uint32_t); -static size_t scheduler_ramqueue_rollback(uint32_t); -static void scheduler_ramqueue_update(struct scheduler_info *); -static void scheduler_ramqueue_delete(uint64_t); -static void scheduler_ramqueue_batch(int, struct scheduler_batch *); -static size_t scheduler_ramqueue_messages(uint32_t, uint32_t *, size_t); -static size_t scheduler_ramqueue_envelopes(uint64_t, struct evpstate *, size_t); -static void scheduler_ramqueue_schedule(uint64_t); -static void scheduler_ramqueue_remove(uint64_t); +static int scheduler_ram_init(void); +static int scheduler_ram_insert(struct scheduler_info *); +static size_t scheduler_ram_commit(uint32_t); +static size_t scheduler_ram_rollback(uint32_t); +static int scheduler_ram_update(struct scheduler_info *); +static int scheduler_ram_delete(uint64_t); +static int scheduler_ram_batch(int, struct scheduler_batch *); +static size_t scheduler_ram_messages(uint32_t, uint32_t *, size_t); +static size_t scheduler_ram_envelopes(uint64_t, struct evpstate *, size_t); +static int scheduler_ram_schedule(uint64_t); +static int scheduler_ram_remove(uint64_t); static void sorted_insert(struct evplist *, struct rq_envelope *); static void sorted_merge(struct evplist *, struct evplist *); @@ -102,26 +101,26 @@ static void rq_queue_merge(struct rq_queue *, struct rq_queue *); static void rq_queue_dump(struct rq_queue *, const char *); static void rq_queue_schedule(struct rq_queue *rq); static void rq_envelope_schedule(struct rq_queue *, struct rq_envelope *); -static void rq_envelope_remove(struct rq_queue *, struct rq_envelope *); +static int rq_envelope_remove(struct rq_queue *, struct rq_envelope *); static void rq_envelope_delete(struct rq_queue *, struct rq_envelope *); static const char *rq_envelope_to_text(struct rq_envelope *); struct scheduler_backend scheduler_backend_ramqueue = { - scheduler_ramqueue_init, + scheduler_ram_init, - scheduler_ramqueue_insert, - scheduler_ramqueue_commit, - scheduler_ramqueue_rollback, + scheduler_ram_insert, + scheduler_ram_commit, + scheduler_ram_rollback, - scheduler_ramqueue_update, - scheduler_ramqueue_delete, + scheduler_ram_update, + scheduler_ram_delete, - scheduler_ramqueue_batch, + scheduler_ram_batch, - scheduler_ramqueue_messages, - scheduler_ramqueue_envelopes, - scheduler_ramqueue_schedule, - scheduler_ramqueue_remove, + scheduler_ram_messages, + scheduler_ram_envelopes, + scheduler_ram_schedule, + scheduler_ram_remove, }; static struct rq_queue ramqueue; @@ -129,15 +128,17 @@ static struct tree updates; static time_t currtime; -static void -scheduler_ramqueue_init(void) +static int +scheduler_ram_init(void) { rq_queue_init(&ramqueue); tree_init(&updates); + + return (1); } -static void -scheduler_ramqueue_insert(struct scheduler_info *si) +static int +scheduler_ram_insert(struct scheduler_info *si) { uint32_t msgid; struct rq_queue *update; @@ -182,10 +183,12 @@ scheduler_ramqueue_insert(struct scheduler_info *si) sorted_insert(&update->q_pending, envelope); si->nexttry = envelope->sched; + + return (1); } static size_t -scheduler_ramqueue_commit(uint32_t msgid) +scheduler_ram_commit(uint32_t msgid) { struct rq_queue *update; size_t r; @@ -212,7 +215,7 @@ scheduler_ramqueue_commit(uint32_t msgid) } static size_t -scheduler_ramqueue_rollback(uint32_t msgid) +scheduler_ram_rollback(uint32_t msgid) { struct rq_queue *update; struct rq_envelope *evp; @@ -235,8 +238,8 @@ scheduler_ramqueue_rollback(uint32_t msgid) return (r); } -static void -scheduler_ramqueue_update(struct scheduler_info *si) +static int +scheduler_ram_update(struct scheduler_info *si) { struct rq_message *msg; struct rq_envelope *evp; @@ -261,10 +264,12 @@ scheduler_ramqueue_update(struct scheduler_info *si) evp->flags |= RQ_ENVELOPE_PENDING; si->nexttry = evp->sched; + + return (1); } -static void -scheduler_ramqueue_delete(uint64_t evpid) +static int +scheduler_ram_delete(uint64_t evpid) { struct rq_message *msg; struct rq_envelope *evp; @@ -283,10 +288,12 @@ scheduler_ramqueue_delete(uint64_t evpid) TAILQ_REMOVE(&ramqueue.q_inflight, evp, entry); evp->flags &= ~RQ_ENVELOPE_INFLIGHT; rq_envelope_delete(&ramqueue, evp); + + return (1); } -static void -scheduler_ramqueue_batch(int typemask, struct scheduler_batch *ret) +static int +scheduler_ram_batch(int typemask, struct scheduler_batch *ret) { struct evplist *q; struct rq_envelope *evp; @@ -297,7 +304,7 @@ scheduler_ramqueue_batch(int typemask, struct scheduler_batch *ret) rq_queue_schedule(&ramqueue); if (verbose & TRACE_SCHEDULER) - rq_queue_dump(&ramqueue, "scheduler_ramqueue_batch()"); + rq_queue_dump(&ramqueue, "scheduler_ram_batch()"); if (typemask & SCHED_REMOVE && TAILQ_FIRST(&ramqueue.q_removed)) { q = &ramqueue.q_removed; @@ -324,15 +331,17 @@ scheduler_ramqueue_batch(int typemask, struct scheduler_batch *ret) } else if ((evp = TAILQ_FIRST(&ramqueue.q_pending))) { ret->type = SCHED_DELAY; + ret->evpcount = 0; if (evp->sched < evp->expire) ret->delay = evp->sched - currtime; else ret->delay = evp->expire - currtime; - return; + return (1); } else { ret->type = SCHED_NONE; - return; + ret->evpcount = 0; + return (0); } for (n = 0; (evp = TAILQ_FIRST(q)) && n < ret->evpcount; n++) { @@ -356,68 +365,12 @@ scheduler_ramqueue_batch(int typemask, struct scheduler_batch *ret) } ret->evpcount = n; -} -static void -scheduler_ramqueue_schedule(uint64_t evpid) -{ - struct rq_message *msg; - struct rq_envelope *evp; - uint32_t msgid; - void *i; - - currtime = time(NULL); - - if (evpid > 0xffffffff) { - msgid = evpid_to_msgid(evpid); - if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) - return; - if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) - return; - if (evp->flags & RQ_ENVELOPE_PENDING) - rq_envelope_schedule(&ramqueue, evp); - } - else { - msgid = evpid; - if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) - return; - i = NULL; - while (tree_iter(&msg->envelopes, &i, NULL, (void*)(&evp))) - if (evp->flags & RQ_ENVELOPE_PENDING) - rq_envelope_schedule(&ramqueue, evp); - } -} - -static void -scheduler_ramqueue_remove(uint64_t evpid) -{ - struct rq_message *msg; - struct rq_envelope *evp; - uint32_t msgid; - void *i; - - currtime = time(NULL); - - if (evpid > 0xffffffff) { - msgid = evpid_to_msgid(evpid); - if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) - return; - if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) - return; - rq_envelope_remove(&ramqueue, evp); - } - else { - msgid = evpid; - if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) - return; - i = NULL; - while (tree_iter(&msg->envelopes, &i, NULL, (void*)(&evp))) - rq_envelope_remove(&ramqueue, evp); - } + return (1); } static size_t -scheduler_ramqueue_messages(uint32_t from, uint32_t *dst, size_t size) +scheduler_ram_messages(uint32_t from, uint32_t *dst, size_t size) { uint64_t id; size_t n; @@ -433,7 +386,7 @@ scheduler_ramqueue_messages(uint32_t from, uint32_t *dst, size_t size) } static size_t -scheduler_ramqueue_envelopes(uint64_t from, struct evpstate *dst, size_t size) +scheduler_ram_envelopes(uint64_t from, struct evpstate *dst, size_t size) { struct rq_message *msg; struct rq_envelope *evp; @@ -472,6 +425,78 @@ scheduler_ramqueue_envelopes(uint64_t from, struct evpstate *dst, size_t size) return (n); } +static int +scheduler_ram_schedule(uint64_t evpid) +{ + struct rq_message *msg; + struct rq_envelope *evp; + uint32_t msgid; + void *i; + int r; + + currtime = time(NULL); + + if (evpid > 0xffffffff) { + msgid = evpid_to_msgid(evpid); + if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) + return (0); + if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) + return (0); + if (evp->flags & RQ_ENVELOPE_PENDING) { + rq_envelope_schedule(&ramqueue, evp); + return (1); + } + return (0); + } + else { + msgid = evpid; + if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) + return (0); + i = NULL; + r = 0; + while (tree_iter(&msg->envelopes, &i, NULL, (void*)(&evp))) + if (evp->flags & RQ_ENVELOPE_PENDING) { + rq_envelope_schedule(&ramqueue, evp); + r++; + } + return (r); + } +} + +static int +scheduler_ram_remove(uint64_t evpid) +{ + struct rq_message *msg; + struct rq_envelope *evp; + uint32_t msgid; + void *i; + int r; + + currtime = time(NULL); + + if (evpid > 0xffffffff) { + msgid = evpid_to_msgid(evpid); + if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) + return (0); + if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) + return (0); + if (rq_envelope_remove(&ramqueue, evp)) + return (1); + return (0); + } + else { + msgid = evpid; + if ((msg = tree_get(&ramqueue.messages, msgid)) == NULL) + return (0); + i = NULL; + r = 0; + while (tree_iter(&msg->envelopes, &i, NULL, (void*)(&evp))) + if (rq_envelope_remove(&ramqueue, evp)) + r++; + return (r); + } +} + static void sorted_insert(struct evplist *list, struct rq_envelope *evp) { @@ -591,20 +616,20 @@ rq_envelope_schedule(struct rq_queue *rq, struct rq_envelope *evp) evp->t_scheduled = currtime; } -static void +static int rq_envelope_remove(struct rq_queue *rq, struct rq_envelope *evp) { struct rq_message *m; struct evplist *q = NULL; if (evp->flags & (RQ_ENVELOPE_REMOVED | RQ_ENVELOPE_EXPIRED)) - return; + return (0); /* * For now we just ignore it, but we could mark the envelope for * removal and possibly send a cancellation to the agent. */ if (evp->flags & (RQ_ENVELOPE_INFLIGHT)) - return; + return (0); if (evp->flags & RQ_ENVELOPE_SCHEDULED) { if (evp->type == D_MTA) @@ -639,6 +664,8 @@ rq_envelope_remove(struct rq_queue *rq, struct rq_envelope *evp) } evp->message->q_next = NULL; } + + return (1); } static void diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c index 0874c38b272..92d0c553d36 100644 --- a/usr.sbin/smtpd/smtp.c +++ b/usr.sbin/smtpd/smtp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp.c,v 1.124 2013/03/11 17:40:11 deraadt Exp $ */ +/* $OpenBSD: smtp.c,v 1.125 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <err.h> @@ -354,7 +353,7 @@ static int smtp_enqueue(uid_t *euid) { static struct listener local, *listener = NULL; - char buf[MAXHOSTNAMELEN], *hostname; + char buf[SMTPD_MAXHOSTNAMELEN], *hostname; int fd[2]; if (listener == NULL) { @@ -429,6 +428,7 @@ smtp_accept(int fd, short event, void *p) close(sock); return; } + io_set_blocking(sock, 0); sessions++; stat_increment("smtp.session", 1); diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c index 4f008eaecd8..d9bb2faa10a 100644 --- a/usr.sbin/smtpd/smtp_session.c +++ b/usr.sbin/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.182 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.183 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -22,7 +22,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/uio.h> @@ -78,6 +77,7 @@ enum session_flags { SF_KICK = 0x0020, SF_VERIFIED = 0x0040, SF_MFACONNSENT = 0x0080, + SF_BADINPUT = 0x0100, }; enum message_flags { @@ -107,7 +107,7 @@ struct smtp_session { struct io io; struct listener *listener; struct sockaddr_storage ss; - char hostname[MAXHOSTNAMELEN]; + char hostname[SMTPD_MAXHOSTNAMELEN]; int flags; int phase; @@ -117,7 +117,7 @@ struct smtp_session { char helo[SMTPD_MAXLINESIZE]; char cmd[SMTPD_MAXLINESIZE]; - char username[MAXLOGNAME]; + char username[SMTPD_MAXLOGNAME]; struct envelope evp; @@ -132,6 +132,8 @@ struct smtp_session { size_t datalen; FILE *ofile; + + struct event pause; }; #define ADVERTISE_TLS(s) \ @@ -160,6 +162,8 @@ static void smtp_wait_mfa(struct smtp_session *s, int); static void smtp_free(struct smtp_session *, const char *); static const char *smtp_strstate(int); static int smtp_verify_certificate(struct smtp_session *); +static void smtp_auth_failure_pause(struct smtp_session *); +static void smtp_auth_failure_resume(int, short, void *); static struct { int code; const char *cmd; } commands[] = { { CMD_HELO, "HELO" }, @@ -256,7 +260,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) struct ca_vrfy_resp_msg *resp_ca_vrfy; struct smtp_session *s; void *ssl; - char user[MAXLOGNAME]; + char user[SMTPD_MAXLOGNAME]; struct msg m; const char *line; uint64_t reqid, evpid; @@ -282,13 +286,14 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) m_msg(&m, imsg); m_get_id(&m, &reqid); m_get_int(&m, &status); + m_get_string(&m, &line); m_end(&m); s = tree_xpop(&wait_lka_rcpt, reqid); switch (status) { case LKA_OK: fatalx("unexpected ok"); case LKA_PERMFAIL: - smtp_reply(s, "550 Invalid recipient"); + smtp_reply(s, "%s", line); s->rcptfail += 1; if (s->rcptfail >= SMTP_KICK_RCPTFAIL) { log_info("smtp-in: Ending session %016"PRIx64 @@ -297,9 +302,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) } break; case LKA_TEMPFAIL: - smtp_reply(s, "421 Temporary failure"); - smtp_enter_state(s, STATE_QUIT); - break; + smtp_reply(s, "%s", line); } io_reload(&s->io); return; @@ -340,6 +343,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) smtp_reply(s, "250 Ok"); } else { smtp_reply(s, "421 Temporary Error"); + smtp_enter_state(s, STATE_QUIT); } m_end(&m); io_reload(&s->io); @@ -364,13 +368,15 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) fprintf(s->ofile, "Received: from %s (%s [%s]);\n" - "\tby %s (%s) with %sSMTP id %08x;\n", + "\tby %s (%s) with %sSMTP%s%s id %08x;\n", s->evp.helo, s->hostname, ss_to_text(&s->ss), s->listener->helo[0] ? s->listener->helo : env->sc_hostname, SMTPD_NAME, s->flags & SF_EHLO ? "E" : "", + s->flags & SF_SECURE ? "S" : "", + s->flags & SF_AUTHENTICATED ? "A" : "", evpid_to_msgid(s->evp.id)); if (s->flags & SF_SECURE) { @@ -449,7 +455,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) m_end(&m); s = tree_xpop(&wait_queue_commit, reqid); if (!success) { - m_create(p_mfa, IMSG_MFA_EVENT_ROLLBACK, 0, 0, -1, 8); + m_create(p_mfa, IMSG_MFA_EVENT_ROLLBACK, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); smtp_reply(s, "421 Temporary failure"); @@ -458,7 +464,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) return; } - m_create(p_mfa, IMSG_MFA_EVENT_COMMIT, 0, 0, -1, 16); + m_create(p_mfa, IMSG_MFA_EVENT_COMMIT, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); @@ -502,7 +508,8 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) else if (success == LKA_PERMFAIL) { log_info("smtp-in: Authentication failed for user %s " "on session %016"PRIx64, user, s->id); - smtp_reply(s, "535 Authentication failed"); + smtp_auth_failure_pause(s); + return; } else if (success == LKA_TEMPFAIL) { log_info("smtp-in: Authentication temporarily failed " @@ -511,6 +518,7 @@ smtp_session_imsg(struct mproc *p, struct imsg *imsg) } else fatalx("bad lka response"); + smtp_enter_state(s, STATE_HELO); io_reload(&s->io); return; @@ -645,7 +653,7 @@ smtp_mfa_response(struct smtp_session *s, int status, uint32_t code, return; } - m_create(p_queue, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, 32); + m_create(p_queue, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1); m_add_id(p_queue, s->id); m_close(p_queue); tree_xset(&wait_queue_msg, s->id, s); @@ -667,7 +675,7 @@ smtp_mfa_response(struct smtp_session *s, int status, uint32_t code, return; } - m_create(p_lka, IMSG_LKA_EXPAND_RCPT, 0, 0, -1, MSZ_EVP); + m_create(p_lka, IMSG_LKA_EXPAND_RCPT, 0, 0, -1); m_add_id(p_lka, s->id); m_add_envelope(p_lka, &s->evp); m_close(p_lka); @@ -682,7 +690,7 @@ smtp_mfa_response(struct smtp_session *s, int status, uint32_t code, io_reload(&s->io); return; } - m_create(p_queue, IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1, 16); + m_create(p_queue, IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1); m_add_id(p_queue, s->id); m_add_msgid(p_queue, evpid_to_msgid(s->evp.id)); m_close(p_queue); @@ -756,6 +764,7 @@ smtp_io(struct io *io, int evt) line = iobuf_getline(&s->iobuf, &len); if ((line == NULL && iobuf_len(&s->iobuf) >= SMTPD_MAXLINESIZE) || (line && len >= SMTPD_MAXLINESIZE)) { + s->flags |= SF_BADINPUT; smtp_reply(s, "500 Line too long"); smtp_enter_state(s, STATE_QUIT); io_set_write(io); @@ -787,6 +796,7 @@ smtp_io(struct io *io, int evt) /* Pipelining not supported */ if (iobuf_len(&s->iobuf)) { + s->flags |= SF_BADINPUT; smtp_reply(s, "500 Pipelining not supported"); smtp_enter_state(s, STATE_QUIT); io_set_write(io); @@ -798,7 +808,7 @@ smtp_io(struct io *io, int evt) iobuf_normalize(&s->iobuf); io_set_write(io); - m_create(p_mfa, IMSG_MFA_REQ_EOM, 0, 0, -1, 16); + m_create(p_mfa, IMSG_MFA_REQ_EOM, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); smtp_wait_mfa(s, IMSG_MFA_REQ_EOM); @@ -940,8 +950,7 @@ smtp_command(struct smtp_session *s, char *line) smtp_message_reset(s, 1); - m_create(p_mfa, IMSG_MFA_REQ_HELO, 0, 0, -1, - 32 + strlen(s->helo)); + m_create(p_mfa, IMSG_MFA_REQ_HELO, 0, 0, -1); m_add_id(p_mfa, s->id); m_add_string(p_mfa, s->helo); m_close(p_mfa); @@ -1044,8 +1053,7 @@ smtp_command(struct smtp_session *s, char *line) if (args && smtp_parse_mail_args(s, args) == -1) break; - m_create(p_mfa, IMSG_MFA_REQ_MAIL, 0, 0, -1, - 32 + sizeof(struct mailaddr)); + m_create(p_mfa, IMSG_MFA_REQ_MAIL, 0, 0, -1); m_add_id(p_mfa, s->id); m_add_mailaddr(p_mfa, &s->evp.sender); m_close(p_mfa); @@ -1076,8 +1084,7 @@ smtp_command(struct smtp_session *s, char *line) break; } - m_create(p_mfa, IMSG_MFA_REQ_RCPT, 0, 0, -1, - 32 + sizeof(struct mailaddr)); + m_create(p_mfa, IMSG_MFA_REQ_RCPT, 0, 0, -1); m_add_id(p_mfa, s->id); m_add_mailaddr(p_mfa, &s->evp.rcpt); m_close(p_mfa); @@ -1090,13 +1097,12 @@ smtp_command(struct smtp_session *s, char *line) break; } - m_create(p_mfa, IMSG_MFA_EVENT_RSET, 0, 0, -1, 8); + m_create(p_mfa, IMSG_MFA_EVENT_RSET, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); if (s->evp.id) { - m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1, - 4); + m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1); m_add_msgid(p_queue, evpid_to_msgid(s->evp.id)); m_close(p_queue); } @@ -1116,7 +1122,7 @@ smtp_command(struct smtp_session *s, char *line) break; } - m_create(p_mfa, IMSG_MFA_REQ_DATA, 0, 0, -1, 16); + m_create(p_mfa, IMSG_MFA_REQ_DATA, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); smtp_wait_mfa(s, IMSG_MFA_REQ_DATA); @@ -1187,7 +1193,7 @@ smtp_rfc4954_auth_plain(struct smtp_session *s, char *arg) goto abort; pass++; /* skip NUL */ - m_create(p_lka, IMSG_LKA_AUTHENTICATE, 0, 0, -1, 128); + m_create(p_lka, IMSG_LKA_AUTHENTICATE, 0, 0, -1); m_add_id(p_lka, s->id); m_add_string(p_lka, s->listener->authtable); m_add_string(p_lka, user); @@ -1231,7 +1237,7 @@ smtp_rfc4954_auth_login(struct smtp_session *s, char *arg) if (__b64_pton(arg, (unsigned char *)buf, sizeof(buf)-1) == -1) goto abort; - m_create(p_lka, IMSG_LKA_AUTHENTICATE, 0, 0, -1, 128); + m_create(p_lka, IMSG_LKA_AUTHENTICATE, 0, 0, -1); m_add_id(p_lka, s->id); m_add_string(p_lka, s->listener->authtable); m_add_string(p_lka, s->username); @@ -1293,7 +1299,7 @@ smtp_connected(struct smtp_session *s) return; } - m_create(p_mfa, IMSG_MFA_REQ_CONNECT, 0, 0, -1, 64 + strlen(s->hostname)); + m_create(p_mfa, IMSG_MFA_REQ_CONNECT, 0, 0, -1); m_add_id(p_mfa, s->id); m_add_sockaddr(p_mfa, (struct sockaddr *)&ss); m_add_sockaddr(p_mfa, (struct sockaddr *)&s->ss); @@ -1352,7 +1358,7 @@ smtp_message_end(struct smtp_session *s) s->ofile = NULL; if (s->msgflags & (MF_ERROR_SIZE | MF_ERROR_MFA | MF_ERROR_IO)) { - m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1, 4); + m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1); m_add_msgid(p_queue, evpid_to_msgid(s->evp.id)); m_close(p_queue); if (s->msgflags & MF_ERROR_SIZE) @@ -1364,7 +1370,7 @@ smtp_message_end(struct smtp_session *s) return; } - m_create(p_queue, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, 16); + m_create(p_queue, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1); m_add_id(p_queue, s->id); m_add_msgid(p_queue, evpid_to_msgid(s->evp.id)); m_close(p_queue); @@ -1415,9 +1421,19 @@ smtp_reply(struct smtp_session *s, char *fmt, ...) switch (buf[0]) { case '5': case '4': - strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE | VIS_CSTYLE); - log_info("smtp-in: Failed command on session %016" PRIx64 - ": \"%s\" => %.*s", s->id, tmp, n, buf); + if (s->flags & SF_BADINPUT) { + log_info("smtp-in: Bad input on session %016"PRIx64 + ": %.*s", s->id, n, buf); + } + else if (strstr(s->cmd, "AUTH ") == s->cmd) { + log_info("smtp-in: Failed command on session %016"PRIx64 + ": \"AUTH [...]\" => %.*s", s->id, n, buf); + } + else { + strnvis(tmp, s->cmd, sizeof tmp, VIS_SAFE | VIS_CSTYLE); + log_info("smtp-in: Failed command on session %016"PRIx64 + ": \"%s\" => %.*s", s->id, tmp, n, buf); + } break; } } @@ -1441,13 +1457,13 @@ smtp_free(struct smtp_session *s, const char * reason) fclose(s->ofile); if (s->evp.id) { - m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1, 5); + m_create(p_queue, IMSG_QUEUE_REMOVE_MESSAGE, 0, 0, -1); m_add_msgid(p_queue, evpid_to_msgid(s->evp.id)); m_close(p_queue); } if (s->flags & SF_MFACONNSENT) { - m_create(p_mfa, IMSG_MFA_EVENT_DISCONNECT, 0, 0, -1, 16); + m_create(p_mfa, IMSG_MFA_EVENT_DISCONNECT, 0, 0, -1); m_add_id(p_mfa, s->id); m_close(p_mfa); } @@ -1493,7 +1509,7 @@ smtp_mailaddr(struct mailaddr *maddr, char *line, int mailfrom, char **args) } if (!valid_localpart(maddr->user) || - !valid_localpart(maddr->domain)) { + !valid_domainpart(maddr->domain)) { /* We accept empty sender for MAIL FROM */ if (mailfrom && maddr->user[0] == '\0' && @@ -1569,6 +1585,30 @@ smtp_verify_certificate(struct smtp_session *s) return 1; } +static void +smtp_auth_failure_resume(int fd, short event, void *p) +{ + struct smtp_session *s = p; + + smtp_reply(s, "535 Authentication failed"); + smtp_enter_state(s, STATE_HELO); + io_reload(&s->io); +} + +static void +smtp_auth_failure_pause(struct smtp_session *s) +{ + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = arc4random_uniform(1000000); + log_trace(TRACE_SMTP, "smtp: timing-attack protection triggered, " + "will defer answer for %lu microseconds", tv.tv_usec); + evtimer_set(&s->pause, smtp_auth_failure_resume, s); + evtimer_add(&s->pause, &tv); +} + + #define CASE(x) case x : return #x const char * diff --git a/usr.sbin/smtpd/smtpctl.8 b/usr.sbin/smtpd/smtpctl.8 index d7b2dac6e05..6b107f44e27 100644 --- a/usr.sbin/smtpd/smtpctl.8 +++ b/usr.sbin/smtpd/smtpctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: smtpctl.8,v 1.40 2013/02/14 13:21:16 gilles Exp $ +.\" $OpenBSD: smtpctl.8,v 1.41 2013/05/24 17:03:14 eric Exp $ .\" .\" Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> .\" Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: February 14 2013 $ +.Dd $Mdocdate: May 24 2013 $ .Dt SMTPCTL 8 .Os .Sh NAME @@ -188,7 +188,7 @@ stat .It rules (matched by incoming sessions) .It -imsg-size +mproc .It all .El diff --git a/usr.sbin/smtpd/smtpctl.c b/usr.sbin/smtpd/smtpctl.c index 78aaa26ab12..d0ee54a419e 100644 --- a/usr.sbin/smtpd/smtpctl.c +++ b/usr.sbin/smtpd/smtpctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpctl.c,v 1.103 2013/04/17 15:02:38 deraadt Exp $ */ +/* $OpenBSD: smtpctl.c,v 1.104 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2006 Gilles Chehade <gilles@poolp.org> @@ -25,7 +25,7 @@ #include <sys/queue.h> #include <sys/tree.h> #include <sys/un.h> -#include <sys/param.h> +#include <sys/wait.h> #include <err.h> #include <errno.h> @@ -44,7 +44,7 @@ #include "log.h" #define PATH_CAT "/bin/cat" -#define PATH_GZCAT "/bin/gzcat" +#define PATH_GZCAT "/usr/bin/gzcat" #define PATH_QUEUE "/queue" void usage(void); @@ -237,51 +237,51 @@ main(int argc, char *argv[]) if ((ulval = text_to_evpid(res->data)) == 0) errx(1, "invalid msgid/evpid"); - imsg_compose(ibuf, IMSG_CTL_SCHEDULE, 0, 0, -1, &ulval, + imsg_compose(ibuf, IMSG_CTL_SCHEDULE, IMSG_VERSION, 0, -1, &ulval, sizeof(ulval)); break; case REMOVE: if ((ulval = text_to_evpid(res->data)) == 0) errx(1, "invalid msgid/evpid"); - imsg_compose(ibuf, IMSG_CTL_REMOVE, 0, 0, -1, &ulval, + imsg_compose(ibuf, IMSG_CTL_REMOVE, IMSG_VERSION, 0, -1, &ulval, sizeof(ulval)); break; case SHOW_QUEUE: return action_show_queue(); case SHUTDOWN: - imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, IMSG_VERSION, 0, -1, NULL, 0); break; case PAUSE_MDA: - imsg_compose(ibuf, IMSG_CTL_PAUSE_MDA, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_PAUSE_MDA, IMSG_VERSION, 0, -1, NULL, 0); break; case PAUSE_MTA: - imsg_compose(ibuf, IMSG_CTL_PAUSE_MTA, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_PAUSE_MTA, IMSG_VERSION, 0, -1, NULL, 0); break; case PAUSE_SMTP: - imsg_compose(ibuf, IMSG_CTL_PAUSE_SMTP, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_PAUSE_SMTP, IMSG_VERSION, 0, -1, NULL, 0); break; case RESUME_MDA: - imsg_compose(ibuf, IMSG_CTL_RESUME_MDA, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_RESUME_MDA, IMSG_VERSION, 0, -1, NULL, 0); break; case RESUME_MTA: - imsg_compose(ibuf, IMSG_CTL_RESUME_MTA, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_RESUME_MTA, IMSG_VERSION, 0, -1, NULL, 0); break; case RESUME_SMTP: - imsg_compose(ibuf, IMSG_CTL_RESUME_SMTP, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_CTL_RESUME_SMTP, IMSG_VERSION, 0, -1, NULL, 0); break; case SHOW_STATS: - imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_STATS, IMSG_VERSION, 0, -1, NULL, 0); break; case UPDATE_TABLE: if (strlcpy(name, res->data, sizeof name) >= sizeof name) errx(1, "table name too long."); - imsg_compose(ibuf, IMSG_LKA_UPDATE_TABLE, 0, 0, -1, + imsg_compose(ibuf, IMSG_LKA_UPDATE_TABLE, IMSG_VERSION, 0, -1, name, strlen(name) + 1); done = 1; break; case MONITOR: while (1) { - imsg_compose(ibuf, IMSG_DIGEST, 0, 0, -1, NULL, 0); + imsg_compose(ibuf, IMSG_DIGEST, IMSG_VERSION, 0, -1, NULL, 0); flush(); next_message(&imsg); show_monitor(imsg.data); @@ -290,10 +290,10 @@ main(int argc, char *argv[]) } break; case LOG_VERBOSE: - verb = TRACE_VERBOSE; + verb = TRACE_DEBUG; /* FALLTHROUGH */ case LOG_BRIEF: - imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1, &verb, + imsg_compose(ibuf, IMSG_CTL_VERBOSE, IMSG_VERSION, 0, -1, &verb, sizeof(verb)); printf("logging request sent.\n"); done = 1; @@ -309,11 +309,11 @@ main(int argc, char *argv[]) case LOG_TRACE_LOOKUP: case LOG_TRACE_STAT: case LOG_TRACE_RULES: - case LOG_TRACE_IMSG_SIZE: + case LOG_TRACE_MPROC: case LOG_TRACE_EXPAND: case LOG_TRACE_ALL: verb = trace_convert(action); - imsg_compose(ibuf, IMSG_CTL_TRACE, 0, 0, -1, &verb, + imsg_compose(ibuf, IMSG_CTL_TRACE, IMSG_VERSION, 0, -1, &verb, sizeof(verb)); done = 1; break; @@ -328,11 +328,11 @@ main(int argc, char *argv[]) case LOG_UNTRACE_LOOKUP: case LOG_UNTRACE_STAT: case LOG_UNTRACE_RULES: - case LOG_UNTRACE_IMSG_SIZE: + case LOG_UNTRACE_MPROC: case LOG_UNTRACE_EXPAND: case LOG_UNTRACE_ALL: verb = trace_convert(action); - imsg_compose(ibuf, IMSG_CTL_UNTRACE, 0, 0, -1, &verb, + imsg_compose(ibuf, IMSG_CTL_UNTRACE, IMSG_VERSION, 0, -1, &verb, sizeof(verb)); done = 1; break; @@ -340,7 +340,7 @@ main(int argc, char *argv[]) case LOG_PROFILE_IMSG: case LOG_PROFILE_QUEUE: profile = profile_convert(action); - imsg_compose(ibuf, IMSG_CTL_PROFILE, 0, 0, -1, &profile, + imsg_compose(ibuf, IMSG_CTL_PROFILE, IMSG_VERSION, 0, -1, &profile, sizeof(profile)); done = 1; break; @@ -348,7 +348,7 @@ main(int argc, char *argv[]) case LOG_UNPROFILE_IMSG: case LOG_UNPROFILE_QUEUE: profile = profile_convert(action); - imsg_compose(ibuf, IMSG_CTL_UNPROFILE, 0, 0, -1, &profile, + imsg_compose(ibuf, IMSG_CTL_UNPROFILE, IMSG_VERSION, 0, -1, &profile, sizeof(profile)); done = 1; break; @@ -361,6 +361,12 @@ main(int argc, char *argv[]) flush(); next_message(&imsg); + /* ANY command can return IMSG_CTL_FAIL if version mismatch */ + if (imsg.hdr.type == IMSG_CTL_FAIL) { + show_command_output(&imsg); + break; + } + switch (action) { case REMOVE: case SCHEDULE: @@ -383,7 +389,7 @@ main(int argc, char *argv[]) case LOG_TRACE_LOOKUP: case LOG_TRACE_STAT: case LOG_TRACE_RULES: - case LOG_TRACE_IMSG_SIZE: + case LOG_TRACE_MPROC: case LOG_TRACE_EXPAND: case LOG_TRACE_ALL: case LOG_UNTRACE_IMSG: @@ -396,7 +402,7 @@ main(int argc, char *argv[]) case LOG_UNTRACE_LOOKUP: case LOG_UNTRACE_STAT: case LOG_UNTRACE_RULES: - case LOG_UNTRACE_IMSG_SIZE: + case LOG_UNTRACE_MPROC: case LOG_UNTRACE_EXPAND: case LOG_UNTRACE_ALL: case LOG_PROFILE_IMSG: @@ -440,7 +446,7 @@ action_show_queue_message(uint32_t msgid) nextbatch: found = 0; - imsg_compose(ibuf, IMSG_CTL_LIST_ENVELOPES, 0, 0, -1, + imsg_compose(ibuf, IMSG_CTL_LIST_ENVELOPES, IMSG_VERSION, 0, -1, &evpid, sizeof evpid); flush(); @@ -475,7 +481,7 @@ action_show_queue(void) now = time(NULL); do { - imsg_compose(ibuf, IMSG_CTL_LIST_MESSAGES, 0, 0, -1, + imsg_compose(ibuf, IMSG_CTL_LIST_MESSAGES, IMSG_VERSION, 0, -1, &msgid, sizeof msgid); flush(); next_message(&imsg); @@ -508,7 +514,7 @@ action_schedule_all(void) from = 0; while (1) { - imsg_compose(ibuf, IMSG_CTL_LIST_MESSAGES, 0, 0, -1, + imsg_compose(ibuf, IMSG_CTL_LIST_MESSAGES, IMSG_VERSION, 0, -1, &from, sizeof from); flush(); next_message(&imsg); @@ -521,7 +527,7 @@ action_schedule_all(void) for (i = 0; i < n; i++) { evpid = msgids[i]; - imsg_compose(ibuf, IMSG_CTL_SCHEDULE, 0, + imsg_compose(ibuf, IMSG_CTL_SCHEDULE, IMSG_VERSION, 0, -1, &evpid, sizeof(evpid)); } from = msgids[n - 1] + 1; @@ -551,7 +557,10 @@ show_command_output(struct imsg *imsg) printf("command succeeded\n"); break; case IMSG_CTL_FAIL: - printf("command failed\n"); + if (imsg->hdr.peerid != IMSG_VERSION) + printf("command failed: incompatible smtpctl and smtpd\n"); + else + printf("command failed\n"); break; default: errx(1, "wrong message in summary: %u", imsg->hdr.type); @@ -569,7 +578,7 @@ show_stats_output(void) bzero(&kv, sizeof kv); while (1) { - imsg_compose(ibuf, IMSG_STATS_GET, 0, 0, -1, &kv, sizeof kv); + imsg_compose(ibuf, IMSG_STATS_GET, IMSG_VERSION, 0, -1, &kv, sizeof kv); flush(); next_message(&imsg); if (imsg.hdr.type != IMSG_STATS_GET) @@ -583,7 +592,7 @@ show_stats_output(void) if (strcmp(kvp->key, "uptime") == 0) { duration = time(NULL) - kvp->val.u.counter; - printf("uptime=%lld\n", (long long)duration); + printf("uptime=%zd\n", (size_t)duration); printf("uptime.human=%s\n", duration_to_text(duration)); } @@ -598,8 +607,8 @@ show_stats_output(void) kvp->key, (int64_t)kvp->val.u.timestamp); break; case STAT_TIMEVAL: - printf("%s=%lld.%ld\n", - kvp->key, (long long)kvp->val.u.tv.tv_sec, + printf("%s=%zd.%zd\n", + kvp->key, kvp->val.u.tv.tv_sec, kvp->val.u.tv.tv_usec); break; case STAT_TIMESPEC: @@ -717,25 +726,37 @@ getflag(uint *bitmap, int bit, char *bitstr, char *buf, size_t len) static void display(const char *s) { + pid_t pid; arglist args; char *cmd; + int status; - if (env->sc_queue_flags & QUEUE_COMPRESS) + pid = fork(); + if (pid < 0) + err(1, "fork"); + if (pid == 0) { cmd = PATH_GZCAT; - else - cmd = PATH_CAT; - + bzero(&args, sizeof(args)); + addargs(&args, "%s", cmd); + addargs(&args, "%s", s); + execvp(cmd, args.list); + err(1, "execvp"); + } + wait(&status); + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + exit(0); + cmd = PATH_CAT; bzero(&args, sizeof(args)); addargs(&args, "%s", cmd); addargs(&args, "%s", s); execvp(cmd, args.list); - errx(1, "execvp"); + err(1, "execvp"); } static void show_envelope(const char *s) { - char buf[MAXPATHLEN]; + char buf[SMTPD_MAXPATHLEN]; uint64_t evpid; if ((evpid = text_to_evpid(s)) == 0) @@ -755,7 +776,7 @@ show_envelope(const char *s) static void show_message(const char *s) { - char buf[MAXPATHLEN]; + char buf[SMTPD_MAXPATHLEN]; uint32_t msgid; uint64_t evpid; @@ -764,10 +785,10 @@ show_message(const char *s) msgid = evpid_to_msgid(evpid); if (! bsnprintf(buf, sizeof(buf), "%s%s/%02x/%08x/message", - PATH_SPOOL, - PATH_QUEUE, - msgid & 0xff, - msgid)) + PATH_SPOOL, + PATH_QUEUE, + (evpid_to_msgid(evpid) & 0xff000000) >> 24, + msgid)) errx(1, "unable to retrieve message"); display(buf); @@ -866,9 +887,9 @@ trace_convert(uint32_t trace) case LOG_UNTRACE_RULES: return TRACE_RULES; - case LOG_TRACE_IMSG_SIZE: - case LOG_UNTRACE_IMSG_SIZE: - return TRACE_IMSGSIZE; + case LOG_TRACE_MPROC: + case LOG_UNTRACE_MPROC: + return TRACE_MPROC; case LOG_TRACE_EXPAND: case LOG_UNTRACE_EXPAND: @@ -876,7 +897,7 @@ trace_convert(uint32_t trace) case LOG_TRACE_ALL: case LOG_UNTRACE_ALL: - return ~TRACE_VERBOSE; + return ~TRACE_DEBUG; } return 0; diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile index 44f4fe17314..e61249f252a 100644 --- a/usr.sbin/smtpd/smtpctl/Makefile +++ b/usr.sbin/smtpd/smtpctl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.30 2013/01/26 09:37:24 gilles Exp $ +# $OpenBSD: Makefile,v 1.31 2013/05/24 17:03:14 eric Exp $ .PATH: ${.CURDIR}/.. diff --git a/usr.sbin/smtpd/smtpd-api.h b/usr.sbin/smtpd/smtpd-api.h index ac43bc095d8..579b3f2e001 100644 --- a/usr.sbin/smtpd/smtpd-api.h +++ b/usr.sbin/smtpd/smtpd-api.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd-api.h,v 1.3 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: smtpd-api.h,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -28,17 +28,23 @@ #define FILTER_API_VERSION 50 -#define SMTPD_MAXLINESIZE 2048 -#define MAX_LOCALPART_SIZE (64 + 1) -#define MAX_DOMAINPART_SIZE (255 + 1) - struct mailaddr { - char user[MAX_LOCALPART_SIZE]; - char domain[MAX_DOMAINPART_SIZE]; + char user[SMTPD_MAXLOCALPARTSIZE]; + char domain[SMTPD_MAXDOMAINPARTSIZE]; }; -SPLAY_HEAD(dict, dictentry); -SPLAY_HEAD(tree, treeentry); +SPLAY_HEAD(_dict, dictentry); +SPLAY_HEAD(_tree, treeentry); + +struct tree { + struct _tree tree; + size_t count; +}; + +struct dict { + struct _dict dict; + size_t count; +}; enum filter_status { FILTER_OK, @@ -81,8 +87,9 @@ struct filter_connect { }; /* dict.c */ -#define dict_init(d) SPLAY_INIT((d)) -#define dict_empty(d) SPLAY_EMPTY((d)) +#define dict_init(d) do { SPLAY_INIT(&((d)->dict)); (d)->count = 0; } while(0) +#define dict_empty(d) SPLAY_EMPTY(&((d)->dict)) +#define dict_count(d) ((d)->count) int dict_check(struct dict *, const char *); void *dict_set(struct dict *, const char *, void *); void dict_xset(struct dict *, const char *, void *); @@ -116,8 +123,9 @@ void filter_api_on_eom(void(*)(uint64_t, uint64_t)); void filter_api_on_event(void(*)(uint64_t, enum filter_hook)); /* tree.c */ -#define tree_init(t) SPLAY_INIT((t)) -#define tree_empty(t) SPLAY_EMPTY((t)) +#define tree_init(t) do { SPLAY_INIT(&((t)->tree)); (t)->count = 0; } while(0) +#define tree_empty(t) SPLAY_EMPTY(&((t)->tree)) +#define tree_count(t) ((t)->count) int tree_check(struct tree *, uint64_t); void *tree_set(struct tree *, uint64_t, void *); void tree_xset(struct tree *, uint64_t, void *); diff --git a/usr.sbin/smtpd/smtpd-defines.h b/usr.sbin/smtpd/smtpd-defines.h new file mode 100644 index 00000000000..c0c78f4bc51 --- /dev/null +++ b/usr.sbin/smtpd/smtpd-defines.h @@ -0,0 +1,29 @@ +/* $OpenBSD: smtpd-defines.h,v 1.1 2013/05/24 17:03:14 eric Exp $ */ + +/* + * Copyright (c) 2013 Gilles Chehade <gilles@poolp.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +#define SMTPD_MAXLOCALPARTSIZE (255 + 1) +#define SMTPD_MAXDOMAINPARTSIZE (255 + 1) + +#define SMTPD_MAXLOGNAME 32 +#define SMTPD_MAXPATHLEN 1024 +#define SMTPD_MAXHOSTNAMELEN 256 +#define SMTPD_MAXLINESIZE 2048 diff --git a/usr.sbin/smtpd/smtpd.8 b/usr.sbin/smtpd/smtpd.8 index bfbdfeb8052..37b46237f42 100644 --- a/usr.sbin/smtpd/smtpd.8 +++ b/usr.sbin/smtpd/smtpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: smtpd.8,v 1.21 2013/05/08 14:22:38 jmc Exp $ +.\" $OpenBSD: smtpd.8,v 1.22 2013/05/24 17:03:14 eric Exp $ .\" .\" Copyright (c) 2012, Eric Faurot <eric@openbsd.org> .\" Copyright (c) 2008, Gilles Chehade <gilles@poolp.org> @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 8 2013 $ +.Dd $Mdocdate: May 24 2013 $ .Dt SMTPD 8 .Os .Sh NAME diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c index 0788c81c6d8..7599f2bf298 100644 --- a/usr.sbin/smtpd/smtpd.c +++ b/usr.sbin/smtpd/smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.c,v 1.190 2013/04/17 15:02:38 deraadt Exp $ */ +/* $OpenBSD: smtpd.c,v 1.191 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/stat.h> @@ -75,6 +74,7 @@ static int offline_enqueue(char *); static void purge_task(int, short, void *); static void log_imsg(int, int, struct imsg *); static int parent_auth_user(const char *, const char *); +static void load_ssl_trees(void); enum child_type { CHILD_DAEMON, @@ -102,6 +102,7 @@ struct offline { static size_t offline_running = 0; TAILQ_HEAD(, offline) offline_q; +static struct event config_ev; static struct event offline_ev; static struct timeval offline_timeout; @@ -133,6 +134,7 @@ const char *backend_stat = "ram"; int profiling = 0; int verbose = 0; int debug = 0; +int foreground = 0; struct tree children; @@ -150,14 +152,6 @@ parent_imsg(struct mproc *p, struct imsg *imsg) void *i; int fd, n, v, ret; - if (p->proc == PROC_SMTP) { - switch (imsg->hdr.type) { - case IMSG_PARENT_SEND_CONFIG: - parent_send_config_smtp(); - return; - } - } - if (p->proc == PROC_LKA) { switch (imsg->hdr.type) { case IMSG_PARENT_FORWARD_OPEN: @@ -188,7 +182,7 @@ parent_imsg(struct mproc *p, struct imsg *imsg) ret = parent_auth_user(username, password); - m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1, 128); + m_create(p, IMSG_LKA_AUTHENTICATE, 0, 0, -1); m_add_id(p, reqid); m_add_int(p, ret); m_close(p); @@ -222,13 +216,13 @@ parent_imsg(struct mproc *p, struct imsg *imsg) c->cause == NULL) break; if (!n) { - log_debug("debug: smptd: " + log_debug("debug: smtpd: " "kill request: proc not found"); return; } c->cause = xstrdup(cause, "parent_imsg"); - log_debug("debug: smptd: kill requested for %u: %s", + log_debug("debug: smtpd: kill requested for %u: %s", c->pid, c->cause); kill(c->pid, SIGTERM); return; @@ -426,7 +420,7 @@ parent_send_config_lka() } iter_tree = NULL; - while (tree_iter(env->sc_tables_tree, &iter_tree, NULL, + while (dict_iter(env->sc_tables_dict, &iter_tree, NULL, (void **)&t)) { m_compose(p_lka, IMSG_CONF_TABLE, 0, 0, -1, t, sizeof(*t)); @@ -547,7 +541,7 @@ parent_sig_handler(int sig, short event, void *p) "for session %016"PRIx64 ": %s", child->mda_id, cause); m_create(p_mda, IMSG_MDA_DONE, 0, 0, - child->mda_out, 32 + strlen(cause)); + child->mda_out); m_add_id(p_mda, child->mda_id); m_add_string(p_mda, cause); m_close(p_mda); @@ -595,9 +589,6 @@ main(int argc, char *argv[]) struct event ev_sighup; struct timeval tv; struct passwd *pwq; - struct listener *l; - struct rule *r; - struct ssl *ssl; env = &smtpd; @@ -625,8 +616,7 @@ main(int argc, char *argv[]) optarg); break; case 'd': - debug = 2; - verbose |= TRACE_VERBOSE; + foreground = 1; break; case 'D': if (cmdline_symset(optarg) < 0) @@ -662,12 +652,16 @@ main(int argc, char *argv[]) verbose |= TRACE_STAT; else if (!strcmp(optarg, "rules")) verbose |= TRACE_RULES; - else if (!strcmp(optarg, "imsg-size")) - verbose |= TRACE_IMSGSIZE; + else if (!strcmp(optarg, "mproc")) + verbose |= TRACE_MPROC; else if (!strcmp(optarg, "expand")) verbose |= TRACE_EXPAND; + else if (!strcmp(optarg, "tables")) + verbose |= TRACE_TABLES; + else if (!strcmp(optarg, "queue")) + verbose |= TRACE_QUEUE; else if (!strcmp(optarg, "all")) - verbose |= ~TRACE_VERBOSE; + verbose |= ~TRACE_DEBUG; else if (!strcmp(optarg, "profstat")) profiling |= PROFILE_TOSTAT; else if (!strcmp(optarg, "profile-imsg")) @@ -687,16 +681,13 @@ main(int argc, char *argv[]) flags |= SMTPD_MDA_PAUSED; break; case 'v': - verbose |= TRACE_VERBOSE; + verbose |= TRACE_DEBUG; break; default: usage(); } } - if (!(verbose & TRACE_VERBOSE)) - verbose = 0; - argv += optind; argc -= optind; @@ -708,10 +699,12 @@ main(int argc, char *argv[]) if (parse_config(&smtpd, conffile, opts)) exit(1); - if (strlcpy(env->sc_conffile, conffile, MAXPATHLEN) >= MAXPATHLEN) - errx(1, "config file exceeds MAXPATHLEN"); + if (strlcpy(env->sc_conffile, conffile, SMTPD_MAXPATHLEN) + >= SMTPD_MAXPATHLEN) + errx(1, "config file exceeds SMTPD_MAXPATHLEN"); if (env->sc_opts & SMTPD_OPT_NOACTION) { + load_ssl_trees(); fprintf(stderr, "configuration OK\n"); exit(0); } @@ -756,12 +749,15 @@ main(int argc, char *argv[]) if (env->sc_stat == NULL) errx(1, "could not find stat backend \"%s\"", backend_stat); - log_init(debug); + if (env->sc_queue_flags & QUEUE_COMPRESSION) + env->sc_comp = compress_backend_lookup("gzip"); + + log_init(foreground); log_verbose(verbose); log_info("info: %s %s starting", SMTPD_NAME, SMTPD_VERSION); - if (!debug) + if (! foreground) if (daemon(0, 0) == -1) err(1, "failed to daemonize"); @@ -775,35 +771,13 @@ main(int argc, char *argv[]) log_debug("debug: using \"%s\" queue backend", backend_queue); log_debug("debug: using \"%s\" scheduler backend", backend_scheduler); log_debug("debug: using \"%s\" stat backend", backend_stat); - log_info("info: startup%s", (debug > 1)?" [debug mode]":""); + log_info("info: startup%s", (verbose & TRACE_DEBUG)?" [debug mode]":""); if (env->sc_hostname[0] == '\0') errx(1, "machine does not have a hostname set"); env->sc_uptime = time(NULL); - log_debug("debug: init server-ssl tree"); - TAILQ_FOREACH(l, env->sc_listeners, entry) { - if (!(l->flags & F_SSL)) - continue; - ssl = NULL; - if (! ssl_load_certfile(&ssl, "/etc/mail/certs", - l->ssl_cert_name, F_SCERT)) - errx(1, "cannot load certificate: %s", l->ssl_cert_name); - dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl); - } - - log_debug("debug: init client-ssl tree"); - TAILQ_FOREACH(r, env->sc_rules, r_entry) { - if (r->r_action != A_RELAY && r->r_action != A_RELAYVIA) - continue; - if (! r->r_value.relayhost.cert[0]) - continue; - ssl = NULL; - if (! ssl_load_certfile(&ssl, "/etc/mail/certs", - r->r_value.relayhost.cert, F_CCERT)) - errx(1, "cannot load certificate: %s", r->r_value.relayhost.cert); - dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl); - } + load_ssl_trees(); fork_peers(); @@ -831,9 +805,9 @@ main(int argc, char *argv[]) config_peer(PROC_QUEUE); config_done(); - evtimer_set(&env->sc_ev, parent_send_config, NULL); + evtimer_set(&config_ev, parent_send_config, NULL); bzero(&tv, sizeof(tv)); - evtimer_add(&env->sc_ev, &tv); + evtimer_add(&config_ev, &tv); /* defer offline scanning for a second */ evtimer_set(&offline_ev, offline_scan, NULL); @@ -854,6 +828,40 @@ main(int argc, char *argv[]) } static void +load_ssl_trees(void) +{ + struct listener *l; + struct ssl *ssl; + struct rule *r; + + log_debug("debug: init server-ssl tree"); + TAILQ_FOREACH(l, env->sc_listeners, entry) { + if (!(l->flags & F_SSL)) + continue; + ssl = NULL; + if (! ssl_load_certfile(&ssl, "/etc/mail/certs", + l->ssl_cert_name, F_SCERT)) + errx(1, "cannot load certificate: %s", + l->ssl_cert_name); + dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl); + } + + log_debug("debug: init client-ssl tree"); + TAILQ_FOREACH(r, env->sc_rules, r_entry) { + if (r->r_action != A_RELAY && r->r_action != A_RELAYVIA) + continue; + if (! r->r_value.relayhost.cert[0]) + continue; + ssl = NULL; + if (! ssl_load_certfile(&ssl, "/etc/mail/certs", + r->r_value.relayhost.cert, F_CCERT)) + errx(1, "cannot load certificate: %s", + r->r_value.relayhost.cert); + dict_set(env->sc_ssl_dict, ssl->ssl_name, ssl); + } +} + +static void fork_peers(void) { tree_init(&children); @@ -968,7 +976,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) if (deliver->userinfo.uid == 0 && ! db->allow_root) { snprintf(ebuf, sizeof ebuf, "not allowed to deliver to: %s", deliver->user); - m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1, 128); + m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1); m_add_id(p_mda, id); m_add_string(p_mda, ebuf); m_close(p_mda); @@ -983,7 +991,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) n = snprintf(ebuf, sizeof ebuf, "pipe: %s", strerror(errno)); if (seteuid(0) < 0) fatal("smtpd: forkmda: cannot restore privileges"); - m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1, 128); + m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1); m_add_id(p_mda, id); m_add_string(p_mda, ebuf); m_close(p_mda); @@ -999,7 +1007,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) n = snprintf(ebuf, sizeof ebuf, "mkstemp: %s", strerror(errno)); if (seteuid(0) < 0) fatal("smtpd: forkmda: cannot restore privileges"); - m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1, 128); + m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1); m_add_id(p_mda, id); m_add_string(p_mda, ebuf); m_close(p_mda); @@ -1014,7 +1022,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) n = snprintf(ebuf, sizeof ebuf, "fork: %s", strerror(errno)); if (seteuid(0) < 0) fatal("smtpd: forkmda: cannot restore privileges"); - m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1, 128); + m_create(p_mda, IMSG_MDA_DONE, 0, 0, -1); m_add_id(p_mda, id); m_add_string(p_mda, ebuf); m_close(p_mda); @@ -1032,7 +1040,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) child->mda_out = allout; child->mda_id = id; close(pipefd[0]); - m_create(p, IMSG_PARENT_FORK_MDA, 0, 0, pipefd[1], 9); + m_create(p, IMSG_PARENT_FORK_MDA, 0, 0, pipefd[1]); m_add_id(p, id); m_close(p); return; @@ -1110,7 +1118,7 @@ offline_scan(int fd, short ev, void *arg) static int offline_enqueue(char *name) { - char t[MAXPATHLEN], *path; + char t[SMTPD_MAXPATHLEN], *path; struct stat sb; pid_t pid; struct child *child; @@ -1250,7 +1258,7 @@ offline_done(void) static int parent_forward_open(char *username, char *directory, uid_t uid, gid_t gid) { - char pathname[MAXPATHLEN]; + char pathname[SMTPD_MAXPATHLEN]; int fd; if (! bsnprintf(pathname, sizeof (pathname), "%s/.forward", @@ -1286,7 +1294,6 @@ imsg_dispatch(struct mproc *p, struct imsg *imsg) struct timespec t0, t1, dt; if (imsg == NULL) { - log_warnx("warn: pipe error with %s", p->name); exit(1); return; } @@ -1302,12 +1309,12 @@ imsg_dispatch(struct mproc *p, struct imsg *imsg) clock_gettime(CLOCK_MONOTONIC, &t1); timespecsub(&t1, &t0, &dt); - log_debug("profile-imsg: %s %s %s %i %lld.%06li", + log_debug("profile-imsg: %s %s %s %i %li.%06li", proc_name(smtpd_process), proc_name(p->proc), imsg_to_str(imsg->hdr.type), (int)imsg->hdr.len, - (long long)dt.tv_sec * 1000000 + dt.tv_nsec / 1000000, + dt.tv_sec * 1000000 + dt.tv_nsec / 1000000, dt.tv_nsec % 1000000); if (profiling & PROFILE_TOSTAT) { @@ -1352,24 +1359,24 @@ const char * proc_title(enum smtp_proc_type proc) { switch (proc) { - case PROC_CONTROL: - return "control"; + case PROC_PARENT: + return "[priv]"; + case PROC_SMTP: + return "smtp"; + case PROC_MFA: + return "filter"; case PROC_LKA: return "lookup"; + case PROC_QUEUE: + return "queue"; case PROC_MDA: return "delivery"; - case PROC_MFA: - return "filter"; case PROC_MTA: return "transfer"; - case PROC_PARENT: - return "[priv]"; - case PROC_QUEUE: - return "queue"; + case PROC_CONTROL: + return "control"; case PROC_SCHEDULER: return "scheduler"; - case PROC_SMTP: - return "smtp"; default: return "unknown"; } @@ -1397,6 +1404,11 @@ proc_name(enum smtp_proc_type proc) return "control"; case PROC_SCHEDULER: return "scheduler"; + + case PROC_FILTER: + return "filter-proc"; + case PROC_CLIENT: + return "client-proc"; default: return "unknown"; } @@ -1498,7 +1510,6 @@ imsg_to_str(int type) CASE(IMSG_PARENT_FORWARD_OPEN); CASE(IMSG_PARENT_FORK_MDA); CASE(IMSG_PARENT_KILL_MDA); - CASE(IMSG_PARENT_SEND_CONFIG); CASE(IMSG_SMTP_ENQUEUE_FD); @@ -1526,7 +1537,7 @@ imsg_to_str(int type) int parent_auth_user(const char *username, const char *password) { - char user[MAXLOGNAME]; + char user[SMTPD_MAXLOGNAME]; char pass[SMTPD_MAXLINESIZE]; int ret; @@ -1542,27 +1553,27 @@ parent_auth_user(const char *username, const char *password) static void parent_broadcast_verbose(uint32_t v) { - m_create(p_lka, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_lka, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_lka, v); m_close(p_lka); - m_create(p_mda, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_mda, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_mda, v); m_close(p_mda); - m_create(p_mfa, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_mfa, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_mfa, v); m_close(p_mfa); - m_create(p_mta, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_mta, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_mta, v); m_close(p_mta); - m_create(p_queue, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_queue, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_queue, v); m_close(p_queue); - m_create(p_smtp, IMSG_CTL_VERBOSE, 0, 0, -1, sizeof v); + m_create(p_smtp, IMSG_CTL_VERBOSE, 0, 0, -1); m_add_int(p_smtp, v); m_close(p_smtp); } @@ -1570,27 +1581,27 @@ parent_broadcast_verbose(uint32_t v) static void parent_broadcast_profile(uint32_t v) { - m_create(p_lka, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_lka, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_lka, v); m_close(p_lka); - m_create(p_mda, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_mda, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_mda, v); m_close(p_mda); - m_create(p_mfa, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_mfa, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_mfa, v); m_close(p_mfa); - m_create(p_mta, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_mta, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_mta, v); m_close(p_mta); - m_create(p_queue, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_queue, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_queue, v); m_close(p_queue); - m_create(p_smtp, IMSG_CTL_PROFILE, 0, 0, -1, sizeof v); + m_create(p_smtp, IMSG_CTL_PROFILE, 0, 0, -1); m_add_int(p_smtp, v); m_close(p_smtp); } diff --git a/usr.sbin/smtpd/smtpd.conf.5 b/usr.sbin/smtpd/smtpd.conf.5 index 20f2272646d..0b0a7404298 100644 --- a/usr.sbin/smtpd/smtpd.conf.5 +++ b/usr.sbin/smtpd/smtpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: smtpd.conf.5,v 1.92 2013/02/17 17:45:01 jmc Exp $ +.\" $OpenBSD: smtpd.conf.5,v 1.93 2013/05/24 17:03:14 eric Exp $ .\" .\" Copyright (c) 2008 Janne Johansson <jj@openbsd.org> .\" Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -17,7 +17,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" -.Dd $Mdocdate: February 17 2013 $ +.Dd $Mdocdate: May 24 2013 $ .Dt SMTPD.CONF 5 .Os .Sh NAME @@ -241,6 +241,12 @@ function. .Pp Finally, the method of delivery is specified: .Bl -tag -width Ds +.It Ic deliver to lmtp Ar [host:port|socket] +Mail is delivered to +.Pa host:port +or to the unix socket +.Pa socket +over LMTP. .It Ic deliver to maildir Ar path Mail is added to a maildir. Its location, @@ -525,6 +531,14 @@ bytes. The argument may contain a multiplier, as documented in .Xr scan_scaled 3 . The default maximum message size is 35MB if none is specified. +.It Ic queue compression +Enable transparent compression of envelopes and messages. +The only supported algorithm at the moment is gzip. +Envelopes and messages may be inspected using the +.Xr smtpctl 8 +or +.Xr gzcat 1 +utilities. .It Ic table Ar name Oo Ar type : Oc Ns Ar config Tables are used to provide additional configuration information for .Xr smtpd 8 diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index dd013c10ea0..5b05e52d6c8 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.409 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: smtpd.h,v 1.410 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -22,11 +22,13 @@ #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif +#include "smtpd-defines.h" #include "smtpd-api.h" #include "ioev.h" #include "iobuf.h" #define CONF_FILE "/etc/mail/smtpd.conf" +#define CA_FILE "/etc/ssl/cert.pem" #define MAX_LISTEN 16 #define PROC_COUNT 10 #define MAX_NAME_SIZE 64 @@ -40,8 +42,7 @@ /* return and forward path size */ #define MAX_FILTER_NAME 32 -#define MAX_PATH_SIZE 256 -/*#define MAX_RULEBUFFER_LEN 512*/ + #define EXPAND_BUFFER 1024 #define SMTPD_QUEUE_INTERVAL (15 * 60) @@ -54,7 +55,7 @@ #ifndef SMTPD_NAME #define SMTPD_NAME "OpenSMTPD" #endif -#define SMTPD_VERSION "5.3" +#define SMTPD_VERSION "5.3.2" #define SMTPD_BANNER "220 %s ESMTP %s" #define SMTPD_SESSION_TIMEOUT 300 #define SMTPD_BACKLOG 5 @@ -70,16 +71,6 @@ #define PATH_FILTERS "/usr/libexec/smtpd" - -/* number of MX records to lookup */ -#define MAX_MX_COUNT 10 - -/* max response delay under flood conditions */ -#define MAX_RESPONSE_DELAY 60 - -/* how many responses per state are undelayed */ -#define FAST_RESPONSES 2 - #define F_STARTTLS 0x01 #define F_SMTPS 0x02 #define F_TLS_OPTIONAL 0x04 @@ -103,11 +94,9 @@ #define RELAY_MX 0x20 #define RELAY_LMTP 0x80 -typedef uint32_t objid_t; - struct userinfo { - char username[MAXLOGNAME]; - char directory[MAXPATHLEN]; + char username[SMTPD_MAXLOGNAME]; + char directory[SMTPD_MAXPATHLEN]; uid_t uid; gid_t gid; }; @@ -117,20 +106,15 @@ struct netaddr { int bits; }; -union sockaddr_any { - struct in6_addr in6; - struct in_addr in4; -}; - struct relayhost { uint8_t flags; - char hostname[MAXHOSTNAMELEN]; + char hostname[SMTPD_MAXHOSTNAMELEN]; uint16_t port; - char cert[PATH_MAX]; - char authtable[MAX_PATH_SIZE]; - char authlabel[MAX_PATH_SIZE]; - char sourcetable[MAX_PATH_SIZE]; - char helotable[MAX_PATH_SIZE]; + char cert[SMTPD_MAXPATHLEN]; + char authtable[SMTPD_MAXPATHLEN]; + char authlabel[SMTPD_MAXPATHLEN]; + char sourcetable[SMTPD_MAXPATHLEN]; + char helotable[SMTPD_MAXPATHLEN]; }; struct credentials { @@ -139,18 +123,36 @@ struct credentials { }; struct destination { - char name[MAXHOSTNAMELEN]; + char name[SMTPD_MAXHOSTNAMELEN]; }; struct source { - union sockaddr_any addr; + struct sockaddr_storage addr; }; struct addrname { - union sockaddr_any addr; - char name[MAXHOSTNAMELEN]; + struct sockaddr_storage addr; + char name[SMTPD_MAXHOSTNAMELEN]; }; +union lookup { + struct expand *expand; + struct credentials creds; + struct netaddr netaddr; + struct source source; + struct destination domain; + struct userinfo userinfo; + struct mailaddr mailaddr; + struct addrname addrname; +}; + +/* XXX */ +/* + * Bump IMSG_VERSION whenever a change is made to enum imsg_type. + * This will ensure that we can never use a wrong version of smtpctl with smtpd. + */ +#define IMSG_VERSION 2 + enum imsg_type { IMSG_NONE, IMSG_CTL_OK, /* answer to smtpctl requests */ @@ -240,7 +242,6 @@ enum imsg_type { IMSG_PARENT_FORWARD_OPEN, IMSG_PARENT_FORK_MDA, IMSG_PARENT_KILL_MDA, - IMSG_PARENT_SEND_CONFIG, IMSG_SMTP_ENQUEUE_FD, @@ -274,6 +275,9 @@ enum smtp_proc_type { PROC_MTA, PROC_CONTROL, PROC_SCHEDULER, + + PROC_FILTER, + PROC_CLIENT, }; enum table_type { @@ -297,28 +301,24 @@ enum table_service { struct table { char t_name[SMTPD_MAXLINESIZE]; - objid_t t_id; enum table_type t_type; - char t_src[MAX_TABLE_BACKEND_SIZE]; - char t_config[MAXPATHLEN]; + char t_config[SMTPD_MAXPATHLEN]; struct dict t_dict; void *t_handle; struct table_backend *t_backend; - void *t_payload; void *t_iter; - char t_cfgtable[MAXPATHLEN]; }; struct table_backend { const unsigned int services; - int (*config)(struct table *, const char *); - void *(*open)(struct table *); + int (*config)(struct table *); + void *(*open)(struct table *); int (*update)(struct table *); void (*close)(void *); - int (*lookup)(void *, const char *, enum table_service, void **); - int (*fetch)(void *, enum table_service, char **); + int (*lookup)(void *, const char *, enum table_service, union lookup *); + int (*fetch)(void *, enum table_service, union lookup *); }; @@ -333,7 +333,8 @@ enum action_type { A_MAILDIR, A_MBOX, A_FILENAME, - A_MDA + A_MDA, + A_LMTP }; enum decision { @@ -371,8 +372,8 @@ enum delivery_type { struct delivery_mda { enum action_type method; - char usertable[MAX_PATH_SIZE]; - char username[MAXLOGNAME]; + char usertable[SMTPD_MAXPATHLEN]; + char username[SMTPD_MAXLOGNAME]; char buffer[EXPAND_BUFFER]; }; @@ -397,7 +398,8 @@ enum expand_type { EXPAND_FILENAME, EXPAND_FILTER, EXPAND_INCLUDE, - EXPAND_ADDRESS + EXPAND_ADDRESS, + EXPAND_ERROR }; struct expandnode { @@ -416,7 +418,7 @@ struct expandnode { * user field handles both expansion user and system user * so we MUST make it large enough to fit a mailaddr user */ - char user[MAX_LOCALPART_SIZE]; + char user[SMTPD_MAXLOCALPARTSIZE]; char buffer[EXPAND_BUFFER]; struct mailaddr mailaddr; } u; @@ -452,8 +454,8 @@ struct envelope { uint64_t id; enum envelope_flags flags; - char helo[MAXHOSTNAMELEN]; - char hostname[MAXHOSTNAMELEN]; + char helo[SMTPD_MAXHOSTNAMELEN]; + char hostname[SMTPD_MAXHOSTNAMELEN]; char errorline[SMTPD_MAXLINESIZE]; struct sockaddr_storage ss; @@ -515,17 +517,17 @@ struct listener { in_port_t port; struct timeval timeout; struct event ev; - char ssl_cert_name[PATH_MAX]; + char ssl_cert_name[SMTPD_MAXPATHLEN]; struct ssl *ssl; void *ssl_ctx; char tag[MAX_TAG_SIZE]; char authtable[SMTPD_MAXLINESIZE]; - char helo[MAXHOSTNAMELEN]; + char helo[SMTPD_MAXHOSTNAMELEN]; TAILQ_ENTRY(listener) entry; }; struct smtpd { - char sc_conffile[MAXPATHLEN]; + char sc_conffile[SMTPD_MAXPATHLEN]; size_t sc_maxsize; pid_t sc_pid; @@ -533,6 +535,7 @@ struct smtpd { #define SMTPD_OPT_VERBOSE 0x00000001 #define SMTPD_OPT_NOACTION 0x00000002 uint32_t sc_opts; + #define SMTPD_CONFIGURING 0x00000001 #define SMTPD_EXITING 0x00000002 #define SMTPD_MDA_PAUSED 0x00000004 @@ -543,18 +546,18 @@ struct smtpd { #define SMTPD_BOUNCE_BUSY 0x00000080 #define SMTPD_SMTP_DISABLED 0x00000100 uint32_t sc_flags; + +#define QUEUE_COMPRESSION 0x00000001 uint32_t sc_queue_flags; -#define QUEUE_COMPRESS 0x00000001 - char *sc_queue_compress_algo; + int sc_qexpire; #define MAX_BOUNCE_WARN 4 time_t sc_bounce_warn[MAX_BOUNCE_WARN]; - struct event sc_ev; struct passwd *sc_pw; struct passwd *sc_pwqueue; - char sc_hostname[MAXHOSTNAMELEN]; - struct scheduler_backend *sc_scheduler; + char sc_hostname[SMTPD_MAXHOSTNAMELEN]; struct stat_backend *sc_stat; + struct compress_backend *sc_comp; time_t sc_uptime; @@ -565,13 +568,12 @@ struct smtpd { struct dict *sc_ssl_dict; struct dict *sc_tables_dict; /* keyed lookup */ - struct tree *sc_tables_tree; /* id lookup */ struct dict sc_filters; uint32_t filtermask; }; -#define TRACE_VERBOSE 0x0001 +#define TRACE_DEBUG 0x0001 #define TRACE_IMSG 0x0002 #define TRACE_IO 0x0004 #define TRACE_SMTP 0x0008 @@ -582,8 +584,10 @@ struct smtpd { #define TRACE_LOOKUP 0x0100 #define TRACE_STAT 0x0200 #define TRACE_RULES 0x0400 -#define TRACE_IMSGSIZE 0x0800 +#define TRACE_MPROC 0x0800 #define TRACE_EXPAND 0x1000 +#define TRACE_TABLES 0x2000 +#define TRACE_QUEUE 0x4000 #define PROFILE_TOSTAT 0x0001 #define PROFILE_IMSG 0x0002 @@ -593,16 +597,16 @@ struct forward_req { uint64_t id; uint8_t status; - char user[MAXLOGNAME]; + char user[SMTPD_MAXLOGNAME]; uid_t uid; gid_t gid; - char directory[MAXPATHLEN]; + char directory[SMTPD_MAXPATHLEN]; }; struct deliver { - char to[PATH_MAX]; - char from[PATH_MAX]; - char user[MAXLOGNAME]; + char to[SMTPD_MAXPATHLEN]; + char from[SMTPD_MAXPATHLEN]; + char user[SMTPD_MAXLOGNAME]; short mode; struct userinfo userinfo; @@ -611,7 +615,7 @@ struct deliver { struct filter { struct imsgproc *process; char name[MAX_FILTER_NAME]; - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; }; struct mta_host { @@ -740,6 +744,7 @@ struct mta_relay { struct mta_envelope { TAILQ_ENTRY(mta_envelope) entry; uint64_t id; + uint64_t session; time_t creation; char *dest; char *rcpt; @@ -773,12 +778,10 @@ struct queue_backend { }; struct compress_backend { - void * (*compress_new)(void); - size_t (*compress_chunk)(void *, void *, size_t, void *, size_t); - size_t (*compress_finalize)(void *, void *, size_t); - void * (*uncompress_new)(void); - size_t (*uncompress_chunk)(void *, void *, size_t, void *, size_t); - size_t (*uncompress_finalize)(void *, void *, size_t); + size_t (*compress_chunk)(void *, size_t, void *, size_t); + size_t (*uncompress_chunk)(void *, size_t, void *, size_t); + int (*compress_file)(FILE *, FILE *); + int (*uncompress_file)(FILE *, FILE *); }; /* auth structures */ @@ -832,21 +835,21 @@ struct scheduler_batch { }; struct scheduler_backend { - void (*init)(void); + int (*init)(void); - void (*insert)(struct scheduler_info *); + int (*insert)(struct scheduler_info *); size_t (*commit)(uint32_t); size_t (*rollback)(uint32_t); - void (*update)(struct scheduler_info *); - void (*delete)(uint64_t); + int (*update)(struct scheduler_info *); + int (*delete)(uint64_t); - void (*batch)(int, struct scheduler_batch *); + int (*batch)(int, struct scheduler_batch *); size_t (*messages)(uint32_t, uint32_t *, size_t); size_t (*envelopes)(uint64_t, struct evpstate *, size_t); - void (*schedule)(uint64_t); - void (*remove)(uint64_t); + int (*schedule)(uint64_t); + int (*remove)(uint64_t); }; @@ -903,8 +906,6 @@ struct stat_digest { size_t dlv_loop; }; -#define MSZ_EVP 512 - struct mproc { pid_t pid; @@ -912,8 +913,15 @@ struct mproc { int proc; void (*handler)(struct mproc *, struct imsg *); struct imsgbuf imsgbuf; - struct ibuf *ibuf; - int ibuferror; + + char *m_buf; + size_t m_alloc; + size_t m_pos; + uint32_t m_type; + uint32_t m_peerid; + pid_t m_pid; + int m_fd; + int enable; short events; struct event ev; @@ -995,7 +1003,7 @@ enum ca_resp_status { struct ca_cert_req_msg { uint64_t reqid; - char name[MAXPATHLEN]; + char name[SMTPD_MAXPATHLEN]; }; struct ca_cert_resp_msg { @@ -1044,15 +1052,10 @@ int ca_X509_verify(void *, void *, const char *, const char *, const char **); /* compress_backend.c */ -int compress_backend_init(const char *); -void* compress_new(void); -size_t compress_chunk(void *, void *, size_t, void *, size_t); -size_t compress_finalize(void *, void *, size_t); -size_t compress_buffer(char *, size_t, char *, size_t); -void* uncompress_new(void); -size_t uncompress_chunk(void *, void *, size_t, void *, size_t); -size_t uncompress_finalize(void *, void *, size_t); -size_t uncompress_buffer(char *, size_t, char *, size_t); +struct compress_backend *compress_backend_lookup(const char *); +size_t compress_chunk(void *, size_t, void *, size_t); +size_t uncompress_chunk(void *, size_t, void *, size_t); +int compress_file(FILE *, FILE *); int uncompress_file(FILE *, FILE *); /* config.c */ @@ -1106,6 +1109,7 @@ struct expandnode *expand_lookup(struct expand *, struct expandnode *); void expand_clear(struct expand *); void expand_free(struct expand *); int expand_line(struct expand *, const char *, int); +int expand_to_text(struct expand *, char *, size_t); RB_PROTOTYPE(expandtree, expandnode, nodes, expand_cmp); @@ -1127,15 +1131,15 @@ void imsgproc_reset_callback(struct imsgproc *, void (*)(struct imsg *, void *), pid_t lka(void); -/* log.c */ -void vlog(int, const char *, va_list); - - /* lka_session.c */ void lka_session(uint64_t, struct envelope *); void lka_session_forward_reply(struct forward_req *, int); +/* log.c */ +void vlog(int, const char *, va_list); + + /* mda.c */ pid_t mda(void); @@ -1164,7 +1168,7 @@ void m_compose(struct mproc *, uint32_t, uint32_t, pid_t, int, void *, size_t); void m_composev(struct mproc *, uint32_t, uint32_t, pid_t, int, const struct iovec *, int); void m_forward(struct mproc *, struct imsg *); -void m_create(struct mproc *, uint32_t, uint32_t, pid_t, int, size_t); +void m_create(struct mproc *, uint32_t, uint32_t, pid_t, int); void m_add(struct mproc *, const void *, size_t); void m_add_int(struct mproc *, int); void m_add_u32(struct mproc *, uint32_t); @@ -1201,7 +1205,7 @@ void mta_route_ok(struct mta_relay *, struct mta_route *); void mta_route_error(struct mta_relay *, struct mta_route *); void mta_route_collect(struct mta_relay *, struct mta_route *); void mta_source_error(struct mta_relay *, struct mta_route *, const char *); -void mta_delivery(struct mta_envelope *, const char *, int, const char *); +void mta_delivery(struct mta_envelope *, const char *, const char *, int, const char *); struct mta_task *mta_route_next_task(struct mta_relay *, struct mta_route *); const char *mta_host_to_text(struct mta_host *); const char *mta_relay_to_text(struct mta_relay *); @@ -1292,37 +1296,31 @@ struct stat_value *stat_timespec(struct timespec *); /* table.c */ +struct table *table_find(const char *, const char *); +struct table *table_create(const char *, const char *, const char *, + const char *); +int table_config(struct table *); int table_open(struct table *); -void table_update(struct table *); +int table_update(struct table *); void table_close(struct table *); int table_check_use(struct table *, uint32_t, uint32_t); int table_check_type(struct table *, uint32_t); int table_check_service(struct table *, uint32_t); -int table_lookup(struct table *, const char *, enum table_service, void **); -int table_fetch(struct table *, enum table_service, char **); -struct table *table_find(objid_t); -struct table *table_findbyname(const char *); -struct table *table_create(const char *, const char *, const char *); +int table_lookup(struct table *, const char *, enum table_service, + union lookup *); +int table_fetch(struct table *, enum table_service, union lookup *); void table_destroy(struct table *); void table_add(struct table *, const char *, const char *); void table_delete(struct table *, const char *); -void table_delete_all(struct table *); -void table_replace(struct table *, struct table *); int table_domain_match(const char *, const char *); int table_netaddr_match(const char *, const char *); int table_mailaddr_match(const char *, const char *); void table_open_all(void); +void table_dump_all(void); void table_close_all(void); -void table_set_payload(struct table *, void *); -void *table_get_payload(struct table *); -void table_set_configuration(struct table *, struct table *); -struct table *table_get_configuration(struct table *); const void *table_get(struct table *, const char *); - -void *table_config_create(void); -const char *table_config_get(void *, const char *); -void table_config_destroy(void *); -int table_config_parse(void *, const char *, enum table_type); +int table_parse_lookup(enum table_service, const char *, const char *, + union lookup *); /* to.c */ diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile index 0ebdd33e8e2..47dd0b14b96 100644 --- a/usr.sbin/smtpd/smtpd/Makefile +++ b/usr.sbin/smtpd/smtpd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.59 2013/03/27 07:48:42 eric Exp $ +# $OpenBSD: Makefile,v 1.60 2013/05/24 17:03:14 eric Exp $ .PATH: ${.CURDIR}/.. ${.CURDIR}/../../../lib/libc/asr @@ -20,6 +20,7 @@ SRCS+= delivery_filename.c SRCS+= delivery_maildir.c SRCS+= delivery_mbox.c SRCS+= delivery_mda.c +SRCS+= delivery_lmtp.c SRCS+= table_db.c SRCS+= table_getpwnam.c SRCS+= table_static.c @@ -46,7 +47,6 @@ BINDIR= /usr/sbin LDADD+= -levent -lutil -lssl -lcrypto -lm -lz -lsqlite3 DPADD+= ${LIBEVENT} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBM} ${LIBZ} ${LIBSQLITE3} CFLAGS+= -g3 -ggdb -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/asr - CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual diff --git a/usr.sbin/smtpd/ssl.c b/usr.sbin/smtpd/ssl.c index 1a5e051c4dd..b814f71b4a4 100644 --- a/usr.sbin/smtpd/ssl.c +++ b/usr.sbin/smtpd/ssl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.c,v 1.52 2013/01/26 09:37:24 gilles Exp $ */ +/* $OpenBSD: ssl.c,v 1.53 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> @@ -29,6 +28,7 @@ #include <event.h> #include <fcntl.h> #include <imsg.h> +#include <limits.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> @@ -320,11 +320,8 @@ ssl_error(const char *where) { unsigned long code; char errbuf[128]; - extern int debug; for (; (code = ERR_get_error()) != 0 ;) { - if (!debug) - continue; ERR_error_string_n(code, errbuf, sizeof(errbuf)); log_debug("debug: SSL library error: %s: %s", where, errbuf); } diff --git a/usr.sbin/smtpd/ssl_smtpd.c b/usr.sbin/smtpd/ssl_smtpd.c index e1cea87eee1..20aa6ad313f 100644 --- a/usr.sbin/smtpd/ssl_smtpd.c +++ b/usr.sbin/smtpd/ssl_smtpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_smtpd.c,v 1.1 2013/01/26 09:37:24 gilles Exp $ */ +/* $OpenBSD: ssl_smtpd.c,v 1.2 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -21,7 +21,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <sys/stat.h> diff --git a/usr.sbin/smtpd/stat_backend.c b/usr.sbin/smtpd/stat_backend.c index 4b8c7cc6f4f..d145b10c33e 100644 --- a/usr.sbin/smtpd/stat_backend.c +++ b/usr.sbin/smtpd/stat_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: stat_backend.c,v 1.7 2013/03/08 19:11:52 chl Exp $ */ +/* $OpenBSD: stat_backend.c,v 1.8 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/socket.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <event.h> #include <imsg.h> @@ -48,13 +47,11 @@ stat_backend_lookup(const char *name) void stat_increment(const char *key, size_t count) { - size_t len; struct stat_value *value; value = stat_counter(count); - len = 32 + strlen(key) + sizeof(*value); - m_create(p_control, IMSG_STAT_INCREMENT, 0, 0, -1, len); + m_create(p_control, IMSG_STAT_INCREMENT, 0, 0, -1); m_add_string(p_control, key); m_add_data(p_control, value, sizeof(*value)); m_close(p_control); @@ -63,13 +60,11 @@ stat_increment(const char *key, size_t count) void stat_decrement(const char *key, size_t count) { - size_t len; struct stat_value *value; value = stat_counter(count); - len = 32 + strlen(key) + sizeof(*value); - m_create(p_control, IMSG_STAT_DECREMENT, 0, 0, -1, len); + m_create(p_control, IMSG_STAT_DECREMENT, 0, 0, -1); m_add_string(p_control, key); m_add_data(p_control, value, sizeof(*value)); m_close(p_control); @@ -78,10 +73,7 @@ stat_decrement(const char *key, size_t count) void stat_set(const char *key, const struct stat_value *value) { - size_t len; - - len = 32 + strlen(key) + sizeof(*value); - m_create(p_control, IMSG_STAT_SET, 0, 0, -1, len); + m_create(p_control, IMSG_STAT_SET, 0, 0, -1); m_add_string(p_control, key); m_add_data(p_control, value, sizeof(*value)); m_close(p_control); diff --git a/usr.sbin/smtpd/stat_ramstat.c b/usr.sbin/smtpd/stat_ramstat.c index fccd5f9cc4f..910a8e170f2 100644 --- a/usr.sbin/smtpd/stat_ramstat.c +++ b/usr.sbin/smtpd/stat_ramstat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: stat_ramstat.c,v 1.7 2013/03/08 19:11:52 chl Exp $ */ +/* $OpenBSD: stat_ramstat.c,v 1.8 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -20,7 +20,6 @@ #include <sys/socket.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <event.h> #include <imsg.h> diff --git a/usr.sbin/smtpd/table.c b/usr.sbin/smtpd/table.c index d58ebbf8a45..4da759384e2 100644 --- a/usr.sbin/smtpd/table.c +++ b/usr.sbin/smtpd/table.c @@ -1,6 +1,7 @@ -/* $OpenBSD: table.c,v 1.3 2013/02/05 15:23:40 gilles Exp $ */ +/* $OpenBSD: table.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* + * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> * * Permission to use, copy, modify, and distribute this software for any @@ -19,10 +20,11 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> #include <ctype.h> #include <err.h> @@ -44,7 +46,12 @@ extern struct table_backend table_backend_getpwnam; extern struct table_backend table_backend_sqlite; extern struct table_backend table_backend_ldap; -static objid_t last_table_id = 0; +static const char * table_service_name(enum table_service); +static const char * table_backend_name(struct table_backend *); +static const char * table_dump_lookup(enum table_service, union lookup *); +static int parse_sockaddr(struct sockaddr *, int, const char *); + +static unsigned int last_table_id = 0; struct table_backend * table_backend_lookup(const char *backend) @@ -62,39 +69,140 @@ table_backend_lookup(const char *backend) return NULL; } -struct table * -table_findbyname(const char *name) -{ - return dict_get(env->sc_tables_dict, name); +static const char * +table_backend_name(struct table_backend *backend) +{ + if (backend == &table_backend_static) + return "static"; + if (backend == &table_backend_db) + return "db"; + if (backend == &table_backend_getpwnam) + return "getpwnam"; + if (backend == &table_backend_sqlite) + return "sqlite"; + if (backend == &table_backend_ldap) + return "ldap"; + return "???"; +} + +static const char * +table_service_name(enum table_service s) +{ + switch (s) { + case K_NONE: return "NONE"; + case K_ALIAS: return "ALIAS"; + case K_DOMAIN: return "DOMAIN"; + case K_CREDENTIALS: return "CREDENTIALS"; + case K_NETADDR: return "NETADDR"; + case K_USERINFO: return "USERINFO"; + case K_SOURCE: return "SOURCE"; + case K_MAILADDR: return "MAILADDR"; + case K_ADDRNAME: return "ADDRNAME"; + default: return "???"; + } } struct table * -table_find(objid_t id) +table_find(const char *name, const char *tag) { - return tree_get(env->sc_tables_tree, id); + char buf[SMTPD_MAXLINESIZE]; + + if (tag == NULL) + return dict_get(env->sc_tables_dict, name); + + if (snprintf(buf, sizeof(buf), "%s#%s", name, tag) >= (int)sizeof(buf)) { + log_warnx("warn: table name too long: %s#%s", name, tag); + return (NULL); + } + + return dict_get(env->sc_tables_dict, buf); } int table_lookup(struct table *table, const char *key, enum table_service kind, - void **retp) + union lookup *lk) { - return table->t_backend->lookup(table->t_handle, key, kind, retp); + int r; + char lkey[1024]; + + if (table->t_backend->lookup == NULL) + return (-1); + + if (! lowercase(lkey, key, sizeof lkey)) { + log_warnx("warn: lookup key too long: %s", key); + return -1; + } + + r = table->t_backend->lookup(table->t_handle, lkey, kind, lk); + + if (r == 1) + log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s", + lk ? "lookup" : "check", + lkey, + table_service_name(kind), + table_backend_name(table->t_backend), + table->t_name, + lk ? "\"" : "", + (lk) ? table_dump_lookup(kind, lk): "found", + lk ? "\"" : ""); + else + log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %i", + lk ? "lookup" : "check", + lkey, + table_service_name(kind), + table_backend_name(table->t_backend), + table->t_name, + r); + + return (r); } int -table_fetch(struct table *table, enum table_service kind, char **retp) +table_fetch(struct table *table, enum table_service kind, union lookup *lk) { - return table->t_backend->fetch(table->t_handle, kind, retp); + int r; + + if (table->t_backend->fetch == NULL) + return (-1); + + r = table->t_backend->fetch(table->t_handle, kind, lk); + + if (r == 1) + log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> %s%s%s", + table_service_name(kind), + table_backend_name(table->t_backend), + table->t_name, + lk ? "\"" : "", + (lk) ? table_dump_lookup(kind, lk): "found", + lk ? "\"" : ""); + else + log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> %i", + table_service_name(kind), + table_backend_name(table->t_backend), + table->t_name, + r); + + return (r); } struct table * -table_create(const char *backend, const char *name, const char *config) +table_create(const char *backend, const char *name, const char *tag, + const char *config) { struct table *t; struct table_backend *tb; - size_t n; + char buf[SMTPD_MAXLINESIZE]; + size_t n; + + if (name && tag) { + if (snprintf(buf, sizeof(buf), "%s#%s", name, tag) + >= (int)sizeof(buf)) + errx(1, "table_create: name too long \"%s#%s\"", + name, tag); + name = buf; + } - if (name && table_findbyname(name)) + if (name && table_find(name, NULL)) errx(1, "table_create: table \"%s\" already defined", name); if ((tb = table_backend_lookup(backend)) == NULL) @@ -110,26 +218,19 @@ table_create(const char *backend, const char *name, const char *config) if (!strcmp(backend, "file")) backend = "static"; - if (strlcpy(t->t_src, backend, sizeof t->t_src) >= sizeof t->t_src) - errx(1, "table_create: table backend \"%s\" too large", - t->t_src); - - if (config && *config) { + if (config) { if (strlcpy(t->t_config, config, sizeof t->t_config) >= sizeof t->t_config) errx(1, "table_create: table config \"%s\" too large", t->t_config); } - if (strcmp(t->t_src, "static") != 0) + if (strcmp(backend, "static") != 0) t->t_type = T_DYNAMIC; - t->t_id = ++last_table_id; - if (t->t_id == INT_MAX) - errx(1, "table_create: too many tables defined"); - if (name == NULL) - snprintf(t->t_name, sizeof(t->t_name), "<dynamic:%u>", t->t_id); + snprintf(t->t_name, sizeof(t->t_name), "<dynamic:%u>", + last_table_id++); else { n = strlcpy(t->t_name, name, sizeof(t->t_name)); if (n >= sizeof(t->t_name)) @@ -138,7 +239,6 @@ table_create(const char *backend, const char *name, const char *config) dict_init(&t->t_dict); dict_set(env->sc_tables_dict, t->t_name, t); - tree_set(env->sc_tables_tree, t->t_id, t); return (t); } @@ -152,49 +252,21 @@ table_destroy(struct table *t) free(p); dict_xpop(env->sc_tables_dict, t->t_name); - tree_xpop(env->sc_tables_tree, t->t_id); free(t); } -void -table_replace(struct table *orig, struct table *tnew) -{ - void *p = NULL; - - while (dict_poproot(&orig->t_dict, NULL, (void **)&p)) - free(p); - dict_merge(&orig->t_dict, &tnew->t_dict); - table_destroy(tnew); -} - -void -table_set_configuration(struct table *t, struct table *config) -{ - strlcpy(t->t_cfgtable, config->t_name, sizeof t->t_cfgtable); -} - -struct table * -table_get_configuration(struct table *t) -{ - return table_findbyname(t->t_cfgtable); -} - -void -table_set_payload(struct table *t, void *payload) -{ - t->t_payload = payload; -} - -void * -table_get_payload(struct table *t) +int +table_config(struct table *t) { - return t->t_payload; + if (t->t_backend->config == NULL) + return (1); + return (t->t_backend->config(t)); } void table_add(struct table *t, const char *key, const char *val) { - if (strcmp(t->t_src, "static") != 0) + if (t->t_type & T_DYNAMIC) errx(1, "table_add: cannot add to table"); dict_set(&t->t_dict, key, val ? xstrdup(val, "table_add") : NULL); } @@ -202,16 +274,16 @@ table_add(struct table *t, const char *key, const char *val) const void * table_get(struct table *t, const char *key) { - if (strcmp(t->t_src, "static") != 0) - errx(1, "table_add: cannot get from table"); + if (t->t_type & T_DYNAMIC) + errx(1, "table_get: cannot get from table"); return dict_get(&t->t_dict, key); } void table_delete(struct table *t, const char *key) { - if (strcmp(t->t_src, "static") != 0) - errx(1, "map_add: cannot delete from map"); + if (t->t_type & T_DYNAMIC) + errx(1, "table_delete: cannot delete from table"); free(dict_pop(&t->t_dict, key)); } @@ -236,112 +308,28 @@ table_check_use(struct table *t, uint32_t tmask, uint32_t smask) int table_open(struct table *t) { + t->t_handle = NULL; + if (t->t_backend->open == NULL) + return (1); t->t_handle = t->t_backend->open(t); if (t->t_handle == NULL) - return 0; - return 1; + return (0); + return (1); } void table_close(struct table *t) { - t->t_backend->close(t->t_handle); -} - - -void -table_update(struct table *t) -{ - t->t_backend->update(t); -} - -void * -table_config_create(void) -{ - return table_create("static", NULL, NULL); -} - -const char * -table_config_get(void *p, const char *key) -{ - return (const char *)table_get(p, key); -} - -void -table_config_destroy(void *p) -{ - table_destroy(p); + if (t->t_backend->close) + t->t_backend->close(t->t_handle); } int -table_config_parse(void *p, const char *config, enum table_type type) +table_update(struct table *t) { - struct table *t = p; - FILE *fp; - char *buf, *lbuf; - size_t flen; - char *keyp; - char *valp; - size_t ret = 0; - - if (strcmp("static", t->t_src) != 0) { - log_warn("table_config_parser: config table must be static"); - return 0; - } - - fp = fopen(config, "r"); - if (fp == NULL) - return 0; - - lbuf = NULL; - while ((buf = fgetln(fp, &flen))) { - if (buf[flen - 1] == '\n') - buf[flen - 1] = '\0'; - else { - lbuf = xmalloc(flen + 1, "table_stdio_get_entry"); - memcpy(lbuf, buf, flen); - lbuf[flen] = '\0'; - buf = lbuf; - } - - keyp = buf; - while (isspace((int)*keyp)) - ++keyp; - if (*keyp == '\0' || *keyp == '#') - continue; - valp = keyp; - strsep(&valp, " \t:"); - if (valp) { - while (*valp) { - if (!isspace(*valp) && - !(*valp == ':' && isspace(*(valp + 1)))) - break; - ++valp; - } - if (*valp == '\0') - valp = NULL; - } - - /**/ - if (t->t_type == 0) - t->t_type = (valp == keyp || valp == NULL) ? T_LIST : - T_HASH; - - if (!(t->t_type & type)) - goto end; - - if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) - table_add(t, keyp, NULL); - else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) - table_add(t, keyp, valp); - else - goto end; - } - ret = 1; -end: - free(lbuf); - fclose(fp); - return ret; + if (t->t_backend->update == NULL) + return (1); + return (t->t_backend->update(t)); } int @@ -380,7 +368,7 @@ table_netaddr_match(const char *s1, const char *s2) struct netaddr n1; struct netaddr n2; - if (strcmp(s1, s2) == 0) + if (strcasecmp(s1, s2) == 0) return 1; if (! text_to_netaddr(&n1, s1)) return 0; @@ -453,13 +441,52 @@ table_inet6_match(struct sockaddr_in6 *ss, struct netaddr *ssmask) } void +table_dump_all(void) +{ + struct table *t; + void *iter, *i2; + const char *key, *sep; + char *value; + char buf[1024]; + + iter = NULL; + while (dict_iter(env->sc_tables_dict, &iter, NULL, (void **)&t)) { + i2 = NULL; + sep = ""; + buf[0] = '\0'; + if (t->t_type & T_DYNAMIC) { + strlcat(buf, "DYNAMIC", sizeof(buf)); + sep = ","; + } + if (t->t_type & T_LIST) { + strlcat(buf, sep, sizeof(buf)); + strlcat(buf, "LIST", sizeof(buf)); + sep = ","; + } + if (t->t_type & T_HASH) { + strlcat(buf, sep, sizeof(buf)); + strlcat(buf, "HASH", sizeof(buf)); + sep = ","; + } + log_debug("TABLE \"%s\" type=%s config=\"%s\"", + t->t_name, buf, t->t_config); + while(dict_iter(&t->t_dict, &i2, &key, (void**)&value)) { + if (value) + log_debug(" \"%s\" -> \"%s\"", key, value); + else + log_debug(" \"%s\"", key); + } + } +} + +void table_open_all(void) { struct table *t; void *iter; iter = NULL; - while (tree_iter(env->sc_tables_tree, &iter, NULL, (void **)&t)) + while (dict_iter(env->sc_tables_dict, &iter, NULL, (void **)&t)) if (! table_open(t)) errx(1, "failed to open table %s", t->t_name); } @@ -471,6 +498,222 @@ table_close_all(void) void *iter; iter = NULL; - while (tree_iter(env->sc_tables_tree, &iter, NULL, (void **)&t)) + while (dict_iter(env->sc_tables_dict, &iter, NULL, (void **)&t)) table_close(t); } + +int +table_parse_lookup(enum table_service service, const char *key, + const char *line, union lookup *lk) +{ + char buffer[SMTPD_MAXLINESIZE], *p; + size_t len; + + len = strlen(line); + + switch (service) { + case K_ALIAS: + lk->expand = calloc(1, sizeof(*lk->expand)); + if (lk->expand == NULL) + return (-1); + if (!expand_line(lk->expand, line, 1)) { + expand_free(lk->expand); + return (-1); + } + return (1); + + case K_DOMAIN: + if (strlcpy(lk->domain.name, line, sizeof(lk->domain.name)) + >= sizeof(lk->domain.name)) + return (-1); + return (1); + + case K_CREDENTIALS: + + /* credentials are stored as user:password */ + if (len < 3) + return (-1); + + /* too big to fit in a smtp session line */ + if (len >= SMTPD_MAXLINESIZE) + return (-1); + + p = strchr(line, ':'); + if (p == NULL || p == line || p == line + len - 1) + return (-1); + + memmove(lk->creds.username, line, p - line); + lk->creds.username[p - line] = '\0'; + + if (strlcpy(lk->creds.password, p+1, sizeof(lk->creds.password)) + >= sizeof(lk->creds.password)) + return (-1); + + return (1); + + case K_NETADDR: + if (!text_to_netaddr(&lk->netaddr, line)) + return (-1); + return (1); + + case K_USERINFO: + if (!bsnprintf(buffer, sizeof(buffer), "%s:%s", key, line)) + return (-1); + if (!text_to_userinfo(&lk->userinfo, buffer)) + return (-1); + return (1); + + case K_SOURCE: + if (parse_sockaddr((struct sockaddr *)&lk->source.addr, + PF_UNSPEC, line) == -1) + return (-1); + return (1); + + case K_MAILADDR: + if (!text_to_mailaddr(&lk->mailaddr, line)) + return (-1); + return (1); + + case K_ADDRNAME: + if (parse_sockaddr((struct sockaddr *)&lk->addrname.addr, + PF_UNSPEC, key) == -1) + return (-1); + if (strlcpy(lk->addrname.name, line, sizeof(lk->addrname.name)) + >= sizeof(lk->addrname.name)) + return (-1); + return (1); + + default: + return (-1); + } +} + +static const char * +table_dump_lookup(enum table_service s, union lookup *lk) +{ + static char buf[SMTPD_MAXLINESIZE]; + + switch (s) { + case K_NONE: + break; + + case K_ALIAS: + expand_to_text(lk->expand, buf, sizeof(buf)); + break; + + case K_DOMAIN: + snprintf(buf, sizeof(buf), "%s", lk->domain.name); + break; + + case K_CREDENTIALS: + snprintf(buf, sizeof(buf), "%s:%s", + lk->creds.username, lk->creds.password); + break; + + case K_NETADDR: + snprintf(buf, sizeof(buf), "%s/%i", + sockaddr_to_text((struct sockaddr *)&lk->netaddr.ss), + lk->netaddr.bits); + break; + + case K_USERINFO: + snprintf(buf, sizeof(buf), "%s:%i:%i:%s", + lk->userinfo.username, + lk->userinfo.uid, + lk->userinfo.gid, + lk->userinfo.directory); + break; + + case K_SOURCE: + snprintf(buf, sizeof(buf), "%s", + ss_to_text(&lk->source.addr)); + break; + + case K_MAILADDR: + snprintf(buf, sizeof(buf), "%s@%s", + lk->mailaddr.user, + lk->mailaddr.domain); + break; + + case K_ADDRNAME: + snprintf(buf, sizeof(buf), "%s", + lk->addrname.name); + break; + + default: + break; + } + + return (buf); +} + + +static int +parse_sockaddr(struct sockaddr *sa, int family, const char *str) +{ + struct in_addr ina; + struct in6_addr in6a; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + char *cp, *str2; + const char *errstr; + + switch (family) { + case PF_UNSPEC: + if (parse_sockaddr(sa, PF_INET, str) == 0) + return (0); + return parse_sockaddr(sa, PF_INET6, str); + + case PF_INET: + if (inet_pton(PF_INET, str, &ina) != 1) + return (-1); + + sin = (struct sockaddr_in *)sa; + memset(sin, 0, sizeof *sin); + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_family = PF_INET; + sin->sin_addr.s_addr = ina.s_addr; + return (0); + + case PF_INET6: + cp = strchr(str, SCOPE_DELIMITER); + if (cp) { + str2 = strdup(str); + if (str2 == NULL) + return (-1); + str2[cp - str] = '\0'; + if (inet_pton(PF_INET6, str2, &in6a) != 1) { + free(str2); + return (-1); + } + cp++; + free(str2); + } else if (inet_pton(PF_INET6, str, &in6a) != 1) + return (-1); + + sin6 = (struct sockaddr_in6 *)sa; + memset(sin6, 0, sizeof *sin6); + sin6->sin6_len = sizeof(struct sockaddr_in6); + sin6->sin6_family = PF_INET6; + sin6->sin6_addr = in6a; + + if (cp == NULL) + return (0); + + if (IN6_IS_ADDR_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || + IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + if ((sin6->sin6_scope_id = if_nametoindex(cp))) + return (0); + + sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); + if (errstr) + return (-1); + return (0); + + default: + break; + } + + return (-1); +} diff --git a/usr.sbin/smtpd/table_db.c b/usr.sbin/smtpd/table_db.c index 23030422817..853654dfcb0 100644 --- a/usr.sbin/smtpd/table_db.c +++ b/usr.sbin/smtpd/table_db.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_db.c,v 1.4 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: table_db.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> @@ -20,9 +20,11 @@ #include <sys/stat.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + #include <db.h> #include <ctype.h> #include <err.h> @@ -38,25 +40,19 @@ /* db(3) backend */ -static int table_db_config(struct table *, const char *); +static int table_db_config(struct table *); static int table_db_update(struct table *); static void *table_db_open(struct table *); -static int table_db_lookup(void *, const char *, enum table_service, void **); -static int table_db_fetch(void *, enum table_service, char **); +static int table_db_lookup(void *, const char *, enum table_service, union lookup *); +static int table_db_fetch(void *, enum table_service, union lookup *); static void table_db_close(void *); static char *table_db_get_entry(void *, const char *, size_t *); static char *table_db_get_entry_match(void *, const char *, size_t *, int(*)(const char *, const char *)); -static int table_db_credentials(const char *, char *, size_t, void **); -static int table_db_alias(const char *, char *, size_t, void **); -static int table_db_domain(const char *, char *, size_t, void **); -static int table_db_netaddr(const char *, char *, size_t, void **); -static int table_db_userinfo(const char *, char *, size_t, void **); - struct table_backend table_backend_db = { - K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE, + K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE|K_ADDRNAME, table_db_config, table_db_open, table_db_update, @@ -75,13 +71,13 @@ static struct keycmp { struct dbhandle { DB *db; - char pathname[MAXPATHLEN]; + char pathname[SMTPD_MAXPATHLEN]; time_t mtime; struct table *table; }; static int -table_db_config(struct table *table, const char *config) +table_db_config(struct table *table) { struct dbhandle *handle; @@ -146,9 +142,10 @@ table_db_close(void *hdl) static int table_db_lookup(void *hdl, const char *key, enum table_service service, - void **retp) + union lookup *lk) { struct dbhandle *handle = hdl; + struct table *table = NULL; char *line; size_t len = 0; int ret; @@ -160,58 +157,33 @@ table_db_lookup(void *hdl, const char *key, enum table_service service, return -1; /* DB has changed, close and reopen */ - if (sb.st_mtime != handle->mtime) + if (sb.st_mtime != handle->mtime) { + table = handle->table; table_db_update(handle->table); + handle = table->t_handle; + } for (i = 0; i < nitems(keycmp); ++i) if (keycmp[i].service == service) match = keycmp[i].func; if (match == NULL) - line = table_db_get_entry(hdl, key, &len); + line = table_db_get_entry(handle, key, &len); else - line = table_db_get_entry_match(hdl, key, &len, match); + line = table_db_get_entry_match(handle, key, &len, match); if (line == NULL) return 0; - if (retp == NULL) { - free(line); - return 1; - } - - ret = 0; - switch (service) { - case K_ALIAS: - ret = table_db_alias(key, line, len, retp); - break; - - case K_CREDENTIALS: - ret = table_db_credentials(key, line, len, retp); - break; - - case K_DOMAIN: - ret = table_db_domain(key, line, len, retp); - break; - - case K_NETADDR: - ret = table_db_netaddr(key, line, len, retp); - break; - - case K_USERINFO: - ret = table_db_userinfo(key, line, len, retp); - break; - - default: - break; - } - + ret = 1; + if (lk) + ret = table_parse_lookup(service, key, line, lk); free(line); return ret; } static int -table_db_fetch(void *hdl, enum table_service service, char **retp) +table_db_fetch(void *hdl, enum table_service service, union lookup *lk) { struct dbhandle *handle = hdl; struct table *table = handle->table; @@ -229,8 +201,8 @@ table_db_fetch(void *hdl, enum table_service service, char **retp) if (!r) return 0; } - *retp = xmemdup(dbk.data, dbk.size, "table_db_get_entry_cmp"); - return 1; + + return table_parse_lookup(service, NULL, dbk.data, lk); } @@ -278,117 +250,3 @@ table_db_get_entry(void *hdl, const char *key, size_t *len) return xmemdup(dbv.data, dbv.size, "table_db_get_entry"); } - -static int -table_db_credentials(const char *key, char *line, size_t len, void **retp) -{ - struct credentials *credentials = NULL; - char *p; - - /* credentials are stored as user:password */ - if (len < 3) - return -1; - - /* too big to fit in a smtp session line */ - if (len >= SMTPD_MAXLINESIZE) - return -1; - - p = strchr(line, ':'); - if (p == NULL) - return -1; - - if (p == line || p == line + len - 1) - return -1; - *p++ = '\0'; - - credentials = xcalloc(1, sizeof *credentials, - "table_db_credentials"); - if (strlcpy(credentials->username, line, sizeof(credentials->username)) - >= sizeof(credentials->username)) - goto err; - - if (strlcpy(credentials->password, p, sizeof(credentials->password)) - >= sizeof(credentials->password)) - goto err; - - *retp = credentials; - return 1; - -err: - *retp = NULL; - free(credentials); - return -1; -} - -static int -table_db_alias(const char *key, char *line, size_t len, void **retp) -{ - struct expand *xp = NULL; - - xp = xcalloc(1, sizeof *xp, "table_db_alias"); - if (! expand_line(xp, line, 1)) - goto error; - *retp = xp; - return 1; - -error: - *retp = NULL; - expand_free(xp); - return -1; -} - -static int -table_db_netaddr(const char *key, char *line, size_t len, void **retp) -{ - struct netaddr *netaddr; - - netaddr = xcalloc(1, sizeof *netaddr, "table_db_netaddr"); - if (! text_to_netaddr(netaddr, line)) - goto error; - *retp = netaddr; - return 1; - -error: - *retp = NULL; - free(netaddr); - return -1; -} - -static int -table_db_domain(const char *key, char *line, size_t len, void **retp) -{ - struct destination *destination; - - destination = xcalloc(1, sizeof *destination, "table_db_domain"); - if (strlcpy(destination->name, line, sizeof destination->name) - >= sizeof destination->name) - goto error; - *retp = destination; - return 1; - -error: - *retp = NULL; - free(destination); - return -1; -} - -static int -table_db_userinfo(const char *key, char *line, size_t len, void **retp) -{ - struct userinfo *userinfo = NULL; - char buffer[1024]; - - if (! bsnprintf(buffer, sizeof buffer, "%s:%s", key, line)) - goto error; - - userinfo = xcalloc(1, sizeof *userinfo, "table_db_userinfo"); - if (! text_to_userinfo(userinfo, buffer)) - goto error; - *retp = userinfo; - return 1; - -error: - *retp = NULL; - free(userinfo); - return -1; -} diff --git a/usr.sbin/smtpd/table_getpwnam.c b/usr.sbin/smtpd/table_getpwnam.c index 25c2cbf3da0..f66effbf414 100644 --- a/usr.sbin/smtpd/table_getpwnam.c +++ b/usr.sbin/smtpd/table_getpwnam.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_getpwnam.c,v 1.1 2013/01/26 09:37:24 gilles Exp $ */ +/* $OpenBSD: table_getpwnam.c,v 1.2 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -38,11 +37,11 @@ /* getpwnam(3) backend */ -static int table_getpwnam_config(struct table *, const char *); +static int table_getpwnam_config(struct table *); static int table_getpwnam_update(struct table *); static void *table_getpwnam_open(struct table *); static int table_getpwnam_lookup(void *, const char *, enum table_service, - void **); + union lookup *); static void table_getpwnam_close(void *); struct table_backend table_backend_getpwnam = { @@ -56,9 +55,9 @@ struct table_backend table_backend_getpwnam = { static int -table_getpwnam_config(struct table *table, const char *config) +table_getpwnam_config(struct table *table) { - if (config) + if (table->t_config[0]) return 0; return 1; } @@ -83,9 +82,8 @@ table_getpwnam_close(void *hdl) static int table_getpwnam_lookup(void *hdl, const char *key, enum table_service kind, - void **ret) + union lookup *lk) { - struct userinfo *userinfo; struct passwd *pw; size_t s; @@ -102,25 +100,19 @@ table_getpwnam_lookup(void *hdl, const char *key, enum table_service kind, return -1; return 0; } - if (ret == NULL) + if (lk == NULL) return 1; - userinfo = xcalloc(1, sizeof *userinfo, "table_getpwnam_lookup"); - userinfo->uid = pw->pw_uid; - userinfo->gid = pw->pw_gid; - s = strlcpy(userinfo->username, pw->pw_name, - sizeof(userinfo->username)); - if (s >= sizeof(userinfo->username)) - goto error; - s = strlcpy(userinfo->directory, pw->pw_dir, - sizeof(userinfo->directory)); - if (s >= sizeof(userinfo->directory)) - goto error; - - *ret = userinfo; - return 1; - -error: - free(userinfo); - return -1; + lk->userinfo.uid = pw->pw_uid; + lk->userinfo.gid = pw->pw_gid; + s = strlcpy(lk->userinfo.username, pw->pw_name, + sizeof(lk->userinfo.username)); + if (s >= sizeof(lk->userinfo.username)) + return (-1); + s = strlcpy(lk->userinfo.directory, pw->pw_dir, + sizeof(lk->userinfo.directory)); + if (s >= sizeof(lk->userinfo.directory)) + return (-1); + + return (1); } diff --git a/usr.sbin/smtpd/table_ldap.c b/usr.sbin/smtpd/table_ldap.c index 02569ad8552..f3aff8b43a7 100644 --- a/usr.sbin/smtpd/table_ldap.c +++ b/usr.sbin/smtpd/table_ldap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_ldap.c,v 1.3 2013/03/08 19:11:52 chl Exp $ */ +/* $OpenBSD: table_ldap.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2010-2012 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> @@ -48,13 +47,13 @@ #define MAX_LDAP_FILTERLEN 1024 #define MAX_LDAP_FIELDLEN 128 -static void *table_ldap_open(struct table *); -static int table_ldap_update(struct table *); -static int table_ldap_config(struct table *, const char *); -static int table_ldap_lookup(void *, const char *, enum table_service, void **); -static int table_ldap_fetch(void *, enum table_service, char **); -static void table_ldap_close(void *); -static struct aldap *ldap_client_connect(const char *); +static void *table_ldap_open(struct table *); +static int table_ldap_update(struct table *); +static int table_ldap_config(struct table *); +static int table_ldap_lookup(void *, const char *, enum table_service, union lookup *); +static int table_ldap_fetch(void *, enum table_service, union lookup *); +static void table_ldap_close(void *); +static struct aldap *ldap_client_connect(const char *); struct table_backend table_backend_ldap = { K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_USERINFO, /* K_NETADDR|K_SOURCE,*/ @@ -75,37 +74,36 @@ static int parse_attributes(char **, const char *, size_t); static int table_ldap_internal_query(struct aldap *, const char *, const char *, char **, char ***, size_t); -static int table_ldap_alias(struct table_ldap_handle *, const char *, void **); -static int table_ldap_credentials(struct table_ldap_handle *, const char *, void **); -static int table_ldap_domain(struct table_ldap_handle *, const char *, void **); -static int table_ldap_userinfo(struct table_ldap_handle *, const char *, void **); +static int table_ldap_alias(struct table_ldap_handle *, const char *, union lookup *); +static int table_ldap_credentials(struct table_ldap_handle *, const char *, union lookup *); +static int table_ldap_domain(struct table_ldap_handle *, const char *, union lookup *); +static int table_ldap_userinfo(struct table_ldap_handle *, const char *, union lookup *); static int -table_ldap_config(struct table *table, const char *config) +table_ldap_config(struct table *table) { - void *cfg = NULL; + struct table *cfg = NULL; /* no config ? broken */ - if (config == NULL) + if (table->t_config[0] == '\0') return 0; - cfg = table_config_create(); - if (! table_config_parse(cfg, config, T_HASH)) + cfg = table_create("static", table->t_name, "conf", table->t_config); + if (!table_config(cfg)) goto err; /* sanity checks */ - if (table_config_get(cfg, "url") == NULL) { + if (table_get(cfg, "url") == NULL) { log_warnx("table_ldap: missing 'url' configuration"); goto err; } - if (table_config_get(cfg, "basedn") == NULL) { + if (table_get(cfg, "basedn") == NULL) { log_warnx("table_ldap: missing 'basedn' configuration"); goto err; } - table_set_configuration(table, cfg); return 1; err: @@ -130,7 +128,7 @@ table_ldap_open(struct table *table) char *username = NULL; char *password = NULL; - cfg = table_get_configuration(table); + cfg = table_find(table->t_name, "conf"); if (table_get(cfg, "url") == NULL || table_get(cfg, "username") == NULL || table_get(cfg, "password") == NULL) @@ -194,22 +192,22 @@ table_ldap_close(void *hdl) static int table_ldap_lookup(void *hdl, const char *key, enum table_service service, - void **retp) + union lookup *lk) { struct table_ldap_handle *tlh = hdl; switch (service) { case K_ALIAS: - return table_ldap_alias(tlh, key, retp); + return table_ldap_alias(tlh, key, lk); case K_CREDENTIALS: - return table_ldap_credentials(tlh, key, retp); + return table_ldap_credentials(tlh, key, lk); case K_DOMAIN: - return table_ldap_domain(tlh, key, retp); + return table_ldap_domain(tlh, key, lk); case K_USERINFO: - return table_ldap_userinfo(tlh, key, retp); + return table_ldap_userinfo(tlh, key, lk); default: break; @@ -219,7 +217,7 @@ table_ldap_lookup(void *hdl, const char *key, enum table_service service, } static int -table_ldap_fetch(void *hdl, enum table_service service, char **retp) +table_ldap_fetch(void *hdl, enum table_service service, union lookup *lk) { /* fetch not support for LDAP at this point */ return -1; @@ -300,20 +298,19 @@ end: static int -table_ldap_credentials(struct table_ldap_handle *tlh, const char *key, void **retp) +table_ldap_credentials(struct table_ldap_handle *tlh, const char *key, union lookup *lk) { - struct aldap *aldap = tlh->aldap; - struct table *cfg = table_get_configuration(tlh->table); - const char *filter = NULL; - const char *basedn = NULL; - struct credentials credentials; - char *expfilter = NULL; - char *attributes[4]; - char **ret_attr[4]; - const char *attr; - char line[1024]; - int ret = -1; - size_t i; + struct aldap *aldap = tlh->aldap; + struct table *cfg = table_find(tlh->table->t_name, "conf"); + const char *filter = NULL; + const char *basedn = NULL; + char *expfilter = NULL; + char *attributes[4]; + char **ret_attr[4]; + const char *attr; + char line[1024]; + int ret = -1; + size_t i; bzero(&attributes, sizeof attributes); bzero(&ret_attr, sizeof ret_attr); @@ -343,7 +340,7 @@ table_ldap_credentials(struct table_ldap_handle *tlh, const char *key, void **re ret_attr, nitems(attributes))) <= 0) goto end; - if (retp == NULL) + if (lk == NULL) goto end; if (! bsnprintf(line, sizeof line, "%s:%s", ret_attr[0][0], ret_attr[0][1])) { @@ -351,13 +348,9 @@ table_ldap_credentials(struct table_ldap_handle *tlh, const char *key, void **re goto end; } - bzero(&credentials, sizeof credentials); - if (! text_to_credentials(&credentials, line)) { + bzero(&lk->creds, sizeof(lk->creds)); + if (! text_to_credentials(&lk->creds, line)) ret = -1; - goto end; - } - - *retp = xmemdup(&credentials, sizeof credentials, "table_ldap_credentials"); end: for (i = 0; i < nitems(attributes); ++i) { @@ -372,19 +365,18 @@ end: } static int -table_ldap_domain(struct table_ldap_handle *tlh, const char *key, void **retp) +table_ldap_domain(struct table_ldap_handle *tlh, const char *key, union lookup *lk) { - struct aldap *aldap = tlh->aldap; - struct table *cfg = table_get_configuration(tlh->table); - const char *filter = NULL; - const char *basedn = NULL; - struct destination destination; - char *expfilter = NULL; - char *attributes[1]; - char **ret_attr[1]; - const char *attr; - int ret = -1; - size_t i; + struct aldap *aldap = tlh->aldap; + struct table *cfg = table_find(tlh->table->t_name, "conf"); + const char *filter = NULL; + const char *basedn = NULL; + char *expfilter = NULL; + char *attributes[1]; + char **ret_attr[1]; + const char *attr; + int ret = -1; + size_t i; bzero(&attributes, sizeof attributes); bzero(&ret_attr, sizeof ret_attr); @@ -415,13 +407,13 @@ table_ldap_domain(struct table_ldap_handle *tlh, const char *key, void **retp) ret_attr, nitems(attributes))) <= 0) goto end; - if (retp == NULL) + if (lk == NULL) goto end; - bzero(&destination, sizeof destination); - if (strlcpy(destination.name, ret_attr[0][0], sizeof destination.name) - >= sizeof destination.name); - *retp = xmemdup(&destination, sizeof destination, "table_ldap_destination"); + bzero(&lk->domain, sizeof(lk->domain)); + if (strlcpy(lk->domain.name, ret_attr[0][0], sizeof(lk->domain.name)) + >= sizeof(lk->domain.name)) + ret = -1; end: for (i = 0; i < nitems(attributes); ++i) { @@ -430,25 +422,24 @@ end: aldap_free_attr(ret_attr[i]); } free(expfilter); - log_debug("debug: table_ldap_destination: ret=%d", ret); + log_debug("debug: table_ldap_domain: ret=%d", ret); return ret; } static int -table_ldap_userinfo(struct table_ldap_handle *tlh, const char *key, void **retp) +table_ldap_userinfo(struct table_ldap_handle *tlh, const char *key, union lookup *lk) { - struct aldap *aldap = tlh->aldap; - struct table *cfg = table_get_configuration(tlh->table); - const char *filter = NULL; - const char *basedn = NULL; - struct userinfo userinfo; - char *expfilter = NULL; - char *attributes[4]; - char **ret_attr[4]; - const char *attr; - char line[1024]; - int ret = -1; - size_t i; + struct aldap *aldap = tlh->aldap; + struct table *cfg = table_find(tlh->table->t_name, "conf"); + const char *filter = NULL; + const char *basedn = NULL; + char *expfilter = NULL; + char *attributes[4]; + char **ret_attr[4]; + const char *attr; + char line[1024]; + int ret = -1; + size_t i; bzero(&attributes, sizeof attributes); bzero(&ret_attr, sizeof ret_attr); @@ -478,7 +469,7 @@ table_ldap_userinfo(struct table_ldap_handle *tlh, const char *key, void **retp) ret_attr, nitems(attributes))) <= 0) goto end; - if (retp == NULL) + if (lk == NULL) goto end; if (! bsnprintf(line, sizeof line, "%s:%s:%s:%s", @@ -487,13 +478,9 @@ table_ldap_userinfo(struct table_ldap_handle *tlh, const char *key, void **retp) goto end; } - bzero(&userinfo, sizeof userinfo); - if (! text_to_userinfo(&userinfo, line)) { + bzero(&lk->userinfo, sizeof(lk->userinfo)); + if (!text_to_userinfo(&(lk->userinfo), line)) ret = -1; - goto end; - } - - *retp = xmemdup(&userinfo, sizeof userinfo, "table_ldap_userinfo"); end: for (i = 0; i < nitems(attributes); ++i) { @@ -507,22 +494,23 @@ end: } static int -table_ldap_alias(struct table_ldap_handle *tlh, const char *key, void **retp) +table_ldap_alias(struct table_ldap_handle *tlh, const char *key, union lookup *lk) { - struct aldap *aldap = tlh->aldap; - struct table *cfg = table_get_configuration(tlh->table); - const char *filter = NULL; - const char *basedn = NULL; - struct expand *xp = NULL; - char *expfilter = NULL; - char *attributes[1]; - char **ret_attr[1]; - const char *attr; - int ret = -1; - size_t i; + struct aldap *aldap = tlh->aldap; + struct table *cfg = table_find(tlh->table->t_name, "conf"); + const char *filter = NULL; + const char *basedn = NULL; + char *expfilter = NULL; + char *attributes[1]; + char **ret_attr[1]; + const char *attr; + int ret = -1; + size_t i; bzero(&attributes, sizeof attributes); bzero(&ret_attr, sizeof ret_attr); + if (lk) + lk->expand = NULL; basedn = table_get(cfg, "basedn"); if ((filter = table_get(cfg, "alias_filter")) == NULL) { @@ -549,17 +537,16 @@ table_ldap_alias(struct table_ldap_handle *tlh, const char *key, void **retp) ret_attr, nitems(attributes))) <= 0) goto end; - if (retp == NULL) + if (lk == NULL) goto end; - xp = xcalloc(1, sizeof *xp, "table_ldap_alias"); + lk->expand = xcalloc(1, sizeof(*lk->expand), "table_ldap_alias"); for (i = 0; ret_attr[0][i]; ++i) { - if (! expand_line(xp, ret_attr[0][i], 1)) { + if (! expand_line(lk->expand, ret_attr[0][i], 1)) { ret = -1; goto end; } } - *retp = xp; end: for (i = 0; i < nitems(attributes); ++i) { @@ -567,12 +554,9 @@ end: if (ret_attr[i]) aldap_free_attr(ret_attr[i]); } - if (ret != 1) { - if (retp) - *retp = NULL; - if (xp) - expand_free(xp); - } + if (ret != 1 && lk && lk->expand) + expand_free(lk->expand); + free(expfilter); log_debug("debug: table_ldap_alias: ret=%d", ret); return ret; diff --git a/usr.sbin/smtpd/table_sqlite.c b/usr.sbin/smtpd/table_sqlite.c index b2ec3141452..bfcf11fa4d4 100644 --- a/usr.sbin/smtpd/table_sqlite.c +++ b/usr.sbin/smtpd/table_sqlite.c @@ -1,4 +1,4 @@ -/* $OpenBSD: table_sqlite.c,v 1.2 2013/01/31 18:34:43 eric Exp $ */ +/* $OpenBSD: table_sqlite.c,v 1.3 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -19,7 +19,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <ctype.h> @@ -36,11 +35,11 @@ #include "log.h" /* sqlite(3) backend */ -static int table_sqlite_config(struct table *, const char *); +static int table_sqlite_config(struct table *); static int table_sqlite_update(struct table *); static void *table_sqlite_open(struct table *); static int table_sqlite_lookup(void *, const char *, enum table_service, - void **); + union lookup *); static void table_sqlite_close(void *); struct table_backend table_backend_sqlite = { @@ -57,36 +56,35 @@ struct table_sqlite_handle { struct table *table; }; -static int table_sqlite_alias(struct table_sqlite_handle *, const char *, void **); -static int table_sqlite_domain(struct table_sqlite_handle *, const char *, void **); -static int table_sqlite_userinfo(struct table_sqlite_handle *, const char *, void **); -static int table_sqlite_credentials(struct table_sqlite_handle *, const char *, void **); -static int table_sqlite_netaddr(struct table_sqlite_handle *, const char *, void **); +static int table_sqlite_alias(struct table_sqlite_handle *, const char *, union lookup *); +static int table_sqlite_domain(struct table_sqlite_handle *, const char *, union lookup *); +static int table_sqlite_userinfo(struct table_sqlite_handle *, const char *, union lookup *); +static int table_sqlite_credentials(struct table_sqlite_handle *, const char *, union lookup *); +static int table_sqlite_netaddr(struct table_sqlite_handle *, const char *, union lookup *); static int -table_sqlite_config(struct table *table, const char *config) +table_sqlite_config(struct table *table) { - void *cfg; + struct table *cfg; /* no config ? broken */ - if (config == NULL) + if (table->t_config[0] == '\0') return 0; - cfg = table_config_create(); - if (! table_config_parse(cfg, config, T_HASH)) + cfg = table_create("static", table->t_name, "conf", table->t_config); + if (!table_config(cfg)) goto err; /* sanity checks */ - if (table_config_get(cfg, "dbpath") == NULL) { + if (table_get(cfg, "dbpath") == NULL) { log_warnx("table_sqlite: missing 'dbpath' configuration"); return 0; } - table_set_configuration(table, cfg); return 1; err: - table_config_destroy(cfg); + table_destroy(cfg); return 0; } @@ -101,13 +99,13 @@ static void * table_sqlite_open(struct table *table) { struct table_sqlite_handle *tsh; - void *cfg; + struct table *cfg; const char *dbpath; tsh = xcalloc(1, sizeof *tsh, "table_sqlite_open"); tsh->table = table; - cfg = table_get_configuration(table); + cfg = table_find(table->t_name, "conf"); dbpath = table_get(cfg, "dbpath"); if (sqlite3_open(dbpath, &tsh->ppDb) != SQLITE_OK) { @@ -127,21 +125,21 @@ table_sqlite_close(void *hdl) static int table_sqlite_lookup(void *hdl, const char *key, enum table_service service, - void **retp) + union lookup *lk) { struct table_sqlite_handle *tsh = hdl; switch (service) { case K_ALIAS: - return table_sqlite_alias(tsh, key, retp); + return table_sqlite_alias(tsh, key, lk); case K_DOMAIN: - return table_sqlite_domain(tsh, key, retp); + return table_sqlite_domain(tsh, key, lk); case K_USERINFO: - return table_sqlite_userinfo(tsh, key, retp); + return table_sqlite_userinfo(tsh, key, lk); case K_CREDENTIALS: - return table_sqlite_credentials(tsh, key, retp); + return table_sqlite_credentials(tsh, key, lk); case K_NETADDR: - return table_sqlite_netaddr(tsh, key, retp); + return table_sqlite_netaddr(tsh, key, lk); default: log_warnx("table_sqlite: lookup: unsupported lookup service"); return -1; @@ -151,13 +149,12 @@ table_sqlite_lookup(void *hdl, const char *key, enum table_service service, } static int -table_sqlite_alias(struct table_sqlite_handle *tsh, const char *key, void **retp) +table_sqlite_alias(struct table_sqlite_handle *tsh, const char *key, union lookup *lk) { - struct table *cfg = table_get_configuration(tsh->table); + struct table *cfg = table_find(tsh->table->t_name, "conf"); const char *query = table_get(cfg, "query_alias"); sqlite3_stmt *stmt; - struct expand *xp = NULL; struct expandnode xn; int nrows; @@ -177,43 +174,38 @@ table_sqlite_alias(struct table_sqlite_handle *tsh, const char *key, void **retp return -1; } - if (retp) - xp = xcalloc(1, sizeof *xp, "table_sqlite_alias"); + if (lk) + lk->expand = xcalloc(1, sizeof(*lk->expand), "table_sqlite_alias"); nrows = 0; sqlite3_bind_text(stmt, 1, key, strlen(key), NULL); while (sqlite3_step(stmt) == SQLITE_ROW) { - if (retp == NULL) { + if (lk == NULL) { sqlite3_finalize(stmt); return 1; } if (! text_to_expandnode(&xn, sqlite3_column_text(stmt, 0))) goto error; - expand_insert(xp, &xn); + expand_insert(lk->expand, &xn); nrows++; } sqlite3_finalize(stmt); - if (retp) - *retp = xp; return nrows ? 1 : 0; error: - if (retp) - *retp = NULL; - if (xp) - expand_free(xp); + if (lk && lk->expand) + expand_free(lk->expand); return -1; } static int -table_sqlite_domain(struct table_sqlite_handle *tsh, const char *key, void **retp) +table_sqlite_domain(struct table_sqlite_handle *tsh, const char *key, union lookup *lk) { - struct table *cfg = table_get_configuration(tsh->table); + struct table *cfg = table_find(tsh->table->t_name, "conf"); const char *query = table_get(cfg, "query_domain"); sqlite3_stmt *stmt; - struct destination *domain = NULL; if (query == NULL) { log_warnx("table_sqlite: lookup: no query configured for domain"); @@ -235,11 +227,8 @@ table_sqlite_domain(struct table_sqlite_handle *tsh, const char *key, void **ret switch (sqlite3_step(stmt)) { case SQLITE_ROW: - if (retp) { - domain = xcalloc(1, sizeof *domain, "table_sqlite_domain"); - strlcpy(domain->name, sqlite3_column_text(stmt, 0), sizeof domain->name); - *retp = domain; - } + if (lk) + strlcpy(lk->domain.name, sqlite3_column_text(stmt, 0), sizeof(lk->domain.name)); sqlite3_finalize(stmt); return 1; @@ -251,19 +240,15 @@ table_sqlite_domain(struct table_sqlite_handle *tsh, const char *key, void **ret sqlite3_finalize(stmt); } - free(domain); - if (retp) - *retp = NULL; return -1; } static int -table_sqlite_userinfo(struct table_sqlite_handle *tsh, const char *key, void **retp) +table_sqlite_userinfo(struct table_sqlite_handle *tsh, const char *key, union lookup *lk) { - struct table *cfg = table_get_configuration(tsh->table); + struct table *cfg = table_find(tsh->table->t_name, "conf"); const char *query = table_get(cfg, "query_userinfo"); sqlite3_stmt *stmt; - struct userinfo *userinfo = NULL; size_t s; if (query == NULL) { @@ -286,19 +271,17 @@ table_sqlite_userinfo(struct table_sqlite_handle *tsh, const char *key, void **r switch (sqlite3_step(stmt)) { case SQLITE_ROW: - if (retp) { - userinfo = xcalloc(1, sizeof *userinfo, "table_sqlite_userinfo"); - s = strlcpy(userinfo->username, sqlite3_column_text(stmt, 0), - sizeof(userinfo->username)); - if (s >= sizeof(userinfo->username)) + if (lk) { + s = strlcpy(lk->userinfo.username, sqlite3_column_text(stmt, 0), + sizeof(lk->userinfo.username)); + if (s >= sizeof(lk->userinfo.username)) goto error; - userinfo->uid = sqlite3_column_int(stmt, 1); - userinfo->gid = sqlite3_column_int(stmt, 2); - s = strlcpy(userinfo->directory, sqlite3_column_text(stmt, 3), - sizeof(userinfo->directory)); - if (s >= sizeof(userinfo->directory)) + lk->userinfo.uid = sqlite3_column_int(stmt, 1); + lk->userinfo.gid = sqlite3_column_int(stmt, 2); + s = strlcpy(lk->userinfo.directory, sqlite3_column_text(stmt, 3), + sizeof(lk->userinfo.directory)); + if (s >= sizeof(lk->userinfo.directory)) goto error; - *retp = userinfo; } sqlite3_finalize(stmt); return 1; @@ -313,19 +296,15 @@ table_sqlite_userinfo(struct table_sqlite_handle *tsh, const char *key, void **r error: sqlite3_finalize(stmt); - free(userinfo); - if (retp) - *retp = NULL; return -1; } static int -table_sqlite_credentials(struct table_sqlite_handle *tsh, const char *key, void **retp) +table_sqlite_credentials(struct table_sqlite_handle *tsh, const char *key, union lookup *lk) { - struct table *cfg = table_get_configuration(tsh->table); + struct table *cfg = table_find(tsh->table->t_name, "conf"); const char *query = table_get(cfg, "query_credentials"); sqlite3_stmt *stmt; - struct credentials *creds = NULL; size_t s; if (query == NULL) { @@ -347,17 +326,15 @@ table_sqlite_credentials(struct table_sqlite_handle *tsh, const char *key, void sqlite3_bind_text(stmt, 1, key, strlen(key), NULL); switch (sqlite3_step(stmt)) { case SQLITE_ROW: - if (retp) { - creds = xcalloc(1, sizeof *creds, "table_sqlite_credentials"); - s = strlcpy(creds->username, sqlite3_column_text(stmt, 0), - sizeof(creds->username)); - if (s >= sizeof(creds->username)) + if (lk) { + s = strlcpy(lk->creds.username, sqlite3_column_text(stmt, 0), + sizeof(lk->creds.username)); + if (s >= sizeof(lk->creds.username)) goto error; - s = strlcpy(creds->password, sqlite3_column_text(stmt, 1), - sizeof(creds->password)); - if (s >= sizeof(creds->password)) + s = strlcpy(lk->creds.password, sqlite3_column_text(stmt, 1), + sizeof(lk->creds.password)); + if (s >= sizeof(lk->creds.password)) goto error; - *retp = creds; } sqlite3_finalize(stmt); return 1; @@ -372,20 +349,16 @@ table_sqlite_credentials(struct table_sqlite_handle *tsh, const char *key, void error: sqlite3_finalize(stmt); - free(creds); - if (retp) - *retp = NULL; return -1; } static int -table_sqlite_netaddr(struct table_sqlite_handle *tsh, const char *key, void **retp) +table_sqlite_netaddr(struct table_sqlite_handle *tsh, const char *key, union lookup *lk) { - struct table *cfg = table_get_configuration(tsh->table); + struct table *cfg = table_find(tsh->table->t_name, "conf"); const char *query = table_get(cfg, "query_netaddr"); sqlite3_stmt *stmt; - struct netaddr *netaddr = NULL; if (query == NULL) { log_warnx("table_sqlite: lookup: no query configured for netaddr"); @@ -406,11 +379,9 @@ table_sqlite_netaddr(struct table_sqlite_handle *tsh, const char *key, void **re sqlite3_bind_text(stmt, 1, key, strlen(key), NULL); switch (sqlite3_step(stmt)) { case SQLITE_ROW: - if (retp) { - netaddr = xcalloc(1, sizeof *netaddr, "table_sqlite_netaddr"); - if (! text_to_netaddr(netaddr, sqlite3_column_text(stmt, 0))) + if (lk) { + if (! text_to_netaddr(&lk->netaddr, sqlite3_column_text(stmt, 0))) goto error; - *retp = netaddr; } sqlite3_finalize(stmt); return 1; @@ -425,8 +396,5 @@ table_sqlite_netaddr(struct table_sqlite_handle *tsh, const char *key, void **re error: sqlite3_finalize(stmt); - free(netaddr); - if (retp) - *retp = NULL; return -1; } diff --git a/usr.sbin/smtpd/table_static.c b/usr.sbin/smtpd/table_static.c index cd77677ab02..9fe1ceae9f9 100644 --- a/usr.sbin/smtpd/table_static.c +++ b/usr.sbin/smtpd/table_static.c @@ -1,6 +1,7 @@ -/* $OpenBSD: table_static.c,v 1.4 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: table_static.c,v 1.5 2013/05/24 17:03:14 eric Exp $ */ /* + * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> * * Permission to use, copy, modify, and distribute this software for any @@ -19,7 +20,6 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> -#include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> @@ -38,22 +38,14 @@ #include "log.h" /* static backend */ -static int table_static_config(struct table *, const char *); +static int table_static_config(struct table *); static int table_static_update(struct table *); static void *table_static_open(struct table *); static int table_static_lookup(void *, const char *, enum table_service, - void **); -static int table_static_fetch(void *, enum table_service, char **); + union lookup *); +static int table_static_fetch(void *, enum table_service, union lookup *); static void table_static_close(void *); - -static int table_static_credentials(const char *, char *, size_t, void **); -static int table_static_alias(const char *, char *, size_t, void **); -static int table_static_domain(const char *, char *, size_t, void **); -static int table_static_netaddr(const char *, char *, size_t, void **); -static int table_static_source(const char *, char *, size_t, void **); -static int table_static_userinfo(const char *, char *, size_t, void **); -static int table_static_mailaddr(const char *, char *, size_t, void **); -static int table_static_addrname(const char *, char *, size_t, void **); +static int table_static_parse(struct table *, const char *, enum table_type); struct table_backend table_backend_static = { K_ALIAS|K_CREDENTIALS|K_DOMAIN|K_NETADDR|K_USERINFO|K_SOURCE|K_MAILADDR|K_ADDRNAME, @@ -76,30 +68,99 @@ static struct keycmp { static int -table_static_config(struct table *table, const char *config) +table_static_config(struct table *table) { /* no config ? ok */ - if (config == NULL) + if (*table->t_config == '\0') return 1; - return table_config_parse(table, config, T_LIST|T_HASH); + return table_static_parse(table, table->t_config, T_LIST|T_HASH); +} + +static int +table_static_parse(struct table *t, const char *config, enum table_type type) +{ + FILE *fp; + char *buf, *lbuf; + size_t flen; + char *keyp; + char *valp; + size_t ret = 0; + + fp = fopen(config, "r"); + if (fp == NULL) + return 0; + + lbuf = NULL; + while ((buf = fgetln(fp, &flen))) { + if (buf[flen - 1] == '\n') + buf[flen - 1] = '\0'; + else { + lbuf = xmalloc(flen + 1, "table_config_parse"); + memcpy(lbuf, buf, flen); + lbuf[flen] = '\0'; + buf = lbuf; + } + + keyp = buf; + while (isspace((int)*keyp)) + ++keyp; + if (*keyp == '\0' || *keyp == '#') + continue; + valp = keyp; + strsep(&valp, " \t:"); + if (valp) { + while (*valp) { + if (!isspace(*valp) && + !(*valp == ':' && isspace(*(valp + 1)))) + break; + ++valp; + } + if (*valp == '\0') + valp = NULL; + } + + /**/ + if (t->t_type == 0) + t->t_type = (valp == keyp || valp == NULL) ? T_LIST : + T_HASH; + + if (!(t->t_type & type)) + goto end; + + if ((valp == keyp || valp == NULL) && t->t_type == T_LIST) + table_add(t, keyp, NULL); + else if ((valp != keyp && valp != NULL) && t->t_type == T_HASH) + table_add(t, keyp, valp); + else + goto end; + } + ret = 1; +end: + free(lbuf); + fclose(fp); + return ret; } static int table_static_update(struct table *table) { - struct table *t; + struct table *t; + void *p = NULL; /* no config ? ok */ if (table->t_config[0] == '\0') goto ok; - t = table_create(table->t_src, NULL, table->t_config); - if (! t->t_backend->config(t, table->t_config)) + t = table_create("static", table->t_name, "update", table->t_config); + if (!table_config(t)) goto err; /* replace former table, frees t */ - table_replace(table, t); + while (dict_poproot(&table->t_dict, NULL, (void **)&p)) + free(p); + dict_merge(&table->t_dict, &t->t_dict); + table_destroy(t); ok: log_info("info: Table \"%s\" successfully updated", table->t_name); @@ -125,11 +186,10 @@ table_static_close(void *hdl) static int table_static_lookup(void *hdl, const char *key, enum table_service service, - void **retp) + union lookup *lk) { struct table *m = hdl; char *line; - size_t len; int ret; int (*match)(const char *, const char *) = NULL; size_t i; @@ -161,65 +221,20 @@ table_static_lookup(void *hdl, const char *key, enum table_service service, break; } - if (retp == NULL) + if (lk == NULL) return ret ? 1 : 0; - if (ret == 0) { - *retp = NULL; + if (ret == 0) return 0; - } - - if ((line = strdup(line)) == NULL) - return -1; - len = strlen(line); - switch (service) { - case K_ALIAS: - ret = table_static_alias(key, line, len, retp); - break; - - case K_CREDENTIALS: - ret = table_static_credentials(key, line, len, retp); - break; - - case K_DOMAIN: - ret = table_static_domain(key, line, len, retp); - break; - - case K_NETADDR: - ret = table_static_netaddr(key, line, len, retp); - break; - - case K_SOURCE: - ret = table_static_source(key, line, len, retp); - break; - - case K_USERINFO: - ret = table_static_userinfo(key, line, len, retp); - break; - - case K_MAILADDR: - ret = table_static_mailaddr(key, line, len, retp); - break; - - case K_ADDRNAME: - ret = table_static_addrname(key, line, len, retp); - break; - default: - ret = -1; - } - - free(line); - - return ret; + return table_parse_lookup(service, key, line, lk); } static int -table_static_fetch(void *hdl, enum table_service service, char **retp) +table_static_fetch(void *hdl, enum table_service service, union lookup *lk) { struct table *t = hdl; const char *k; - char *line; if (! dict_iter(&t->t_dict, &t->t_iter, &k, (void **)NULL)) { t->t_iter = NULL; @@ -227,185 +242,8 @@ table_static_fetch(void *hdl, enum table_service service, char **retp) return 0; } - if (retp == NULL) + if (lk == NULL) return 1; - if ((line = strdup(k)) == NULL) - return -1; - - *retp = line; - - return 1; -} - -static int -table_static_credentials(const char *key, char *line, size_t len, void **retp) -{ - struct credentials *creds; - char *p; - - /* credentials are stored as user:password */ - if (len < 3) - return -1; - - /* too big to fit in a smtp session line */ - if (len >= SMTPD_MAXLINESIZE) - return -1; - - p = strchr(line, ':'); - if (p == NULL) - return -1; - - if (p == line || p == line + len - 1) - return -1; - *p++ = '\0'; - - creds = xcalloc(1, sizeof *creds, "table_static_credentials"); - if (strlcpy(creds->username, line, sizeof(creds->username)) - >= sizeof(creds->username)) - goto err; - - if (strlcpy(creds->password, p, sizeof(creds->password)) - >= sizeof(creds->password)) - goto err; - - *retp = creds; - return 1; - -err: - *retp = NULL; - free(creds); - return -1; -} - -static int -table_static_alias(const char *key, char *line, size_t len, void **retp) -{ - struct expand *xp; - - xp = xcalloc(1, sizeof *xp, "table_static_alias"); - if (! expand_line(xp, line, 1)) - goto error; - *retp = xp; - return 1; - -error: - *retp = NULL; - expand_free(xp); - return -1; -} - -static int -table_static_netaddr(const char *key, char *line, size_t len, void **retp) -{ - struct netaddr *netaddr; - - netaddr = xcalloc(1, sizeof *netaddr, "table_static_netaddr"); - if (! text_to_netaddr(netaddr, line)) - goto error; - *retp = netaddr; - return 1; - -error: - *retp = NULL; - free(netaddr); - return -1; -} - -static int -table_static_source(const char *key, char *line, size_t len, void **retp) -{ - struct source *source = NULL; - - source = xcalloc(1, sizeof *source, "table_static_source"); - if (inet_pton(AF_INET6, line, &source->addr.in6) != 1) - if (inet_pton(AF_INET, line, &source->addr.in4) != 1) - goto error; - *retp = source; - return 1; - -error: - *retp = NULL; - free(source); - return 0; -} - -static int -table_static_domain(const char *key, char *line, size_t len, void **retp) -{ - struct destination *destination; - - destination = xcalloc(1, sizeof *destination, "table_static_domain"); - if (strlcpy(destination->name, line, sizeof destination->name) - >= sizeof destination->name) - goto error; - *retp = destination; - return 1; - -error: - *retp = NULL; - free(destination); - return -1; -} - -static int -table_static_userinfo(const char *key, char *line, size_t len, void **retp) -{ - struct userinfo *userinfo = NULL; - char buffer[1024]; - - if (! bsnprintf(buffer, sizeof buffer, "%s:%s", key, line)) - goto error; - - userinfo = xcalloc(1, sizeof *userinfo, "table_static_userinfo"); - if (! text_to_userinfo(userinfo, buffer)) - goto error; - *retp = userinfo; - return 1; - -error: - *retp = NULL; - free(userinfo); - return -1; -} - -static int -table_static_mailaddr(const char *key, char *line, size_t len, void **retp) -{ - struct mailaddr *mailaddr; - - mailaddr = xcalloc(1, sizeof *mailaddr, "table_static_mailaddr"); - if (! text_to_mailaddr(mailaddr, line)) - goto error; - *retp = mailaddr; - return 1; - -error: - *retp = NULL; - free(mailaddr); - return -1; -} - -static int -table_static_addrname(const char *key, char *line, size_t len, void **retp) -{ - struct addrname *addrname; - - addrname = xcalloc(1, sizeof *addrname, "table_static_addrname"); - - if (inet_pton(AF_INET6, key, &addrname->addr.in6) != 1) - if (inet_pton(AF_INET, key, &addrname->addr.in4) != 1) - goto error; - - if (strlcpy(addrname->name, line, sizeof addrname->name) - >= sizeof addrname->name) - goto error; - - *retp = addrname; - return 1; - -error: - *retp = NULL; - free(addrname); - return -1; + return table_parse_lookup(service, NULL, k, lk); } diff --git a/usr.sbin/smtpd/to.c b/usr.sbin/smtpd/to.c index 0d23103c395..862c25af45d 100644 --- a/usr.sbin/smtpd/to.c +++ b/usr.sbin/smtpd/to.c @@ -1,4 +1,4 @@ -/* $OpenBSD: to.c,v 1.6 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: to.c,v 1.7 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -19,7 +19,6 @@ */ #include <sys/types.h> -#include <sys/param.h> #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> @@ -56,6 +55,7 @@ static int alias_is_username(struct expandnode *, const char *, size_t); static int alias_is_address(struct expandnode *, const char *, size_t); static int alias_is_filename(struct expandnode *, const char *, size_t); static int alias_is_include(struct expandnode *, const char *, size_t); +static int alias_is_error(struct expandnode *, const char *, size_t); const char * sockaddr_to_text(struct sockaddr *sa) @@ -270,7 +270,7 @@ text_to_netaddr(struct netaddr *netaddr, const char *s) bzero(&ssin, sizeof(struct sockaddr_in)); bzero(&ssin6, sizeof(struct sockaddr_in6)); - if (strncmp("IPv6:", s, 5) == 0) + if (strncasecmp("IPv6:", s, 5) == 0) s += 5; if (strchr(s, '/') != NULL) { @@ -571,6 +571,11 @@ rule_to_text(struct rule *r) strlcat(buf, r->r_value.buffer, sizeof buf); strlcat(buf, "\"", sizeof buf); break; + case A_LMTP: + strlcat(buf, " deliver to lmtp \"", sizeof buf); + strlcat(buf, r->r_value.buffer, sizeof buf); + strlcat(buf, "\"", sizeof buf); + break; } return buf; @@ -579,7 +584,7 @@ rule_to_text(struct rule *r) int text_to_userinfo(struct userinfo *userinfo, const char *s) { - char buf[MAXPATHLEN]; + char buf[SMTPD_MAXPATHLEN]; char *p; const char *errstr; @@ -664,7 +669,8 @@ text_to_expandnode(struct expandnode *expandnode, const char *s) size_t l; l = strlen(s); - if (alias_is_include(expandnode, s, l) || + if (alias_is_error(expandnode, s, l) || + alias_is_include(expandnode, s, l) || alias_is_filter(expandnode, s, l) || alias_is_filename(expandnode, s, l) || alias_is_address(expandnode, s, l) || @@ -681,6 +687,7 @@ expandnode_to_text(struct expandnode *expandnode) case EXPAND_FILTER: case EXPAND_FILENAME: case EXPAND_INCLUDE: + case EXPAND_ERROR: return expandnode->u.buffer; case EXPAND_USERNAME: return expandnode->u.user; @@ -807,3 +814,34 @@ alias_is_include(struct expandnode *alias, const char *line, size_t len) alias->type = EXPAND_INCLUDE; return 1; } + +static int +alias_is_error(struct expandnode *alias, const char *line, size_t len) +{ + size_t skip; + + bzero(alias, sizeof *alias); + + if (strncasecmp(":error:", line, 7) == 0) + skip = 7; + else if (strncasecmp("error:", line, 6) == 0) + skip = 6; + else + return 0; + + if (strlcpy(alias->u.buffer, line + skip, + sizeof(alias->u.buffer)) >= sizeof(alias->u.buffer)) + return 0; + + if (strlen(alias->u.buffer) < 5) + return 0; + + /* [45][0-9]{2} [a-zA-Z0-9].* */ + if (alias->u.buffer[3] != ' ' || !isalnum(alias->u.buffer[4]) || + (alias->u.buffer[0] != '4' && alias->u.buffer[0] != '5') || + !isdigit(alias->u.buffer[1]) || !isdigit(alias->u.buffer[2])) + return 0; + + alias->type = EXPAND_ERROR; + return 1; +} diff --git a/usr.sbin/smtpd/tree.c b/usr.sbin/smtpd/tree.c index e972839b6ee..796b1f26721 100644 --- a/usr.sbin/smtpd/tree.c +++ b/usr.sbin/smtpd/tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tree.c,v 1.3 2013/01/26 09:37:24 gilles Exp $ */ +/* $OpenBSD: tree.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> @@ -38,7 +38,7 @@ struct treeentry { static int treeentry_cmp(struct treeentry *, struct treeentry *); -SPLAY_PROTOTYPE(tree, treeentry, entry, treeentry_cmp); +SPLAY_PROTOTYPE(_tree, treeentry, entry, treeentry_cmp); int tree_check(struct tree *t, uint64_t id) @@ -46,7 +46,7 @@ tree_check(struct tree *t, uint64_t id) struct treeentry key; key.id = id; - return (SPLAY_FIND(tree, t, &key) != NULL); + return (SPLAY_FIND(_tree, &t->tree, &key) != NULL); } void * @@ -56,11 +56,13 @@ tree_set(struct tree *t, uint64_t id, void *data) char *old; key.id = id; - if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) { - entry = xmalloc(sizeof *entry, "tree_set"); + if ((entry = SPLAY_FIND(_tree, &t->tree, &key)) == NULL) { + if ((entry = malloc(sizeof *entry)) == NULL) + err(1, "tree_set: malloc"); entry->id = id; - SPLAY_INSERT(tree, t, entry); + SPLAY_INSERT(_tree, &t->tree, entry); old = NULL; + t->count += 1; } else old = entry->data; @@ -74,11 +76,13 @@ tree_xset(struct tree *t, uint64_t id, void *data) { struct treeentry *entry; - entry = xmalloc(sizeof *entry, "tree_xset"); + if ((entry = malloc(sizeof *entry)) == NULL) + err(1, "tree_xset: malloc"); entry->id = id; entry->data = data; - if (SPLAY_INSERT(tree, t, entry)) + if (SPLAY_INSERT(_tree, &t->tree, entry)) errx(1, "tree_xset(%p, 0x%016"PRIx64 ")", t, id); + t->count += 1; } void * @@ -87,7 +91,7 @@ tree_get(struct tree *t, uint64_t id) struct treeentry key, *entry; key.id = id; - if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) + if ((entry = SPLAY_FIND(_tree, &t->tree, &key)) == NULL) return (NULL); return (entry->data); @@ -99,7 +103,7 @@ tree_xget(struct tree *t, uint64_t id) struct treeentry key, *entry; key.id = id; - if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) + if ((entry = SPLAY_FIND(_tree, &t->tree, &key)) == NULL) errx(1, "tree_get(%p, 0x%016"PRIx64 ")", t, id); return (entry->data); @@ -112,12 +116,13 @@ tree_pop(struct tree *t, uint64_t id) void *data; key.id = id; - if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) + if ((entry = SPLAY_FIND(_tree, &t->tree, &key)) == NULL) return (NULL); data = entry->data; - SPLAY_REMOVE(tree, t, entry); + SPLAY_REMOVE(_tree, &t->tree, entry); free(entry); + t->count -= 1; return (data); } @@ -129,12 +134,13 @@ tree_xpop(struct tree *t, uint64_t id) void *data; key.id = id; - if ((entry = SPLAY_FIND(tree, t, &key)) == NULL) + if ((entry = SPLAY_FIND(_tree, &t->tree, &key)) == NULL) errx(1, "tree_xpop(%p, 0x%016" PRIx64 ")", t, id); data = entry->data; - SPLAY_REMOVE(tree, t, entry); + SPLAY_REMOVE(_tree, &t->tree, entry); free(entry); + t->count -= 1; return (data); } @@ -144,15 +150,17 @@ tree_poproot(struct tree *t, uint64_t *id, void **data) { struct treeentry *entry; - entry = SPLAY_ROOT(t); + entry = SPLAY_ROOT(&t->tree); if (entry == NULL) return (0); if (id) *id = entry->id; if (data) *data = entry->data; - SPLAY_REMOVE(tree, t, entry); + SPLAY_REMOVE(_tree, &t->tree, entry); free(entry); + t->count -= 1; + return (1); } @@ -161,7 +169,7 @@ tree_root(struct tree *t, uint64_t *id, void **data) { struct treeentry *entry; - entry = SPLAY_ROOT(t); + entry = SPLAY_ROOT(&t->tree); if (entry == NULL) return (0); if (id) @@ -177,9 +185,9 @@ tree_iter(struct tree *t, void **hdl, uint64_t *id, void **data) struct treeentry *curr = *hdl; if (curr == NULL) - curr = SPLAY_MIN(tree, t); + curr = SPLAY_MIN(_tree, &t->tree); else - curr = SPLAY_NEXT(tree, t, curr); + curr = SPLAY_NEXT(_tree, &t->tree, curr); if (curr) { *hdl = curr; @@ -200,18 +208,18 @@ tree_iterfrom(struct tree *t, void **hdl, uint64_t k, uint64_t *id, void **data) if (curr == NULL) { if (k == 0) - curr = SPLAY_MIN(tree, t); + curr = SPLAY_MIN(_tree, &t->tree); else { key.id = k; - curr = SPLAY_FIND(tree, t, &key); + curr = SPLAY_FIND(_tree, &t->tree, &key); if (curr == NULL) { - SPLAY_INSERT(tree, t, &key); - curr = SPLAY_NEXT(tree, t, &key); - SPLAY_REMOVE(tree, t, &key); + SPLAY_INSERT(_tree, &t->tree, &key); + curr = SPLAY_NEXT(_tree, &t->tree, &key); + SPLAY_REMOVE(_tree, &t->tree, &key); } } } else - curr = SPLAY_NEXT(tree, t, curr); + curr = SPLAY_NEXT(_tree, &t->tree, curr); if (curr) { *hdl = curr; @@ -230,12 +238,14 @@ tree_merge(struct tree *dst, struct tree *src) { struct treeentry *entry; - while (!SPLAY_EMPTY(src)) { - entry = SPLAY_ROOT(src); - SPLAY_REMOVE(tree, src, entry); - if (SPLAY_INSERT(tree, dst, entry)) + while (!SPLAY_EMPTY(&src->tree)) { + entry = SPLAY_ROOT(&src->tree); + SPLAY_REMOVE(_tree, &src->tree, entry); + if (SPLAY_INSERT(_tree, &dst->tree, entry)) errx(1, "tree_merge: duplicate"); } + dst->count += src->count; + src->count = 0; } static int @@ -248,4 +258,4 @@ treeentry_cmp(struct treeentry *a, struct treeentry *b) return (0); } -SPLAY_GENERATE(tree, treeentry, entry, treeentry_cmp); +SPLAY_GENERATE(_tree, treeentry, entry, treeentry_cmp); diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c index 93c7aff31b0..97078c766db 100644 --- a/usr.sbin/smtpd/util.c +++ b/usr.sbin/smtpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.93 2013/04/12 18:22:49 eric Exp $ */ +/* $OpenBSD: util.c,v 1.94 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2000,2001 Markus Friedl. All rights reserved. @@ -20,7 +20,6 @@ */ #include <sys/types.h> -#include <sys/param.h> #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> @@ -175,7 +174,7 @@ mkdirs_component(char *path, mode_t mode) int mkdirs(char *path, mode_t mode) { - char buf[MAXPATHLEN]; + char buf[SMTPD_MAXPATHLEN]; int i = 0; int done = 0; char *p; @@ -184,7 +183,7 @@ mkdirs(char *path, mode_t mode) if (*path != '/') return 0; - /* make sure we don't exceed MAXPATHLEN */ + /* make sure we don't exceed SMTPD_MAXPATHLEN */ if (strlen(path) >= sizeof buf) return 0; @@ -333,7 +332,7 @@ mvpurge(char *from, char *to) size_t n; int retry; const char *sep; - char buf[MAXPATHLEN]; + char buf[SMTPD_MAXPATHLEN]; if ((n = strlen(to)) == 0) fatalx("to is empty"); @@ -341,7 +340,7 @@ mvpurge(char *from, char *to) sep = (to[n - 1] == '/') ? "" : "/"; retry = 0; - again: +again: snprintf(buf, sizeof buf, "%s%s%u", to, sep, arc4random()); if (rename(from, buf) == -1) { /* ENOTDIR has actually 2 meanings, and incorrect input @@ -363,12 +362,12 @@ mvpurge(char *from, char *to) int mktmpfile(void) { - char path[MAXPATHLEN]; + char path[SMTPD_MAXPATHLEN]; int fd; mode_t omode; if (! bsnprintf(path, sizeof(path), "%s/smtpd.XXXXXXXXXX", - PATH_TEMPORARY)) + PATH_TEMPORARY)) err(1, "snprintf"); omode = umask(7077); @@ -454,25 +453,32 @@ valid_domainpart(const char *s) { struct in_addr ina; struct in6_addr ina6; - char *c, domain[MAX_DOMAINPART_SIZE]; + char *c, domain[SMTPD_MAXDOMAINPARTSIZE]; + const char *p; if (*s == '[') { - strlcpy(domain, s + 1, sizeof domain); + if (strncasecmp("[IPv6:", s, 6) == 0) + p = s + 6; + else + p = s + 1; + + if (strlcpy(domain, p, sizeof domain) >= sizeof domain) + return 0; c = strchr(domain, (int)']'); if (!c || c[1] != '\0') return 0; - + *c = '\0'; - + if (inet_pton(AF_INET6, domain, &ina6) == 1) return 1; if (inet_pton(AF_INET, domain, &ina) == 1) return 1; - + return 0; } - + nextsub: if (!isalnum((int)*s)) return 0; @@ -492,15 +498,14 @@ nextsub: return 1; } - /* * Check file for security. Based on usr.bin/ssh/auth.c. */ int secure_file(int fd, char *path, char *userdir, uid_t uid, int mayread) { - char buf[MAXPATHLEN]; - char homedir[MAXPATHLEN]; + char buf[PATH_MAX]; + char homedir[PATH_MAX]; struct stat st; char *cp; diff --git a/usr.sbin/smtpd/waitq.c b/usr.sbin/smtpd/waitq.c index 9adbaa986cd..09793624941 100644 --- a/usr.sbin/smtpd/waitq.c +++ b/usr.sbin/smtpd/waitq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: waitq.c,v 1.3 2013/01/26 09:37:24 gilles Exp $ */ +/* $OpenBSD: waitq.c,v 1.4 2013/05/24 17:03:14 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> @@ -17,8 +17,8 @@ */ #include <sys/types.h> -#include <sys/tree.h> #include <sys/queue.h> +#include <sys/tree.h> #include <sys/uio.h> #include <imsg.h> |