/*
 *  Globals of the ZMailer  smtp-server
 *
 *  Matti Aarnio <mea@nic.funet.fi> 1997-2001
 */


#define SMTP_COMMAND_ALARM_IVAL 1200	/* 20 minutes.. */
#define SMTP_DATA_TIME_PER_LINE  600	/* 10 minutes of life.. */
#define SMTP_REPLY_ALARM_IVAL    300	/*  5 minutes to write to socket.. */

/*
 * The smtpserver connects to the router to ask it various questions, like,
 * is this a valid address?  What is the alias expansion of that? etc.
 * This is done through a portal function called "server".  Its only standard
 * argument is a keyword for what we want done.  These are the definitions:
 */

#ifndef __STDC__
# define const
# define volatile
#endif

#define	ROUTER_SERVER	"server"	/* name of portal function */

#define	RKEY_INIT	"init"		/* initialize state of server	*/
#define	RKEY_FROM	"from"		/* mail from address verification */
#define	RKEY_TO		"to"		/* recipient to address verification */
#define	RKEY_VERIFY	"verify"	/* verify this address		*/
#define	RKEY_EXPAND	"expand"	/* expand this address		*/
#define RKEY_HELLO	"hello"		/* connection from a client	*/

#define SMTPLINESIZE	8192

#include "hostenv.h"

#include <stdio.h>
#ifndef FILE /* Some systems don't have this as a MACRO.. */
# define FILE FILE
#endif
#include <sfio.h>

#include "zmalloc.h"
#include <sys/types.h>
#include <ctype.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sysexits.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "zmsignal.h"
#include <errno.h>
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#else
#include <varargs.h>		/* If no  <stdarg.h>,  then presume <varargs.h> ... */
#endif

#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef LONG_MAX
# define LONG_MAX 2147483647L /* For 32 bit machine! */
#endif

#include <netinet/in.h> /* In some systems needed before <arpa/inet.h> */
#include <arpa/inet.h>

#include "mail.h"

#include <setjmp.h>

#ifdef  HAVE_WAITPID
#include <sys/wait.h>
#else
#ifdef HAVE_WAIT4
#include <sys/wait.h>		/* Has BSD wait4() */
#else
#ifdef HAVE_WAIT3
#include <sys/wait.h>		/* Has BSD wait3() */
#else
#ifdef HAVE_SYS_WAIT_H		/* POSIX.1 compatible */
#include <sys/wait.h>
#else				/* Not POSIX.1 compatible, lets fake it.. */
extern int wait();
#endif
#endif
#endif
#endif

#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifndef EAI_AGAIN
# include "netdb6.h"
#endif

#include <sys/socket.h>
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#include <netinet/in.h>
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#else
#ifdef HAVE_NETINET6_IN6_H
#include <netinet6/in6.h>
#else
#ifdef HAVE_LINUX_IN6_H
#include <linux/in6.h>
#endif
#endif
#endif
#include <arpa/inet.h>

#include "libc.h"
#include "libz.h"

#include "shmmib.h"

#ifndef	SIGCHLD
#define	SIGCHLD	SIGCLD
#endif				/* SIGCHLD */

#ifndef	MAXHOSTNAMELEN
#define	MAXHOSTNAMELEN 256
#endif				/* MAXHOSTNAMELEN */

#include "zsyslog.h"



#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif

#include <sys/time.h>

#ifndef	NFDBITS
/*
 * This stuff taken from the 4.3bsd /usr/include/sys/types.h, but on the
 * assumption we are dealing with pre-4.3bsd select().
 */

/* #error "FDSET macro susceptible" */

typedef long	fd_mask;

#ifndef	NBBY
#define	NBBY	8
#endif	/* NBBY */
#define	NFDBITS		((sizeof fd_mask) * NBBY)

/* SunOS 3.x and 4.x>2 BSD already defines this in /usr/include/sys/types.h */
#ifdef	notdef
typedef	struct fd_set { fd_mask	fds_bits[1]; } fd_set;
#endif	/* notdef */

