/*++
/* NAME
/*	smtpd 3h
/* SUMMARY
/*	smtp server
/* SYNOPSIS
/*	include "smtpd.h"
/* DESCRIPTION
/* .nf

 /*
  * System library.
  */
#include <sys/time.h>
#include <unistd.h>

 /*
  * Utility library.
  */
#include <vstream.h>
#include <vstring.h>
#include <argv.h>
#include <myaddrinfo.h>

 /*
  * Global library.
  */
#include <mail_stream.h>

 /*
  * Postfix TLS library.
  */
#include <tls.h>

 /*
  * Milter library.
  */
#include <milter.h>

 /*
  * Variables that keep track of conversation state. There is only one SMTP
  * conversation at a time, so the state variables can be made global. And
  * some of this has to be global anyway, so that the run-time error handler
  * can clean up in case of a fatal error deep down in some library routine.
  */
typedef struct SMTPD_DEFER {
    int     active;			/* is this active */
    VSTRING *reason;			/* reason for deferral */
    VSTRING *dsn;			/* DSN detail */
    int     code;			/* SMTP reply code */
    int     class;			/* error notification class */
} SMTPD_DEFER;

typedef struct {
    int     flags;			/* XFORWARD server state */
    char   *name;			/* name for access control */
    char   *addr;			/* address for access control */
    char   *port;			/* port for logging */
    char   *namaddr;			/* name[address]:port */
    char   *rfc_addr;			/* address for RFC 2821 */
    char   *protocol;			/* email protocol */
    char   *helo_name;			/* helo/ehlo parameter */
    char   *ident;			/* local message identifier */
    char   *domain;			/* rewrite context */
} SMTPD_XFORWARD_ATTR;

