/*
* Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
* $Id: smtps.h,v 1.189 2007/11/02 04:54:58 ca Exp $
*/
#ifndef SMTPS_H
#define SMTPS_H 1
#include "sm/generic.h"
#include "sm/rpool.h"
#include "sm/time.h"
#include "sm/io.h"
#include "sm/rfc2821.h"
#include "sm/regex.h"
#include "sm/mta.h"
#include "sm/cstr.h"
#include "sm/rcb.h"
#include "sm/net.h"
#include "sm/log.h"
#include "sm/cdb.h"
#include "sm/hdrmod.h"
#include "statethreads/st.h"
#include "sm/tls.h"
#include "sm/sasl.h"
#include "sm/sm-conf.h"
#include "sm/ssdef.h"
#include "sm/sscnf.h"
#if MTA_USE_PMILTER
# include "sm/pmilter.h"
# include "sm/pmfdef.h"
#endif
#include "smtps-str.h"
#ifndef MTA_USE_RSAD
# define MTA_USE_RSAD 2
#endif
#ifndef SS_STATS
# define SS_STATS 0
#endif
#ifndef SSSE_S2Q_IDX
# define SSSE_S2Q_IDX 1
#endif
#ifndef SS_CHECK_LINE_LEN
# define SS_CHECK_LINE_LEN 0
#endif
#ifndef SS_CTX_CHECK
# define SS_CTX_CHECK 1
#endif
#ifndef SS_SESS_CHECK
# define SS_SESS_CHECK 1
#endif
#include "sm/sscnfdef.h"
#ifndef SS_TA_CHECK
/*
** Currently not useful because it's neither allocated nor freed, it's only
** cleaned out and it's a local variable in ss_hdl_session().
*/
# define SS_TA_CHECK 0
#endif /* SS_TA_CHECK */
#if SS_TEST
/*
** Values to trigger errors in certain places to test error handling.
** Currently these are used as bitflags which allows for combining them.
** Alternatively numbers might be used if there are many tests that don't
** need to be combined.
*/
# define SS_TEST_S2A_FAIL 0x00000001 /* cause a s2q comm. failure */
#endif
#define SS_R_OK "250 2.0.0 Ok.\r\n"
#define SS_R_CONT "354 Go.\r\n"
#define SS_R_REJ "550 5.7.0 Rejected.\r\n"
#define SS_R_EHLO_REQ "503 5.0.0 Need EHLO first\r\n"
#define SS_R_SEQ "503 5.5.1 Bad sequence of commands.\r\n"
#define SS_R_SYN_PAR "501 5.5.2 Syntax error in parameters or arguments.\r\n"
#define SS_R_SYN_S_A "501 5.1.7 Bad sender's mailbox address syntax.\r\n"
#define SS_R_SYN_R_A "501 5.1.3 Bad destination mailbox address syntax.\r\n"
#define SS_R_SYN_ARG "501 5.5.2 Syntax error in argument(s).\r\n"
#define SS_R_SYNE "501 5.5.2 Syntax error.\r\n"
#define SS_R_NOTNOW "503 5.5.0 Not now\r\n"
#define SS_R_TMP "451 4.5.0 Temporary error.\r\n"
#define SS_R_SSD "421 4.3.0 Too busy.\r\n"
#define SS_R_GREY "421 4.7.0 Come back later.\r\n"
/* access check result structure, see sm/smar.h */
struct ss_acc_S
{
sm_ret_T ssa_map_result; /* result of map lookup: SM_ACC_x */
/* the next values are only valid if the map result is SM_ACC_FOUND */
sm_ret_T ssa_reply_code; /* sm/mta.h: */
sm_str_P ssa_reply_text; /* NULL by default */
};
typedef struct ss_acc_S ss_acc_T, *ss_acc_P;
struct ss_ctx_S
{
#if SS_CTX_CHECK
sm_magic_T sm_magic;
#endif
ss_cnf_T ssc_cnf;
int ssc_id; /* smtps id */
sm_str_P ssc_hostname; /* hostname of server */
regex_t ssc_relayfrom;
regex_t ssc_relayto;
uint32_t ssc_flags;
sm_log_ctx_P ssc_lctx;
sm_logconfig_P ssc_lcfg;
cdb_ctx_P ssc_cdb_ctx;
st_utime_t ssc_mod_tmo; /* ss_cnf_mod_tmo as micro seconds */
/* ctx for SMTPS/QMGR communication subsystem */
s2q_ctx_P ssc_s2q_ctx;
/* ctx for SMTPS/SMAR communication subsystem */
s2q_ctx_P ssc_s2a_ctx;
time_t ssc_shutdown; /* when to shutdown forcefully */
#if MTA_USE_PMILTER
/*
** currently only used for policy milter, could be general,
** but then the individual states of the modules need to be
** stored somewhere (QMGR, SMAR)
*/
sm_ret_T ssc_state;
uint32_t ssc_pmcap; /* what does milter want? */
time_t ssc_pm_lasttry;
uint32_t ssc_mac_names[PM_SMST_MAX][PM_MAX_MACROS];
/* ctx for SMTPS/Milter communication subsystem */
s2q_ctx_P ssc_s2m_ctx;
#endif /* MTA_USE_PMILTER */
#if MTA_USE_TLS
SSL_CTX *ssc_ssl_ctx;
tlsl_ctx_P ssc_tlsl_ctx;
#endif
#if MTA_USE_SASL
sm_sasl_ctx_P ssc_sasl_ctx;
#endif
};
/* SMTP Server Context flags */
#define SSC_FL_RELAYFROM 0x0001u /* relay from pattern ok */
#define SSC_FL_RELAYTO 0x0002u /* relay to pattern ok */
#define SSC_FL_TLS_OK 0x0004u /* TLS initialized ok */
#define SSC_FL_SASL_OK 0x0008u /* SASL initialized ok */
#define SSC_FL_TERMINATING 0x0010u /* server is terminating */
#define SSC_FL_RESTARTDEP 0x0020u /* ask to restart dependencies */
#define SSC_FL_SHUTDOWN 0x0040u /* shutdown requested */
#define SSC_FL_SHTDWN_TS 0x0080u /* shutdown timer started */
#define SSC_FL_SHTDWN_FRC 0x0100u /* shutdown forced */
#if MTA_USE_PMILTER
#define SSC_FL_PM_USE 0x0100u /* use policy milter */
#define SSC_FL_PM_TRYCONN 0x0200u /* try to reconnect to policy milter */
/*
it is possible to encode the milter connect state in this way:
00 do no use milter
01 use milter
10 try to reconnect to milter, tempfail on error
11 try to reconnect to milter, ssd on error
but that's not worth it: it is not easily extendible for other error states.
Hence the error state is stored in ssc_state
*/
/* trying to connect to policy milter (mutex) */
#define SSC_FL_PM_TRYING 0x0400u
#endif /* MTA_USE_PMILTER */
#define SSC_SET_FLAG(ss_ctx, fl) (ss_ctx)->ssc_flags |= (fl)
#define SSC_CLR_FLAG(ss_ctx, fl) (ss_ctx)->ssc_flags &= ~(fl)
#define SSC_IS_FLAG(ss_ctx, fl) (((ss_ctx)->ssc_flags & (fl)) != 0)
#define SSC_SET_CFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_cflags |= (fl)
#define SSC_CLR_CFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_cflags &= ~(fl)
#define SSC_IS_CFLAG(ss_ctx, fl) (((ss_ctx)->ssc_cnf.ss_cnf_cflags & (fl)) != 0)
#define SSC_SET_MFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_mflags |= (fl)
#define SSC_CLR_MFLAG(ss_ctx, fl) (ss_ctx)->ssc_cnf.ss_cnf_mflags &= ~(fl)
#define SSC_IS_MFLAG(ss_ctx, fl) (((ss_ctx)->ssc_cnf.ss_cnf_mflags & (fl)) != 0)
/* state of server */
#define SSC_ST_OK 0 /* everything ok */
#define SSC_ST_SSD 421 /* service shutting down */
#define SSC_ST_TEMP 450 /* answer everything with temp fail */
#define SSC_ST_PERM 550 /* permanently reject connections (unused?) */
#define SSC_SET_STATE(ss_ctx, newstate) do { \
if ((ss_ctx)->ssc_state < (newstate)) \
(ss_ctx)->ssc_state = (newstate); \
} while (0)
#define SSC_SET_PMCAP(ss_ctx, fl) (ss_ctx)->ssc_pmcap |= (fl)
#define SSC_CLR_PMCAP(ss_ctx, fl) (ss_ctx)->ssc_pmcap &= ~(fl)
#define SSC_IS_PMCAP(ss_ctx, fl) (((ss_ctx)->ssc_pmcap & (fl)) != 0)
#if MTA_USE_PMILTER
# define S2s_IS_IOERR(ss_ctx) \
(S2Q_IS_IOERR(ss_ctx->ssc_s2a_ctx) \
|| S2Q_IS_IOERR(ss_ctx->ssc_s2q_ctx) \
|| S2Q_IS_IOERR(ss_ctx->ssc_s2m_ctx))
#else
# define S2s_IS_IOERR(ss_ctx) \
(S2Q_IS_IOERR(ss_ctx->ssc_s2a_ctx) \
|| S2Q_IS_IOERR(ss_ctx->ssc_s2q_ctx))
#endif
/* question: put into ss_ctx_S?? */
extern uint Max_threads;
extern uint Max_cur_threads;
extern uint Ss_wait4srv;
/* SMTP server session context */
struct ss_sess_S
{
#if SS_SESS_CHECK
sm_magic_T sm_magic;
#endif
ss_ctx_P ssse_sctx; /* pointer to server context */
sm_file_T *ssse_fp; /* file to use */
sm_str_P ssse_rd; /* smtp read buffer */
sm_str_P ssse_wr; /* smtp write buffer */
sm_str_P ssse_str; /* str for general use */
sm_rpool_P ssse_rpool;
uint ssse_idx; /* index for ss_sck_ctx[] array */
uint32_t ssse_flags;
uint32_t ssse_cnf_flags;
uint ssse_state;
in_addr_T ssse_client; /* fixme: use a generic struct! */
sm_ret_T ssse_cltrslv; /* result of resolving addr/hostname */
sm_cstr_P ssse_cltname; /* resolved hostname */
sm_str_P ssse_helo; /* helo param */
ss_ta_P ssse_ta; /* current transaction */
uint ssse_badcmds; /* bad commands */
uint ssse_nopcmds; /* number of "useless" commands */
uint ssse_invldaddr; /* #cmds with invalid addresses */
sessta_id_T ssse_id;
sm_rcb_P ssse_rcb; /* rcb for communication with QMGR */
st_cond_t ssse_cond_rd; /* receiving data from QMGR */
int ssse_s2q_idx; /* index in s2q_ctx->s2q_sess */
uint ssse_ta_tot; /* number of transactions */
uint ssse_rcpts_tot; /* total recipients */
uint ssse_max_line_len; /* max line length */
ss_acc_T ssse_acc;
time_t ssse_connect;
sm_ret_T ssse_maprescnf; /* map lookup result for session conf */
/* id of s2q "server" (qmgr/smar/pmilter) to which this session is connected */
int ssse_s2q_id[SS_MAX_COMM_SRVS];
sm_conf_T *ssse_cnf;
tlsreq_cnf_T ssse_tlsreq_cnf;
char *ssse_feat_name;
#if MTA_USE_TLS
SSL *ssse_con;
sm_file_T *ssse_fptls;
tlsi_ctx_P ssse_tlsi;
#endif
#if MTA_USE_SASL
sasl_conn_t *ssse_sasl_conn;
uint ssse_sasl_ext_ssf;
uint ssse_sasl_tries;
uint ssse_sasl_state;
char *ssse_sasl_mech_list;
#endif /* MTA_USE_SASL */
#if MTA_USE_PMILTER
sm_str_P ssse_mac_values[PM_SMST_MAX][PM_MAX_MACROS];
sm_str_P ssse_macv;
# if MTA_USE_SASL
sm_str_P ssse_sasl_mech;
sm_str_P ssse_sasl_authen;
sm_str_P ssse_sasl_author;
# endif /* MTA_USE_SASL */
#endif /* MTA_USE_PMILTER */
#if 0
session-id /* session identifier, maybe obtained from QMGR */
host /* identification of connecting host
(IP address, host name, ident) */
fd /* file descriptor/handle for connection */
helo-host /* host name from HELO/EHLO */
access times /* start time, last read, last write */
status /* EHLO/HELO, AUTH, STARTTLS (see above) */
features /* features offered: AUTH, TLS, EXPN, ... */
workarounds /* work around bugs in client */
reject-msg /* message to use for rejections (nullserver) */
auth /* AUTH context */
starttls /* TLS context */
transaction /* pointer to current transaction */
#endif /* 0 */
};
#define SSSE_S2Q_IDX_NONE (-1) /* initial value for s2q_idx */
#define SSSE_S2Q_IDX_CLSD (-2) /* connection has been closed */
#define S2Q_ID_NONE (-1) /* initial value for s2q_id */
typedef struct ss_mail_S ss_mail_T, *ss_mail_P;
typedef struct ss_rcpt_S ss_rcpt_T, *ss_rcpt_P;
typedef struct ss_rcpts_S ss_rcpts_T, *ss_rcpts_P;
struct ss_mail_S
{
sm_a2821_T ssm_a2821; /* mail */
/* parameters?? */
sm_str_P ssm_pa;
};
/*
** Note: currently this data isn't used anywhere: the recipients
** are stored in here but the data isn't read. It could be used
** to send rcpts in "chunks" to qmgr instead of one by one.
** Only for pmilter recipient additions/deletions this data will be read.
*/
struct ss_rcpt_S
{
sm_a2821_T ssr_a2821; /* rcpt */
/* parameters?? */
rcpt_idx_T ssr_idx; /* rcpt idx */
TAILQ_ENTRY(ss_rcpt_S) ssr_link; /* links */
#if MTA_USE_PMILTER
ushort ssr_type; /* rcpt type: add/delete */
# if MTA_USE_RSAD
sm_ret_T ssr_rcode; /* sm/mta.h */
# endif
#endif
};
TAILQ_HEAD(ss_rcpts_S, ss_rcpt_S);
/* operations on rcpt lists */
#define SS_RCPTS_INIT(rcpts) TAILQ_INIT(rcpts)
#define SS_RCPTS_EMPTY(rcpts) TAILQ_EMPTY(rcpts)
#define SS_RCPTS_FIRST(rcpts) TAILQ_FIRST(rcpts)
#define SS_RCPTS_END(rcpts) TAILQ_END(rcpts)
#define SS_RCPTS_NEXT(rcpt) TAILQ_NEXT(rcpt, ssr_link)
#define SS_RCPTS_INSERT_TAIL(rcpts, rcpt) TAILQ_INSERT_TAIL(rcpts, rcpt, ssr_link)
#define SS_RCPTS_INSERT_HEAD(rcpts, rcpt) TAILQ_INSERT_HEAD(rcpts, rcpt, ssr_link)
#define SS_RCPTS_REMOVE(rcpts, rcpt) TAILQ_REMOVE(rcpts, rcpt, ssr_link)
#define SS_RCPTS_REMOVE_FREE(ta, rcpts, rcpt) do { \
TAILQ_REMOVE((rcpts), (rcpt), ssr_link); \
ssr_rcpt_free((ta), (rcpt)); \
} while (0)
/*
** SMTPS transaction
** Note: an SMTPS session always has an SMTP transaction associated,
** even if no transaction has been started yet. Check ssta_state
** to figure out in which state the transaction is (SSTA_ST_*).
*/
struct ss_ta_S
{
#if SS_TA_CHECK
sm_magic_T sm_magic;
#endif
sm_rpool_P ssta_rpool;
uint ssta_flags;
sm_hdrmodhd_P ssta_hdrmodhd;
ss_mail_P ssta_mail; /* mail from */
ss_acc_T ssta_mail_acc; /* access check for mail */
ss_rcpts_T ssta_rcpts; /* rcpts */
/*
** Access check for current recipient. If multiple recipients
** can be checked concurrently, then this must be in ss_rcpt_S.
*/
ss_acc_T ssta_rcpt_acc;
ss_acc_T ssta_rcpt_acc2;
uint ssta_rcpts_tot; /* number of recipients total */
uint ssta_rcpts_ok; /* number of recipients ok */
uint ssta_rcpts_len; /* length of all recipient addresses */
uint ssta_state;
off_t ssta_msg_sz_b; /* messages size (bytes) */
sessta_id_T ssta_id;
sm_file_T *ssta_dfp; /* cdb (currently: fp) */
/* message-id, used for logging and pmilter */
sm_str_P ssta_msgid;
uint ssta_badcmds; /* bad commands */
uint ssta_nopcmds; /* number of "useless" commands */
uint ssta_invldaddr; /* #cmds with invalid addresses */
#if 0
transaction-id /* transaction identifier, maybe obtained from QMGR */
cdb-id /* CDB identifier (obtained from cdb?) */
cmd-failures /* number of failures for certain commands */
#endif
#if SS_EHLO_ACCESS_CHK
ss_acc_T ssta_ehlo_acc; /* access check for ehlo */
#endif
#if MTA_USE_PMILTER
sm_str_P ssta_mail_new; /* new MAIL address */
uint ssta_rcpts_tot_orig;
uint ssta_rcpts_ok_orig;
ss_acc_T ssta_msg_acc; /* result of msg check */
uint ssta_msg_st; /* state of message replacement */
uint ssta_eot_state;
sm_file_T *ssta_msg_fp;
sm_cstr_P ssta_cdb_id; /* cdb-id */
off_t ssta_rmsg_sz_b; /* new messages size (bytes) */
uint ssta_hops;
# if MTA_USE_RSAD
uint ssta_nreplies; /* number of replies */
uint32_t *ssta_rcodes;
sm_str_P *ssta_replies; /* replies */
# endif
#endif /* MTA_USE_PMILTER */
};
/* SMTP Server Session flags */
/* #define SSSE_FL_ACTIVE 0x00000001 * session is active (currently UNUSED!) */
/* local only, don't accept, don't tell QMGR (set but not checked) */
#define SSSE_FL_LOCAL_SSD 0x00000002
#define SSSE_FL_CSEID 0x00000004 /* tell QMGR about session close */
#define SSSE_FL_NULL 0x00000008 /* null server */
#define SSSE_FL_QUICK 0x00000010 /* session check returned QUICK */
#define SSSE_FL_SASL_OK 0x00000020 /* SASL initialized ok */
#define SSSE_FL_AUTH 0x00000040 /* AUTH (only once, additive) */
#define SSSE_FL_STARTTLS 0x00000080 /* STARTTLS is in use */
#define SSSE_FL_HELO 0x00000100 /* client used HELO instead of EHLO */
#define SSSE_FL_CLT_RLY_TMP 0x00001000 /* clt relay: temp.error during test */
#define SSSE_FL_CLIENT_RELAY 0x00002000 /* client can relay */
#define SSSE_FL_CLIENT_OK 0x00004000 /* client OK (access map) */
#define SSSE_FL_DISCARD 0x00008000 /* discard entire session */
#if MTA_USE_PMILTER
/* use policy milter in this session */
# define SSSE_FL_PM_USE 0x00020000
/* pmilter has been called in this session */
# define SSSE_FL_PM_CALLED 0x00040000
#endif
#define SSSE_FL_GREYCHKD 0x00080000 /* grey check done for session */
#define SSSE_FL_GREYLSTD 0x00100000 /* greylisted */
#define SSSE_FL_CONN_LOGGED 0x00200000 /* connection info has been logged */
#define SSSE_SET_FLAG(ss_sess, fl) (ss_sess)->ssse_flags |= (fl)
#define SSSE_CLR_FLAG(ss_sess, fl) (ss_sess)->ssse_flags &= ~(fl)
#define SSSE_IS_FLAG(ss_sess, fl) (((ss_sess)->ssse_flags & (fl)) != 0)
#define SSSE_ARE_FLAGS(ss_sess, fl) (((ss_sess)->ssse_flags & (fl)) == (fl))
#define SSSE_SET_CFLAG(ss_sess, fl) (ss_sess)->ssse_cnf_flags |= (fl)
#define SSSE_CLR_CFLAG(ss_sess, fl) (ss_sess)->ssse_cnf_flags &= ~(fl)
#define SSSE_IS_CFLAG(ss_sess, fl) (((ss_sess)->ssse_cnf_flags & (fl)) != 0)
/* session states (fixme: some of these belong into SSSE flags) */
#define SSSE_ST_NONE 0x0000 /* no session active */
#define SSSE_ST_CONNECTING 0x0001 /* connection attempt */
#define SSSE_ST_CONNECTED 0x0002 /* connection succeeded */
#define SSSE_ST_GREETED 0x0004 /* sent greeting */
#define SSSE_ST_EHLO 0x0010 /* EHLO; aborts transaction */
#define SSSE_ST_HELO 0x0020 /* HELO; aborts transaction */
#define SSSE_ST_QUIT 0x0800 /* QUIT command received */
/* transaction states, these must be sorted! */
#define SSTA_ST_NONE 0x00 /* must be 0 */
#define SSTA_ST_INIT 0x01 /* ta initialized, rpool created, etc */
#define SSTA_ST_MAIL 0x02 /* MAIL received */
#define SSTA_ST_RCPT 0x04 /* RCPT received */
#define SSTA_ST_DATA 0x08 /* DATA received */
#define SSTA_ST_DOT 0x10 /* Final dot received */
/* a transaction is "active" */
#define SSTA_IS_ACTIVE(ss_ta) ((ss_ta)->ssta_state >= SSTA_ST_MAIL)
/* SMTP Server Transaction flags */
#define SSTA_FL_NONE 0x00000000
/* #define SSTA_FL_MAIL_QCK 0x00000001 * mail check returned QUICK */
/* #define SSTA_FL_RCPT_QCK 0x00000002 * rcpt check returned QUICK */
#define SSTA_FL_LL_EXC 0x00000004 /* maximum line length exceeded */
#define SSTA_FL_DISCARD 0x00000008 /* discard entire transaction */
#define SSTA_FL_DSCRD_RCPT 0x00000010 /* discarded at least one recipient */
#define SSTA_FL_DELAY_CHKS 0x00000020 /* delay checks */
#define SSTA_FL_CDB_EXISTS 0x00000040 /* cdb exists */
#define SSTA_FL_DSN 0x00000080 /* MAIL From:<> (DSN) */
#if MTA_USE_PMILTER
#define SSTA_FL_PM_USE 0x00000100 /* use pmilter for this TA */
#define SSTA_FL_PM_CALLED 0x00000200 /* pmilter has been called for this TA */
#define SSTA_FL_PM_SKIP_MSG 0x00000400 /* pmilter has been called for this TA */
#endif
#define SSTA_FL_XVERP 0x00002000 /* XVERB for MAIL */
#if MTA_USE_PMILTER
#define SSTA_FL_RCPT_MOD 0x00004000 /* recipient modifications exist */
#define SSTA_FL_MAIL_MOD 0x00008000 /* MAIL modification exist */
#endif
#define SSTA_FL_RSAD 0x00020000 /* RSAD for MAIL */
#define SSTA_SET_FLAG(ss_ta, fl) (ss_ta)->ssta_flags |= (fl)
#define SSTA_CLR_FLAG(ss_ta, fl) (ss_ta)->ssta_flags &= ~(fl)
#define SSTA_IS_FLAG(ss_ta, fl) (((ss_ta)->ssta_flags & (fl)) != 0)
#if MTA_USE_PMILTER
#define SSTA_ST_MR_NONE 0x0000 /* Must be 0 */
#define SSTA_ST_MR_CDB_OK 0x0001 /* cdb created */
#define SSTA_ST_MR_CDB_NONE 0x0002 /* cdb creation failed */
#define SSTA_ST_MR_CDB_WR 0x0004 /* writing to cdb */
#define SSTA_ST_MR_CDB_FAIL 0x0002 /* cdb write failed */
#define SSTA_ST_MR_CDB_CLSD 0x0008 /* cdb closed */
sm_ret_T ss_replacemsg(ss_sess_P _ss_sess, uint32_t _l);
sm_ret_T ss_rplcmsg(ss_sess_P _ss_sess);
#endif /* MTA_USE_PMILTER */
typedef char *ss_id_T;
typedef struct ss_socket_ctx_S ss_socket_ctx_T;
struct ss_socket_ctx_S
{
st_netfd_t sssc_lfd; /* Listening socket */
char *sssc_addr; /* Bind address */
int sssc_port; /* Port */
int sssc_wait_threads; /* threads waiting to accept */
int sssc_busy_threads; /* threads processing request */
int sssc_maxb_threads; /* max # of threads */
ulong sssc_rqst_count; /* Total # of processed requests */
ulong sssc_ta_count; /* Total # of processed transactions */
};
sm_ret_T ss_read_cnf(ss_ctx_P _ss_ctx, const char *_fn, sm_conf_T **_psmc);
sm_ret_T ss_chk_cnf(ss_ctx_P _ss_ctx);
sm_ret_T ss_id_init(id_count_T _id_val);
sm_ret_T ss_id_end(void);
sm_ret_T ss_id_next(int _smtpsid, ss_id_T _id);
#if 0
sm_ret_T ss_id_set(id_count_T _id_val);
#endif
sm_ret_T ss_relay_to(ss_ctx_P _ss_ctx, const char *_str);
sm_ret_T ss_relay_from(ss_ctx_P _ss_ctx, const char *_str);
#define SS_PHASE_OTHER 0 /* no special treatment */
#define SS_PHASE_INIT 1 /* initial 220 greeting */
#define SS_PHASE_EHLO 2 /* EHLO response */
#define SS_PHASE_TLS 3 /* STARTTLS response */
#define SS_PHASE_AUTH 4 /* AUTH response */
#define SS_PHASE_MAIL 5 /* MAIL response */
#define SS_PHASE_RCPT 6 /* RCPT response */
#define SS_PHASE_DATA 7 /* DATA response */
#define SS_PHASE_DOT 8 /* response to final dot */
#define SS_PHASE_QUIT 9 /* QUIT */
#define SS_PHASE_NOREPLY 10 /* no reply requested */
sm_ret_T ss_crt_reply(sm_str_P _reply, sm_ret_T _ret, int _phase, bool _new);
/* #if SSQ_DEBUG */
void dump_thrd_info(void);
/* #endif */
/* useful macros */
#define WAIT_THREADS(i) (ss_sck_ctx[i].sssc_wait_threads)
#define BUSY_THREADS(i) (ss_sck_ctx[i].sssc_busy_threads)
#define MAXB_THREADS(i) (ss_sck_ctx[i].sssc_maxb_threads)
#define TOTAL_THREADS(i) (WAIT_THREADS(i) + BUSY_THREADS(i))
#define RQST_COUNT(i) (ss_sck_ctx[i].sssc_rqst_count)
#define TA_COUNT(i) (ss_sck_ctx[i].sssc_ta_count)
#if SS_CTX_CHECK
# define SM_IS_SS_CTX(ss_ctx) SM_REQUIRE_ISA((ss_ctx), SM_SS_CTX_MAGIC)
#else
# define SM_IS_SS_CTX(ss_ctx) SM_REQUIRE((ss_ctx) != NULL)
#endif
#if SS_SESS_CHECK
# define SM_IS_SS_SESS(ss_sess) SM_REQUIRE_ISA((ss_sess), SM_SS_SESS_MAGIC)
#else
# define SM_IS_SS_SESS(ss_sess) SM_REQUIRE((ss_sess) != NULL)
#endif
#if SS_TA_CHECK
# define SM_IS_SS_TA(ss_ta) SM_REQUIRE_ISA((ss_ta), SM_SS_TA_MAGIC)
#else
# define SM_IS_SS_TA(ss_ta) SM_REQUIRE((ss_ta) != NULL)
#endif
#endif /* SMTPS_H */
syntax highlighted by Code2HTML, v. 0.9.1