#ifndef	_Z_FD_SET
/* #warning "_Z_FD_SET[1]" */
#define	_Z_FD_SET(n, p)   ((p)->fds_bits[0] |= (1 << (n)))
#define	_Z_FD_CLR(n, p)   ((p)->fds_bits[0] &= ~(1 << (n)))
#define	_Z_FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n)))
#define _Z_FD_ZERO(p)	  memset((char *)(p), 0, sizeof(*(p)))
#endif	/* !FD_SET */
#endif	/* !NFDBITS */

#ifdef FD_SET
/* #warning "_Z_FD_SET[2]" */
#define _Z_FD_SET(sock,var) FD_SET(sock,&var)
#define _Z_FD_CLR(sock,var) FD_CLR(sock,&var)
#define _Z_FD_ZERO(var) FD_ZERO(&var)
#define _Z_FD_ISSET(i,var) FD_ISSET(i,&var)
#else
/* #warning "_Z_FD_SET[3]" */
#define _Z_FD_SET(sock,var) var |= (1 << sock)
#define _Z_FD_CLR(sock,var) var &= ~(1 << sock)
#define _Z_FD_ZERO(var) var = 0
#define _Z_FD_ISSET(i,var) ((var & (1 << i)) != 0)
#endif


#include "policytest.h"

#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#endif /* - HAVE_OPENSSL */

#ifdef HAVE_SASL2
#ifdef HAVE_SASL_SASL_H
#include <sasl/sasl.h>
#include <sasl/saslutil.h>
#else
# error "No <sasl/sasl.h> available!"
#endif
#endif


struct smtpconf {
    const char *pattern;
    int maxloadavg;
    const char *flags;
    struct smtpconf *next;
};

typedef enum {
    Null, Hello, Mail, MailOrHello, Recipient,
    RecipientOrData, Data, Send, SendOrMail,
    SendAndMail, Reset, Verify, Expand, Help,
    NoOp, Quit, Turn, Tick, Verbose, DebugIdent,
    Turnme, BData, DebugMode, Auth,
#ifdef HAVE_OPENSSL
    StartTLS,
#endif /* - HAVE_OPENSSL */
    Hello2, Mail2, Send2, Verify2,	/* 8-bit extensions */
    HelloL,		/* RFC 2033 LHLO -- sort of */
    Silent		/* One particular client error trap.. */
} Command;


struct command {
    const char *verb;
    Command cmd;
};

extern struct command command_list[];

#ifdef HAVE_OPENSSL

#define CCERT_BUFSIZ 256

struct smtpserver_ssl_subset {
    SSL * ssl;

    const char *protocol;
    const char *cipher_name;
    int         cipher_usebits;
    int         cipher_algbits;

    int  peer_verified;

    const char *cipher_info;
    const char *issuer_CN;
    const char *peer_issuer;
    const char *peer_CN;
    const char *peer_subject;
    const char *peer_fingerprint;

    unsigned char peer_md[EVP_MAX_MD_SIZE];
};


#endif /* - HAVE_OPENSSL */

#ifdef HAVE_SASL2
struct SmtpSASLState {
    char  *volatile auth_type;
    const char *mechlist;
    sasl_conn_t *conn;
    volatile int sasl_ok;
    volatile unsigned int n_auth;	/* count of AUTH commands */
    volatile unsigned int n_mechs;
    unsigned int len;
    sasl_security_properties_t ssp;
#if 0 /* Is in SASL-1, different/not in SASL-2 */
#ifdef SASL_SSF_EXTERNAL
    sasl_external_properties_t ext_ssf;
#endif
#endif
    sasl_ssf_t *ssf;
};
#endif /* HAVE_SASL2 */