typedef struct {
    int     flags;			/* see below */
    int     err;			/* cleanup server/queue file errors */
    VSTREAM *client;			/* SMTP client handle */
    VSTRING *buffer;			/* SMTP client buffer */
    VSTRING *addr_buf;			/* internalized address buffer */
    char   *service;			/* for event rate control */
    struct timeval arrival_time;	/* start of MAIL FROM transaction */
    char   *name;			/* verified client hostname */
    char   *reverse_name;		/* unverified client hostname */
    char   *addr;			/* client host address string */
    char   *port;			/* port for logging */
    char   *namaddr;			/* name[address]:port */
    char   *anvil_range;		/* client address or network/length */
    char   *rfc_addr;			/* address for RFC 2821 */
    int     addr_family;		/* address family */
    char   *dest_addr;			/* Dovecot AUTH, Milter {daemon_addr} */
    char   *dest_port;			/* Milter {daemon_port} */
    struct sockaddr_storage sockaddr;	/* binary client endpoint */
    SOCKADDR_SIZE sockaddr_len;		/* binary client endpoint */
    struct sockaddr_storage dest_sockaddr;	/* binary local endpoint */
    SOCKADDR_SIZE dest_sockaddr_len;	/* binary local endpoint */
    int     name_status;		/* 2=ok 4=soft 5=hard 6=forged */
    int     reverse_name_status;	/* 2=ok 4=soft 5=hard */
    int     conn_count;			/* connections from this client */
    int     conn_rate;			/* connection rate for this client */
    int     error_count;		/* reset after DOT */
    int     error_mask;			/* client errors */
    int     notify_mask;		/* what to report to postmaster */
    char   *helo_name;			/* client HELO/EHLO argument */
    char   *queue_id;			/* from cleanup server/queue file */
    VSTREAM *cleanup;			/* cleanup server/queue file handle */
    MAIL_STREAM *dest;			/* another server/file handle */
    int     rcpt_count;			/* number of accepted recipients */
    char   *access_denied;		/* fixme */
    ARGV   *history;			/* protocol transcript */
    char   *reason;			/* cause of connection loss */
    char   *sender;			/* sender address */
    char   *encoding;			/* owned by mail_cmd() */
    char   *verp_delims;		/* owned by mail_cmd() */
    char   *recipient;			/* recipient address */
    char   *etrn_name;			/* client ETRN argument */
    char   *protocol;			/* SMTP or ESMTP */
    char   *where;			/* protocol stage */
    int     recursion;			/* Kellerspeicherpegelanzeiger */
    off_t   msg_size;			/* MAIL FROM message size */
    off_t   act_size;			/* END-OF-DATA message size */
    int     junk_cmds;			/* counter */
    int     rcpt_overshoot;		/* counter */
    char   *rewrite_context;		/* address rewriting context */
    int     notes;			/* notes aggregator */

    /*
     * SASL specific.
     */
#ifdef USE_SASL_AUTH
    struct XSASL_SERVER *sasl_server;
    VSTRING *sasl_reply;
    char   *sasl_mechanism_list;
    char   *sasl_method;
    char   *sasl_username;
    char   *sasl_sender;
#endif

    /*
     * Specific to smtpd access checks.
     */
    int     sender_rcptmap_checked;	/* sender validated against maps */
    int     recipient_rcptmap_checked;	/* recipient validated against maps */
    int     warn_if_reject;		/* force reject into warning */
    SMTPD_DEFER defer_if_reject;	/* force reject into deferral */
    SMTPD_DEFER defer_if_permit;	/* force permit into deferral */
    int     defer_if_permit_client;	/* force permit into warning */
    int     defer_if_permit_helo;	/* force permit into warning */
    int     defer_if_permit_sender;	/* force permit into warning */
    int     discard;			/* discard message */
    char   *saved_filter;		/* postponed filter action */
    char   *saved_redirect;		/* postponed redirect action */
    ARGV   *saved_bcc;			/* postponed bcc action */
    int     saved_flags;		/* postponed hold/discard */
#ifdef DELAY_ACTION
    int     saved_delay;		/* postponed deferred delay */
#endif
    VSTRING *expand_buf;		/* scratch space for $name expansion */
    ARGV   *prepend;			/* prepended headers */
    VSTRING *instance;			/* policy query correlation */
    int     seqno;			/* policy query correlation */
    int     ehlo_discard_mask;		/* suppressed EHLO features */
    char   *dsn_envid;			/* temporary MAIL FROM state */
    int     dsn_ret;			/* temporary MAIL FROM state */
    VSTRING *dsn_buf;			/* scratch space for xtext expansion */
    VSTRING *dsn_orcpt_buf;		/* scratch space for ORCPT parsing */

    /*
     * Pass-through proxy client.
     */
    struct SMTPD_PROXY *proxy;
    char   *proxy_mail;			/* owned by mail_cmd() */

    /*
     * XFORWARD server state.
     */
    SMTPD_XFORWARD_ATTR xforward;	/* up-stream logging info */

    /*
     * TLS related state.
     */
#ifdef USE_TLS
#ifdef USE_TLSPROXY
    VSTREAM *tlsproxy;			/* tlsproxy(8) temp. handle */
#endif
    TLS_SESS_STATE *tls_context;	/* TLS session state */
#endif

    /*
     * Milter support.
     */
    const char **milter_argv;		/* SMTP command vector */
    ssize_t milter_argc;		/* SMTP command vector */
    const char *milter_reject_text;	/* input to call-back from Milter */
    MILTERS *milters;			/* Milter initialization status. */

    /*
     * EHLO temporary space.
     */
    VSTRING *ehlo_buf;
    ARGV   *ehlo_argv;

    /*
     * BDAT processing state.
     */
#define SMTPD_BDAT_STAT_NONE	0	/* not processing BDAT */
#define SMTPD_BDAT_STAT_OK	1	/* accepting BDAT chunks */
#define SMTPD_BDAT_STAT_ERROR	2	/* skipping BDAT chunks */
    int     bdat_state;			/* see above */
    VSTREAM *bdat_get_stream;		/* memory stream from BDAT chunk */
    VSTRING *bdat_get_buffer;		/* read from memory stream */
    int     bdat_prev_rec_type;
} SMTPD_STATE;

