aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd/smtpd.h
diff options
context:
space:
mode:
Diffstat (limited to 'smtpd/smtpd.h')
-rw-r--r--smtpd/smtpd.h1784
1 files changed, 1784 insertions, 0 deletions
diff --git a/smtpd/smtpd.h b/smtpd/smtpd.h
new file mode 100644
index 00000000..4385f747
--- /dev/null
+++ b/smtpd/smtpd.h
@@ -0,0 +1,1784 @@
+/* $OpenBSD: smtpd.h,v 1.656 2020/04/08 07:30:44 eric Exp $ */
+
+/*
+ * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.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 <event.h>
+
+#include <imsg.h>
+
+#include "openbsd-compat.h"
+
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <event.h>
+
+#include "smtpd-defines.h"
+#include "smtpd-api.h"
+#include "ioev.h"
+
+#define CHECK_IMSG_DATA_SIZE(imsg, expected_sz) do { \
+ if ((imsg)->hdr.len - IMSG_HEADER_SIZE != (expected_sz)) \
+ fatalx("smtpd: imsg %d: data size expected %zd got %zd",\
+ (imsg)->hdr.type, \
+ (expected_sz), (imsg)->hdr.len - IMSG_HEADER_SIZE); \
+} while (0)
+
+#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
+
+#define MAX_HOPS_COUNT 100
+#define DEFAULT_MAX_BODY_SIZE (35*1024*1024)
+
+#define EXPAND_BUFFER 1024
+
+#define SMTPD_QUEUE_EXPIRY (4 * 24 * 60 * 60)
+#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"
+#endif
+#define SMTPD_VERSION "6.7.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
+
+
+/*
+ * RFC 5322 defines these characters as valid, some of them are
+ * potentially dangerous and need to be escaped.
+ */
+#define MAILADDR_ALLOWED "!#$%&'*/?^`{|}~+-=_"
+#define MAILADDR_ESCAPE "!#$%&'*?`{|}~"
+
+
+#define F_STARTTLS 0x01
+#define F_SMTPS 0x02
+#define F_SSL (F_STARTTLS | F_SMTPS)
+#define F_AUTH 0x08
+#define F_STARTTLS_REQUIRE 0x20
+#define F_AUTH_REQUIRE 0x40
+#define F_MASK_SOURCE 0x100
+#define F_TLS_VERIFY 0x200
+#define F_EXT_DSN 0x400
+#define F_RECEIVEDAUTH 0x800
+#define F_MASQUERADE 0x1000
+#define F_FILTERED 0x2000
+#define F_PROXY 0x4000
+
+#define RELAY_TLS_OPPORTUNISTIC 0
+#define RELAY_TLS_STARTTLS 1
+#define RELAY_TLS_SMTPS 2
+#define RELAY_TLS_NO 3
+
+#define RELAY_AUTH 0x08
+#define RELAY_LMTP 0x80
+#define RELAY_TLS_VERIFY 0x200
+
+#define MTA_EXT_DSN 0x400
+
+
+#define P_SENDMAIL 0
+#define P_NEWALIASES 1
+#define P_MAKEMAP 2
+
+#define CERT_ERROR -1
+#define CERT_OK 0
+#define CERT_NOCA 1
+#define CERT_NOCERT 2
+#define CERT_INVALID 3
+
+struct userinfo {
+ char username[SMTPD_VUSERNAME_SIZE];
+ char directory[PATH_MAX];
+ uid_t uid;
+ gid_t gid;
+};
+
+struct netaddr {
+ struct sockaddr_storage ss;
+ int bits;
+};
+
+struct relayhost {
+ uint16_t flags;
+ int tls;
+ char hostname[HOST_NAME_MAX+1];
+ uint16_t port;
+ char authlabel[PATH_MAX];
+};
+
+struct credentials {
+ char username[LINE_MAX];
+ char password[LINE_MAX];
+};
+
+struct destination {
+ char name[HOST_NAME_MAX+1];
+};
+
+struct source {
+ struct sockaddr_storage addr;
+};
+
+struct addrname {
+ struct sockaddr_storage addr;
+ char name[HOST_NAME_MAX+1];
+};
+
+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;
+ struct maddrmap *maddrmap;
+ char relayhost[LINE_MAX];
+};
+
+/*
+ * 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 16
+
+enum imsg_type {
+ IMSG_NONE,
+
+ IMSG_CTL_OK,
+ IMSG_CTL_FAIL,
+
+ IMSG_CTL_GET_DIGEST,
+ IMSG_CTL_GET_STATS,
+ IMSG_CTL_LIST_MESSAGES,
+ IMSG_CTL_LIST_ENVELOPES,
+ IMSG_CTL_MTA_SHOW_HOSTS,
+ IMSG_CTL_MTA_SHOW_RELAYS,
+ IMSG_CTL_MTA_SHOW_ROUTES,
+ IMSG_CTL_MTA_SHOW_HOSTSTATS,
+ IMSG_CTL_MTA_BLOCK,
+ IMSG_CTL_MTA_UNBLOCK,
+ IMSG_CTL_MTA_SHOW_BLOCK,
+ IMSG_CTL_PAUSE_EVP,
+ IMSG_CTL_PAUSE_MDA,
+ IMSG_CTL_PAUSE_MTA,
+ IMSG_CTL_PAUSE_SMTP,
+ IMSG_CTL_PROFILE,
+ IMSG_CTL_PROFILE_DISABLE,
+ IMSG_CTL_PROFILE_ENABLE,
+ IMSG_CTL_RESUME_EVP,
+ IMSG_CTL_RESUME_MDA,
+ IMSG_CTL_RESUME_MTA,
+ IMSG_CTL_RESUME_SMTP,
+ IMSG_CTL_RESUME_ROUTE,
+ IMSG_CTL_REMOVE,
+ IMSG_CTL_SCHEDULE,
+ IMSG_CTL_SHOW_STATUS,
+ IMSG_CTL_TRACE_DISABLE,
+ IMSG_CTL_TRACE_ENABLE,
+ IMSG_CTL_UPDATE_TABLE,
+ IMSG_CTL_VERBOSE,
+ IMSG_CTL_DISCOVER_EVPID,
+ IMSG_CTL_DISCOVER_MSGID,
+
+ IMSG_CTL_SMTP_SESSION,
+
+ IMSG_GETADDRINFO,
+ IMSG_GETADDRINFO_END,
+ IMSG_GETNAMEINFO,
+ IMSG_RES_QUERY,
+
+ IMSG_CERT_INIT,
+ IMSG_CERT_CERTIFICATE,
+ IMSG_CERT_VERIFY,
+
+ IMSG_SETUP_KEY,
+ IMSG_SETUP_PEER,
+ IMSG_SETUP_DONE,
+
+ IMSG_CONF_START,
+ IMSG_CONF_END,
+
+ IMSG_STAT_INCREMENT,
+ IMSG_STAT_DECREMENT,
+ IMSG_STAT_SET,
+
+ IMSG_LKA_AUTHENTICATE,
+ IMSG_LKA_OPEN_FORWARD,
+ IMSG_LKA_ENVELOPE_SUBMIT,
+ IMSG_LKA_ENVELOPE_COMMIT,
+
+ IMSG_QUEUE_DELIVER,
+ IMSG_QUEUE_DELIVERY_OK,
+ IMSG_QUEUE_DELIVERY_TEMPFAIL,
+ IMSG_QUEUE_DELIVERY_PERMFAIL,
+ IMSG_QUEUE_DELIVERY_LOOP,
+ IMSG_QUEUE_DISCOVER_EVPID,
+ IMSG_QUEUE_DISCOVER_MSGID,
+ IMSG_QUEUE_ENVELOPE_ACK,
+ IMSG_QUEUE_ENVELOPE_COMMIT,
+ IMSG_QUEUE_ENVELOPE_REMOVE,
+ IMSG_QUEUE_ENVELOPE_SCHEDULE,
+ IMSG_QUEUE_ENVELOPE_SUBMIT,
+ IMSG_QUEUE_HOLDQ_HOLD,
+ IMSG_QUEUE_HOLDQ_RELEASE,
+ IMSG_QUEUE_MESSAGE_COMMIT,
+ IMSG_QUEUE_MESSAGE_ROLLBACK,
+ IMSG_QUEUE_SMTP_SESSION,
+ IMSG_QUEUE_TRANSFER,
+
+ IMSG_MDA_DELIVERY_OK,
+ IMSG_MDA_DELIVERY_TEMPFAIL,
+ IMSG_MDA_DELIVERY_PERMFAIL,
+ IMSG_MDA_DELIVERY_LOOP,
+ IMSG_MDA_DELIVERY_HOLD,
+ IMSG_MDA_DONE,
+ IMSG_MDA_FORK,
+ IMSG_MDA_HOLDQ_RELEASE,
+ IMSG_MDA_LOOKUP_USERINFO,
+ IMSG_MDA_KILL,
+ IMSG_MDA_OPEN_MESSAGE,
+
+ IMSG_MTA_DELIVERY_OK,
+ IMSG_MTA_DELIVERY_TEMPFAIL,
+ IMSG_MTA_DELIVERY_PERMFAIL,
+ IMSG_MTA_DELIVERY_LOOP,
+ IMSG_MTA_DELIVERY_HOLD,
+ IMSG_MTA_DNS_HOST,
+ IMSG_MTA_DNS_HOST_END,
+ IMSG_MTA_DNS_MX,
+ IMSG_MTA_DNS_MX_PREFERENCE,
+ IMSG_MTA_HOLDQ_RELEASE,
+ IMSG_MTA_LOOKUP_CREDENTIALS,
+ IMSG_MTA_LOOKUP_SOURCE,
+ IMSG_MTA_LOOKUP_HELO,
+ IMSG_MTA_LOOKUP_SMARTHOST,
+ IMSG_MTA_OPEN_MESSAGE,
+ IMSG_MTA_SCHEDULE,
+
+ IMSG_SCHED_ENVELOPE_BOUNCE,
+ IMSG_SCHED_ENVELOPE_DELIVER,
+ IMSG_SCHED_ENVELOPE_EXPIRE,
+ IMSG_SCHED_ENVELOPE_INJECT,
+ IMSG_SCHED_ENVELOPE_REMOVE,
+ IMSG_SCHED_ENVELOPE_TRANSFER,
+
+ IMSG_SMTP_AUTHENTICATE,
+ IMSG_SMTP_MESSAGE_COMMIT,
+ IMSG_SMTP_MESSAGE_CREATE,
+ IMSG_SMTP_MESSAGE_ROLLBACK,
+ IMSG_SMTP_MESSAGE_OPEN,
+ IMSG_SMTP_CHECK_SENDER,
+ IMSG_SMTP_EXPAND_RCPT,
+ IMSG_SMTP_LOOKUP_HELO,
+
+ IMSG_SMTP_REQ_CONNECT,
+ IMSG_SMTP_REQ_HELO,
+ IMSG_SMTP_REQ_MAIL,
+ IMSG_SMTP_REQ_RCPT,
+ IMSG_SMTP_REQ_DATA,
+ IMSG_SMTP_REQ_EOM,
+ IMSG_SMTP_EVENT_RSET,
+ IMSG_SMTP_EVENT_COMMIT,
+ IMSG_SMTP_EVENT_ROLLBACK,
+ IMSG_SMTP_EVENT_DISCONNECT,
+
+ IMSG_LKA_PROCESSOR_FORK,
+ IMSG_LKA_PROCESSOR_ERRFD,
+
+ IMSG_REPORT_SMTP_LINK_CONNECT,
+ IMSG_REPORT_SMTP_LINK_DISCONNECT,
+ IMSG_REPORT_SMTP_LINK_GREETING,
+ IMSG_REPORT_SMTP_LINK_IDENTIFY,
+ IMSG_REPORT_SMTP_LINK_TLS,
+ IMSG_REPORT_SMTP_LINK_AUTH,
+ IMSG_REPORT_SMTP_TX_RESET,
+ IMSG_REPORT_SMTP_TX_BEGIN,
+ IMSG_REPORT_SMTP_TX_MAIL,
+ IMSG_REPORT_SMTP_TX_RCPT,
+ IMSG_REPORT_SMTP_TX_ENVELOPE,
+ IMSG_REPORT_SMTP_TX_DATA,
+ IMSG_REPORT_SMTP_TX_COMMIT,
+ IMSG_REPORT_SMTP_TX_ROLLBACK,
+ IMSG_REPORT_SMTP_PROTOCOL_CLIENT,
+ IMSG_REPORT_SMTP_PROTOCOL_SERVER,
+ IMSG_REPORT_SMTP_FILTER_RESPONSE,
+ IMSG_REPORT_SMTP_TIMEOUT,
+
+ IMSG_FILTER_SMTP_BEGIN,
+ IMSG_FILTER_SMTP_END,
+ IMSG_FILTER_SMTP_PROTOCOL,
+ IMSG_FILTER_SMTP_DATA_BEGIN,
+ IMSG_FILTER_SMTP_DATA_END,
+
+ IMSG_CA_RSA_PRIVENC,
+ IMSG_CA_RSA_PRIVDEC,
+ IMSG_CA_ECDSA_SIGN,
+};
+
+enum smtp_proc_type {
+ PROC_PARENT = 0,
+ PROC_LKA,
+ PROC_QUEUE,
+ PROC_CONTROL,
+ PROC_SCHEDULER,
+ PROC_PONY,
+ PROC_CA,
+ PROC_PROCESSOR,
+ PROC_CLIENT,
+};
+
+enum table_type {
+ T_NONE = 0,
+ T_DYNAMIC = 0x01, /* table with external source */
+ T_LIST = 0x02, /* table holding a list */
+ T_HASH = 0x04, /* table holding a hash table */
+};
+
+struct table {
+ char t_name[LINE_MAX];
+ enum table_type t_type;
+ char t_config[PATH_MAX];
+
+ void *t_handle;
+ struct table_backend *t_backend;
+};
+
+struct table_backend {
+ const char *name;
+ const unsigned int services;
+ int (*config)(struct table *);
+ int (*add)(struct table *, const char *, const char *);
+ void (*dump)(struct table *);
+ int (*open)(struct table *);
+ int (*update)(struct table *);
+ void (*close)(struct table *);
+ int (*lookup)(struct table *, enum table_service, const char *, char **);
+ int (*fetch)(struct table *, enum table_service, char **);
+};
+
+
+enum bounce_type {
+ B_FAILED,
+ B_DELAYED,
+ B_DELIVERED
+};
+
+enum dsn_ret {
+ DSN_RETFULL = 1,
+ DSN_RETHDRS
+};
+
+struct delivery_bounce {
+ enum bounce_type type;
+ time_t delay;
+ time_t ttl;
+ enum dsn_ret dsn_ret;
+ int mta_without_dsn;
+};
+
+enum expand_type {
+ EXPAND_INVALID,
+ EXPAND_USERNAME,
+ EXPAND_FILENAME,
+ EXPAND_FILTER,
+ EXPAND_INCLUDE,
+ EXPAND_ADDRESS,
+ EXPAND_ERROR,
+};
+
+enum filter_phase {
+ FILTER_CONNECT,
+ FILTER_HELO,
+ FILTER_EHLO,
+ FILTER_STARTTLS,
+ FILTER_AUTH,
+ FILTER_MAIL_FROM,
+ FILTER_RCPT_TO,
+ FILTER_DATA,
+ FILTER_DATA_LINE,
+ FILTER_RSET,
+ FILTER_QUIT,
+ FILTER_NOOP,
+ FILTER_HELP,
+ FILTER_WIZ,
+ FILTER_COMMIT,
+ FILTER_PHASES_COUNT /* must be last */
+};
+
+struct expandnode {
+ RB_ENTRY(expandnode) entry;
+ TAILQ_ENTRY(expandnode) tq_entry;
+ enum expand_type type;
+ int sameuser;
+ int realuser;
+ int forwarded;
+ struct rule *rule;
+ struct expandnode *parent;
+ unsigned int depth;
+ union {
+ /*
+ * user field handles both expansion user and system user
+ * so we MUST make it large enough to fit a mailaddr user
+ */
+ char user[SMTPD_MAXLOCALPARTSIZE];
+ char buffer[EXPAND_BUFFER];
+ struct mailaddr mailaddr;
+ } u;
+ char subaddress[SMTPD_SUBADDRESS_SIZE];
+};
+
+struct expand {
+ RB_HEAD(expandtree, expandnode) tree;
+ TAILQ_HEAD(xnodes, expandnode) *queue;
+ size_t nb_nodes;
+ struct rule *rule;
+ struct expandnode *parent;
+};
+
+struct maddrnode {
+ TAILQ_ENTRY(maddrnode) entries;
+ struct mailaddr mailaddr;
+};
+
+struct maddrmap {
+ TAILQ_HEAD(xmaddr, maddrnode) queue;
+};
+
+#define DSN_SUCCESS 0x01
+#define DSN_FAILURE 0x02
+#define DSN_DELAY 0x04
+#define DSN_NEVER 0x08
+
+#define DSN_ENVID_LEN 100
+
+#define SMTPD_ENVELOPE_VERSION 3
+struct envelope {
+ TAILQ_ENTRY(envelope) entry;
+
+ char dispatcher[HOST_NAME_MAX+1];
+
+ char tag[SMTPD_TAG_SIZE];
+
+ uint32_t version;
+ uint64_t id;
+ enum envelope_flags flags;
+
+ char smtpname[HOST_NAME_MAX+1];
+ char helo[HOST_NAME_MAX+1];
+ char hostname[HOST_NAME_MAX+1];
+ char username[SMTPD_MAXMAILADDRSIZE];
+ char errorline[LINE_MAX];
+ struct sockaddr_storage ss;
+
+ struct mailaddr sender;
+ struct mailaddr rcpt;
+ struct mailaddr dest;
+
+ char mda_user[SMTPD_VUSERNAME_SIZE];
+ char mda_subaddress[SMTPD_SUBADDRESS_SIZE];
+ char mda_exec[LINE_MAX];
+
+ enum delivery_type type;
+ union {
+ struct delivery_bounce bounce;
+ } agent;
+
+ uint16_t retry;
+ time_t creation;
+ time_t ttl;
+ time_t lasttry;
+ time_t nexttry;
+ time_t lastbounce;
+
+ struct mailaddr dsn_orcpt;
+ char dsn_envid[DSN_ENVID_LEN+1];
+ uint8_t dsn_notify;
+ enum dsn_ret dsn_ret;
+
+ uint8_t esc_class;
+ uint8_t esc_code;
+};
+
+struct listener {
+ uint16_t flags;
+ int fd;
+ struct sockaddr_storage ss;
+ in_port_t port;
+ struct timeval timeout;
+ struct event ev;
+ char filter_name[PATH_MAX];
+ char pki_name[PATH_MAX];
+ char ca_name[PATH_MAX];
+ char tag[SMTPD_TAG_SIZE];
+ char authtable[LINE_MAX];
+ char hostname[HOST_NAME_MAX+1];
+ char hostnametable[PATH_MAX];
+ char sendertable[PATH_MAX];
+
+ TAILQ_ENTRY(listener) entry;
+
+ int local; /* there must be a better way */
+};
+
+struct smtpd {
+ char sc_conffile[PATH_MAX];
+ size_t sc_maxsize;
+
+#define SMTPD_OPT_VERBOSE 0x00000001
+#define SMTPD_OPT_NOACTION 0x00000002
+ uint32_t sc_opts;
+
+#define SMTPD_EXITING 0x00000001 /* unused */
+#define SMTPD_MDA_PAUSED 0x00000002
+#define SMTPD_MTA_PAUSED 0x00000004
+#define SMTPD_SMTP_PAUSED 0x00000008
+#define SMTPD_MDA_BUSY 0x00000010
+#define SMTPD_MTA_BUSY 0x00000020
+#define SMTPD_BOUNCE_BUSY 0x00000040
+#define SMTPD_SMTP_DISABLED 0x00000080
+ uint32_t sc_flags;
+
+#define QUEUE_COMPRESSION 0x00000001
+#define QUEUE_ENCRYPTION 0x00000002
+#define QUEUE_EVPCACHE 0x00000004
+ uint32_t sc_queue_flags;
+ char *sc_queue_key;
+ size_t sc_queue_evpcache_size;
+
+ size_t sc_session_max_rcpt;
+ size_t sc_session_max_mails;
+
+ struct dict *sc_mda_wrappers;
+ size_t sc_mda_max_session;
+ size_t sc_mda_max_user_session;
+ size_t sc_mda_task_hiwat;
+ size_t sc_mda_task_lowat;
+ size_t sc_mda_task_release;
+
+ size_t sc_mta_max_deferred;
+
+ size_t sc_scheduler_max_inflight;
+ size_t sc_scheduler_max_evp_batch_size;
+ size_t sc_scheduler_max_msg_batch_size;
+ size_t sc_scheduler_max_schedule;
+
+ struct dict *sc_filter_processes_dict;
+
+ int sc_ttl;
+#define MAX_BOUNCE_WARN 4
+ time_t sc_bounce_warn[MAX_BOUNCE_WARN];
+ char sc_hostname[HOST_NAME_MAX+1];
+ struct stat_backend *sc_stat;
+ struct compress_backend *sc_comp;
+
+ time_t sc_uptime;
+
+ /* This is a listener for a local socket used by smtp_enqueue(). */
+ struct listener *sc_sock_listener;
+
+ TAILQ_HEAD(listenerlist, listener) *sc_listeners;
+
+ TAILQ_HEAD(rulelist, rule) *sc_rules;
+
+
+ struct dict *sc_filters_dict;
+ struct dict *sc_dispatchers;
+ struct dispatcher *sc_dispatcher_bounce;
+
+ struct dict *sc_ca_dict;
+ struct dict *sc_pki_dict;
+ struct dict *sc_ssl_dict;
+
+ struct dict *sc_tables_dict; /* keyed lookup */
+
+ struct dict *sc_limits_dict;
+
+ char *sc_tls_ciphers;
+
+ char *sc_subaddressing_delim;
+
+ char *sc_srs_key;
+ char *sc_srs_key_backup;
+ int sc_srs_ttl;
+};
+
+#define TRACE_DEBUG 0x0001
+#define TRACE_IMSG 0x0002
+#define TRACE_IO 0x0004
+#define TRACE_SMTP 0x0008
+#define TRACE_FILTERS 0x0010
+#define TRACE_MTA 0x0020
+#define TRACE_BOUNCE 0x0040
+#define TRACE_SCHEDULER 0x0080
+#define TRACE_LOOKUP 0x0100
+#define TRACE_STAT 0x0200
+#define TRACE_RULES 0x0400
+#define TRACE_MPROC 0x0800
+#define TRACE_EXPAND 0x1000
+#define TRACE_TABLES 0x2000
+#define TRACE_QUEUE 0x4000
+
+#define PROFILE_TOSTAT 0x0001
+#define PROFILE_IMSG 0x0002
+#define PROFILE_QUEUE 0x0004
+
+struct forward_req {
+ uint64_t id;
+ uint8_t status;
+
+ char user[SMTPD_VUSERNAME_SIZE];
+ uid_t uid;
+ gid_t gid;
+ char directory[PATH_MAX];
+};
+
+struct deliver {
+ char dispatcher[EXPAND_BUFFER];
+
+ struct mailaddr sender;
+ struct mailaddr rcpt;
+ struct mailaddr dest;
+
+ char mda_subaddress[SMTPD_SUBADDRESS_SIZE];
+ char mda_exec[LINE_MAX];
+
+ struct userinfo userinfo;
+};
+
+struct mta_host {
+ SPLAY_ENTRY(mta_host) entry;
+ struct sockaddr *sa;
+ char *ptrname;
+ int refcount;
+ size_t nconn;
+ time_t lastconn;
+ time_t lastptrquery;
+
+#define HOST_IGNORE 0x01
+ int flags;
+};
+
+struct mta_mx {
+ TAILQ_ENTRY(mta_mx) entry;
+ struct mta_host *host;
+ char *mxname;
+ int preference;
+};
+
+struct mta_domain {
+ SPLAY_ENTRY(mta_domain) entry;
+ char *name;
+ int as_host;
+ TAILQ_HEAD(, mta_mx) mxs;
+ int mxstatus;
+ int refcount;
+ size_t nconn;
+ time_t lastconn;
+ time_t lastmxquery;
+};
+
+struct mta_source {
+ SPLAY_ENTRY(mta_source) entry;
+ struct sockaddr *sa;
+ int refcount;
+ size_t nconn;
+ time_t lastconn;
+};
+
+struct mta_connector {
+ struct mta_source *source;
+ struct mta_relay *relay;
+
+#define CONNECTOR_ERROR_FAMILY 0x0001
+#define CONNECTOR_ERROR_SOURCE 0x0002
+#define CONNECTOR_ERROR_MX 0x0004
+#define CONNECTOR_ERROR_ROUTE_NET 0x0008
+#define CONNECTOR_ERROR_ROUTE_SMTP 0x0010
+#define CONNECTOR_ERROR_ROUTE 0x0018
+#define CONNECTOR_ERROR_BLOCKED 0x0020
+#define CONNECTOR_ERROR 0x00ff
+
+#define CONNECTOR_LIMIT_HOST 0x0100
+#define CONNECTOR_LIMIT_ROUTE 0x0200
+#define CONNECTOR_LIMIT_SOURCE 0x0400
+#define CONNECTOR_LIMIT_RELAY 0x0800
+#define CONNECTOR_LIMIT_CONN 0x1000
+#define CONNECTOR_LIMIT_DOMAIN 0x2000
+#define CONNECTOR_LIMIT 0xff00
+
+#define CONNECTOR_NEW 0x10000
+#define CONNECTOR_WAIT 0x20000
+ int flags;
+
+ int refcount;
+ size_t nconn;
+ time_t lastconn;
+};
+
+struct mta_route {
+ SPLAY_ENTRY(mta_route) entry;
+ uint64_t id;
+ struct mta_source *src;
+ struct mta_host *dst;
+#define ROUTE_NEW 0x01
+#define ROUTE_RUNQ 0x02
+#define ROUTE_KEEPALIVE 0x04
+#define ROUTE_DISABLED 0xf0
+#define ROUTE_DISABLED_NET 0x10
+#define ROUTE_DISABLED_SMTP 0x20
+ int flags;
+ int nerror;
+ int penalty;
+ int refcount;
+ size_t nconn;
+ time_t lastconn;
+ time_t lastdisc;
+ time_t lastpenalty;
+};
+
+struct mta_limits {
+ size_t maxconn_per_host;
+ size_t maxconn_per_route;
+ size_t maxconn_per_source;
+ size_t maxconn_per_connector;
+ size_t maxconn_per_relay;
+ size_t maxconn_per_domain;
+
+ time_t conndelay_host;
+ time_t conndelay_route;
+ time_t conndelay_source;
+ time_t conndelay_connector;
+ time_t conndelay_relay;
+ time_t conndelay_domain;
+
+ time_t discdelay_route;
+
+ size_t max_mail_per_session;
+ time_t sessdelay_transaction;
+ time_t sessdelay_keepalive;
+
+ size_t max_failures_per_session;
+
+ int family;
+
+ int task_hiwat;
+ int task_lowat;
+ int task_release;
+};
+
+struct mta_relay {
+ SPLAY_ENTRY(mta_relay) entry;
+ uint64_t id;
+
+ struct dispatcher *dispatcher;
+ struct mta_domain *domain;
+ struct mta_limits *limits;
+ int tls;
+ int flags;
+ char *backupname;
+ int backuppref;
+ char *sourcetable;
+ uint16_t port;
+ char *pki_name;
+ char *ca_name;
+ char *authtable;
+ char *authlabel;
+ char *helotable;
+ char *heloname;
+ char *secret;
+ int srs;
+
+ int state;
+ size_t ntask;
+ TAILQ_HEAD(, mta_task) tasks;
+
+ struct tree connectors;
+ size_t sourceloop;
+ time_t lastsource;
+ time_t nextsource;
+
+ int fail;
+ char *failstr;
+
+#define RELAY_WAIT_MX 0x01
+#define RELAY_WAIT_PREFERENCE 0x02
+#define RELAY_WAIT_SECRET 0x04
+#define RELAY_WAIT_LIMITS 0x08
+#define RELAY_WAIT_SOURCE 0x10
+#define RELAY_WAIT_CONNECTOR 0x20
+#define RELAY_WAIT_SMARTHOST 0x40
+#define RELAY_WAITMASK 0x7f
+ int status;
+
+ int refcount;
+ size_t nconn;
+ size_t nconn_ready;
+ time_t lastconn;
+};
+
+struct mta_envelope {
+ TAILQ_ENTRY(mta_envelope) entry;
+ uint64_t id;
+ uint64_t session;
+ time_t creation;
+ char *smtpname;
+ char *dest;
+ char *rcpt;
+ struct mta_task *task;
+ int delivery;
+
+ int ext;
+ char *dsn_orcpt;
+ char dsn_envid[DSN_ENVID_LEN+1];
+ uint8_t dsn_notify;
+ enum dsn_ret dsn_ret;
+
+ char status[LINE_MAX];
+};
+
+struct mta_task {
+ TAILQ_ENTRY(mta_task) entry;
+ struct mta_relay *relay;
+ uint32_t msgid;
+ TAILQ_HEAD(, mta_envelope) envelopes;
+ char *sender;
+};
+
+struct passwd;
+
+struct queue_backend {
+ int (*init)(struct passwd *, int, const char *);
+};
+
+struct compress_backend {
+ 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 */
+enum auth_type {
+ AUTH_BSD,
+ AUTH_PWD,
+};
+
+struct auth_backend {
+ int (*authenticate)(char *, char *);
+};
+
+struct scheduler_backend {
+ int (*init)(const char *);
+
+ int (*insert)(struct scheduler_info *);
+ size_t (*commit)(uint32_t);
+ size_t (*rollback)(uint32_t);
+
+ int (*update)(struct scheduler_info *);
+ int (*delete)(uint64_t);
+ int (*hold)(uint64_t, uint64_t);
+ int (*release)(int, uint64_t, int);
+
+ int (*batch)(int, int*, size_t*, uint64_t*, int*);
+
+ size_t (*messages)(uint32_t, uint32_t *, size_t);
+ size_t (*envelopes)(uint64_t, struct evpstate *, size_t);
+ int (*schedule)(uint64_t);
+ int (*remove)(uint64_t);
+ int (*suspend)(uint64_t);
+ int (*resume)(uint64_t);
+ int (*query)(uint64_t);
+};
+
+enum stat_type {
+ STAT_COUNTER,
+ STAT_TIMESTAMP,
+ STAT_TIMEVAL,
+ STAT_TIMESPEC,
+};
+
+struct stat_value {
+ enum stat_type type;
+ union stat_v {
+ size_t counter;
+ time_t timestamp;
+ struct timeval tv;
+ struct timespec ts;
+ } u;
+};
+
+#define STAT_KEY_SIZE 1024
+struct stat_kv {
+ void *iter;
+ char key[STAT_KEY_SIZE];
+ struct stat_value val;
+};
+
+struct stat_backend {
+ void (*init)(void);
+ void (*close)(void);
+ void (*increment)(const char *, size_t);
+ void (*decrement)(const char *, size_t);
+ void (*set)(const char *, const struct stat_value *);
+ int (*iter)(void **, char **, struct stat_value *);
+};
+
+struct stat_digest {
+ time_t startup;
+ time_t timestamp;
+
+ size_t clt_connect;
+ size_t clt_disconnect;
+
+ size_t evp_enqueued;
+ size_t evp_dequeued;
+
+ size_t evp_expired;
+ size_t evp_removed;
+ size_t evp_bounce;
+
+ size_t dlv_ok;
+ size_t dlv_permfail;
+ size_t dlv_tempfail;
+ size_t dlv_loop;
+};
+
+
+struct mproc {
+ pid_t pid;
+ char *name;
+ int proc;
+ void (*handler)(struct mproc *, struct imsg *);
+ struct imsgbuf imsgbuf;
+
+ 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;
+ void *data;
+};
+
+struct msg {
+ const uint8_t *pos;
+ const uint8_t *end;
+};
+
+extern enum smtp_proc_type smtpd_process;
+
+extern int tracing;
+extern int foreground_log;
+extern int profiling;
+
+extern struct mproc *p_control;
+extern struct mproc *p_parent;
+extern struct mproc *p_lka;
+extern struct mproc *p_queue;
+extern struct mproc *p_scheduler;
+extern struct mproc *p_pony;
+extern struct mproc *p_ca;
+
+extern struct smtpd *env;
+extern void (*imsg_callback)(struct mproc *, struct imsg *);
+
+/* inter-process structures */
+
+struct bounce_req_msg {
+ uint64_t evpid;
+ time_t timestamp;
+ struct delivery_bounce bounce;
+};
+
+enum dns_error {
+ DNS_OK = 0,
+ DNS_RETRY,
+ DNS_EINVAL,
+ DNS_ENONAME,
+ DNS_ENOTFOUND,
+};
+
+enum lka_resp_status {
+ LKA_OK,
+ LKA_TEMPFAIL,
+ LKA_PERMFAIL
+};
+
+enum filter_type {
+ FILTER_TYPE_BUILTIN,
+ FILTER_TYPE_PROC,
+ FILTER_TYPE_CHAIN,
+};
+
+enum filter_subsystem {
+ FILTER_SUBSYSTEM_SMTP_IN = 1<<0,
+ FILTER_SUBSYSTEM_SMTP_OUT = 1<<1,
+};
+
+struct filter_proc {
+ const char *command;
+ const char *user;
+ const char *group;
+ const char *chroot;
+ int errfd;
+ enum filter_subsystem filter_subsystem;
+};
+
+struct filter_config {
+ char *name;
+ enum filter_subsystem filter_subsystem;
+ enum filter_type filter_type;
+ enum filter_phase phase;
+ char *reject;
+ char *disconnect;
+ char *rewrite;
+ char *report;
+ uint8_t junk;
+ uint8_t bypass;
+ char *proc;
+
+ const char **chain;
+ size_t chain_size;
+ struct dict chain_procs;
+
+ int8_t not_fcrdns;
+ int8_t fcrdns;
+
+ int8_t not_rdns;
+ int8_t rdns;
+
+ int8_t not_rdns_table;
+ struct table *rdns_table;
+
+ int8_t not_rdns_regex;
+ struct table *rdns_regex;
+
+ int8_t not_src_table;
+ struct table *src_table;
+
+ int8_t not_src_regex;
+ struct table *src_regex;
+
+ int8_t not_helo_table;
+ struct table *helo_table;
+
+ int8_t not_helo_regex;
+ struct table *helo_regex;
+
+ int8_t not_auth;
+ int8_t auth;
+
+ int8_t not_auth_table;
+ struct table *auth_table;
+
+ int8_t not_auth_regex;
+ struct table *auth_regex;
+
+ int8_t not_mail_from_table;
+ struct table *mail_from_table;
+
+ int8_t not_mail_from_regex;
+ struct table *mail_from_regex;
+
+ int8_t not_rcpt_to_table;
+ struct table *rcpt_to_table;
+
+ int8_t not_rcpt_to_regex;
+ struct table *rcpt_to_regex;
+
+};
+
+enum filter_status {
+ FILTER_PROCEED,
+ FILTER_REWRITE,
+ FILTER_REJECT,
+ FILTER_DISCONNECT,
+ FILTER_JUNK,
+};
+
+enum ca_resp_status {
+ CA_OK,
+ CA_FAIL
+};
+
+enum mda_resp_status {
+ MDA_OK,
+ MDA_TEMPFAIL,
+ MDA_PERMFAIL
+};
+
+struct msg_walkinfo {
+ struct event ev;
+ uint32_t msgid;
+ uint32_t peerid;
+ size_t n_evp;
+ void *data;
+ int done;
+};
+
+
+enum dispatcher_type {
+ DISPATCHER_LOCAL,
+ DISPATCHER_REMOTE,
+ DISPATCHER_BOUNCE,
+};
+
+struct dispatcher_local {
+ uint8_t is_mbox; /* only for MBOX */
+
+ uint8_t expand_only;
+ uint8_t forward_only;
+
+ char *mda_wrapper;
+ char *command;
+
+ char *table_alias;
+ char *table_virtual;
+ char *table_userbase;
+
+ char *user;
+};
+
+struct dispatcher_remote {
+ char *helo;
+ char *helo_source;
+
+ char *source;
+
+ char *ca;
+ char *pki;
+
+ char *mail_from;
+
+ char *smarthost;
+ int smarthost_domain;
+
+ char *auth;
+ int tls_required;
+ int tls_noverify;
+
+ int backup;
+ char *backupmx;
+
+ char *filtername;
+
+ int srs;
+};
+
+struct dispatcher_bounce {
+};
+
+struct dispatcher {
+ enum dispatcher_type type;
+ union dispatcher_agent {
+ struct dispatcher_local local;
+ struct dispatcher_remote remote;
+ struct dispatcher_bounce bounce;
+ } u;
+
+ time_t ttl;
+};
+
+struct rule {
+ TAILQ_ENTRY(rule) r_entry;
+
+ uint8_t reject;
+
+ int8_t flag_tag;
+ int8_t flag_from;
+ int8_t flag_for;
+ int8_t flag_from_rdns;
+ int8_t flag_from_socket;
+
+ int8_t flag_tag_regex;
+ int8_t flag_from_regex;
+ int8_t flag_for_regex;
+
+ int8_t flag_smtp_helo;
+ int8_t flag_smtp_starttls;
+ int8_t flag_smtp_auth;
+ int8_t flag_smtp_mail_from;
+ int8_t flag_smtp_rcpt_to;
+
+ int8_t flag_smtp_helo_regex;
+ int8_t flag_smtp_starttls_regex;
+ int8_t flag_smtp_auth_regex;
+ int8_t flag_smtp_mail_from_regex;
+ int8_t flag_smtp_rcpt_to_regex;
+
+
+ char *table_tag;
+ char *table_from;
+ char *table_for;
+
+ char *table_smtp_helo;
+ char *table_smtp_auth;
+ char *table_smtp_mail_from;
+ char *table_smtp_rcpt_to;
+
+ char *dispatcher;
+};
+
+
+/* aliases.c */
+int aliases_get(struct expand *, const char *);
+int aliases_virtual_get(struct expand *, const struct mailaddr *);
+int alias_parse(struct expandnode *, const char *);
+
+
+/* auth.c */
+struct auth_backend *auth_backend_lookup(enum auth_type);
+
+
+/* bounce.c */
+void bounce_add(uint64_t);
+void bounce_fd(int);
+
+
+/* ca.c */
+int ca(void);
+int ca_X509_verify(void *, void *, const char *, const char *, const char **);
+void ca_imsg(struct mproc *, struct imsg *);
+void ca_init(void);
+void ca_engine_init(void);
+
+
+/* cert.c */
+int cert_init(const char *, int,
+ void (*)(void *, int, const char *, const void *, size_t), void *);
+int cert_verify(const void *, const char *, int, void (*)(void *, int), void *);
+void cert_dispatch_request(struct mproc *, struct imsg *);
+void cert_dispatch_result(struct mproc *, struct imsg *);
+
+
+/* compress_backend.c */
+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 */
+#define PURGE_LISTENERS 0x01
+#define PURGE_TABLES 0x02
+#define PURGE_RULES 0x04
+#define PURGE_PKI 0x08
+#define PURGE_PKI_KEYS 0x10
+#define PURGE_DISPATCHERS 0x20
+#define PURGE_EVERYTHING 0xff
+struct smtpd *config_default(void);
+void purge_config(uint8_t);
+void config_process(enum smtp_proc_type);
+void config_peer(enum smtp_proc_type);
+
+
+/* control.c */
+int control(void);
+int control_create_socket(void);
+
+
+/* crypto.c */
+int crypto_setup(const char *, size_t);
+int crypto_encrypt_file(FILE *, FILE *);
+int crypto_decrypt_file(FILE *, FILE *);
+size_t crypto_encrypt_buffer(const char *, size_t, char *, size_t);
+size_t crypto_decrypt_buffer(const char *, size_t, char *, size_t);
+
+
+/* dns.c */
+void dns_imsg(struct mproc *, struct imsg *);
+
+
+/* enqueue.c */
+int enqueue(int, char **, FILE *);
+
+
+/* envelope.c */
+void envelope_set_errormsg(struct envelope *, char *, ...);
+void envelope_set_esc_class(struct envelope *, enum enhanced_status_class);
+void envelope_set_esc_code(struct envelope *, enum enhanced_status_code);
+int envelope_load_buffer(struct envelope *, const char *, size_t);
+int envelope_dump_buffer(const struct envelope *, char *, size_t);
+
+
+/* expand.c */
+int expand_cmp(struct expandnode *, struct expandnode *);
+void expand_insert(struct expand *, struct expandnode *);
+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);
+
+
+/* forward.c */
+int forwards_get(int, struct expand *);
+
+
+/* limit.c */
+void limit_mta_set_defaults(struct mta_limits *);
+int limit_mta_set(struct mta_limits *, const char*, int64_t);
+
+
+/* lka.c */
+int lka(void);
+
+
+/* lka_proc.c */
+int lka_proc_ready(void);
+void lka_proc_forked(const char *, uint32_t, int);
+void lka_proc_errfd(const char *, int);
+struct io *lka_proc_get_io(const char *);
+
+
+/* lka_report.c */
+void lka_report_init(void);
+void lka_report_register_hook(const char *, const char *);
+void lka_report_smtp_link_connect(const char *, struct timeval *, uint64_t, const char *, int,
+ const struct sockaddr_storage *, const struct sockaddr_storage *);
+void lka_report_smtp_link_disconnect(const char *, struct timeval *, uint64_t);
+void lka_report_smtp_link_greeting(const char *, uint64_t, struct timeval *,
+ const char *);
+void lka_report_smtp_link_identify(const char *, struct timeval *, uint64_t, const char *, const char *);
+void lka_report_smtp_link_tls(const char *, struct timeval *, uint64_t, const char *);
+void lka_report_smtp_link_auth(const char *, struct timeval *, uint64_t, const char *, const char *);
+void lka_report_smtp_tx_reset(const char *, struct timeval *, uint64_t, uint32_t);
+void lka_report_smtp_tx_begin(const char *, struct timeval *, uint64_t, uint32_t);
+void lka_report_smtp_tx_mail(const char *, struct timeval *, uint64_t, uint32_t, const char *, int);
+void lka_report_smtp_tx_rcpt(const char *, struct timeval *, uint64_t, uint32_t, const char *, int);
+void lka_report_smtp_tx_envelope(const char *, struct timeval *, uint64_t, uint32_t, uint64_t);
+void lka_report_smtp_tx_commit(const char *, struct timeval *, uint64_t, uint32_t, size_t);
+void lka_report_smtp_tx_data(const char *, struct timeval *, uint64_t, uint32_t, int);
+void lka_report_smtp_tx_rollback(const char *, struct timeval *, uint64_t, uint32_t);
+void lka_report_smtp_protocol_client(const char *, struct timeval *, uint64_t, const char *);
+void lka_report_smtp_protocol_server(const char *, struct timeval *, uint64_t, const char *);
+void lka_report_smtp_filter_response(const char *, struct timeval *, uint64_t,
+ int, int, const char *);
+void lka_report_smtp_timeout(const char *, struct timeval *, uint64_t);
+void lka_report_filter_report(uint64_t, const char *, int, const char *,
+ struct timeval *, const char *);
+void lka_report_proc(const char *, const char *);
+
+
+/* lka_filter.c */
+void lka_filter_init(void);
+void lka_filter_register_hook(const char *, const char *);
+void lka_filter_ready(void);
+int lka_filter_proc_in_session(uint64_t, const char *);
+void lka_filter_begin(uint64_t, const char *);
+void lka_filter_end(uint64_t);
+void lka_filter_protocol(uint64_t, enum filter_phase, const char *);
+void lka_filter_data_begin(uint64_t);
+void lka_filter_data_end(uint64_t);
+int lka_filter_response(uint64_t, const char *, const char *);
+
+
+/* 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);
+void logit(int, const char *, ...) __attribute__((format (printf, 2, 3)));
+
+
+/* mda.c */
+void mda_postfork(void);
+void mda_postprivdrop(void);
+void mda_imsg(struct mproc *, struct imsg *);
+
+
+/* mda_mbox.c */
+void mda_mbox_init(struct deliver *);
+void mda_mbox(struct deliver *);
+
+
+/* mda_unpriv.c */
+void mda_unpriv(struct dispatcher *, struct deliver *, const char *, const char *);
+
+
+/* mda_variables.c */
+ssize_t mda_expand_format(char *, size_t, const struct deliver *,
+ const struct userinfo *, const char *);
+
+
+/* makemap.c */
+int makemap(int, int, char **);
+
+
+/* mailaddr.c */
+int mailaddr_line(struct maddrmap *, const char *);
+void maddrmap_init(struct maddrmap *);
+void maddrmap_insert(struct maddrmap *, struct maddrnode *);
+void maddrmap_free(struct maddrmap *);
+
+
+/* mproc.c */
+int mproc_fork(struct mproc *, const char*, char **);
+void mproc_init(struct mproc *, int);
+void mproc_clear(struct mproc *);
+void mproc_enable(struct mproc *);
+void mproc_disable(struct mproc *);
+void mproc_event_add(struct mproc *);
+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);
+void m_add(struct mproc *, const void *, size_t);
+void m_add_int(struct mproc *, int);
+void m_add_u32(struct mproc *, uint32_t);
+void m_add_size(struct mproc *, size_t);
+void m_add_time(struct mproc *, time_t);
+void m_add_timeval(struct mproc *, struct timeval *tv);
+void m_add_string(struct mproc *, const char *);
+void m_add_data(struct mproc *, const void *, size_t);
+void m_add_evpid(struct mproc *, uint64_t);
+void m_add_msgid(struct mproc *, uint32_t);
+void m_add_id(struct mproc *, uint64_t);
+void m_add_sockaddr(struct mproc *, const struct sockaddr *);
+void m_add_mailaddr(struct mproc *, const struct mailaddr *);
+void m_add_envelope(struct mproc *, const struct envelope *);
+void m_add_params(struct mproc *, struct dict *);
+void m_close(struct mproc *);
+void m_flush(struct mproc *);
+
+void m_msg(struct msg *, struct imsg *);
+int m_is_eom(struct msg *);
+void m_end(struct msg *);
+void m_get_int(struct msg *, int *);
+void m_get_size(struct msg *, size_t *);
+void m_get_u32(struct msg *, uint32_t *);
+void m_get_time(struct msg *, time_t *);
+void m_get_timeval(struct msg *, struct timeval *);
+void m_get_string(struct msg *, const char **);
+void m_get_data(struct msg *, const void **, size_t *);
+void m_get_evpid(struct msg *, uint64_t *);
+void m_get_msgid(struct msg *, uint32_t *);
+void m_get_id(struct msg *, uint64_t *);
+void m_get_sockaddr(struct msg *, struct sockaddr *);
+void m_get_mailaddr(struct msg *, struct mailaddr *);
+void m_get_envelope(struct msg *, struct envelope *);
+void m_get_params(struct msg *, struct dict *);
+void m_clear_params(struct dict *);
+
+
+/* mta.c */
+void mta_postfork(void);
+void mta_postprivdrop(void);
+void mta_imsg(struct mproc *, struct imsg *);
+void mta_route_ok(struct mta_relay *, struct mta_route *);
+void mta_route_error(struct mta_relay *, struct mta_route *);
+void mta_route_down(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_log(struct mta_envelope *, const char *, const char *, int, const char *);
+void mta_delivery_notify(struct mta_envelope *);
+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 *);
+
+
+/* mta_session.c */
+void mta_session(struct mta_relay *, struct mta_route *, const char *);
+void mta_session_imsg(struct mproc *, struct imsg *);
+
+
+/* parse.y */
+int parse_config(struct smtpd *, const char *, int);
+int cmdline_symset(char *);
+
+
+/* queue.c */
+int queue(void);
+
+
+/* queue_backend.c */
+uint32_t queue_generate_msgid(void);
+uint64_t queue_generate_evpid(uint32_t);
+int queue_init(const char *, int);
+int queue_close(void);
+int queue_message_create(uint32_t *);
+int queue_message_delete(uint32_t);
+int queue_message_commit(uint32_t);
+int queue_message_fd_r(uint32_t);
+int queue_message_fd_rw(uint32_t);
+int queue_envelope_create(struct envelope *);
+int queue_envelope_delete(uint64_t);
+int queue_envelope_load(uint64_t, struct envelope *);
+int queue_envelope_update(struct envelope *);
+int queue_envelope_walk(struct envelope *);
+int queue_message_walk(struct envelope *, uint32_t, int *, void **);
+
+
+/* report_smtp.c */
+void report_smtp_link_connect(const char *, uint64_t, const char *, int,
+ const struct sockaddr_storage *, const struct sockaddr_storage *);
+void report_smtp_link_disconnect(const char *, uint64_t);
+void report_smtp_link_greeting(const char *, uint64_t, const char *);
+void report_smtp_link_identify(const char *, uint64_t, const char *, const char *);
+void report_smtp_link_tls(const char *, uint64_t, const char *);
+void report_smtp_link_auth(const char *, uint64_t, const char *, const char *);
+void report_smtp_tx_reset(const char *, uint64_t, uint32_t);
+void report_smtp_tx_begin(const char *, uint64_t, uint32_t);
+void report_smtp_tx_mail(const char *, uint64_t, uint32_t, const char *, int);
+void report_smtp_tx_rcpt(const char *, uint64_t, uint32_t, const char *, int);
+void report_smtp_tx_envelope(const char *, uint64_t, uint32_t, uint64_t);
+void report_smtp_tx_data(const char *, uint64_t, uint32_t, int);
+void report_smtp_tx_commit(const char *, uint64_t, uint32_t, size_t);
+void report_smtp_tx_rollback(const char *, uint64_t, uint32_t);
+void report_smtp_protocol_client(const char *, uint64_t, const char *);
+void report_smtp_protocol_server(const char *, uint64_t, const char *);
+void report_smtp_filter_response(const char *, uint64_t, int, int, const char *);
+void report_smtp_timeout(const char *, uint64_t);
+
+
+/* ruleset.c */
+struct rule *ruleset_match(const struct envelope *);
+
+
+/* scheduler.c */
+int scheduler(void);
+
+
+/* scheduler_bakend.c */
+struct scheduler_backend *scheduler_backend_lookup(const char *);
+void scheduler_info(struct scheduler_info *, struct envelope *);
+
+
+/* pony.c */
+int pony(void);
+void pony_imsg(struct mproc *, struct imsg *);
+
+
+/* resolver.c */
+void resolver_getaddrinfo(const char *, const char *, const struct addrinfo *,
+ void(*)(void *, int, struct addrinfo*), void *);
+void resolver_getnameinfo(const struct sockaddr *, int,
+ void(*)(void *, int, const char *, const char *), void *);
+void resolver_res_query(const char *, int, int,
+ void (*cb)(void *, int, int, int, const void *, int), void *);
+void resolver_dispatch_request(struct mproc *, struct imsg *);
+void resolver_dispatch_result(struct mproc *, struct imsg *);
+
+
+/* smtp.c */
+void smtp_postfork(void);
+void smtp_postprivdrop(void);
+void smtp_imsg(struct mproc *, struct imsg *);
+void smtp_configure(void);
+void smtp_collect(void);
+
+
+/* smtp_session.c */
+int smtp_session(struct listener *, int, const struct sockaddr_storage *,
+ const char *, struct io *);
+void smtp_session_imsg(struct mproc *, struct imsg *);
+
+
+/* smtpf_session.c */
+int smtpf_session(struct listener *, int, const struct sockaddr_storage *,
+ const char *);
+void smtpf_session_imsg(struct mproc *, struct imsg *);
+
+
+/* smtpd.c */
+void imsg_dispatch(struct mproc *, struct imsg *);
+const char *proc_name(enum smtp_proc_type);
+const char *proc_title(enum smtp_proc_type);
+const char *imsg_to_str(int);
+void log_imsg(int, int, struct imsg *);
+int fork_proc_backend(const char *, const char *, const char *);
+
+
+/* srs.c */
+const char *srs_encode(const char *, const char *);
+const char *srs_decode(const char *);
+
+
+/* ssl_smtpd.c */
+void *ssl_mta_init(void *, char *, off_t, const char *);
+void *ssl_smtp_init(void *, int);
+
+
+/* stat_backend.c */
+struct stat_backend *stat_backend_lookup(const char *);
+void stat_increment(const char *, size_t);
+void stat_decrement(const char *, size_t);
+void stat_set(const char *, const struct stat_value *);
+struct stat_value *stat_counter(size_t);
+struct stat_value *stat_timestamp(time_t);
+struct stat_value *stat_timeval(struct timeval *);
+struct stat_value *stat_timespec(struct timespec *);
+
+
+/* table.c */
+struct table *table_find(struct smtpd *, const char *);
+struct table *table_create(struct smtpd *, const char *, const char *,
+ const char *);
+int table_config(struct table *);
+int table_open(struct table *);
+int table_update(struct table *);
+void table_close(struct table *);
+void table_dump(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_match(struct table *, enum table_service, const char *);
+int table_lookup(struct table *, enum table_service, const char *,
+ union lookup *);
+int table_fetch(struct table *, enum table_service, union lookup *);
+void table_destroy(struct smtpd *, struct table *);
+void table_add(struct table *, const char *, const char *);
+int table_domain_match(const char *, const char *);
+int table_netaddr_match(const char *, const char *);
+int table_mailaddr_match(const char *, const char *);
+int table_regex_match(const char *, const char *);
+void table_open_all(struct smtpd *);
+void table_dump_all(struct smtpd *);
+void table_close_all(struct smtpd *);
+
+
+/* to.c */
+int email_to_mailaddr(struct mailaddr *, char *);
+int text_to_netaddr(struct netaddr *, const char *);
+int text_to_mailaddr(struct mailaddr *, const char *);
+int text_to_relayhost(struct relayhost *, const char *);
+int text_to_userinfo(struct userinfo *, const char *);
+int text_to_credentials(struct credentials *, const char *);
+int text_to_expandnode(struct expandnode *, const char *);
+uint64_t text_to_evpid(const char *);
+uint32_t text_to_msgid(const char *);
+const char *sa_to_text(const struct sockaddr *);
+const char *ss_to_text(const struct sockaddr_storage *);
+const char *time_to_text(time_t);
+const char *duration_to_text(time_t);
+const char *rule_to_text(struct rule *);
+const char *sockaddr_to_text(struct sockaddr *);
+const char *mailaddr_to_text(const struct mailaddr *);
+const char *expandnode_to_text(struct expandnode *);
+
+
+/* util.c */
+typedef struct arglist arglist;
+struct arglist {
+ char **list;
+ uint num;
+ uint nalloc;
+};
+void addargs(arglist *, char *, ...)
+ __attribute__((format(printf, 2, 3)));
+int bsnprintf(char *, size_t, const char *, ...)
+ __attribute__((format (printf, 3, 4)));
+int safe_fclose(FILE *);
+int hostname_match(const char *, const char *);
+int mailaddr_match(const struct mailaddr *, const struct mailaddr *);
+int valid_localpart(const char *);
+int valid_domainpart(const char *);
+int valid_domainname(const char *);
+int valid_smtp_response(const char *);
+int secure_file(int, char *, char *, uid_t, int);
+int lowercase(char *, const char *, size_t);
+void xlowercase(char *, const char *, size_t);
+int uppercase(char *, const char *, size_t);
+uint64_t generate_uid(void);
+int availdesc(void);
+int ckdir(const char *, mode_t, uid_t, gid_t, int);
+int rmtree(char *, int);
+int mvpurge(char *, char *);
+int mktmpfile(void);
+const char *parse_smtp_response(char *, size_t, char **, int *);
+int xasprintf(char **, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void *xmalloc(size_t);
+void *xcalloc(size_t, size_t);
+char *xstrdup(const char *);
+void *xmemdup(const void *, size_t);
+char *strip(char *);
+int io_xprint(struct io *, const char *);
+int io_xprintf(struct io *, const char *, ...)
+ __attribute__((__format__ (printf, 2, 3)));
+void log_envelope(const struct envelope *, const char *, const char *,
+ const char *);
+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);
+int base64_encode_rfc3548(unsigned char const *, size_t,
+ char *, size_t);
+void xclosefrom(int);
+
+void log_trace_verbose(int);
+void log_trace(int, const char *, ...)
+ __attribute__((format (printf, 2, 3)));
+
+/* waitq.c */
+int waitq_wait(void *, void (*)(void *, void *, void *), void *);
+void waitq_run(void *, void *);
+
+
+/* runq.c */
+struct runq;
+
+int runq_init(struct runq **, void (*)(struct runq *, void *));
+int runq_schedule(struct runq *, time_t, void *);
+int runq_schedule_at(struct runq *, time_t, void *);
+int runq_cancel(struct runq *, void *);
+int runq_pending(struct runq *, void *, time_t *);