typedef struct SmtpState {
    int  outputfd;		/* stdout */
    int  inputfd;		/* stdin  */
    FILE *mfp;			/* Storage-bound mail-file fp */
    long messagesize;		/* Reset at MAIL, add at BDATs / DATA */
    long sizeoptval;		/* "MAIL FROM:<xxx> SIZE=nnn" -value    */
    long sizeoptsum;
    char myhostname[MAXHOSTNAMELEN + 1];
    char rhostname[MAXHOSTNAMELEN + 1];
    const char *with_protocol;	/* = WITH_SMTP */
    const char *style;		/* = "ve" */
    Command state;		/* = Hello */
    int  VerboseCommand;
    struct command *carp;
    struct policystate policystate;
    int  policyresult, reject_net;
    int  postmasteronly;
    int  netconnected_flg;
    int  tarpit;
    int  tarpit_cval;		/* current tarpit value */
    int  rport;
    char ihostaddr[sizeof("[ipv6.ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]") + 8];
    Usockaddr raddr;
    Usockaddr localsock;

    const char * smtpfrom;	/* MAIL FROM:<...> */
    time_t  deliverby_time;	/* RFC 2852 */
    int	    deliverby_flags;
#define DELIVERBY_R  1
#define DELIVERBY_N  2
#define DELIVERBY_T  4

    char *sslwrbuf;		/* Despite of the name, all modes
				   use this write-out buffer.. */
    int   sslwrspace, sslwrin, sslwrout;
    /* space, how much stuff in, where the output cursor is */

    int   sslmode;		/* Set, when SSL/TLS in running */
#ifdef HAVE_OPENSSL
    struct smtpserver_ssl_subset TLS; /* TLS specific things */
#endif /* - HAVE_OPENSSL */

    int  read_alarm_ival;
    int  s_bufread;
    int  s_readout;
    int  s_status;
    int  s_readerrno;
    char s_buffer[SMTPLINESIZE];
    int  s_ungetcbuf;
    int  s_seen_pipeline;

    int  from_box;		/* Set when:  MAIL FROM:<>  */
    int  rcpt_count;
    int  ok_rcpt_count;
    int  sender_ok;
    /* For BDAT -command */
    int  bdata_blocknum;
    int  mvbstate;
    char *authuser;

    char ident_username[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 2];
    char helobuf[200]; /* Carefully limited copy into this buffer */
    struct smtpconf *cfinfo;

#ifdef HAVE_WHOSON_H
    int whoson_result;
    char whoson_data[128];
#endif

    int unknown_cmd_count;
    long sameipcount;

#ifdef HAVE_SASL2
    struct SmtpSASLState sasl;
#endif

} SmtpState;


#define STYLE(i,c)	(strchr(((i)==NULL ? style : (i)->flags), (c)) != NULL)

#define	WITH_SMTP	"SMTP"
#define	WITH_ESMTP	"ESMTP"
#define	WITH_BSMTP	"BSMTP"

#define HELPMAX 40
extern char *helplines[];
#define HDR220MAX 4
extern char *hdr220lines[];
extern char logtag[];
extern time_t logtagepoch, now;

extern long availspace;
extern long minimum_availspace;
extern long maxsize;
extern int use_ipv6;
extern int tarpit_initial;
extern int tarpit_exponent;
extern int tarpit_toplimit;
extern int MaxErrorRecipients;
extern int TcpRcvBufferSize;
extern int TcpXmitBufferSize;
extern int ListenQueueSize;
extern int MaxSameIpSource;
extern int MaxParallelConnections;
extern int percent_accept;
extern int smtp_syslog;
extern int allow_source_route;
extern int debugcmdok;
extern int expncmdok;
extern int vrfycmdok;
extern int pipeliningok;
extern int mime8bitok;
extern int chunkingok;
extern int enhancedstatusok;
extern int multilinereplies;
extern int dsn_ok;
extern int auth_ok;
extern int ehlo_ok;
extern int etrn_ok;
extern int starttls_ok;
extern int ssmtp_listen;
extern int msa_mode;
extern int deliverby_ok;
#define MAX_ETRN_CLUSTER_IDX 40
typedef struct {
  char *nodename; char *username; char *password;
} etrn_cluster_ent;
extern etrn_cluster_ent etrn_cluster[];
extern const char *tls_cert_file, *tls_key_file, *tls_CAfile, *tls_CApath;
extern const char *tls_dcert_file, *tls_dkey_file, *tls_dh1024_param;
extern const char *tls_dh512_param;
extern const char *tls_random_source;
extern const char *tls_cipherlist;
extern const char *SASL_Auth_Mechanisms;
extern int tls_loglevel, tls_enforce_tls, tls_ccert_vd, tls_use_scache;
extern int tls_ask_cert, tls_req_cert, tls_scache_timeout;
extern int log_rcvd_whoson, log_rcvd_ident, log_rcvd_authuser;
extern int log_rcvd_tls_mode, log_rcvd_tls_peer;
extern int auth_login_without_tls;
extern char *smtpauth_via_pipe;
extern char *contentfilter;
extern int debug_content_filter;
extern int strict_protocol;
extern int rcptlimitcnt;
extern int enable_router;
extern int use_tcpwrapper;
extern int configuration_ok;
extern int unknown_cmd_limit;
extern int sum_sizeoption_value;
extern int lmtp_mode;
extern int do_sasl;
extern int MaxSLBits;
extern char *AuthMechanisms;
extern int detect_incorrect_tls_use;
extern int force_rcpt_notify_never;