#define SMTPD_FLAG_HANGUP	   (1<<0)	/* 421/521 disconnect */
#define SMTPD_FLAG_ILL_PIPELINING  (1<<1)	/* inappropriate pipelining */
#define SMTPD_FLAG_AUTH_USED	   (1<<2)	/* don't reuse SASL state */
#define SMTPD_FLAG_SMTPUTF8	   (1<<3)	/* RFC 6531/2 transaction */
#define SMTPD_FLAG_NEED_MILTER_ABORT (1<<4)	/* undo milter_mail_event() */
#define SMTPD_FLAG_REQTLS	   (1<<5)	/* RFC 8689 */

#define SMTPD_NOTE_BARE_LF	   (1<<0)	/* saw at least one bare LF */

/* Flags that apply to only one MAIL transaction. */
#define SMTPD_FLAGS_PER_MESSAGE	(SMTPD_FLAG_SMTPUTF8 | SMTPD_FLAG_REQTLS)

 /* Security: don't reset SMTPD_FLAG_AUTH_USED. */
#define SMTPD_MASK_MAIL_KEEP \
	    ~(SMTPD_FLAG_SMTPUTF8)	/* Fix 20140706 */

#define SMTPD_STATE_XFORWARD_INIT  (1<<0)	/* xforward preset done */
#define SMTPD_STATE_XFORWARD_NAME  (1<<1)	/* client name received */
#define SMTPD_STATE_XFORWARD_ADDR  (1<<2)	/* client address received */
#define SMTPD_STATE_XFORWARD_PROTO (1<<3)	/* protocol received */
#define SMTPD_STATE_XFORWARD_HELO  (1<<4)	/* client helo received */
#define SMTPD_STATE_XFORWARD_IDENT (1<<5)	/* message identifier */
#define SMTPD_STATE_XFORWARD_DOMAIN (1<<6)	/* address context */
#define SMTPD_STATE_XFORWARD_PORT  (1<<7)	/* client port received */

#define SMTPD_STATE_XFORWARD_CLIENT_MASK \
	(SMTPD_STATE_XFORWARD_NAME | SMTPD_STATE_XFORWARD_ADDR \
	| SMTPD_STATE_XFORWARD_PROTO | SMTPD_STATE_XFORWARD_HELO \
	| SMTPD_STATE_XFORWARD_PORT)

extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *, const char *);
extern void smtpd_state_reset(SMTPD_STATE *);

 /*
  * Conversation stages.  This is used for "lost connection after XXX"
  * diagnostics.
  */
#define SMTPD_AFTER_CONNECT	"CONNECT"
#define SMTPD_AFTER_DATA	"DATA content"
#define SMTPD_AFTER_BDAT	"BDAT content"
#define SMTPD_AFTER_EOM		"END-OF-MESSAGE"

 /*
  * Other stages. These are sometimes used to change the way information is
  * logged or what information will be available for access control.
  */
