windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/smtp/server/smtpout.hxx
2020-09-26 16:20:57 +08:00

502 lines
18 KiB
C++

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name :
smtpout.hxx
Abstract:
This module defines the SMTP_CONNOUT class.
This object maintains information about a new client connection
Author:
Rohan Phillips ( Rohanp ) 11-Dec-1995
Project:
SMTP Server DLL
Revision History:
--*/
#ifndef _SMTP_OUT_HXX_
#define _SMTP_OUT_HXX_
/************************************************************
* Include Headers
************************************************************/
#include "smtpcli.hxx"
#include "conn.hxx"
#include "simssl2.h"
//
// Protocl Events
//
#include "pe_out.hxx"
#include <smtpevent.h>
#include "pe_supp.hxx"
#include "pe_disp.h"
//
// Forward for IEventRouter
//
interface IEventRouter;
//
// Redefine the type to indicate that this is a call-back function
//
typedef ATQ_COMPLETION PFN_ATQ_COMPLETION;
/************************************************************
* Symbolic Constants
************************************************************/
#define SIZE_OPTION 0x00000001
#define PIPELINE_OPTION 0x00000002
#define EBITMIME_OPTION 0x00000004
#define SMARTHOST_OPTION 0x00000008
#define DSN_OPTION 0x00000010
#define TLS_OPTION 0x00000020
#define AUTH_NTLM 0x00000040
#define AUTH_CLEARTEXT 0x00000080
#define ETRN_SENT 0x00000100
#define ETRN_OPTION 0x00000200
#define SASL_OPTION 0x00000400
#define CHUNKING_OPTION 0x00000800
#define BINMIME_OPTION 0x00001000
#define ENHANCEDSTATUSCODE_OPTION 0x00002000
#define AUTH_GSSAPI 0x00004000
#define AUTH_DIGEST 0x00008000
#define ETRN_ONLY_OPTION 0x00010000
#define STARTTLS_OPTION 0x00020000
#define EMPTY_CONNECTION_OPTION 0x00040000
#define TURN_ONLY_OPTION 0x00080000
const DWORD SMTP_MAX_REPLY_LENGTH = 4096;
const DWORD SMTP_MAX_COMMAND_LENGTH = 512;
const char CONTINUATION_CHAR = (char) '-';
#define SMTP_PRELIMINARY_SUCCESS (char) '1'
#define SMTP_COMPLETE_SUCCESS (char) '2'
#define SMTP_INTERMEDIATE_SUCCESS (char) '3'
#define SMTP_TRANSIENT_FAILURE (char) '4'
#define SMTP_COMPLETE_FAILURE (char) '5'
#define KNOWN_AUTH_FLAGS ((DWORD)(DOMAIN_INFO_USE_NTLM | DOMAIN_INFO_USE_PLAINTEXT | DOMAIN_INFO_USE_DPA \
| DOMAIN_INFO_USE_KERBEROS))
enum RSETCODE
{
NO_SMTP_ERROR, BETWEEN_MSG, NO_RCPTS_SENT, ALL_RCPTS_FAILED, FATAL_ERROR
};
/************************************************************
* Type Definitions
************************************************************/
enum FORMAT_SMTP_MESSAGE_LOGLEVEL {
FSM_LOG_ALL,
FSM_LOG_VERB_ONLY,
FSM_LOG_NONE
};
enum TLS_ACTIONS {DONT_DO_TLS, MUST_DO_TLS, STARTTLS_SENT, SSL_NEG, CHANNEL_SECURE};
class SMTP_CONNOUT;
/*++
class SMTP_CONNOUT
This class is used for keeping track of individual client
connections established with the server.
It maintains the state of the connection being processed.
--*/
class SMTP_CONNOUT :
public CLIENT_CONNECTION
{
public:
enum LASTIOSTATE {READIO, WRITEIO, TRANSFILEIO};
static CPool Pool;
// override the mem functions to use CPool functions
void *operator new (size_t cSize)
{ return Pool.Alloc(); }
void operator delete (void *pInstance)
{ Pool.Free(pInstance); }
~SMTP_CONNOUT(void);
VOID DisconnectClient( IN DWORD dwErrorCode = NO_ERROR);
BOOL SendSmtpResponse(BOOL SyncSend = TRUE);
virtual BOOL ProcessClient( IN DWORD cbWritten,
IN DWORD dwCompletionStatus,
IN OUT OVERLAPPED * lpo);
BOOL IsNTLMSupported(void) {return ((m_Flags & AUTH_NTLM) == AUTH_NTLM);}
BOOL IsClearTextSupported(void) {return ((m_Flags & AUTH_CLEARTEXT) == AUTH_CLEARTEXT);}
BOOL IsUsingSASL(void) {return ((m_Flags & SASL_OPTION) == SASL_OPTION);}
void SetCarrierOption(DWORD NewOption){ m_Flags |= NewOption;}
void SetCurrentObjectToNull(void) { m_pISMTPConnection = NULL;}
void SetCurrentObject(ISMTPConnection * pISMTPConnection)
{
m_pISMTPConnection = pISMTPConnection;
}
BOOL ConnectToNextIpAddress(void);
void SetConnectedDomain(const char * RealDomain)
{
lstrcpyn(m_ConnectedDomain, RealDomain, MAX_INTERNET_NAME);
}
virtual BOOL StartSession( VOID);
BOOL ReStartSession(void);
BOOL IsSecure (void) const {return m_UsingSSL;}
BOOL DoEHLOCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoRSETCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoQUITCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSTARTTLSCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSASLCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoMAILCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoRCPTCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoDATACommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoBDATCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSSLNegotiation(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSASLNegotiation(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoTURNCommand(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL WaitForRSETResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL WaitForQuitResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL WaitForConnectResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL ProcessReadIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
BOOL ProcessFileIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
BOOL ProcessWriteIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
BOOL ProcessTransmitFileIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
BOOL DoDATACommandEx(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoETRNCommand(void);
BOOL FormatSmtpMessage(FORMAT_SMTP_MESSAGE_LOGLEVEL eLogLevel,
IN const char * Format, ...);
BOOL FormatBinaryBlob(IN PBYTE pbBlob, IN DWORD cbSize);
//BOOL PipelineRecipients(void);
BOOL AddRcptsDsns(DWORD NotifyOptions, char * OrcptVal, char * AddrBuf, int& AddrSize);
//BOOL CheckPipelinedAnswers (char * Buffer, DWORD BufSize, LPDWORD LastSize, DWORD UndecryptedTailSize);
char * GetConnectedDomain(void) const {return (char *) m_ConnectedDomain;}
BOOL GetConnectionStatus(void) const {return m_Active;}
BOOL TransmitFileEx (HANDLE hFile, LARGE_INTEGER &liSize,
DWORD Offset, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers);
BOOL GoToWaitForConnectResponseState(void);
BOOL GetNextTURNConnection(void);
BOOL UnMarkHandledRcpts(void);
PSMTP_SERVER_INSTANCE QuerySmtpInstance( VOID ) const
{ _ASSERT(m_pInstance != NULL); return m_pInstance; }
BOOL IsSmtpInstance( VOID ) const
{ return m_pInstance != NULL; }
VOID SetSmtpInstance( IN PSMTP_SERVER_INSTANCE pInstance )
{ _ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }
void SetTurnList(IN PTURN_DOMAIN_LIST pTurnList)
{ m_pmszTurnList = pTurnList->pmsz; m_szCurrentTURNDomain = pTurnList->szCurrentDomain;}
void ProtocolLogCommand(LPSTR pszCommand,
DWORD cParameters,
LPCSTR pszIpAddress,
FORMAT_SMTP_MESSAGE_LOGLEVEL eLogLevel);
void ProtocolLogResponse(LPSTR pszResponse,
DWORD cResponse,
LPCSTR pszIpAddress);
void LogRemoteDeliveryTransaction(
LPCSTR pszOperation,
LPCSTR pszTarget,
LPCSTR pszParameters,
LPCSTR pszIpAddress,
DWORD dwWin32Error,
DWORD dwServiceSpecificStatus,
DWORD dwBytesSent,
DWORD dwBytesRecieved,
BOOL fResponse
);
//
// These are overridden from the base CLIENT_CONNECTION class to support
// switching of receive buffers. We need to be able to switch buffers to
// support SSL, which needs upto 32K chunks. Note that even though SSL
// V3.0 restricts fragment sizes to 16K, our schannel is capable of
// generating 32K fragments (due to a bug). So, we read up to 32K.
//
virtual LPCSTR QueryRcvBuffer( VOID) const
{ return ((LPCSTR) m_precvBuffer); }
virtual LPSTR QueryMRcvBuffer(VOID) // modifiable string
{ return (LPSTR) m_precvBuffer; }
//
// This method causes this object to allocate 32K buffers and use them as
// the receive and output buffer.
//
BOOL SwitchToBigSSLBuffers();
static SMTP_CONNOUT * CreateSmtpConnection (
IN PSMTP_SERVER_INSTANCE pInstance,
IN SOCKET sClient,
IN const SOCKADDR_IN * psockAddrRemote,
IN const SOCKADDR_IN * psockAddrLocal /* = NULL */ ,
IN PATQ_CONTEXT pAtqContext /* = NULL */ ,
IN PVOID pvInitialRequest/* = NULL*/ ,
IN DWORD cbInitialData /* = 0 */ ,
IN DWORD Options /* = 0 */,
IN LPSTR pszSSLVerificationName);
//
// Protocol Events additions ...
//
public:
BOOL DoCompletedMessage(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSessionStartEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoMessageStartEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoPerRecipientEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoBeforeDataEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoSessionEndEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoEHLOResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoMAILResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoRCPTResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL DoContentResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
BOOL PE_FormatSmtpMessage(IN const char * Format, ...);
BOOL DecPendingIoCountEx(void);
void SetDnsRec(PSMTPDNS_RECS pDnsRec) {m_pDnsRec = pDnsRec;}
void SetConnectionStatus(DWORD dwConnectionStatus) {m_dwConnectionStatus = dwConnectionStatus;};
private:
typedef BOOL (SMTP_CONNOUT::*PMFI)(char * InputLine, DWORD InputLineSize, DWORD UndecryptedTailSize);
HRESULT GetNextResponse(
char *InputLine,
DWORD BufSize,
char **NextInputLine,
LPDWORD pRemainingBufSize,
DWORD UndecryptedTailSize
);
HRESULT BuildCommandQEntry(
LPOUTBOUND_COMMAND_Q_ENTRY *ppEntry,
BOOL *pfUseNative
);
HRESULT OnOutboundCommandEvent(
IUnknown *pServer,
IUnknown *pSession,
DWORD dwEventType,
BOOL fRepeatLastCommand,
PMFI pDefaultOutboundHandler
);
HRESULT OnServerResponseEvent(
IUnknown *pServer,
IUnknown *pSession,
PMFI pDefaultResponseHandler
);
BOOL GlueDispatch(
const char *InputLine,
DWORD ParameterSize,
DWORD UndecryptedTailSize,
DWORD dwOutboundEventType,
PMFI pDefaultOutboundHandler,
PMFI pDefaultResponseHandler,
LPSTR szDefaultResponseHandlerKeyword,
BOOL *pfDoneWithEvent,
BOOL *pfAbortEvent
);
IUnknown *GetSessionPropertyBag() { return((IUnknown *)(IMailMsgPropertyBag *)(&m_SessionPropertyBag)); }
private:
// BOOL m_fRsetBetweenMessages;
RSETCODE m_RsetReasonCode;
BOOL m_fNativeHandlerFired;
IEventRouter *m_pIEventRouter;
ISmtpOutboundCommandDispatcher *m_pOutboundDispatcher;
ISmtpServerResponseDispatcher *m_pResponseDispatcher;
CFifoQueue m_FifoQ;
COutboundContext m_OutboundContext;
CResponseContext m_ResponseContext;
CMailMsgPropertyBag m_SessionPropertyBag;
//
// End protocol events additions
//
private:
LASTIOSTATE m_LastClientIo;
char m_OutputBuffer[SMTP_MAX_REPLY_LENGTH];
char m_NativeCommandBuffer[SMTP_MAX_COMMAND_LENGTH];
DWORD m_OutputBufferSize;
DWORD m_cbMaxOutputBuffer;
DWORD m_cbMaxRecvBuffer;
DWORD m_cbParsable;
DWORD m_Error;
DWORD m_FileSize;
DWORD m_MsgOptions;
DWORD m_Flags;
DWORD m_AuthToUse;
DWORD m_NumRcptSent;
DWORD m_NumRcptSentSaved;
DWORD m_SizeOptionSize ;
DWORD m_NumFailedAddrs;
DWORD m_dwFileOffset;
LONG m_cActiveThreads;
LONG m_cPendingIoCount;
DWORD m_NextAddress;
DWORD m_FirstPipelinedAddress;
int m_First552Address;
DWORD m_NumRcpts;
DWORD m_FirstAddressinCurrentMail;
DWORD *m_RcptIndexList;
PFIO_CONTEXT m_IMsgFileHandle;
PFIO_CONTEXT m_IMsgDotStuffedFileHandle;
ISMTPConnection * m_pISMTPConnection;
PSMTPDNS_RECS m_pDnsRec;
PMFI m_NextState;
BOOL m_HeloSent;
BOOL m_EhloSent;
BOOL m_EhloFailed;
BOOL m_FirstRcpt;
BOOL m_SendAgain;
BOOL m_SecurePort;
BOOL m_fNegotiatingSSL;
BOOL m_UsingSSL;
BOOL m_HaveDataResponse;
BOOL m_fUseMbsCta;
BOOL m_Active;
BOOL m_fUseBDAT;
BOOL m_bComplete;
BOOL m_fCanTurn;
IMailMsgProperties *m_pIMsg;
IMailMsgRecipients *m_pIMsgRecips;
IMailMsgBind *m_pBindInterface;
PVOID m_AdvContext;
char m_TransmitTailBuffer [5];
char m_ConnectedDomain[MAX_INTERNET_NAME + 1];
TRANSMIT_FILE_BUFFERS m_TransmitBuffers;
TLS_ACTIONS m_TlsState;
PSMTP_SERVER_INSTANCE m_pInstance;
CEncryptCtx m_encryptCtx;
CSecurityCtx m_securityCtx;
HANDLE m_hFile;
TCP_AUTHENT_INFO AuthInfoStruct;
char m_szAuthPackage[64];
char *m_precvBuffer;
char *m_pOutputBuffer;
DWORD m_dwConnectionStatus;
LPSTR m_pszSSLVerificationName;
SERVEREVENT_OVERLAPPED m_SeoOverlapped;
//Turn related data - pointer to a MULTISZ containing all the domain names
//to be turned on this connection and a pointer into the Multisz for the
//current domain being turned
MULTISZ *m_pmszTurnList;
const char *m_szCurrentTURNDomain;
//Keeps track of current place in domains to issue ETRN for
const char *m_szCurrentETRNDomain;
//Connection failure diagnostic information - 2/18/99 MikeSwa
//This additional information is designed to be used as user-level
//diagnostic information. It is reported back to Aqueue which
//will expose it via the QAPI or event logs
//HRESULT can be E_FAIL, S_OK, or specific error from mc files
HRESULT m_hrDiagnosticError;
LPCSTR m_szDiagnosticVerb; //failed protocol VERB
CHAR m_szDiagnosticResponse[100]; //response from remote server
//DSN related
BOOL m_fNeedRelayedDSN;
BOOL m_fHadHardError;
BOOL m_fHadTempError;
BOOL m_fHadSuccessfulDelivery;
SMTP_CONNOUT(
IN PSMTP_SERVER_INSTANCE pInstance,
IN SOCKET sClient,
IN const SOCKADDR_IN * psockAddrRemote,
IN const SOCKADDR_IN * psockAddrLocal = NULL,
IN PATQ_CONTEXT pAtqContext = NULL,
IN PVOID pvInitialRequest = NULL,
IN DWORD cbInitialData = 0);
BOOL InitializeObject (DWORD Options, LPSTR pszSSLVerificationName);
BOOL DecryptInputBuffer ();
BOOL MessageReadFile(void);
void FreeAtqFileContext(void);
BOOL GetEhloOptions(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize, BOOL fIsHelo);
void ShrinkBuffer(char * StartPosition, DWORD SizeToMove)
{
MoveMemory ((void *)QueryMRcvBuffer(), StartPosition, SizeToMove);
}
void SetIMsgConnObj(ISMTPConnection * ISMTPConnObj) {m_pISMTPConnection = ISMTPConnObj;}
void SetNextStateEx(PMFI NextState, DWORD Timeout)
{
AtqContextSetInfo(m_pAtqContext, ATQ_INFO_TIMEOUT, Timeout);
m_NextState = NextState;
}
void SetNextState(PMFI NextState)
{
m_NextState = NextState;
}
void SetDiagnosticInfo(IN HRESULT hrDiagnosticError,
IN LPCSTR szDiagnosticVerb,
IN LPCSTR szDiagnosticResponse);
BOOL IsOptionSet(DWORD Option) {return ((m_Flags & Option) == Option);}
BOOL SaveToErrorFile(char * Buffer, DWORD BufSize);
void HandleCompletedMailObj(DWORD MsgStatus, char * szExtendedStatus, DWORD cbExtendedStatus);
void SendRemainingRecipients (void);
LONG IncPendingIoCount(void) { return InterlockedIncrement( &m_cPendingIoCount ); }
LONG DecPendingIoCount(void) { return InterlockedDecrement( &m_cPendingIoCount ); }
LONG IncThreadCount(void) { return InterlockedIncrement( &m_cActiveThreads ); }
LONG DecThreadCount(void) { return InterlockedDecrement( &m_cActiveThreads ); }
BOOL ValidateSSLCertificate ();
};
#endif
/************************ End of File ***********************/