Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

501 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name :
  4. smtpout.hxx
  5. Abstract:
  6. This module defines the SMTP_CONNOUT class.
  7. This object maintains information about a new client connection
  8. Author:
  9. Rohan Phillips ( Rohanp ) 11-Dec-1995
  10. Project:
  11. SMTP Server DLL
  12. Revision History:
  13. --*/
  14. #ifndef _SMTP_OUT_HXX_
  15. #define _SMTP_OUT_HXX_
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. #include "smtpcli.hxx"
  20. #include "conn.hxx"
  21. #include "simssl2.h"
  22. //
  23. // Protocl Events
  24. //
  25. #include "pe_out.hxx"
  26. #include <smtpevent.h>
  27. #include "pe_supp.hxx"
  28. #include "pe_disp.h"
  29. //
  30. // Forward for IEventRouter
  31. //
  32. interface IEventRouter;
  33. //
  34. // Redefine the type to indicate that this is a call-back function
  35. //
  36. typedef ATQ_COMPLETION PFN_ATQ_COMPLETION;
  37. /************************************************************
  38. * Symbolic Constants
  39. ************************************************************/
  40. #define SIZE_OPTION 0x00000001
  41. #define PIPELINE_OPTION 0x00000002
  42. #define EBITMIME_OPTION 0x00000004
  43. #define SMARTHOST_OPTION 0x00000008
  44. #define DSN_OPTION 0x00000010
  45. #define TLS_OPTION 0x00000020
  46. #define AUTH_NTLM 0x00000040
  47. #define AUTH_CLEARTEXT 0x00000080
  48. #define ETRN_SENT 0x00000100
  49. #define ETRN_OPTION 0x00000200
  50. #define SASL_OPTION 0x00000400
  51. #define CHUNKING_OPTION 0x00000800
  52. #define BINMIME_OPTION 0x00001000
  53. #define ENHANCEDSTATUSCODE_OPTION 0x00002000
  54. #define AUTH_GSSAPI 0x00004000
  55. #define AUTH_DIGEST 0x00008000
  56. #define ETRN_ONLY_OPTION 0x00010000
  57. #define STARTTLS_OPTION 0x00020000
  58. #define EMPTY_CONNECTION_OPTION 0x00040000
  59. #define TURN_ONLY_OPTION 0x00080000
  60. const DWORD SMTP_MAX_REPLY_LENGTH = 4096;
  61. const DWORD SMTP_MAX_COMMAND_LENGTH = 512;
  62. const char CONTINUATION_CHAR = (char) '-';
  63. #define SMTP_PRELIMINARY_SUCCESS (char) '1'
  64. #define SMTP_COMPLETE_SUCCESS (char) '2'
  65. #define SMTP_INTERMEDIATE_SUCCESS (char) '3'
  66. #define SMTP_TRANSIENT_FAILURE (char) '4'
  67. #define SMTP_COMPLETE_FAILURE (char) '5'
  68. #define KNOWN_AUTH_FLAGS ((DWORD)(DOMAIN_INFO_USE_NTLM | DOMAIN_INFO_USE_PLAINTEXT | DOMAIN_INFO_USE_DPA \
  69. | DOMAIN_INFO_USE_KERBEROS))
  70. enum RSETCODE
  71. {
  72. NO_SMTP_ERROR, BETWEEN_MSG, NO_RCPTS_SENT, ALL_RCPTS_FAILED, FATAL_ERROR
  73. };
  74. /************************************************************
  75. * Type Definitions
  76. ************************************************************/
  77. enum FORMAT_SMTP_MESSAGE_LOGLEVEL {
  78. FSM_LOG_ALL,
  79. FSM_LOG_VERB_ONLY,
  80. FSM_LOG_NONE
  81. };
  82. enum TLS_ACTIONS {DONT_DO_TLS, MUST_DO_TLS, STARTTLS_SENT, SSL_NEG, CHANNEL_SECURE};
  83. class SMTP_CONNOUT;
  84. /*++
  85. class SMTP_CONNOUT
  86. This class is used for keeping track of individual client
  87. connections established with the server.
  88. It maintains the state of the connection being processed.
  89. --*/
  90. class SMTP_CONNOUT :
  91. public CLIENT_CONNECTION
  92. {
  93. public:
  94. enum LASTIOSTATE {READIO, WRITEIO, TRANSFILEIO};
  95. static CPool Pool;
  96. // override the mem functions to use CPool functions
  97. void *operator new (size_t cSize)
  98. { return Pool.Alloc(); }
  99. void operator delete (void *pInstance)
  100. { Pool.Free(pInstance); }
  101. ~SMTP_CONNOUT(void);
  102. VOID DisconnectClient( IN DWORD dwErrorCode = NO_ERROR);
  103. BOOL SendSmtpResponse(BOOL SyncSend = TRUE);
  104. virtual BOOL ProcessClient( IN DWORD cbWritten,
  105. IN DWORD dwCompletionStatus,
  106. IN OUT OVERLAPPED * lpo);
  107. BOOL IsNTLMSupported(void) {return ((m_Flags & AUTH_NTLM) == AUTH_NTLM);}
  108. BOOL IsClearTextSupported(void) {return ((m_Flags & AUTH_CLEARTEXT) == AUTH_CLEARTEXT);}
  109. BOOL IsUsingSASL(void) {return ((m_Flags & SASL_OPTION) == SASL_OPTION);}
  110. void SetCarrierOption(DWORD NewOption){ m_Flags |= NewOption;}
  111. void SetCurrentObjectToNull(void) { m_pISMTPConnection = NULL;}
  112. void SetCurrentObject(ISMTPConnection * pISMTPConnection)
  113. {
  114. m_pISMTPConnection = pISMTPConnection;
  115. }
  116. BOOL ConnectToNextIpAddress(void);
  117. void SetConnectedDomain(const char * RealDomain)
  118. {
  119. lstrcpyn(m_ConnectedDomain, RealDomain, MAX_INTERNET_NAME);
  120. }
  121. virtual BOOL StartSession( VOID);
  122. BOOL ReStartSession(void);
  123. BOOL IsSecure (void) const {return m_UsingSSL;}
  124. BOOL DoEHLOCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  125. BOOL DoRSETCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  126. BOOL DoQUITCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  127. BOOL DoSTARTTLSCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  128. BOOL DoSASLCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  129. BOOL DoMAILCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  130. BOOL DoRCPTCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  131. BOOL DoDATACommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  132. BOOL DoBDATCommand(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  133. BOOL DoSSLNegotiation(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  134. BOOL DoSASLNegotiation(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  135. BOOL DoTURNCommand(char *InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  136. BOOL WaitForRSETResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  137. BOOL WaitForQuitResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  138. BOOL WaitForConnectResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  139. BOOL ProcessReadIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
  140. BOOL ProcessFileIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
  141. BOOL ProcessWriteIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
  142. BOOL ProcessTransmitFileIO (IN DWORD InputBufferLen, IN DWORD dwCompletionStatus, IN OUT OVERLAPPED * lpo);
  143. BOOL DoDATACommandEx(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  144. BOOL DoETRNCommand(void);
  145. BOOL FormatSmtpMessage(FORMAT_SMTP_MESSAGE_LOGLEVEL eLogLevel,
  146. IN const char * Format, ...);
  147. BOOL FormatBinaryBlob(IN PBYTE pbBlob, IN DWORD cbSize);
  148. //BOOL PipelineRecipients(void);
  149. BOOL AddRcptsDsns(DWORD NotifyOptions, char * OrcptVal, char * AddrBuf, int& AddrSize);
  150. //BOOL CheckPipelinedAnswers (char * Buffer, DWORD BufSize, LPDWORD LastSize, DWORD UndecryptedTailSize);
  151. char * GetConnectedDomain(void) const {return (char *) m_ConnectedDomain;}
  152. BOOL GetConnectionStatus(void) const {return m_Active;}
  153. BOOL TransmitFileEx (HANDLE hFile, LARGE_INTEGER &liSize,
  154. DWORD Offset, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers);
  155. BOOL GoToWaitForConnectResponseState(void);
  156. BOOL GetNextTURNConnection(void);
  157. BOOL UnMarkHandledRcpts(void);
  158. PSMTP_SERVER_INSTANCE QuerySmtpInstance( VOID ) const
  159. { _ASSERT(m_pInstance != NULL); return m_pInstance; }
  160. BOOL IsSmtpInstance( VOID ) const
  161. { return m_pInstance != NULL; }
  162. VOID SetSmtpInstance( IN PSMTP_SERVER_INSTANCE pInstance )
  163. { _ASSERT(m_pInstance == NULL); m_pInstance = pInstance; }
  164. void SetTurnList(IN PTURN_DOMAIN_LIST pTurnList)
  165. { m_pmszTurnList = pTurnList->pmsz; m_szCurrentTURNDomain = pTurnList->szCurrentDomain;}
  166. void ProtocolLogCommand(LPSTR pszCommand,
  167. DWORD cParameters,
  168. LPCSTR pszIpAddress,
  169. FORMAT_SMTP_MESSAGE_LOGLEVEL eLogLevel);
  170. void ProtocolLogResponse(LPSTR pszResponse,
  171. DWORD cResponse,
  172. LPCSTR pszIpAddress);
  173. void LogRemoteDeliveryTransaction(
  174. LPCSTR pszOperation,
  175. LPCSTR pszTarget,
  176. LPCSTR pszParameters,
  177. LPCSTR pszIpAddress,
  178. DWORD dwWin32Error,
  179. DWORD dwServiceSpecificStatus,
  180. DWORD dwBytesSent,
  181. DWORD dwBytesRecieved,
  182. BOOL fResponse
  183. );
  184. //
  185. // These are overridden from the base CLIENT_CONNECTION class to support
  186. // switching of receive buffers. We need to be able to switch buffers to
  187. // support SSL, which needs upto 32K chunks. Note that even though SSL
  188. // V3.0 restricts fragment sizes to 16K, our schannel is capable of
  189. // generating 32K fragments (due to a bug). So, we read up to 32K.
  190. //
  191. virtual LPCSTR QueryRcvBuffer( VOID) const
  192. { return ((LPCSTR) m_precvBuffer); }
  193. virtual LPSTR QueryMRcvBuffer(VOID) // modifiable string
  194. { return (LPSTR) m_precvBuffer; }
  195. //
  196. // This method causes this object to allocate 32K buffers and use them as
  197. // the receive and output buffer.
  198. //
  199. BOOL SwitchToBigSSLBuffers();
  200. static SMTP_CONNOUT * CreateSmtpConnection (
  201. IN PSMTP_SERVER_INSTANCE pInstance,
  202. IN SOCKET sClient,
  203. IN const SOCKADDR_IN * psockAddrRemote,
  204. IN const SOCKADDR_IN * psockAddrLocal /* = NULL */ ,
  205. IN PATQ_CONTEXT pAtqContext /* = NULL */ ,
  206. IN PVOID pvInitialRequest/* = NULL*/ ,
  207. IN DWORD cbInitialData /* = 0 */ ,
  208. IN DWORD Options /* = 0 */,
  209. IN LPSTR pszSSLVerificationName);
  210. //
  211. // Protocol Events additions ...
  212. //
  213. public:
  214. BOOL DoCompletedMessage(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  215. BOOL DoSessionStartEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  216. BOOL DoMessageStartEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  217. BOOL DoPerRecipientEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  218. BOOL DoBeforeDataEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  219. BOOL DoSessionEndEvent(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  220. BOOL DoEHLOResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  221. BOOL DoMAILResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  222. BOOL DoRCPTResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  223. BOOL DoContentResponse(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize);
  224. BOOL PE_FormatSmtpMessage(IN const char * Format, ...);
  225. BOOL DecPendingIoCountEx(void);
  226. void SetDnsRec(PSMTPDNS_RECS pDnsRec) {m_pDnsRec = pDnsRec;}
  227. void SetConnectionStatus(DWORD dwConnectionStatus) {m_dwConnectionStatus = dwConnectionStatus;};
  228. private:
  229. typedef BOOL (SMTP_CONNOUT::*PMFI)(char * InputLine, DWORD InputLineSize, DWORD UndecryptedTailSize);
  230. HRESULT GetNextResponse(
  231. char *InputLine,
  232. DWORD BufSize,
  233. char **NextInputLine,
  234. LPDWORD pRemainingBufSize,
  235. DWORD UndecryptedTailSize
  236. );
  237. HRESULT BuildCommandQEntry(
  238. LPOUTBOUND_COMMAND_Q_ENTRY *ppEntry,
  239. BOOL *pfUseNative
  240. );
  241. HRESULT OnOutboundCommandEvent(
  242. IUnknown *pServer,
  243. IUnknown *pSession,
  244. DWORD dwEventType,
  245. BOOL fRepeatLastCommand,
  246. PMFI pDefaultOutboundHandler
  247. );
  248. HRESULT OnServerResponseEvent(
  249. IUnknown *pServer,
  250. IUnknown *pSession,
  251. PMFI pDefaultResponseHandler
  252. );
  253. BOOL GlueDispatch(
  254. const char *InputLine,
  255. DWORD ParameterSize,
  256. DWORD UndecryptedTailSize,
  257. DWORD dwOutboundEventType,
  258. PMFI pDefaultOutboundHandler,
  259. PMFI pDefaultResponseHandler,
  260. LPSTR szDefaultResponseHandlerKeyword,
  261. BOOL *pfDoneWithEvent,
  262. BOOL *pfAbortEvent
  263. );
  264. IUnknown *GetSessionPropertyBag() { return((IUnknown *)(IMailMsgPropertyBag *)(&m_SessionPropertyBag)); }
  265. private:
  266. // BOOL m_fRsetBetweenMessages;
  267. RSETCODE m_RsetReasonCode;
  268. BOOL m_fNativeHandlerFired;
  269. IEventRouter *m_pIEventRouter;
  270. ISmtpOutboundCommandDispatcher *m_pOutboundDispatcher;
  271. ISmtpServerResponseDispatcher *m_pResponseDispatcher;
  272. CFifoQueue m_FifoQ;
  273. COutboundContext m_OutboundContext;
  274. CResponseContext m_ResponseContext;
  275. CMailMsgPropertyBag m_SessionPropertyBag;
  276. //
  277. // End protocol events additions
  278. //
  279. private:
  280. LASTIOSTATE m_LastClientIo;
  281. char m_OutputBuffer[SMTP_MAX_REPLY_LENGTH];
  282. char m_NativeCommandBuffer[SMTP_MAX_COMMAND_LENGTH];
  283. DWORD m_OutputBufferSize;
  284. DWORD m_cbMaxOutputBuffer;
  285. DWORD m_cbMaxRecvBuffer;
  286. DWORD m_cbParsable;
  287. DWORD m_Error;
  288. DWORD m_FileSize;
  289. DWORD m_MsgOptions;
  290. DWORD m_Flags;
  291. DWORD m_AuthToUse;
  292. DWORD m_NumRcptSent;
  293. DWORD m_NumRcptSentSaved;
  294. DWORD m_SizeOptionSize ;
  295. DWORD m_NumFailedAddrs;
  296. DWORD m_dwFileOffset;
  297. LONG m_cActiveThreads;
  298. LONG m_cPendingIoCount;
  299. DWORD m_NextAddress;
  300. DWORD m_FirstPipelinedAddress;
  301. int m_First552Address;
  302. DWORD m_NumRcpts;
  303. DWORD m_FirstAddressinCurrentMail;
  304. DWORD *m_RcptIndexList;
  305. PFIO_CONTEXT m_IMsgFileHandle;
  306. PFIO_CONTEXT m_IMsgDotStuffedFileHandle;
  307. ISMTPConnection * m_pISMTPConnection;
  308. PSMTPDNS_RECS m_pDnsRec;
  309. PMFI m_NextState;
  310. BOOL m_HeloSent;
  311. BOOL m_EhloSent;
  312. BOOL m_EhloFailed;
  313. BOOL m_FirstRcpt;
  314. BOOL m_SendAgain;
  315. BOOL m_SecurePort;
  316. BOOL m_fNegotiatingSSL;
  317. BOOL m_UsingSSL;
  318. BOOL m_HaveDataResponse;
  319. BOOL m_fUseMbsCta;
  320. BOOL m_Active;
  321. BOOL m_fUseBDAT;
  322. BOOL m_bComplete;
  323. BOOL m_fCanTurn;
  324. IMailMsgProperties *m_pIMsg;
  325. IMailMsgRecipients *m_pIMsgRecips;
  326. IMailMsgBind *m_pBindInterface;
  327. PVOID m_AdvContext;
  328. char m_TransmitTailBuffer [5];
  329. char m_ConnectedDomain[MAX_INTERNET_NAME + 1];
  330. TRANSMIT_FILE_BUFFERS m_TransmitBuffers;
  331. TLS_ACTIONS m_TlsState;
  332. PSMTP_SERVER_INSTANCE m_pInstance;
  333. CEncryptCtx m_encryptCtx;
  334. CSecurityCtx m_securityCtx;
  335. HANDLE m_hFile;
  336. TCP_AUTHENT_INFO AuthInfoStruct;
  337. char m_szAuthPackage[64];
  338. char *m_precvBuffer;
  339. char *m_pOutputBuffer;
  340. DWORD m_dwConnectionStatus;
  341. LPSTR m_pszSSLVerificationName;
  342. SERVEREVENT_OVERLAPPED m_SeoOverlapped;
  343. //Turn related data - pointer to a MULTISZ containing all the domain names
  344. //to be turned on this connection and a pointer into the Multisz for the
  345. //current domain being turned
  346. MULTISZ *m_pmszTurnList;
  347. const char *m_szCurrentTURNDomain;
  348. //Keeps track of current place in domains to issue ETRN for
  349. const char *m_szCurrentETRNDomain;
  350. //Connection failure diagnostic information - 2/18/99 MikeSwa
  351. //This additional information is designed to be used as user-level
  352. //diagnostic information. It is reported back to Aqueue which
  353. //will expose it via the QAPI or event logs
  354. //HRESULT can be E_FAIL, S_OK, or specific error from mc files
  355. HRESULT m_hrDiagnosticError;
  356. LPCSTR m_szDiagnosticVerb; //failed protocol VERB
  357. CHAR m_szDiagnosticResponse[100]; //response from remote server
  358. //DSN related
  359. BOOL m_fNeedRelayedDSN;
  360. BOOL m_fHadHardError;
  361. BOOL m_fHadTempError;
  362. BOOL m_fHadSuccessfulDelivery;
  363. SMTP_CONNOUT(
  364. IN PSMTP_SERVER_INSTANCE pInstance,
  365. IN SOCKET sClient,
  366. IN const SOCKADDR_IN * psockAddrRemote,
  367. IN const SOCKADDR_IN * psockAddrLocal = NULL,
  368. IN PATQ_CONTEXT pAtqContext = NULL,
  369. IN PVOID pvInitialRequest = NULL,
  370. IN DWORD cbInitialData = 0);
  371. BOOL InitializeObject (DWORD Options, LPSTR pszSSLVerificationName);
  372. BOOL DecryptInputBuffer ();
  373. BOOL MessageReadFile(void);
  374. void FreeAtqFileContext(void);
  375. BOOL GetEhloOptions(char * InputLine, DWORD ParameterSize, DWORD UndecryptedTailSize, BOOL fIsHelo);
  376. void ShrinkBuffer(char * StartPosition, DWORD SizeToMove)
  377. {
  378. MoveMemory ((void *)QueryMRcvBuffer(), StartPosition, SizeToMove);
  379. }
  380. void SetIMsgConnObj(ISMTPConnection * ISMTPConnObj) {m_pISMTPConnection = ISMTPConnObj;}
  381. void SetNextStateEx(PMFI NextState, DWORD Timeout)
  382. {
  383. AtqContextSetInfo(m_pAtqContext, ATQ_INFO_TIMEOUT, Timeout);
  384. m_NextState = NextState;
  385. }
  386. void SetNextState(PMFI NextState)
  387. {
  388. m_NextState = NextState;
  389. }
  390. void SetDiagnosticInfo(IN HRESULT hrDiagnosticError,
  391. IN LPCSTR szDiagnosticVerb,
  392. IN LPCSTR szDiagnosticResponse);
  393. BOOL IsOptionSet(DWORD Option) {return ((m_Flags & Option) == Option);}
  394. BOOL SaveToErrorFile(char * Buffer, DWORD BufSize);
  395. void HandleCompletedMailObj(DWORD MsgStatus, char * szExtendedStatus, DWORD cbExtendedStatus);
  396. void SendRemainingRecipients (void);
  397. LONG IncPendingIoCount(void) { return InterlockedIncrement( &m_cPendingIoCount ); }
  398. LONG DecPendingIoCount(void) { return InterlockedDecrement( &m_cPendingIoCount ); }
  399. LONG IncThreadCount(void) { return InterlockedIncrement( &m_cActiveThreads ); }
  400. LONG DecThreadCount(void) { return InterlockedDecrement( &m_cActiveThreads ); }
  401. BOOL ValidateSSLCertificate ();
  402. };
  403. #endif
  404. /************************ End of File ***********************/