#define SMTPD_CMD_HELO		"HELO"
#define SMTPD_CMD_EHLO		"EHLO"
#define SMTPD_CMD_STARTTLS	"STARTTLS"
#define SMTPD_CMD_AUTH		"AUTH"
#define SMTPD_CMD_MAIL		"MAIL"
#define SMTPD_CMD_RCPT		"RCPT"
#define SMTPD_CMD_DATA		"DATA"
#define SMTPD_CMD_BDAT		"BDAT"
#define SMTPD_CMD_EOD		SMTPD_AFTER_EOM	/* XXX Was: END-OF-DATA */
#define SMTPD_CMD_RSET		"RSET"
#define SMTPD_CMD_NOOP		"NOOP"
#define SMTPD_CMD_VRFY		"VRFY"
#define SMTPD_CMD_ETRN		"ETRN"
#define SMTPD_CMD_QUIT		"QUIT"
#define SMTPD_CMD_XCLIENT	"XCLIENT"
#define SMTPD_CMD_XFORWARD	"XFORWARD"
#define SMTPD_CMD_UNKNOWN	"UNKNOWN"
#define SMTPD_CMD_HELP		"HELP"

 /*
  * Representation of unknown and non-existent client information. Throughout
  * Postfix, we use the "unknown" string value for unknown client information
  * (e.g., unknown remote client hostname), and we use the empty string, null
  * pointer or "no queue file record" for non-existent client information
  * (e.g., no HELO command, or local submission).
  * 
  * Inside the SMTP server, unknown real client attributes are represented by
  * the string "unknown", and non-existent HELO is represented as a null
  * pointer. The SMTP server uses this same representation internally for
  * forwarded client attributes; the XFORWARD syntax makes no distinction
  * between unknown (remote submission) and non-existent (local submission).
  * 
  * The SMTP client sends forwarded client attributes only when upstream client
  * attributes exist (i.e. remote submission). Thus, local submissions will
  * appear to come from an SMTP-based content filter, which is acceptable.
  * 
  * Known/unknown client attribute values use the SMTP server's internal
  * representation in queue files, in queue manager delivery requests, and in
  * delivery agent $name expansions.
  * 
  * Non-existent attribute values are never present in queue files. Non-existent
  * information is represented as empty strings in queue manager delivery
  * requests and in delivery agent $name expansions.
  */
#define CLIENT_ATTR_UNKNOWN	"unknown"

#define CLIENT_NAME_UNKNOWN	CLIENT_ATTR_UNKNOWN
#define CLIENT_ADDR_UNKNOWN	CLIENT_ATTR_UNKNOWN
#define CLIENT_PORT_UNKNOWN	CLIENT_ATTR_UNKNOWN
#define CLIENT_NAMADDR_UNKNOWN	CLIENT_ATTR_UNKNOWN
#define CLIENT_HELO_UNKNOWN	0
#define CLIENT_PROTO_UNKNOWN	CLIENT_ATTR_UNKNOWN
#define CLIENT_IDENT_UNKNOWN	0
#define CLIENT_DOMAIN_UNKNOWN	0
#define CLIENT_LOGIN_UNKNOWN	0

#define SERVER_ATTR_UNKNOWN	"unknown"

#define SERVER_ADDR_UNKNOWN	SERVER_ATTR_UNKNOWN
#define SERVER_PORT_UNKNOWN	SERVER_ATTR_UNKNOWN

#define IS_AVAIL_CLIENT_ATTR(v)	((v) && strcmp((v), CLIENT_ATTR_UNKNOWN))

#define IS_AVAIL_CLIENT_NAME(v)	IS_AVAIL_CLIENT_ATTR(v)
#define IS_AVAIL_CLIENT_ADDR(v)	IS_AVAIL_CLIENT_ATTR(v)
#define IS_AVAIL_CLIENT_PORT(v)	IS_AVAIL_CLIENT_ATTR(v)
#define IS_AVAIL_CLIENT_NAMADDR(v) IS_AVAIL_CLIENT_ATTR(v)
#define IS_AVAIL_CLIENT_HELO(v)	((v) != 0)
#define IS_AVAIL_CLIENT_PROTO(v) IS_AVAIL_CLIENT_ATTR(v)
#define IS_AVAIL_CLIENT_IDENT(v) ((v) != 0)
#define IS_AVAIL_CLIENT_DOMAIN(v) ((v) != 0)

 /*
  * If running in stand-alone mode, do not try to talk to Postfix daemons but
  * write to queue file instead.
  */
#define SMTPD_STAND_ALONE_STREAM(stream) \
	(stream == VSTREAM_IN && getuid() != var_owner_uid)

#define SMTPD_STAND_ALONE(state) \
	(state->client == VSTREAM_IN && getuid() != var_owner_uid)

 /*
  * If running as proxy front-end, disable actions that require communication
  * with the cleanup server.
  */