extern int bindaddr_set, bindport_set, testaddr_set;
extern u_short   bindport;
extern Usockaddr *bindaddrs;
extern int        bindaddrs_count;
extern Usockaddr testaddr;

extern const char *progname;
extern int debug, skeptical, checkhelo, ident_flag, verbose;

extern const char *style;

extern struct smtpconf *readcffile __((const char *fname));
extern struct smtpconf *findcf __((const char *host));

extern int loadavg_current __((void));

extern const char *rfc821_domain __((const char *s, int strict));
extern const char *rfc821_path __((const char *s, int strict));
extern const char *rfc821_path2 __((const char *s, int strict));
extern const char *rfc821_error;
extern const char *rfc821_error_ptr;
#ifdef HAVE_STDARG_H
extern void type821err __((SmtpState *, const int code, const char *status,
			   const char *inbuf, const char *fmt,...));
#else
extern void type821err __(());
#endif

extern struct smtpconf *cfhead;

extern void reporterr __((SmtpState *, long, const char *));

extern const char *Copyright;
extern const char *Copyright2;
extern FILE *logfp;
extern int   logfp_to_syslog;
extern int pid;

extern char *routerprog;
extern int routerpid;
extern int router_status;

extern const char *m200;
extern const char *m400;
extern const char *m410;
extern const char *m412;
extern const char *m413;
extern const char *m415;
extern const char *m417;
extern const char *m418;
extern const char *m430;
extern const char *m431;
extern const char *m433;
extern const char *m443;
extern const char *m454;
extern const char *m471;
extern const char *m510;
extern const char *m512;
extern const char *m513;
extern const char *m515;
extern const char *m517;
extern const char *m518;
extern const char *m530;
extern const char *m534;
extern const char *m540;
extern const char *m543;
extern const char *m550;
extern const char *m551;
extern const char *m552;
extern const char *m554;
extern const char *m571;

extern int getpeername();
extern int isit42inetd();

#ifdef USE_TRANSLATION
extern int X_8bit;
extern int X_translation;
extern int X_settrrc;
extern void header_from_mime __((char *, int *, int));
#endif				/* USE_TRANSLATION */

extern void killr __((SmtpState * SS, int rpid));
extern void killcfilter __((SmtpState * SS, int rpid));
extern void typeflush __((SmtpState *));
#if defined(HAVE_STDARG_H) && defined(HAVE_VPRINTF)
extern void type __((SmtpState *, int code, const char *status, const char *fmt,...));
extern void Z_printf __(( SmtpState *, const char *fmt, ... ));
#else
extern void type __(( /* SmtpState *SS, int code, const char *status, const char *fmt, ... */ ));
extern void Z_printf __(( /* SmtpState *, const char *fmt, ... */ ));
#endif
extern void debug_report __((SmtpState *, int, const char *, const char *));
extern void header_to_mime __((char *, int *, int));
extern void help __((SmtpState *, struct smtpconf *, const char *));
extern time_t time __((time_t *));
extern char *router __((SmtpState *, const char *, const int, const char *, const int));
#ifndef MALLOC_TRACE		/* turns these into macroes.. */
#ifndef __XMALLOC_H__		/* at ../include/malloc.h */
extern univptr_t emalloc __((size_t));
extern univptr_t erealloc __((void *, size_t));
#endif
#endif
extern void runasrootuser __((void));
extern int runastrusteduser __((void));
extern char **environ;
extern int kill __((pid_t, int));

