|
|
/*++
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 ***********************/
|