#define USE_SMTPD_PROXY(state) \
	(SMTPD_STAND_ALONE(state) == 0 && *var_smtpd_proxy_filt)

 /*
  * Are we in a MAIL transaction?
  */
#define SMTPD_IN_MAIL_TRANSACTION(state) ((state)->sender != 0)

 /*
  * Are we processing BDAT requests?
  */
#define SMTPD_PROCESSING_BDAT(state) \
	((state)->bdat_state != SMTPD_BDAT_STAT_NONE)

 /*
  * SMTPD peer information lookup.
  */
extern void smtpd_peer_init(SMTPD_STATE *state);
extern void smtpd_peer_reset(SMTPD_STATE *state);
extern void smtpd_peer_from_default(SMTPD_STATE *);
extern int smtpd_peer_from_haproxy(SMTPD_STATE *);

#define	SMTPD_PEER_CODE_OK	2
#define SMTPD_PEER_CODE_TEMP	4
#define SMTPD_PEER_CODE_PERM	5
#define SMTPD_PEER_CODE_FORGED	6

 /*
  * Construct name[addr] or name[addr]:port as appropriate
  */
#define SMTPD_BUILD_NAMADDRPORT(name, addr, port) \
	concatenate((name), "[", (addr), "]", \
		    var_smtpd_client_port_log ? ":" : (char *) 0, \
		    (port), (char *) 0)

 /*
  * Don't mix information from the current SMTP session with forwarded
  * information from an up-stream session.
  */
#define HAVE_FORWARDED_CLIENT_ATTR(s) \
	((s)->xforward.flags & SMTPD_STATE_XFORWARD_CLIENT_MASK)

#define FORWARD_CLIENT_ATTR(s, a) \
	(HAVE_FORWARDED_CLIENT_ATTR(s) ? \
	    (s)->xforward.a : (s)->a)

#define FORWARD_ADDR(s)		FORWARD_CLIENT_ATTR((s), rfc_addr)
#define FORWARD_NAME(s)		FORWARD_CLIENT_ATTR((s), name)
#define FORWARD_NAMADDR(s)	FORWARD_CLIENT_ATTR((s), namaddr)
#define FORWARD_PROTO(s)	FORWARD_CLIENT_ATTR((s), protocol)
#define FORWARD_HELO(s)		FORWARD_CLIENT_ATTR((s), helo_name)
#define FORWARD_PORT(s)		FORWARD_CLIENT_ATTR((s), port)

 /*
  * Mixing is not a problem with forwarded local message identifiers.
  */
#define HAVE_FORWARDED_IDENT(s) \
	((s)->xforward.ident != 0)

#define FORWARD_IDENT(s) \
	(HAVE_FORWARDED_IDENT(s) ? \
	    (s)->xforward.ident : (s)->queue_id)

 /*
  * Mixing is not a problem with forwarded address rewriting contexts.
  */
#define FORWARD_DOMAIN(s) \
	(((s)->xforward.flags & SMTPD_STATE_XFORWARD_DOMAIN) ? \
	    (s)->xforward.domain : (s)->rewrite_context)

extern void smtpd_xforward_init(SMTPD_STATE *);
extern void smtpd_xforward_preset(SMTPD_STATE *);
extern void smtpd_xforward_reset(SMTPD_STATE *);

 /*
  * Transparency: before mail is queued, do we check for unknown recipients,
  * do we allow address mapping, automatic bcc, header/body checks?
  */
extern int smtpd_input_transp_mask;

 /*
  * More Milter support.
  */
extern MILTERS *smtpd_milters;

 /*
  * Message size multiplication factor for free space check.
  */
extern double smtpd_space_multf;

 /*
  * header_from_format support.
  */
extern int smtpd_hfrom_format;

/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*
/*	TLS support originally by:
/*	Lutz Jaenicke
/*	BTU Cottbus
/*	Allgemeine Elektrotechnik
/*	Universitaetsplatz 3-4
/*	D-03044 Cottbus, Germany
/*--*/