extern const char *rfc822atom __((const char *str));
extern const char *xtext_string __((const char *str));

extern void s_setup  __((SmtpState * SS, int infd, int outfd));
extern void s_ungetc __((SmtpState *SS, int ch));
extern int s_feof __((SmtpState * SS));
extern int s_getc __((SmtpState * SS, int timeout_is_fatal));
extern int s_hasinput __((SmtpState * SS));
extern int s_gets __((SmtpState *SS, char *buf, int buflen, int *rcp, char *cop, char *cp));

extern int errno;
extern int optind;
extern char *optarg;

#ifndef CISTREQN
#define   CISTREQN(x, y, n)  (cistrncmp((x), (y), n) == 0)
#endif
#ifndef CISTREQ
#define   CISTREQ(x, y)  (cistrcmp((x), (y)) == 0)
#endif

#ifdef	lint
#undef	putc
#define	putc	fputc
#endif				/* lint */

extern int  childsameip __((Usockaddr *addr, int *childcntp));
extern void childregister __((int cpid, Usockaddr *addr, int tag));
extern void childreap   __((int cpid));

extern void smtp_helo   __((SmtpState * SS, const char *buf, const char *cp));
extern int  smtp_mail   __((SmtpState * SS, const char *buf, const char *cp, int insecure));
extern int  smtp_rcpt   __((SmtpState * SS, const char *buf, const char *cp));
extern void smtp_turnme __((SmtpState * SS, const char *name, const char *cp));
extern void smtp_verify __((SmtpState * SS, const char *buf, const char *cp));
extern void smtp_expand __((SmtpState * SS, const char *buf, const char *cp));
extern int  smtp_data   __((SmtpState * SS, const char *buf, const char *cp));
extern int  smtp_bdata  __((SmtpState * SS, const char *buf, const char *cp));
extern void add_to_toplevels __((char *str));
extern void smtp_tarpit __((SmtpState * SS));

extern void smtp_auth __((SmtpState * SS, const char *buf, const char *cp));
extern void smtpauth_init __((SmtpState * SS));
extern void smtpauth_ehloresponse __((SmtpState * SS));

#ifdef HAVE_OPENSSL
extern int tls_start_servertls __((SmtpState *SS));
extern void smtp_starttls __((SmtpState * SS, const char *buf, const char *cp));
extern void Z_init    __(( void ));
extern void Z_cleanup __(( SmtpState * ));
extern int  Z_SSL_flush __(( SmtpState * ));
#endif /* - HAVE_OPENSSL */
extern int  Z_pending __(( SmtpState * ));
extern int  Z_write   __(( SmtpState *, const void *, int ));
extern int  Z_read    __(( SmtpState *, void *, int ));

#ifdef USE_TCPWRAPPER
#ifdef HAVE_TCPD_H		/* The hall-mark of having tcp-wrapper things around */
extern int wantconn __((int sock, char *prgname));
#endif
#endif

extern char *rfc822date __((time_t *));

#ifdef HAVE_STDARG_H		/* Fwd declaration */
 void report __((SmtpState *, const char *,...));
#else
 void report __(());
#endif

extern int encodebase64string __((const char *instr, int inlen, char *outstr, int outspc));
extern int decodebase64string __((const char *instr, int inlen, char *outstr, int outspc, const char **inleftover));

/* transports/libta/nonblocking.c */
extern int  fd_nonblockingmode __((int fd));
extern int  fd_blockingmode __((int fd));
extern void fd_restoremode __((int fd, int mode));


syntax highlighted by Code2HTML, v. 0.9.1