/* $OpenBSD: smtpd.h,v 1.632 2019/08/23 07:09:52 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade * Copyright (c) 2008 Pierre-Yves Ritschard * Copyright (c) 2012 Eric Faurot * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif #include #include #include #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) #define CONF_FILE "/etc/mail/smtpd.conf" #define MAILNAME_FILE "/etc/mail/mailname" #define CA_FILE "/etc/ssl/cert.pem" #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) #define SMTPD_SOCKET "/var/run/smtpd.sock" #define SMTPD_NAME "OpenSMTPD" #define SMTPD_VERSION "6.6.0" #define SMTPD_SESSION_TIMEOUT 300 #define SMTPD_BACKLOG 5 #define PATH_SMTPCTL "/usr/sbin/smtpctl" #define PATH_OFFLINE "/offline" #define PATH_PURGE "/purge" #define PATH_TEMPORARY "/temporary" #define PATH_LIBEXEC "/usr/local/libexec/smtpd" /* * 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_NEWALIASES 0 #define P_MAKEMAP 1 #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_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 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_processors_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; }; #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; 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 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 }; struct processor { const char *command; const char *user; const char *group; const char *chroot; int errfd; }; enum filter_type { FILTER_TYPE_BUILTIN, FILTER_TYPE_PROC, FILTER_TYPE_CHAIN, }; struct filter_config { char *name; enum filter_type filter_type; enum filter_phase phase; char *reject; char *disconnect; char *rewrite; 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_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, }; 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 requires_root; /* 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; char *auth; int tls_required; int tls_noverify; int backup; char *backupmx; }; 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 *, 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_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); /* 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 *, const struct sockaddr_storage *, const struct sockaddr_storage *, const char *, int); 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_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 *); 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_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 *); /* 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 mkdirs(char *, mode_t); 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 *, ...); 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 *, ...); 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); 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 *);