diff options
Diffstat (limited to 'smtpd')
83 files changed, 1793 insertions, 75 deletions
diff --git a/smtpd/aliases.c b/smtpd/aliases.c index 93d3fe68..be350897 100644 --- a/smtpd/aliases.c +++ b/smtpd/aliases.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,7 +31,12 @@ #include <stdlib.h> #include <string.h> #include <limits.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/bounce.c b/smtpd/bounce.c index 02239988..41526d8d 100644 --- a/smtpd/bounce.c +++ b/smtpd/bounce.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -17,11 +17,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> #include <sys/tree.h> +#include <grp.h> /* needed for setgroups */ #include <err.h> #include <imsg.h> #include <limits.h> diff --git a/smtpd/cert.c b/smtpd/cert.c index 05aff418..79b1df91 100644 --- a/smtpd/cert.c +++ b/smtpd/cert.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> diff --git a/smtpd/compress_backend.c b/smtpd/compress_backend.c index 516dd1ee..1b974662 100644 --- a/smtpd/compress_backend.c +++ b/smtpd/compress_backend.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/compress_gzip.c b/smtpd/compress_gzip.c index e7421cec..dd60aeec 100644 --- a/smtpd/compress_gzip.c +++ b/smtpd/compress_gzip.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/config.c b/smtpd/config.c index 552803cb..c1089104 100644 --- a/smtpd/config.c +++ b/smtpd/config.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -204,7 +206,9 @@ set_localaddrs(struct smtpd *conf, struct table *localnames) case AF_INET: sain = (struct sockaddr_in *)&ss; *sain = *(struct sockaddr_in *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif table_add(t, ss_to_text(&ss), NULL); table_add(localnames, ss_to_text(&ss), NULL); (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss)); @@ -214,7 +218,9 @@ set_localaddrs(struct smtpd *conf, struct table *localnames) case AF_INET6: sin6 = (struct sockaddr_in6 *)&ss; *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif table_add(t, ss_to_text(&ss), NULL); table_add(localnames, ss_to_text(&ss), NULL); (void)snprintf(buf, sizeof buf, "[%s]", ss_to_text(&ss)); @@ -305,7 +311,8 @@ config_process(enum smtp_proc_type proc) fatal("fdlimit: getrlimit"); rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) == -1) - fatal("fdlimit: setrlimit"); + if (errno != EINVAL) + fatal("fdlimit: setrlimit"); } void diff --git a/smtpd/control.c b/smtpd/control.c index 6f9c9aca..d85bf578 100644 --- a/smtpd/control.c +++ b/smtpd/control.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,6 +31,7 @@ #include <errno.h> #include <event.h> #include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <pwd.h> #include <signal.h> @@ -292,7 +295,7 @@ control_accept(int listenfd, short event, void *arg) uid_t euid; gid_t egid; - if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) + if (available_fds(CONTROL_FD_RESERVE)) goto pause; len = sizeof(s_un); @@ -366,7 +369,7 @@ control_close(struct ctl_conn *c) stat_backend->decrement("control.session", 1); - if (getdtablesize() - getdtablecount() < CONTROL_FD_RESERVE) + if (available_fds(CONTROL_FD_RESERVE)) return; if (!event_pending(&control_state.ev, EV_READ, NULL)) { diff --git a/smtpd/crypto.c b/smtpd/crypto.c index 1cc1af7c..76f98807 100644 --- a/smtpd/crypto.c +++ b/smtpd/crypto.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> diff --git a/smtpd/dict.c b/smtpd/dict.c index 2d65812a..d5998052 100644 --- a/smtpd/dict.c +++ b/smtpd/dict.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/tree.h> diff --git a/smtpd/dns.c b/smtpd/dns.c index 4d369e24..74499e09 100644 --- a/smtpd/dns.c +++ b/smtpd/dns.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -27,10 +29,15 @@ #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <netdb.h> #include <asr.h> #include <event.h> +#include <netdb.h> +#include <resolv.h> #include <imsg.h> #include <stdio.h> #include <stdlib.h> @@ -41,6 +48,11 @@ #include "log.h" #include "unpack_dns.h" +/* On OpenBSD, this function is not needed because we don't free addrinfo */ +#if defined(NOOP_ASR_FREEADDRINFO) +#define asr_freeaddrinfo(x) do { } while(0); +#endif + struct dns_lookup { struct dns_session *session; int preference; @@ -214,7 +226,7 @@ dns_dispatch_host(struct asr_result *ar, void *arg) } free(lookup); if (ar->ar_addrinfo) - freeaddrinfo(ar->ar_addrinfo); + asr_freeaddrinfo(ar->ar_addrinfo); if (ar->ar_gai_errno) s->error = ar->ar_gai_errno; diff --git a/smtpd/enqueue.c b/smtpd/enqueue.c index bc59989a..dcb40cd3 100644 --- a/smtpd/enqueue.c +++ b/smtpd/enqueue.c @@ -18,6 +18,8 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -561,12 +563,12 @@ build_from(char *fake_from, struct passwd *pw) apos, pw->pw_gecos, pw->pw_name, len - apos - 1, p + 1) == -1) - err(1, NULL); + err(1, "asprintf"); msg.fromname[apos] = toupper((unsigned char)msg.fromname[apos]); } else { if (asprintf(&msg.fromname, "%.*s", len, pw->pw_gecos) == -1) - err(1, NULL); + err(1, "asprintf"); } } } diff --git a/smtpd/envelope.c b/smtpd/envelope.c index 7b80259d..9dca6cf8 100644 --- a/smtpd/envelope.c +++ b/smtpd/envelope.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -301,14 +303,18 @@ ascii_load_sockaddr(struct sockaddr_storage *ss, char *buf) return 0; ssin6.sin6_family = AF_INET6; memcpy(ss, &ssin6, sizeof(ssin6)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss->ss_len = sizeof(struct sockaddr_in6); +#endif } else { if (inet_pton(AF_INET, buf, &ssin.sin_addr) != 1) return 0; ssin.sin_family = AF_INET; memcpy(ss, &ssin, sizeof(ssin)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss->ss_len = sizeof(struct sockaddr_in); +#endif } return 1; } diff --git a/smtpd/esc.c b/smtpd/esc.c index a07320ce..64a44c79 100644 --- a/smtpd/esc.c +++ b/smtpd/esc.c @@ -16,12 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> +#include "includes.h" -#include <netinet/in.h> -#include <netdb.h> #include <stdio.h> #include <limits.h> diff --git a/smtpd/expand.c b/smtpd/expand.c index 99b25d51..a4306fc0 100644 --- a/smtpd/expand.c +++ b/smtpd/expand.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,6 +31,12 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/filter.c b/smtpd/filter.c new file mode 100644 index 00000000..614486b7 --- /dev/null +++ b/smtpd/filter.c @@ -0,0 +1,868 @@ +/* $OpenBSD: filter.c,v 1.25 2017/01/09 09:53:23 reyk Exp $ */ + +/* + * Copyright (c) 2011 Gilles Chehade <gilles@poolp.org> + * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/socket.h> +#include <sys/wait.h> + +#include <netinet/in.h> + +#include <ctype.h> +#include <errno.h> +#include <event.h> +#include <imsg.h> +#include <inttypes.h> +#include <limits.h> +#include <resolv.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd.h" +#include "log.h" + +enum { + QUERY_READY, + QUERY_RUNNING, + QUERY_DONE +}; + + +struct filter_proc { + TAILQ_ENTRY(filter_proc) entry; + struct mproc mproc; + int hooks; + int flags; + int ready; +}; + +struct filter { + TAILQ_ENTRY(filter) entry; + struct filter_proc *proc; +}; +TAILQ_HEAD(filter_lst, filter); + +TAILQ_HEAD(filter_query_lst, filter_query); +struct filter_session { + uint64_t id; + int terminate; + struct filter_lst *filters; + struct filter *fcurr; + + int error; + struct io *iev; + size_t idatalen; + FILE *ofile; + + struct filter_query *eom; +}; + +struct filter_query { + uint64_t qid; + int type; + struct filter_session *session; + + int state; + struct filter *current; + + /* current data */ + union { + struct { + struct sockaddr_storage local; + struct sockaddr_storage remote; + char hostname[HOST_NAME_MAX+1]; + } connect; + char line[LINE_MAX]; + struct mailaddr maddr; + size_t datalen; + } u; + + /* current response */ + struct { + int status; + int code; + char *response; + } smtp; +}; + +static void filter_imsg(struct mproc *, struct imsg *); +static void filter_post_event(uint64_t, int, struct filter *, struct filter *); +static struct filter_query *filter_query(struct filter_session *, int); +static void filter_drain_query(struct filter_query *); +static void filter_run_query(struct filter *, struct filter_query *); +static void filter_end_query(struct filter_query *); +static void filter_set_sink(struct filter_session *, int); +static int filter_tx(struct filter_session *, int); +static void filter_tx_io(struct io *, int, void *); + +static TAILQ_HEAD(, filter_proc) procs; +struct dict chains; + +static const char * filter_session_to_text(struct filter_session *); +static const char * filter_query_to_text(struct filter_query *); +static const char * filter_to_text(struct filter *); +static const char * filter_proc_to_text(struct filter_proc *); +static const char * query_to_str(int); +static const char * event_to_str(int); +static const char * status_to_str(int); +static const char * filterimsg_to_str(int); + +struct tree sessions; +struct tree queries; + +static void +filter_add_arg(struct filter_conf *filter, char *arg) +{ + if (filter->argc == MAX_FILTER_ARGS) { + log_warnx("warn: filter \"%s\" is full", filter->name); + fatalx("exiting"); + } + filter->argv[filter->argc++] = arg; +} + +static void +filter_extend_chain(struct filter_lst *chain, const char *name) +{ + struct filter *n; + struct filter_lst *fchain; + struct filter_conf *fconf; + int i; + + fconf = dict_xget(&env->sc_filters, name); + if (fconf->chain) { + log_debug("filter: extending with \"%s\"", name); + for (i = 0; i < fconf->argc; i++) + filter_extend_chain(chain, fconf->argv[i]); + } + else { + log_debug("filter: adding filter \"%s\"", name); + n = xcalloc(1, sizeof(*n), "filter_extend_chain"); + fchain = dict_get(&chains, name); + n->proc = TAILQ_FIRST(fchain)->proc; + TAILQ_INSERT_TAIL(chain, n, entry); + } +} + +void +filter_postfork(void) +{ + static int prepare = 0; + struct filter_conf *filter; + void *iter; + struct filter_proc *proc; + struct filter_lst *fchain; + struct filter *f; + struct mproc *p; + int done, i; + + if (prepare) + return; + prepare = 1; + + TAILQ_INIT(&procs); + dict_init(&chains); + + log_debug("filter: building simple chains..."); + + /* create all filter proc and associated chains */ + iter = NULL; + while (dict_iter(&env->sc_filters, &iter, NULL, (void **)&filter)) { + if (filter->chain) + continue; + + log_debug("filter: building simple chain \"%s\"", filter->name); + proc = xcalloc(1, sizeof(*proc), "filter_postfork"); + p = &proc->mproc; + p->handler = filter_imsg; + p->proc = PROC_FILTER; + p->name = xstrdup(filter->name, "filter_postfork"); + p->data = proc; + if (tracing & TRACE_DEBUG) + filter_add_arg(filter, "-v"); + if (foreground_log) + filter_add_arg(filter, "-d"); + if (mproc_fork(p, filter->path, filter->argv) < 0) + fatalx("filter_postfork"); + + log_debug("filter: registering proc \"%s\"", filter->name); + f = xcalloc(1, sizeof(*f), "filter_postfork"); + f->proc = proc; + + TAILQ_INSERT_TAIL(&procs, proc, entry); + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + TAILQ_INSERT_TAIL(fchain, f, entry); + dict_xset(&chains, filter->name, fchain); + filter->done = 1; + } + + log_debug("filter: building complex chains..."); + + /* resolve all chains */ + done = 0; + while (!done) { + done = 1; + iter = NULL; + while (dict_iter(&env->sc_filters, &iter, NULL, + (void **)&filter)) { + if (filter->done) + continue; + done = 0; + filter->done = 1; + for (i = 0; i < filter->argc; i++) { + if (!dict_get(&chains, filter->argv[i])) { + filter->done = 0; + break; + } + } + if (filter->done == 0) + continue; + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + log_debug("filter: building chain \"%s\"...", + filter->name); + for (i = 0; i < filter->argc; i++) + filter_extend_chain(fchain, filter->argv[i]); + log_debug("filter: done building chain \"%s\"", + filter->name); + dict_xset(&chains, filter->name, fchain); + } + } + log_debug("filter: done building complex chains"); + + fchain = xcalloc(1, sizeof(*fchain), "filter_postfork"); + TAILQ_INIT(fchain); + dict_xset(&chains, "<no-filter>", fchain); +} + +void +filter_configure(void) +{ + static int init = 0; + struct filter_proc *p; + + if (init) + return; + init = 1; + + tree_init(&sessions); + tree_init(&queries); + + TAILQ_FOREACH(p, &procs, entry) { + m_create(&p->mproc, IMSG_FILTER_REGISTER, 0, 0, -1); + m_add_u32(&p->mproc, FILTER_API_VERSION); + m_add_string(&p->mproc, p->mproc.name); + m_close(&p->mproc); + mproc_enable(&p->mproc); + } + + if (TAILQ_FIRST(&procs) == NULL) + smtp_configure(); +} + +void +filter_event(uint64_t id, int event) +{ + struct filter_session *s; + + if (event == EVENT_DISCONNECT) + /* On disconnect, the session is virtualy dead */ + s = tree_xpop(&sessions, id); + else + s = tree_xget(&sessions, id); + + filter_post_event(id, event, TAILQ_FIRST(s->filters), NULL); + + if (event == EVENT_DISCONNECT) { + if (s->iev) + io_free(s->iev); + if (s->ofile) + fclose(s->ofile); + free(s); + } +} + +void +filter_connect(uint64_t id, const struct sockaddr *local, + const struct sockaddr *remote, const char *host, const char *filter) +{ + struct filter_session *s; + struct filter_query *q; + + s = xcalloc(1, sizeof(*s), "filter_event"); + s->id = id; + if (filter == NULL) + filter = "<no-filter>"; + s->filters = dict_xget(&chains, filter); + tree_xset(&sessions, s->id, s); + + filter_event(id, EVENT_CONNECT); + q = filter_query(s, QUERY_CONNECT); + + memmove(&q->u.connect.local, local, SA_LEN(local)); + memmove(&q->u.connect.remote, remote, SA_LEN(remote)); + strlcpy(q->u.connect.hostname, host, sizeof(q->u.connect.hostname)); + + q->smtp.status = FILTER_OK; + q->smtp.code = 0; + q->smtp.response = NULL; + + filter_drain_query(q); +} + +void +filter_mailaddr(uint64_t id, int type, const struct mailaddr *maddr) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + + strlcpy(q->u.maddr.user, maddr->user, sizeof(q->u.maddr.user)); + strlcpy(q->u.maddr.domain, maddr->domain, sizeof(q->u.maddr.domain)); + + filter_drain_query(q); +} + +void +filter_line(uint64_t id, int type, const char *line) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + + if (line) + strlcpy(q->u.line, line, sizeof(q->u.line)); + + filter_drain_query(q); +} + +void +filter_eom(uint64_t id, int type, size_t datalen) +{ + struct filter_session *s; + struct filter_query *q; + + s = tree_xget(&sessions, id); + q = filter_query(s, type); + q->u.datalen = datalen; + + filter_drain_query(q); +} + +static void +filter_set_sink(struct filter_session *s, int sink) +{ + struct mproc *p; + + while (s->fcurr) { + if (s->fcurr->proc->hooks & HOOK_DATALINE) { + log_trace(TRACE_FILTERS, "filter: sending fd %d to %s", + sink, filter_to_text(s->fcurr)); + p = &s->fcurr->proc->mproc; + m_create(p, IMSG_FILTER_PIPE, 0, 0, sink); + m_add_id(p, s->id); + m_close(p); + return; + } + s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); + } + + log_trace(TRACE_FILTERS, "filter: chain input is %d", sink); + smtp_filter_fd(s->id, sink); +} + +void +filter_build_fd_chain(uint64_t id, int sink) +{ + struct filter_session *s; + int fd; + + s = tree_xget(&sessions, id); + s->fcurr = TAILQ_LAST(s->filters, filter_lst); + + fd = filter_tx(s, sink); + filter_set_sink(s, fd); +} + +void +filter_post_event(uint64_t id, int event, struct filter *f, struct filter *end) +{ + for(; f && f != end; f = TAILQ_NEXT(f, entry)) { + log_trace(TRACE_FILTERS, "filter: post-event event=%s filter=%s", + event_to_str(event), f->proc->mproc.name); + + m_create(&f->proc->mproc, IMSG_FILTER_EVENT, 0, 0, -1); + m_add_id(&f->proc->mproc, id); + m_add_int(&f->proc->mproc, event); + m_close(&f->proc->mproc); + } +} + +static struct filter_query * +filter_query(struct filter_session *s, int type) +{ + struct filter_query *q; + + q = xcalloc(1, sizeof(*q), "filter_query"); + q->qid = generate_uid(); + q->session = s; + q->type = type; + + q->state = QUERY_READY; + q->current = TAILQ_FIRST(s->filters); + + log_trace(TRACE_FILTERS, "filter: new query %s", query_to_str(type)); + + return (q); +} + +static void +filter_drain_query(struct filter_query *q) +{ + log_trace(TRACE_FILTERS, "filter: filter_drain_query %s", + filter_query_to_text(q)); + + /* + * The query must be passed through all filters that registered + * a hook, until one rejects it. + */ + while (q->state != QUERY_DONE) { + /* Walk over all filters */ + while (q->current) { + filter_run_query(q->current, q); + if (q->state == QUERY_RUNNING) { + log_trace(TRACE_FILTERS, + "filter: waiting for running query %s", + filter_query_to_text(q)); + return; + } + } + q->state = QUERY_DONE; + } + + /* Defer the response if the file is not closed yet. */ + if (q->type == QUERY_EOM && q->session->ofile && q->smtp.status == FILTER_OK) { + log_debug("filter: deferring eom query..."); + q->session->eom = q; + return; + } + + filter_end_query(q); +} + +static void +filter_run_query(struct filter *f, struct filter_query *q) +{ + log_trace(TRACE_FILTERS, + "filter: running filter %s for query %s", + filter_to_text(f), filter_query_to_text(q)); + + m_create(&f->proc->mproc, IMSG_FILTER_QUERY, 0, 0, -1); + m_add_id(&f->proc->mproc, q->session->id); + m_add_id(&f->proc->mproc, q->qid); + m_add_int(&f->proc->mproc, q->type); + + switch (q->type) { + case QUERY_CONNECT: + m_add_sockaddr(&f->proc->mproc, + (struct sockaddr *)&q->u.connect.local); + m_add_sockaddr(&f->proc->mproc, + (struct sockaddr *)&q->u.connect.remote); + m_add_string(&f->proc->mproc, q->u.connect.hostname); + break; + case QUERY_HELO: + m_add_string(&f->proc->mproc, q->u.line); + break; + case QUERY_MAIL: + case QUERY_RCPT: + m_add_mailaddr(&f->proc->mproc, &q->u.maddr); + break; + case QUERY_EOM: + m_add_u32(&f->proc->mproc, q->u.datalen); + break; + default: + break; + } + m_close(&f->proc->mproc); + + tree_xset(&queries, q->qid, q); + q->state = QUERY_RUNNING; +} + +static void +filter_end_query(struct filter_query *q) +{ + struct filter_session *s = q->session; + const char *response = q->smtp.response; + + log_trace(TRACE_FILTERS, "filter: filter_end_query %s", + filter_query_to_text(q)); + + if (q->type == QUERY_EOM && q->smtp.status == FILTER_OK) { + if (s->error || q->u.datalen != s->idatalen) { + response = "Internal error"; + q->smtp.code = 451; + q->smtp.status = FILTER_FAIL; + if (!s->error) + log_warnx("filter: datalen mismatch on session %" PRIx64 + ": %zu/%zu", s->id, s->idatalen, q->u.datalen); + } + } + + log_trace(TRACE_FILTERS, + "filter: query %016"PRIx64" done: " + "status=%s code=%d response=\"%s\"", + q->qid, + status_to_str(q->smtp.status), + q->smtp.code, + response); + + smtp_filter_response(s->id, q->type, q->smtp.status, q->smtp.code, + response); + free(q->smtp.response); + free(q); +} + +static void +filter_imsg(struct mproc *p, struct imsg *imsg) +{ + struct filter_proc *proc = p->data; + struct filter_session *s; + struct filter_query *q; + struct msg m; + const char *line; + uint64_t qid; + uint32_t datalen; + int type, status, code; + + if (imsg == NULL) { + log_warnx("warn: filter \"%s\" closed unexpectedly", p->name); + fatalx("exiting"); + } + + log_trace(TRACE_FILTERS, "filter: imsg %s from procfilter %s", + filterimsg_to_str(imsg->hdr.type), + filter_proc_to_text(proc)); + + switch (imsg->hdr.type) { + + case IMSG_FILTER_REGISTER: + if (proc->ready) { + log_warnx("warn: filter \"%s\" already registered", + proc->mproc.name); + exit(1); + } + + m_msg(&m, imsg); + m_get_int(&m, &proc->hooks); + m_get_int(&m, &proc->flags); + m_end(&m); + proc->ready = 1; + + log_debug("debug: filter \"%s\": hooks 0x%08x flags 0x%04x", + proc->mproc.name, proc->hooks, proc->flags); + + TAILQ_FOREACH(proc, &procs, entry) + if (!proc->ready) + return; + + smtp_configure(); + break; + + case IMSG_FILTER_RESPONSE: + m_msg(&m, imsg); + m_get_id(&m, &qid); + m_get_int(&m, &type); + if (type == QUERY_EOM) + m_get_u32(&m, &datalen); + m_get_int(&m, &status); + m_get_int(&m, &code); + if (m_is_eom(&m)) + line = NULL; + else + m_get_string(&m, &line); + m_end(&m); + + q = tree_xpop(&queries, qid); + if (q->type != type) { + log_warnx("warn: filter: type mismatch %d != %d", + q->type, type); + fatalx("exiting"); + } + q->smtp.status = status; + if (code) + q->smtp.code = code; + if (line) { + free(q->smtp.response); + q->smtp.response = xstrdup(line, "filter_imsg"); + } + q->state = (status == FILTER_OK) ? QUERY_READY : QUERY_DONE; + if (type == QUERY_EOM) + q->u.datalen = datalen; + + q->current = TAILQ_NEXT(q->current, entry); + filter_drain_query(q); + break; + + case IMSG_FILTER_PIPE: + m_msg(&m, imsg); + m_get_id(&m, &qid); + m_end(&m); + + s = tree_xget(&sessions, qid); + s->fcurr = TAILQ_PREV(s->fcurr, filter_lst, entry); + filter_set_sink(s, imsg->fd); + break; + + default: + log_warnx("warn: bad imsg from filter %s", p->name); + exit(1); + } +} + +static int +filter_tx(struct filter_session *s, int sink) +{ + int sp[2]; + + s->idatalen = 0; + s->eom = NULL; + s->error = 0; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { + log_warn("warn: filter: socketpair"); + return (-1); + } + + if ((s->ofile = fdopen(sink, "w")) == NULL) { + log_warn("warn: filter: fdopen"); + close(sp[0]); + close(sp[1]); + return (-1); + } + + io_set_nonblocking(sp[0]); + io_set_nonblocking(sp[1]); + + s->iev = io_new(); + io_set_callback(s->iev, filter_tx_io, s); + io_set_fd(s->iev, sp[0]); + io_set_read(s->iev); + + return (sp[1]); +} + +static void +filter_tx_io(struct io *io, int evt, void *arg) +{ + struct filter_session *s = arg; + size_t len, n; + char *data; + + log_trace(TRACE_FILTERS, "filter: filter_tx_io(%p, %s)", + s, io_strevent(evt)); + + switch (evt) { + case IO_DATAIN: + data = io_data(s->iev); + len = io_datalen(s->iev); + + log_trace(TRACE_FILTERS, + "filter: filter_tx_io: datain (%zu) for req %016"PRIx64"", + len, s->id); + + n = fwrite(data, 1, len, s->ofile); + if (n != len) { + log_warnx("warn: filter_tx_io: fwrite %zu/%zu", n, len); + s->error = 1; + break; + } + s->idatalen += n; + io_drop(s->iev, n); + return; + + case IO_DISCONNECTED: + log_trace(TRACE_FILTERS, + "debug: filter: tx done (%zu) for req %016"PRIx64, + s->idatalen, s->id); + break; + + default: + log_warn("warn: filter_tx_io: bad evt (%d) for req %016"PRIx64, + evt, s->id); + s->error = 1; + break; + } + + io_free(s->iev); + s->iev = NULL; + fclose(s->ofile); + s->ofile = NULL; + + /* deferred eom request */ + if (s->eom) { + log_debug("filter: running eom query..."); + filter_end_query(s->eom); + } else { + log_debug("filter: eom not received yet"); + } +} + +static const char * +filter_query_to_text(struct filter_query *q) +{ + static char buf[1024]; + char tmp[1024]; + + tmp[0] = '\0'; + + switch (q->type) { + case QUERY_CONNECT: + strlcat(tmp, "=", sizeof tmp); + strlcat(tmp, ss_to_text(&q->u.connect.local), + sizeof tmp); + strlcat(tmp, " <-> ", sizeof tmp); + strlcat(tmp, ss_to_text(&q->u.connect.remote), + sizeof tmp); + strlcat(tmp, "(", sizeof tmp); + strlcat(tmp, q->u.connect.hostname, sizeof tmp); + strlcat(tmp, ")", sizeof tmp); + break; + case QUERY_MAIL: + case QUERY_RCPT: + snprintf(tmp, sizeof tmp, "=%s@%s", + q->u.maddr.user, q->u.maddr.domain); + break; + case QUERY_HELO: + snprintf(tmp, sizeof tmp, "=%s", q->u.line); + break; + default: + break; + } + snprintf(buf, sizeof buf, "%016"PRIx64"[%s%s,%s]", + q->qid, query_to_str(q->type), tmp, + filter_session_to_text(q->session)); + + return (buf); +} + +static const char * +filter_session_to_text(struct filter_session *s) +{ + static char buf[1024]; + + if (s == NULL) + return "filter_session@NULL"; + + snprintf(buf, sizeof(buf), + "filter_session@%p[datalen=%zu,eom=%p,ofile=%p]", + s, s->idatalen, s->eom, s->ofile); + + return buf; +} + +static const char * +filter_to_text(struct filter *f) +{ + static char buf[1024]; + + snprintf(buf, sizeof buf, "filter:%s", filter_proc_to_text(f->proc)); + + return (buf); +} + +static const char * +filter_proc_to_text(struct filter_proc *proc) +{ + static char buf[1024]; + + snprintf(buf, sizeof buf, "%s[hooks=0x%08x,flags=0x%04x]", + proc->mproc.name, proc->hooks, proc->flags); + + return (buf); +} + +#define CASE(x) case x : return #x + +static const char * +filterimsg_to_str(int imsg) +{ + switch (imsg) { + CASE(IMSG_FILTER_REGISTER); + CASE(IMSG_FILTER_EVENT); + CASE(IMSG_FILTER_QUERY); + CASE(IMSG_FILTER_PIPE); + CASE(IMSG_FILTER_RESPONSE); + default: + return "IMSG_FILTER_???"; + } +} + +static const char * +query_to_str(int query) +{ + switch (query) { + CASE(QUERY_CONNECT); + CASE(QUERY_HELO); + CASE(QUERY_MAIL); + CASE(QUERY_RCPT); + CASE(QUERY_DATA); + CASE(QUERY_EOM); + CASE(QUERY_DATALINE); + default: + return "QUERY_???"; + } +} + +static const char * +event_to_str(int event) +{ + switch (event) { + CASE(EVENT_CONNECT); + CASE(EVENT_RESET); + CASE(EVENT_DISCONNECT); + CASE(EVENT_TX_BEGIN); + CASE(EVENT_TX_COMMIT); + CASE(EVENT_TX_ROLLBACK); + default: + return "EVENT_???"; + } +} + +static const char * +status_to_str(int status) +{ + switch (status) { + CASE(FILTER_OK); + CASE(FILTER_FAIL); + CASE(FILTER_CLOSE); + default: + return "FILTER_???"; + } +} diff --git a/smtpd/forward.c b/smtpd/forward.c index d30d55e9..7494c6ce 100644 --- a/smtpd/forward.c +++ b/smtpd/forward.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -28,7 +30,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include <unistd.h> #include <limits.h> diff --git a/smtpd/iobuf.c b/smtpd/iobuf.c index 27c404a0..46d8ef04 100644 --- a/smtpd/iobuf.c +++ b/smtpd/iobuf.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/uio.h> diff --git a/smtpd/ioev.c b/smtpd/ioev.c index 44690766..28de5c7b 100644 --- a/smtpd/ioev.c +++ b/smtpd/ioev.c @@ -15,6 +15,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -749,10 +751,10 @@ io_connect(struct io *io, const struct sockaddr *sa, const struct sockaddr *bsa) io_set_nonblocking(sock); io_set_nolinger(sock); - if (bsa && bind(sock, bsa, bsa->sa_len) == -1) + if (bsa && bind(sock, bsa, SA_LEN(bsa)) == -1) goto fail; - if (connect(sock, sa, sa->sa_len) == -1) + if (connect(sock, sa, SA_LEN(sa)) == -1) if (errno != EINPROGRESS) goto fail; diff --git a/smtpd/libressl.c b/smtpd/libressl.c new file mode 100644 index 00000000..57d74389 --- /dev/null +++ b/smtpd/libressl.c @@ -0,0 +1,213 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* + * SSL operations needed when running in a privilege separated environment. + * Adapted from openssl's ssl_rsa.c by Pierre-Yves Ritschard . + */ + +#include "includes.h" + +#include <sys/types.h> + +#include <limits.h> +#include <unistd.h> +#include <stdio.h> + +#include <openssl/err.h> +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> + +#include "log.h" +#include "ssl.h" + +#define SSL_ECDH_CURVE "prime256v1" + +/* + * Read a bio that contains our certificate in "PEM" format, + * possibly followed by a sequence of CA certificates that should be + * sent to the peer in the Certificate message. + */ +static int +ssl_ctx_use_certificate_chain_bio(SSL_CTX *ctx, BIO *in) +{ + int ret = 0; + X509 *x = NULL; + + ERR_clear_error(); /* clear error stack for SSL_CTX_use_certificate() */ + + x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + + if (ERR_peek_error() != 0) + ret = 0; + /* Key/certificate mismatch doesn't imply ret==0 ... */ + if (ret) { + /* + * If we could set up our certificate, now proceed to + * the CA certificates. + */ + X509 *ca; + int r; + unsigned long err; + + if (ctx->extra_certs != NULL) { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) != NULL) { + r = SSL_CTX_add_extra_chain_cert(ctx, ca); + if (!r) { + X509_free(ca); + ret = 0; + goto end; + } + /* + * Note that we must not free r if it was successfully + * added to the chain (while we must free the main + * certificate, since its reference count is increased + * by SSL_CTX_use_certificate). + */ + } + + /* When the while loop ends, it's usually just EOF. */ + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM && + ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + ERR_clear_error(); + else + ret = 0; /* some real error */ + } + +end: + if (x != NULL) + X509_free(x); + return (ret); +} + +int +SSL_CTX_use_certificate_chain_mem(SSL_CTX *ctx, void *buf, int len) +{ + BIO *in; + int ret = 0; + + in = BIO_new_mem_buf(buf, len); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); + goto end; + } + + ret = ssl_ctx_use_certificate_chain_bio(ctx, in); + +end: + BIO_free(in); + return (ret); +} + +#ifndef HAVE_SSL_CTX_SET_ECDH_AUTO +void +SSL_CTX_set_ecdh_auto(SSL_CTX *ctx, int enable) +{ + int nid; + EC_KEY *ecdh; + + if (!enable) + return; + + if ((nid = OBJ_sn2nid(SSL_ECDH_CURVE)) == 0) { + ssl_error("ssl_set_ecdh_auto"); + fatal("ssl_set_ecdh_auto: unknown curve name " + SSL_ECDH_CURVE); + } + + if ((ecdh = EC_KEY_new_by_curve_name(nid)) == NULL) { + ssl_error("ssl_set_ecdh_auto"); + fatal("ssl_set_ecdh_auto: unable to create curve " + SSL_ECDH_CURVE); + } + + SSL_CTX_set_tmp_ecdh(ctx, ecdh); + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); + EC_KEY_free(ecdh); +} +#endif + +#ifndef HAVE_SSL_CTX_SET_DH_AUTO +void +SSL_CTX_set_dh_auto(SSL_CTX *ctx, int enable) +{ + if (!enable) + return; + + /* stub until OpenSSL catches up with this ... */ + log_warnx("OpenSSL does not support SSL_CTX_set_dh_auto (yet ?)"); + return; +} +#endif diff --git a/smtpd/limit.c b/smtpd/limit.c index e7d0cb17..25e7a026 100644 --- a/smtpd/limit.c +++ b/smtpd/limit.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka.c b/smtpd/lka.c index 27569d19..519fb1d7 100644 --- a/smtpd/lka.c +++ b/smtpd/lka.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -31,6 +33,8 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <netdb.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <openssl/err.h> #include <openssl/ssl.h> diff --git a/smtpd/lka_filter.c b/smtpd/lka_filter.c index 3daa57a3..16c8f2ea 100644 --- a/smtpd/lka_filter.c +++ b/smtpd/lka_filter.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_proc.c b/smtpd/lka_proc.c index fb3a4137..eafebbec 100644 --- a/smtpd/lka_proc.c +++ b/smtpd/lka_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_report.c b/smtpd/lka_report.c index e8eb3348..ddf7c7cf 100644 --- a/smtpd/lka_report.c +++ b/smtpd/lka_report.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/lka_session.c b/smtpd/lka_session.c index 0ae31548..bca6ad31 100644 --- a/smtpd/lka_session.c +++ b/smtpd/lka_session.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -516,7 +518,7 @@ lka_submit(struct lka_session *lks, struct rule *rule, struct expandnode *xn) "run with %s privileges", SMTPD_USER); if (xn->type == EXPAND_FILENAME) - format = "/usr/libexec/mail.mboxfile -f %%{mbox.from} %s"; + format = PATH_LIBEXEC"/mail.mboxfile -f %%{mbox.from} %s"; else if (xn->type == EXPAND_FILTER) format = "%s"; (void)snprintf(ep->mda_exec, sizeof(ep->mda_exec), diff --git a/smtpd/log.c b/smtpd/log.c index 7ec8ca42..14f681e3 100644 --- a/smtpd/log.c +++ b/smtpd/log.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <stdio.h> #include <stdlib.h> #include <stdarg.h> diff --git a/smtpd/log.h b/smtpd/log.h index 22bb4164..81d0973c 100644 --- a/smtpd/log.h +++ b/smtpd/log.h @@ -19,8 +19,14 @@ #ifndef LOG_H #define LOG_H +#include "openbsd-compat.h" + +#include <syslog.h> + #include <stdarg.h> +#ifdef HAVE_SYS_CDEFS_H #include <sys/cdefs.h> +#endif void log_init(int, int); void log_procinit(const char *); diff --git a/smtpd/mail.lmtp.c b/smtpd/mail.lmtp.c index d831ca2f..685ec504 100644 --- a/smtpd/mail.lmtp.c +++ b/smtpd/mail.lmtp.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> diff --git a/smtpd/mail.maildir.c b/smtpd/mail.maildir.c index e1796e0e..637d3f72 100644 --- a/smtpd/mail.maildir.c +++ b/smtpd/mail.maildir.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif diff --git a/smtpd/mail.mboxfile.c b/smtpd/mail.mboxfile.c index 6dbcc058..bf6951d8 100644 --- a/smtpd/mail.mboxfile.c +++ b/smtpd/mail.mboxfile.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> @@ -26,6 +28,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> #include <unistd.h> static void mboxfile_engine(const char *sender, const char *filename); @@ -71,7 +74,13 @@ mboxfile_engine(const char *sender, const char *filename) time(&now); +#ifndef O_EXLOCK +#define O_EXLOCK 0 +#endif fd = open(filename, O_CREAT | O_APPEND | O_WRONLY | O_EXLOCK, 0600); +#ifndef HAVE_O_EXLOCK + /* XXX : do something! */ +#endif if (fd < 0) err(1, NULL); diff --git a/smtpd/mail.mda.c b/smtpd/mail.mda.c index f9fb3236..23958071 100644 --- a/smtpd/mail.mda.c +++ b/smtpd/mail.mda.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> diff --git a/smtpd/mailaddr.c b/smtpd/mailaddr.c index a15470d7..4346e3dc 100644 --- a/smtpd/mailaddr.c +++ b/smtpd/mailaddr.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/makemap.c b/smtpd/makemap.c index 51c475e6..fed53855 100644 --- a/smtpd/makemap.c +++ b/smtpd/makemap.c @@ -17,6 +17,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> /* Needed for flock */ +#endif #include <sys/types.h> #include <sys/stat.h> #include <sys/tree.h> @@ -24,7 +29,13 @@ #include <sys/socket.h> #include <ctype.h> +#ifdef HAVE_DB_H #include <db.h> +#elif defined(HAVE_DB1_DB_H) +#include <db1/db.h> +#elif defined(HAVE_DB_185_H) +#include <db_185.h> +#endif #include <err.h> #include <errno.h> #include <event.h> @@ -36,12 +47,17 @@ #include <syslog.h> #include <unistd.h> #include <limits.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif #include "smtpd.h" #include "log.h" -#define PATH_ALIASES "/etc/mail/aliases" +#define PATH_ALIASES SMTPD_CONFDIR "/aliases" static void usage(void); static int parse_map(DB *, int *, char *); diff --git a/smtpd/mda.c b/smtpd/mda.c index ed7911a2..a8ee7c29 100644 --- a/smtpd/mda.c +++ b/smtpd/mda.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -28,6 +30,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <pwd.h> @@ -39,7 +42,11 @@ #include <time.h> #include <unistd.h> #include <limits.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" @@ -516,7 +523,7 @@ mda_getlastline(int fd, char *dst, size_t dstsz) size_t sz = 0; ssize_t len; int out = 0; - + if (lseek(fd, 0, SEEK_SET) < 0) { log_warn("warn: mda: lseek"); close(fd); diff --git a/smtpd/mda_unpriv.c b/smtpd/mda_unpriv.c index 59c89941..60531051 100644 --- a/smtpd/mda_unpriv.c +++ b/smtpd/mda_unpriv.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/mda_variables.c b/smtpd/mda_variables.c index 03052e21..df453477 100644 --- a/smtpd/mda_variables.c +++ b/smtpd/mda_variables.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/mproc.c b/smtpd/mproc.c index d5a934d4..e1bf324f 100644 --- a/smtpd/mproc.c +++ b/smtpd/mproc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -60,8 +62,7 @@ mproc_fork(struct mproc *p, const char *path, char *argv[]) if (p->pid == 0) { /* child process */ dup2(sp[0], STDIN_FILENO); - if (closefrom(STDERR_FILENO + 1) < 0) - exit(1); + closefrom(STDERR_FILENO + 1); execv(path, argv); err(1, "execv: %s", path); @@ -484,8 +485,8 @@ m_add_msgid(struct mproc *m, uint32_t v) void m_add_sockaddr(struct mproc *m, const struct sockaddr *sa) { - m_add_size(m, sa->sa_len); - m_add(m, sa, sa->sa_len); + m_add_size(m, SA_LEN(sa)); + m_add(m, sa, SA_LEN(sa)); } void diff --git a/smtpd/mta.c b/smtpd/mta.c index b7a841d1..a1e0c030 100644 --- a/smtpd/mta.c +++ b/smtpd/mta.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -31,6 +33,7 @@ #include <imsg.h> #include <inttypes.h> #include <netdb.h> +#include <grp.h> /* needed for setgroups */ #include <limits.h> #include <pwd.h> #include <signal.h> @@ -2093,13 +2096,13 @@ mta_host(const struct sockaddr *sa) struct mta_host key, *h; struct sockaddr_storage ss; - memmove(&ss, sa, sa->sa_len); + memmove(&ss, sa, SA_LEN(sa)); key.sa = (struct sockaddr*)&ss; h = SPLAY_FIND(mta_host_tree, &hosts, &key); if (h == NULL) { h = xcalloc(1, sizeof(*h)); - h->sa = xmemdup(sa, sa->sa_len); + h->sa = xmemdup(sa, SA_LEN(sa)); SPLAY_INSERT(mta_host_tree, &hosts, h); stat_increment("mta.host", 1); } @@ -2144,11 +2147,11 @@ mta_host_to_text(struct mta_host *h) static int mta_host_cmp(const struct mta_host *a, const struct mta_host *b) { - if (a->sa->sa_len < b->sa->sa_len) + if (SA_LEN(a->sa) < SA_LEN(b->sa)) return (-1); - if (a->sa->sa_len > b->sa->sa_len) + if (SA_LEN(a->sa) > SA_LEN(b->sa)) return (1); - return (memcmp(a->sa, b->sa, a->sa->sa_len)); + return (memcmp(a->sa, b->sa, SA_LEN(a->sa))); } SPLAY_GENERATE(mta_host_tree, mta_host, entry, mta_host_cmp); @@ -2222,7 +2225,7 @@ mta_source(const struct sockaddr *sa) struct sockaddr_storage ss; if (sa) { - memmove(&ss, sa, sa->sa_len); + memmove(&ss, sa, SA_LEN(sa)); key.sa = (struct sockaddr*)&ss; } else key.sa = NULL; @@ -2231,7 +2234,7 @@ mta_source(const struct sockaddr *sa) if (s == NULL) { s = xcalloc(1, sizeof(*s)); if (sa) - s->sa = xmemdup(sa, sa->sa_len); + s->sa = xmemdup(sa, SA_LEN(sa)); SPLAY_INSERT(mta_source_tree, &sources, s); stat_increment("mta.source", 1); } @@ -2276,11 +2279,11 @@ mta_source_cmp(const struct mta_source *a, const struct mta_source *b) return ((b->sa == NULL) ? 0 : -1); if (b->sa == NULL) return (1); - if (a->sa->sa_len < b->sa->sa_len) + if (SA_LEN(a->sa) < SA_LEN(b->sa)) return (-1); - if (a->sa->sa_len > b->sa->sa_len) + if (SA_LEN(a->sa) > SA_LEN(b->sa)) return (1); - return (memcmp(a->sa, b->sa, a->sa->sa_len)); + return (memcmp(a->sa, b->sa, SA_LEN(a->sa))); } SPLAY_GENERATE(mta_source_tree, mta_source, entry, mta_source_cmp); diff --git a/smtpd/mta_session.c b/smtpd/mta_session.c index 755ac86d..655c205f 100644 --- a/smtpd/mta_session.c +++ b/smtpd/mta_session.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -533,7 +535,7 @@ mta_connect(struct mta_session *s) if (s->relay->port) portno = s->relay->port; - memmove(&ss, s->route->dst->sa, s->route->dst->sa->sa_len); + memmove(&ss, s->route->dst->sa, SA_LEN(s->route->dst->sa)); sa = (struct sockaddr *)&ss; if (sa->sa_family == AF_INET) diff --git a/smtpd/parse.y b/smtpd/parse.y index f68ebe8e..fae944a0 100644 --- a/smtpd/parse.y +++ b/smtpd/parse.y @@ -22,7 +22,10 @@ */ %{ +#include "includes.h" + #include <sys/types.h> +#include <sys/time.h> #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> @@ -43,13 +46,16 @@ #include <limits.h> #include <netdb.h> #include <pwd.h> +#include <stdarg.h> #include <resolv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <syslog.h> #include <unistd.h> +#ifdef HAVE_UTIL_H #include <util.h> +#endif #include <openssl/ssl.h> @@ -639,41 +645,41 @@ dispatcher_local: MBOX { dispatcher->u.local.requires_root = 1; dispatcher->u.local.user = xstrdup("root"); - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.local -f %%{mbox.from} %%{user.username}"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.local -f %%{mbox.from} %%{user.username}"); } dispatcher_local_options | MAILDIR { - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.maildir"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.maildir"); } dispatcher_local_options | MAILDIR JUNK { - asprintf(&dispatcher->u.local.command, "/usr/libexec/mail.maildir -j"); + asprintf(&dispatcher->u.local.command, PATH_LIBEXEC"/mail.maildir -j"); } dispatcher_local_options | MAILDIR STRING { if (strncmp($2, "~/", 2) == 0) asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir \"%%{user.directory}/%s\"", $2+2); + PATH_LIBEXEC"/mail.maildir \"%%{user.directory}/%s\"", $2+2); else asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir \"%s\"", $2); + PATH_LIBEXEC"/mail.maildir \"%s\"", $2); } dispatcher_local_options | MAILDIR STRING JUNK { if (strncmp($2, "~/", 2) == 0) asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir -j \"%%{user.directory}/%s\"", $2+2); + PATH_LIBEXEC"/mail.maildir -j \"%%{user.directory}/%s\"", $2+2); else asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.maildir -j \"%s\"", $2); + PATH_LIBEXEC"/mail.maildir -j \"%s\"", $2); } dispatcher_local_options | LMTP STRING { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.lmtp -f %%{mbox.from} -d %s %%{user.username}", $2); + PATH_LIBEXEC"/mail.lmtp -f %%{mbox.from} -d %s %%{user.username}", $2); } dispatcher_local_options | LMTP STRING RCPT_TO { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.lmtp -f %%{mbox.from} -d %s %%{dest}", $2); + PATH_LIBEXEC"/mail.lmtp -f %%{mbox.from} -d %s %%{dest}", $2); } dispatcher_local_options | MDA STRING { asprintf(&dispatcher->u.local.command, - "/usr/libexec/mail.mda \"%s\"", $2); + PATH_LIBEXEC"/mail.mda \"%s\"", $2); } dispatcher_local_options | FORWARD_ONLY { dispatcher->u.local.forward_only = 1; @@ -2767,7 +2773,9 @@ create_sock_listener(struct listen_opts *lo) lo->tag = "local"; lo->hostname = conf->sc_hostname; l->ss.ss_family = AF_LOCAL; +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN l->ss.ss_len = sizeof(struct sockaddr *); +#endif l->local = 1; conf->sc_sock_listener = l; config_listener(l, lo); @@ -2899,7 +2907,9 @@ host_v4(struct listen_opts *lo) h = xcalloc(1, sizeof(*h)); sain = (struct sockaddr_in *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_family = AF_INET; sain->sin_addr.s_addr = ina.s_addr; sain->sin_port = lo->port; @@ -2927,7 +2937,9 @@ host_v6(struct listen_opts *lo) h = xcalloc(1, sizeof(*h)); sin6 = (struct sockaddr_in6 *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_family = AF_INET6; sin6->sin6_port = lo->port; memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); @@ -2970,7 +2982,9 @@ host_dns(struct listen_opts *lo) h->ss.ss_family = res->ai_family; if (res->ai_family == AF_INET) { sain = (struct sockaddr_in *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_addr.s_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr.s_addr; sain->sin_port = lo->port; @@ -2978,7 +2992,9 @@ host_dns(struct listen_opts *lo) h->local = 1; } else { sin6 = (struct sockaddr_in6 *)&h->ss; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); sin6->sin6_port = lo->port; @@ -3022,7 +3038,9 @@ interface(struct listen_opts *lo) case AF_INET: sain = (struct sockaddr_in *)&h->ss; *sain = *(struct sockaddr_in *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sain->sin_len = sizeof(struct sockaddr_in); +#endif sain->sin_port = lo->port; if (sain->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) h->local = 1; @@ -3031,7 +3049,9 @@ interface(struct listen_opts *lo) case AF_INET6: sin6 = (struct sockaddr_in6 *)&h->ss; *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_port = lo->port; if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) h->local = 1; @@ -3100,6 +3120,7 @@ bad: int is_if_in_group(const char *ifname, const char *groupname) { +#ifdef HAVE_STRUCT_IFGROUPREQ unsigned int len; struct ifgroupreq ifgr; struct ifg_req *ifg; @@ -3138,6 +3159,9 @@ is_if_in_group(const char *ifname, const char *groupname) end: close(s); return ret; +#else + return (0); +#endif } static int diff --git a/smtpd/parser.c b/smtpd/parser.c index df90e508..997e3405 100644 --- a/smtpd/parser.c +++ b/smtpd/parser.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/socket.h> @@ -281,7 +283,9 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) in = (struct sockaddr_in *)sa; memset(in, 0, sizeof *in); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN in->sin_len = sizeof(struct sockaddr_in); +#endif in->sin_family = PF_INET; in->sin_addr.s_addr = ina.s_addr; return (0); @@ -304,7 +308,9 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) in6 = (struct sockaddr_in6 *)sa; memset(in6, 0, sizeof *in6); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = sizeof(struct sockaddr_in6); +#endif in6->sin6_family = PF_INET6; in6->sin6_addr = in6a; @@ -313,7 +319,7 @@ text_to_sockaddr(struct sockaddr *sa, int family, const char *str) if (IN6_IS_ADDR_LINKLOCAL(&in6a) || IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || - IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + IN6_IS_ADDR_MC_NODELOCAL(&in6a)) if ((in6->sin6_scope_id = if_nametoindex(cp))) return (0); diff --git a/smtpd/pony.c b/smtpd/pony.c index abbde55e..75742fa7 100644 --- a/smtpd/pony.c +++ b/smtpd/pony.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue.c b/smtpd/queue.c index 489069ec..32bc55a7 100644 --- a/smtpd/queue.c +++ b/smtpd/queue.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,6 +28,8 @@ #include <err.h> #include <event.h> +#include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <libgen.h> diff --git a/smtpd/queue_backend.c b/smtpd/queue_backend.c index 4337051e..7472febc 100644 --- a/smtpd/queue_backend.c +++ b/smtpd/queue_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_fs.c b/smtpd/queue_fs.c index 5960663f..869d4287 100644 --- a/smtpd/queue_fs.c +++ b/smtpd/queue_fs.c @@ -16,12 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> +#if HAVE_SYS_MOUNT_H #include <sys/mount.h> +#endif #include <sys/queue.h> #include <sys/tree.h> #include <sys/socket.h> #include <sys/stat.h> +#ifdef HAVE_SYS_STATFS_H +#include <sys/statfs.h> +#endif #include <ctype.h> #include <dirent.h> @@ -341,8 +348,10 @@ queue_fs_message_walk(uint64_t *evpid, char *buf, size_t len, (void)snprintf(msgid_str, sizeof msgid_str, "%08" PRIx32, msgid); while ((dp = readdir(dir)) != NULL) { +#if defined(HAVE_STRUCT_DIR_D_TYPE) if (dp->d_type != DT_REG) continue; +#endif /* ignore files other than envelopes */ if (strlen(dp->d_name) != 16 || @@ -411,6 +420,7 @@ queue_fs_envelope_walk(uint64_t *evpid, char *buf, size_t len) static int fsqueue_check_space(void) { +#ifdef __OpenBSD__ struct statfs buf; uint64_t used; uint64_t total; @@ -454,7 +464,7 @@ fsqueue_check_space(void) log_warnx("warn: temporarily rejecting messages"); return 0; } - +#endif return 1; } @@ -617,7 +627,12 @@ fsqueue_qwalk(void *hdl, uint64_t *evpid) break; if (e->fts_namelen != 16) break; +#if HAVE_STRUCT_STAT_ST_MTIM if (timespeccmp(&e->fts_statp->st_mtim, &startup, >)) +#endif +#if HAVE_STRUCT_STAT_ST_MTIMSPEC + if (timespeccmp(&e->fts_statp->st_mtimspec, &startup, >)) +#endif break; tmp = NULL; *evpid = strtoull(e->fts_name, &tmp, 16); diff --git a/smtpd/queue_null.c b/smtpd/queue_null.c index c555e41d..c661e9cd 100644 --- a/smtpd/queue_null.c +++ b/smtpd/queue_null.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_proc.c b/smtpd/queue_proc.c index 2c4beb4c..d94a6c21 100644 --- a/smtpd/queue_proc.c +++ b/smtpd/queue_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/queue_ram.c b/smtpd/queue_ram.c index 81689f7b..2628faaf 100644 --- a/smtpd/queue_ram.c +++ b/smtpd/queue_ram.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/report_smtp.c b/smtpd/report_smtp.c index d2d8b27d..3f82e2cc 100644 --- a/smtpd/report_smtp.c +++ b/smtpd/report_smtp.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -36,7 +38,11 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/resolver.c b/smtpd/resolver.c index 54221416..aeb4e6bb 100644 --- a/smtpd/resolver.c +++ b/smtpd/resolver.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> @@ -186,7 +188,7 @@ resolver_dispatch_request(struct mproc *proc, struct imsg *imsg) if ((s = calloc(1, sizeof(*s))) && (s->host = malloc(NI_MAXHOST)) && (s->serv = malloc(NI_MAXSERV)) && - (q = getnameinfo_async(sa, sa->sa_len, s->host, NI_MAXHOST, + (q = getnameinfo_async(sa, SA_LEN(sa), s->host, NI_MAXHOST, s->serv, NI_MAXSERV, flags, NULL)) && (event_asr_run(q, resolver_getnameinfo_cb, s))) { s->reqid = reqid; @@ -249,14 +251,14 @@ resolver_dispatch_result(struct mproc *proc, struct imsg *imsg) m_get_string(&m, &cname); m_end(&m); - ai->ai_addr = malloc(ss.ss_len); + ai->ai_addr = malloc(SS_LEN(&ss)); if (ai->ai_addr == NULL) { log_warn("%s: malloc", __func__); free(ai); break; } - memmove(ai->ai_addr, &ss, ss.ss_len); + memmove(ai->ai_addr, &ss, SS_LEN(&ss)); if (cname) { ai->ai_canonname = strdup(cname); diff --git a/smtpd/rfc5322.c b/smtpd/rfc5322.c index 02ea7976..0af66772 100644 --- a/smtpd/rfc5322.c +++ b/smtpd/rfc5322.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <ctype.h> #include <errno.h> #include <limits.h> diff --git a/smtpd/ruleset.c b/smtpd/ruleset.c index 7ab7755c..8fbeec01 100644 --- a/smtpd/ruleset.c +++ b/smtpd/ruleset.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/runq.c b/smtpd/runq.c index ce8c67ef..29b909ae 100644 --- a/smtpd/runq.c +++ b/smtpd/runq.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> diff --git a/smtpd/scheduler.c b/smtpd/scheduler.c index de21342e..1f6810a7 100644 --- a/smtpd/scheduler.c +++ b/smtpd/scheduler.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -30,6 +32,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <inttypes.h> #include <libgen.h> diff --git a/smtpd/scheduler_backend.c b/smtpd/scheduler_backend.c index 061f1129..ad2b4cab 100644 --- a/smtpd/scheduler_backend.c +++ b/smtpd/scheduler_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_null.c b/smtpd/scheduler_null.c index a8c43331..40db6205 100644 --- a/smtpd/scheduler_null.c +++ b/smtpd/scheduler_null.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_proc.c b/smtpd/scheduler_proc.c index 0f8c44b9..5f4e8b70 100644 --- a/smtpd/scheduler_proc.c +++ b/smtpd/scheduler_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/scheduler_ramqueue.c b/smtpd/scheduler_ramqueue.c index 8d5efc10..0c04fc0b 100644 --- a/smtpd/scheduler_ramqueue.c +++ b/smtpd/scheduler_ramqueue.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/smtp.c b/smtpd/smtp.c index 61c99e5a..fc8253f3 100644 --- a/smtpd/smtp.c +++ b/smtpd/smtp.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,6 +28,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <grp.h> /* needed for setgroups */ #include <imsg.h> #include <netdb.h> #include <pwd.h> @@ -55,6 +58,8 @@ static void smtp_accepted(struct listener *, int, const struct sockaddr_storage #define SMTP_FD_RESERVE 5 +#define getdtablecount() 0 + static size_t sessions; static size_t maxsessions; @@ -139,10 +144,26 @@ smtp_setup_listeners(void) fatal("smtpd: socket"); } opt = 1; +#ifdef SO_REUSEADDR if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) fatal("smtpd: setsockopt"); - if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1) +#else + if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEPORT, &opt, + sizeof(opt)) < 0) + fatal("smtpd: setsockopt"); +#endif +#ifdef IPV6_V6ONLY + /* + * If using IPv6, bind only to IPv6 if possible. + * This avoids ambiguities with IPv4-mapped IPv6 addresses. + */ + if (l->ss.ss_family == AF_INET6) + if (setsockopt(l->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, + sizeof(opt)) < 0) + fatal("smtpd: setsockopt"); +#endif + if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1) fatal("smtpd: bind"); } } diff --git a/smtpd/smtp_session.c b/smtpd/smtp_session.c index 0a3d1025..a166d8c9 100644 --- a/smtpd/smtp_session.c +++ b/smtpd/smtp_session.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -39,7 +41,11 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include "smtpd.h" #include "log.h" diff --git a/smtpd/smtpctl.c b/smtpd/smtpctl.c index a78c26fa..6e91ac29 100644 --- a/smtpd/smtpctl.c +++ b/smtpd/smtpctl.c @@ -21,6 +21,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> @@ -29,6 +31,12 @@ #include <sys/wait.h> #include <sys/stat.h> +#include <net/if.h> +/* #include <net/if_media.h> */ +/* #include <net/if_types.h> */ +#include <netinet/in.h> +#include <arpa/inet.h> + #include <err.h> #include <errno.h> #include <event.h> @@ -42,17 +50,30 @@ #include <syslog.h> #include <time.h> #include <unistd.h> +#if defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) #include <vis.h> +#else +#include "bsd-vis.h" +#endif #include <limits.h> #include "smtpd.h" #include "parser.h" #include "log.h" +#ifndef PATH_GZCAT #define PATH_GZCAT "/usr/bin/gzcat" +#endif #define PATH_CAT "/bin/cat" #define PATH_QUEUE "/queue" +#ifndef PATH_ENCRYPT #define PATH_ENCRYPT "/usr/bin/encrypt" +#endif + +#ifndef HAVE_DB_API +#define makemap(x, y, z) 1 +#endif + int srv_connect(void); int srv_connected(void); @@ -1034,6 +1055,8 @@ main(int argc, char **argv) int privileged; char *argv_mailq[] = { "show", "queue", NULL }; + __progname = ssh_get_progname(argv[0]); + sendmail_compat(argc, argv); privileged = geteuid() == 0; diff --git a/smtpd/smtpd-defines.h b/smtpd/smtpd-defines.h index eba3ddd2..e4691c25 100644 --- a/smtpd/smtpd-defines.h +++ b/smtpd/smtpd-defines.h @@ -31,11 +31,21 @@ /* buffer size for virtual username (can be email addresses) */ #define SMTPD_VUSERNAME_SIZE (255 + 1) +#ifndef SMTPD_USER #define SMTPD_USER "_smtpd" +#endif +#ifndef PATH_CHROOT #define PATH_CHROOT "/var/empty" +#endif +#ifndef SMTPD_QUEUE_USER #define SMTPD_QUEUE_USER "_smtpq" +#endif +#ifndef SMTPD_QUEUE_GROUP #define SMTPD_QUEUE_GROUP "_smtpq" +#endif +#ifndef PATH_SPOOL #define PATH_SPOOL "/var/spool/smtpd" +#endif #define SUBADDRESSING_DELIMITER "+" diff --git a/smtpd/smtpd.c b/smtpd/smtpd.c index 1c87350d..97f4742d 100644 --- a/smtpd/smtpd.c +++ b/smtpd/smtpd.c @@ -18,6 +18,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#include <sys/file.h> /* Needed for flock */ #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -27,21 +30,44 @@ #include <sys/uio.h> #include <sys/mman.h> +#ifdef BSD_AUTH #include <bsd_auth.h> +#endif + +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include <security/pam_appl.h> +#elif defined (HAVE_PAM_PAM_APPL_H) +#include <pam/pam_appl.h> +#endif +#endif + +#ifdef HAVE_CRYPT_H +#include <crypt.h> /* needed for crypt() */ +#endif #include <dirent.h> #include <err.h> #include <errno.h> #include <event.h> #include <fcntl.h> +#include <grp.h> /* needed for setgroups */ #include <fts.h> #include <grp.h> #include <imsg.h> #include <inttypes.h> +#include <libgen.h> +#ifdef HAVE_LOGIN_CAP_H #include <login_cap.h> +#endif +#ifdef HAVE_PATHS_H #include <paths.h> +#endif #include <poll.h> #include <pwd.h> #include <signal.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> /* needed for getspnam() */ +#endif #include <stdio.h> #include <syslog.h> #include <limits.h> @@ -50,6 +76,9 @@ #include <sysexits.h> #include <time.h> #include <unistd.h> +#ifdef HAVE_UTIL_H +#include <util.h> +#endif #include <openssl/ssl.h> #include <openssl/evp.h> @@ -58,6 +87,8 @@ #include "log.h" #include "ssl.h" +extern char *__progname; + #define SMTPD_MAXARG 32 static void parent_imsg(struct mproc *, struct imsg *); @@ -152,6 +183,10 @@ int control_socket = -1; struct tree children; +/* Saved arguments to main(). */ +char **saved_argv; +int saved_argc; + static void parent_imsg(struct mproc *p, struct imsg *imsg) { @@ -470,6 +505,25 @@ main(int argc, char *argv[]) char *rexec = NULL; struct smtpd *conf; + __progname = ssh_get_progname(argv[0]); + + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = argc; + saved_argv = __xcalloc(argc + 1, sizeof(*saved_argv)); + for (i = 0; i < argc; i++) + saved_argv[i] = __xstrdup(argv[i]); + saved_argv[i] = NULL; + +#ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ + compat_init_setproctitle(argc, argv); + argv = saved_argv; +#endif + + /* this is to work around GNU getopt + portable setproctitle() fuckery */ + save_argc = saved_argc; + save_argv = saved_argv; + if ((conf = config_default()) == NULL) err(1, NULL); @@ -602,6 +656,8 @@ main(int argc, char *argv[]) if (parse_config(conf, conffile, opts)) exit(1); + seed_rng(); + if (strlcpy(env->sc_conffile, conffile, PATH_MAX) >= PATH_MAX) errx(1, "config file exceeds PATH_MAX"); @@ -832,8 +888,7 @@ start_child(int save_argc, char **save_argv, char *rexec) if (dup2(sp[0], 3) == -1) fatal("%s: dup2", rexec); - if (closefrom(4) == -1) - fatal("%s: closefrom", rexec); + xclosefrom(4); for (argc = 0; argc < save_argc; argc++) argv[argc] = save_argv[argc]; @@ -1066,6 +1121,9 @@ smtpd(void) { offline_timeout.tv_usec = 0; evtimer_add(&offline_ev, &offline_timeout); + if (pidfile(NULL) < 0) + err(1, "pidfile"); + fork_processors(); purge_task(); @@ -1166,8 +1224,7 @@ fork_proc_backend(const char *key, const char *conf, const char *procname) if (pid == 0) { /* child process */ dup2(sp[0], STDIN_FILENO); - if (closefrom(STDERR_FILENO + 1) < 0) - exit(1); + closefrom(STDERR_FILENO + 1); if (procname == NULL) procname = name; @@ -1307,8 +1364,8 @@ fork_processor(const char *name, const char *command, const char *user, const ch setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) err(1, "fork_processor: cannot drop privileges"); - if (closefrom(STDERR_FILENO + 1) < 0) - err(1, "closefrom"); + xclosefrom(STDERR_FILENO + 1); + if (setsid() < 0) err(1, "setsid"); if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || @@ -1453,8 +1510,7 @@ forkmda(struct mproc *p, uint64_t id, struct deliver *deliver) dup2(allout, STDOUT_FILENO) < 0 || dup2(allout, STDERR_FILENO) < 0) err(1, "forkmda: dup2"); - if (closefrom(STDERR_FILENO + 1) < 0) - err(1, "closefrom"); + closefrom(STDERR_FILENO + 1); if (setsid() < 0) err(1, "setsid"); if (signal(SIGPIPE, SIG_DFL) == SIG_ERR || @@ -1565,8 +1621,7 @@ offline_enqueue(char *name) ssize_t len; arglist args; - if (closefrom(STDERR_FILENO + 1) == -1) - _exit(1); + closefrom(STDERR_FILENO + 1); memset(&args, 0, sizeof(args)); @@ -2037,8 +2092,9 @@ imsg_to_str(int type) } } +#ifdef BSD_AUTH int -parent_auth_user(const char *username, const char *password) +parent_auth_bsd(const char *username, const char *password) { char user[LOGIN_NAME_MAX]; char pass[LINE_MAX]; @@ -2052,3 +2108,121 @@ parent_auth_user(const char *username, const char *password) return LKA_OK; return LKA_PERMFAIL; } +#endif + +#ifdef USE_PAM +int +pam_conv_password(int num_msg, const struct pam_message **msg, + struct pam_response **respp, const char *password) +{ + struct pam_response *response; + + if (num_msg != 1) + return PAM_CONV_ERR; + + response = calloc(1, sizeof(struct pam_response)); + if (response == NULL || (response->resp = strdup(password)) == NULL) { + free(response); + return PAM_BUF_ERR; + } + + *respp = response; + return PAM_SUCCESS; +} +int +parent_auth_pam(const char *username, const char *password) +{ + int rc; + pam_handle_t *pamh = NULL; + struct pam_conv conv = { pam_conv_password, password }; + + if ((rc = pam_start(USE_PAM_SERVICE, username, &conv, &pamh)) != PAM_SUCCESS) + goto end; + if ((rc = pam_authenticate(pamh, 0)) != PAM_SUCCESS) + goto end; + if ((rc = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) + goto end; + +end: + pam_end(pamh, rc); + + switch (rc) { + case PAM_SUCCESS: + return LKA_OK; + case PAM_SYSTEM_ERR: + case PAM_ABORT: + case PAM_AUTHINFO_UNAVAIL: + return LKA_TEMPFAIL; + default: + return LKA_PERMFAIL; + } +} +#endif + +#ifdef HAVE_GETSPNAM +int +parent_auth_getspnam(const char *username, const char *password) +{ + struct spwd *pw; + char *ep; + + errno = 0; + do { + pw = getspnam(username); + } while (pw == NULL && errno == EINTR); + + if (pw == NULL) { + if (errno) + return LKA_TEMPFAIL; + return LKA_PERMFAIL; + } + + if ((ep = crypt(password, pw->sp_pwdp)) == NULL) + return LKA_PERMFAIL; + + if (strcmp(pw->sp_pwdp, ep) == 0) + return LKA_OK; + + return LKA_PERMFAIL; +} +#endif + +int +parent_auth_pwd(const char *username, const char *password) +{ + struct passwd *pw; + char *ep; + + errno = 0; + do { + pw = getpwnam(username); + } while (pw == NULL && errno == EINTR); + + if (pw == NULL) { + if (errno) + return LKA_TEMPFAIL; + return LKA_PERMFAIL; + } + + if ((ep = crypt(password, pw->pw_passwd)) == NULL) + return LKA_PERMFAIL; + + if (strcmp(pw->pw_passwd, ep) == 0) + return LKA_OK; + + return LKA_PERMFAIL; +} + +int +parent_auth_user(const char *username, const char *password) +{ +#if defined(BSD_AUTH) + return (parent_auth_bsd(username, password)); +#elif defined(USE_PAM) + return (parent_auth_pam(username, password)); +#elif defined(HAVE_GETSPNAM) + return (parent_auth_getspnam(username, password)); +#else + return (parent_auth_pwd(username, password)); +#endif +} diff --git a/smtpd/smtpd.conf b/smtpd/smtpd.conf new file mode 100644 index 00000000..efecf2a6 --- /dev/null +++ b/smtpd/smtpd.conf @@ -0,0 +1,19 @@ +# $OpenBSD: smtpd.conf,v 1.10 2018/05/24 11:40:17 gilles Exp $ + +# This is the smtpd server system-wide configuration file. +# See smtpd.conf(5) for more information. + +table aliases file:/etc/mail/aliases + +# To accept external mail, replace with: listen on all +# +listen on localhost + +action "local" mbox alias <aliases> +action "relay" relay + +# Uncomment the following to accept external mail for domain "example.org" +# +# match from any for domain "example.org" action "local" +match for local action "local" +match from local for any action "relay" diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h index bcafee60..a5c704bf 100644 --- a/smtpd/smtpd.h +++ b/smtpd/smtpd.h @@ -18,6 +18,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <event.h> + +#include <imsg.h> + +#include "openbsd-compat.h" + #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif @@ -37,9 +43,14 @@ (expected_sz), (imsg)->hdr.len - IMSG_HEADER_SIZE); \ } while (0) -#define CONF_FILE "/etc/mail/smtpd.conf" -#define MAILNAME_FILE "/etc/mail/mailname" -#define CA_FILE "/etc/ssl/cert.pem" +#ifndef SMTPD_CONFDIR +#define SMTPD_CONFDIR "/etc" +#endif +#define CONF_FILE SMTPD_CONFDIR "/smtpd.conf" +#define MAILNAME_FILE SMTPD_CONFDIR "/mailname" +#ifndef CA_FILE +#define CA_FILE "/etc/ssl/cert.pem" +#endif #define PROC_COUNT 7 @@ -49,19 +60,34 @@ #define EXPAND_BUFFER 1024 #define SMTPD_QUEUE_EXPIRY (4 * 24 * 60 * 60) -#define SMTPD_SOCKET "/var/run/smtpd.sock" +#ifndef SMTPD_USER +#define SMTPD_USER "_smtpd" +#endif +#ifndef SMTPD_QUEUE_USER +#define SMTPD_QUEUE_USER "_smtpq" +#endif +#ifndef SMTPD_SOCKDIR +#define SMTPD_SOCKDIR "/var/run" +#endif +#define SMTPD_SOCKET SMTPD_SOCKDIR "/smtpd.sock" +#ifndef SMTPD_NAME #define SMTPD_NAME "OpenSMTPD" -#define SMTPD_VERSION "6.4.0" +#endif +#define SMTPD_VERSION "6.4.0-portable" #define SMTPD_SESSION_TIMEOUT 300 #define SMTPD_BACKLOG 5 +#ifndef PATH_SMTPCTL #define PATH_SMTPCTL "/usr/sbin/smtpctl" +#endif #define PATH_OFFLINE "/offline" #define PATH_PURGE "/purge" #define PATH_TEMPORARY "/temporary" +#ifndef PATH_LIBEXEC #define PATH_LIBEXEC "/usr/local/libexec/smtpd" +#endif /* @@ -1715,7 +1741,7 @@ int session_socket_error(int); int getmailname(char *, size_t); int base64_encode(unsigned char const *, size_t, char *, size_t); int base64_decode(char const *, unsigned char *, size_t); - +void xclosefrom(int); void log_trace_verbose(int); void log_trace(int, const char *, ...) __attribute__((format (printf, 2, 3))); diff --git a/smtpd/spfwalk.c b/smtpd/spfwalk.c index 22b05796..8188c620 100644 --- a/smtpd/spfwalk.c +++ b/smtpd/spfwalk.c @@ -14,10 +14,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/tree.h> +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <arpa/inet.h> #include <arpa/nameser.h> #include <netinet/in.h> @@ -34,7 +39,6 @@ #include <strings.h> #include <unistd.h> -#define LINE_MAX 1024 #include "smtpd-defines.h" #include "smtpd-api.h" #include "unpack_dns.h" diff --git a/smtpd/ssl.c b/smtpd/ssl.c index 7cbee563..74932247 100644 --- a/smtpd/ssl.c +++ b/smtpd/ssl.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -85,7 +87,7 @@ ssl_setup(SSL_CTX **ctxp, struct pki *pki, if (sni_cb) SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb); - SSL_CTX_set_dh_auto(ctx, pki->pki_dhe); + SSL_CTX_set_dh_auto(ctx, 0); SSL_CTX_set_ecdh_auto(ctx, 1); diff --git a/smtpd/ssl.h b/smtpd/ssl.h index dfa6994c..b7c8351f 100644 --- a/smtpd/ssl.h +++ b/smtpd/ssl.h @@ -65,3 +65,4 @@ int ssl_ctx_fake_private_key(SSL_CTX *, const void *, size_t, /* ssl_privsep.c */ int ssl_by_mem_ctrl(X509_LOOKUP *, int, const char *, long, char **); +int SSL_CTX_use_certificate_chain_mem(SSL_CTX *, void *, int); diff --git a/smtpd/ssl_smtpd.c b/smtpd/ssl_smtpd.c index 1f1e62d2..4e5b7e75 100644 --- a/smtpd/ssl_smtpd.c +++ b/smtpd/ssl_smtpd.c @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/stat_backend.c b/smtpd/stat_backend.c index 28e0ea24..b510ab91 100644 --- a/smtpd/stat_backend.c +++ b/smtpd/stat_backend.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> diff --git a/smtpd/stat_ramstat.c b/smtpd/stat_ramstat.c index ede2e130..bbf1541a 100644 --- a/smtpd/stat_ramstat.c +++ b/smtpd/stat_ramstat.c @@ -15,6 +15,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" #include <sys/types.h> #include <sys/socket.h> diff --git a/smtpd/table.c b/smtpd/table.c index 187cb0ed..37249abd 100644 --- a/smtpd/table.c +++ b/smtpd/table.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -46,7 +48,9 @@ struct table_backend *table_backend_lookup(const char *); extern struct table_backend table_backend_static; +#ifdef HAVE_DB_API extern struct table_backend table_backend_db; +#endif extern struct table_backend table_backend_getpwnam; extern struct table_backend table_backend_proc; @@ -62,8 +66,10 @@ table_backend_lookup(const char *backend) { if (!strcmp(backend, "static") || !strcmp(backend, "file")) return &table_backend_static; +#ifdef HAVE_DB_API if (!strcmp(backend, "db")) return &table_backend_db; +#endif if (!strcmp(backend, "getpwnam")) return &table_backend_getpwnam; if (!strcmp(backend, "proc")) @@ -76,8 +82,10 @@ table_backend_name(struct table_backend *backend) { if (backend == &table_backend_static) return "static"; +#ifdef HAVE_DB_API if (backend == &table_backend_db) return "db"; +#endif if (backend == &table_backend_getpwnam) return "getpwnam"; if (backend == &table_backend_proc) @@ -395,7 +403,7 @@ table_netaddr_match(const char *s1, const char *s2) return 0; if (n1.ss.ss_family != n2.ss.ss_family) return 0; - if (n1.ss.ss_len != n2.ss.ss_len) + if (SS_LEN(&n1.ss) != SS_LEN(&n2.ss)) return 0; return table_match_mask(&n1.ss, &n2); } @@ -657,8 +665,9 @@ table_parse_lookup(enum table_service service, const char *key, static const char * table_dump_lookup(enum table_service s, union lookup *lk) { - static char buf[LINE_MAX]; - int ret; + static char buf[LINE_MAX]; + struct maddrnode *mn; + int ret; switch (s) { case K_NONE: @@ -714,6 +723,23 @@ table_dump_lookup(enum table_service s, union lookup *lk) goto err; break; + case K_MAILADDRMAP: + buf[0] = '\0'; + TAILQ_FOREACH(mn, &lk->maddrmap->queue, entries) { + (void)strlcat(buf, mn->mailaddr.user, sizeof(buf)); + (void)strlcat(buf, "@", sizeof(buf)); + ret = strlcat(buf, mn->mailaddr.domain, sizeof(buf)); + + if (mn != TAILQ_LAST(&lk->maddrmap->queue, xmaddr)) + ret = strlcat(buf, ", ", sizeof(buf)); + + if (ret >= sizeof(buf)) { + strlcpy(buf + sizeof(buf) - 4, "...", 4); + break; + } + } + break; + case K_ADDRNAME: ret = snprintf(buf, sizeof(buf), "%s", lk->addrname.name); @@ -760,7 +786,9 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) sin = (struct sockaddr_in *)sa; memset(sin, 0, sizeof *sin); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin->sin_len = sizeof(struct sockaddr_in); +#endif sin->sin_family = PF_INET; sin->sin_addr.s_addr = ina.s_addr; return (0); @@ -785,7 +813,9 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) sin6 = (struct sockaddr_in6 *)sa; memset(sin6, 0, sizeof *sin6); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sin6->sin6_len = sizeof(struct sockaddr_in6); +#endif sin6->sin6_family = PF_INET6; sin6->sin6_addr = in6a; @@ -794,7 +824,7 @@ parse_sockaddr(struct sockaddr *sa, int family, const char *str) if (IN6_IS_ADDR_LINKLOCAL(&in6a) || IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || - IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) + IN6_IS_ADDR_MC_NODELOCAL(&in6a)) if ((sin6->sin6_scope_id = if_nametoindex(cp))) return (0); diff --git a/smtpd/table_api.c b/smtpd/table_api.c index 2eac4860..4c3a51a8 100644 --- a/smtpd/table_api.c +++ b/smtpd/table_api.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -29,6 +31,7 @@ #include <fcntl.h> #include <imsg.h> #include <pwd.h> +#include <grp.h> /* needed for setgroups */ #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/smtpd/table_db.c b/smtpd/table_db.c index aeeed209..4ef23f71 100644 --- a/smtpd/table_db.c +++ b/smtpd/table_db.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/stat.h> #include <sys/queue.h> @@ -24,8 +26,13 @@ #include <netinet/in.h> #include <arpa/inet.h> - +#ifdef HAVE_DB_H #include <db.h> +#elif defined(HAVE_DB1_DB_H) +#include <db1/db.h> +#elif defined(HAVE_DB_185_H) +#include <db_185.h> +#endif #include <ctype.h> #include <err.h> #include <event.h> diff --git a/smtpd/table_getpwnam.c b/smtpd/table_getpwnam.c index 83cbf797..87b0a54c 100644 --- a/smtpd/table_getpwnam.c +++ b/smtpd/table_getpwnam.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> diff --git a/smtpd/table_proc.c b/smtpd/table_proc.c index 27abbfe0..fcf4ffcb 100644 --- a/smtpd/table_proc.c +++ b/smtpd/table_proc.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -26,7 +28,9 @@ #include <event.h> #include <fcntl.h> #include <imsg.h> +#ifdef HAVE_PATHS_H #include <paths.h> +#endif #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/smtpd/table_static.c b/smtpd/table_static.c index 7be9cf21..3a19e7e2 100644 --- a/smtpd/table_static.c +++ b/smtpd/table_static.c @@ -17,6 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -18,6 +18,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -57,12 +59,14 @@ 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); +static int broken_inet_net_pton_ipv6(const char *, void *, size_t); + const char * sockaddr_to_text(struct sockaddr *sa) { static char buf[NI_MAXHOST]; - if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, + if (getnameinfo(sa, SA_LEN(sa), buf, sizeof(buf), NULL, 0, NI_NUMERICHOST)) return ("(unknown)"); else @@ -76,7 +80,9 @@ in6addr_to_text(const struct in6_addr *addr) uint16_t tmp16; memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN sa_in6.sin6_len = sizeof(sa_in6); +#endif sa_in6.sin6_family = AF_INET6; memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); @@ -193,15 +199,20 @@ time_to_text(time_t when) char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; char *month[] = {"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"}; - char *tz; + const char *tz; long offset; lt = localtime(&when); if (lt == NULL || when == 0) fatalx("time_to_text: localtime"); +#if HAVE_STRUCT_TM_TM_GMTOFF offset = lt->tm_gmtoff; tz = lt->tm_zone; +#elif defined HAVE_DECL_ALTZONE && defined HAVE_DECL_TIMEZONE + offset = lt->tm_isdst > 0 ? altzone : timezone; + tz = lt->tm_isdst > 0 ? tzname[1] : tzname[0]; +#endif /* We do not use strftime because it is subject to locale substitution*/ if (!bsnprintf(buf, sizeof(buf), @@ -283,15 +294,25 @@ text_to_netaddr(struct netaddr *netaddr, const char *s) if (bits != -1) { ssin.sin_family = AF_INET; memcpy(&ss, &ssin, sizeof(ssin)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss.ss_len = sizeof(struct sockaddr_in); +#endif } else { bits = inet_net_pton(AF_INET6, s, &ssin6.sin6_addr, sizeof(struct in6_addr)); - if (bits == -1) - return 0; + if (bits == -1) { + if (errno != EAFNOSUPPORT) + return 0; + bits = broken_inet_net_pton_ipv6(s, &ssin6.sin6_addr, + sizeof(struct in6_addr)); + if (bits == -1) + return 0; + } ssin6.sin6_family = AF_INET6; memcpy(&ss, &ssin6, sizeof(ssin6)); +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN ss.ss_len = sizeof(struct sockaddr_in6); +#endif } netaddr->ss = ss; @@ -810,3 +831,35 @@ alias_is_error(struct expandnode *alias, const char *line, size_t len) alias->type = EXPAND_ERROR; return 1; } + +static int +broken_inet_net_pton_ipv6(const char *src, void *dst, size_t size) +{ + int ret; + int bits; + char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")]; + char *sep; + const char *errstr; + + if (strlcpy(buf, src, sizeof buf) >= sizeof buf) { + errno = EMSGSIZE; + return (-1); + } + + sep = strchr(buf, '/'); + if (sep != NULL) + *sep++ = '\0'; + + ret = inet_pton(AF_INET6, buf, dst); + if (ret != 1) + return (-1); + + if (sep == NULL) + return 128; + + bits = strtonum(sep, 0, 128, &errstr); + if (errstr) + return (-1); + + return bits; +} diff --git a/smtpd/tree.c b/smtpd/tree.c index 2022ebaf..03ba8d15 100644 --- a/smtpd/tree.c +++ b/smtpd/tree.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/tree.h> diff --git a/smtpd/unpack_dns.c b/smtpd/unpack_dns.c index fe50b026..974d5727 100644 --- a/smtpd/unpack_dns.c +++ b/smtpd/unpack_dns.c @@ -16,6 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include <arpa/nameser_compat.h> +#endif #include <arpa/inet.h> #include <string.h> diff --git a/smtpd/util.c b/smtpd/util.c index df7fabad..dbcea86e 100644 --- a/smtpd/util.c +++ b/smtpd/util.c @@ -19,6 +19,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/queue.h> #include <sys/tree.h> @@ -832,3 +834,14 @@ log_trace_verbose(int v) /* Set debug logging in log.c */ log_setverbose(v & TRACE_DEBUG ? 2 : foreground_log); } + +void +xclosefrom(int lowfd) +{ +#if defined HAVE_CLOSEFROM_INT + if (closefrom(lowfd) == -1) + err(1, "closefrom"); +#else + closefrom(lowfd); +#endif +} diff --git a/smtpd/waitq.c b/smtpd/waitq.c index dc459372..082a1e51 100644 --- a/smtpd/waitq.c +++ b/smtpd/waitq.c @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "includes.h" + #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> |