Leaked source code of windows server 2003
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.

2329 lines
69 KiB

  1. // --------------------------------------------------------------------------------
  2. // Ixpsmtp.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "dllmain.h"
  8. #include "asynconn.h"
  9. #include "ixpsmtp.h"
  10. #include "ixputil.h"
  11. #include "strconst.h"
  12. #include <shlwapi.h>
  13. #include <demand.h>
  14. // --------------------------------------------------------------------------------
  15. // Useful C++ pointer casting
  16. // --------------------------------------------------------------------------------
  17. #define SMTPTHISIXP ((ISMTPTransport *)(CIxpBase *)this)
  18. // --------------------------------------------------------------------------------
  19. // Some string constants
  20. // --------------------------------------------------------------------------------
  21. // These constants are from the draft spec for SMTP authenication
  22. // draft-myers-smtp-auth-11.txt
  23. static const char g_szSMTPAUTH11[] = "AUTH ";
  24. static const int g_cchSMTPAUTH11 = sizeof(g_szSMTPAUTH11) - 1;
  25. // These constants are from the draft spec for SMTP authenication
  26. // draft-myers-smtp-auth-10.txt
  27. static const char g_szSMTPAUTH10[] = "AUTH=";
  28. static const int g_cchSMTPAUTH10 = sizeof(g_szSMTPAUTH10) - 1;
  29. // These constants are from the draft spec for Secure SMTP over TLS
  30. // draft-hoffman-smtp-ssl-08.txt
  31. static const char g_szSMTPSTARTTLS08[] = "STARTTLS";
  32. static const int g_cchSMTPSTARTTLS08 = sizeof(g_szSMTPSTARTTLS08) - 1;
  33. // These constants are from the draft spec for Secure SMTP over TLS
  34. // draft-hoffman-smtp-ssl-06.txt
  35. static const char g_szSMTPSTARTTLS06[] = "TLS";
  36. static const int g_cchSMTPSTARTTLS06 = sizeof(g_szSMTPSTARTTLS06) - 1;
  37. // These constants are from RFC1891 for DSN support
  38. static const char g_szSMTPDSN[] = "DSN";
  39. static const int g_cchSMTPDSN = sizeof(g_szSMTPDSN) - 1;
  40. static const char g_szDSNENVID[] = "ENVID=";
  41. static const char g_szDSNRET[] = "RET=";
  42. static const char g_szDSNHDRS[] = "HDRS";
  43. static const char g_szDSNFULL[] = "FULL";
  44. static const char g_szDSNNOTIFY[] = "NOTIFY=";
  45. static const char g_szDSNNEVER[] = "NEVER";
  46. static const char g_szDSNSUCCESS[] = "SUCCESS";
  47. static const char g_szDSNFAILURE[] = "FAILURE";
  48. static const char g_szDSNDELAY[] = "DELAY";
  49. // --------------------------------------------------------------------------------
  50. // CSMTPTransport::CSMTPTransport
  51. // --------------------------------------------------------------------------------
  52. CSMTPTransport::CSMTPTransport(void) : CIxpBase(IXP_SMTP)
  53. {
  54. DllAddRef();
  55. m_command = SMTP_NONE;
  56. m_iAddress = 0;
  57. m_cRecipients = 0;
  58. m_cbSent = 0;
  59. m_cbTotal = 0;
  60. m_fReset = FALSE;
  61. m_fSendMessage = FALSE;
  62. m_fSTARTTLSAvail = FALSE;
  63. m_fTLSNegotiation = FALSE;
  64. m_fSecured = FALSE;
  65. *m_szEmail = '\0';
  66. m_pszResponse = NULL;
  67. ZeroMemory(&m_rAuth, sizeof(m_rAuth));
  68. ZeroMemory(&m_rMessage, sizeof(SMTPMESSAGE2));
  69. m_fDSNAvail= FALSE;
  70. }
  71. // --------------------------------------------------------------------------------
  72. // CSMTPTransport::~CSMTPTransport
  73. // --------------------------------------------------------------------------------
  74. CSMTPTransport::~CSMTPTransport(void)
  75. {
  76. ResetBase();
  77. DllRelease();
  78. }
  79. // --------------------------------------------------------------------------------
  80. // CSMTPTransport::ResetBase
  81. // --------------------------------------------------------------------------------
  82. void CSMTPTransport::ResetBase(void)
  83. {
  84. EnterCriticalSection(&m_cs);
  85. FreeAuthInfo(&m_rAuth);
  86. m_command = SMTP_NONE;
  87. m_fSendMessage = FALSE;
  88. m_iAddress = 0;
  89. m_cRecipients = 0;
  90. m_cbSent = 0;
  91. m_fSTARTTLSAvail = FALSE;
  92. m_fTLSNegotiation = FALSE;
  93. m_fSecured = FALSE;
  94. SafeRelease(m_rMessage.smtpMsg.pstmMsg);
  95. SafeMemFree(m_rMessage.smtpMsg.rAddressList.prgAddress);
  96. SafeMemFree(m_rMessage.pszDSNENVID);
  97. ZeroMemory(&m_rMessage, sizeof(SMTPMESSAGE2));
  98. m_fDSNAvail= FALSE;
  99. LeaveCriticalSection(&m_cs);
  100. }
  101. // --------------------------------------------------------------------------------
  102. // CSMTPTransport::QueryInterface
  103. // --------------------------------------------------------------------------------
  104. STDMETHODIMP CSMTPTransport::QueryInterface(REFIID riid, LPVOID *ppv)
  105. {
  106. // Locals
  107. HRESULT hr=S_OK;
  108. // Bad param
  109. if (ppv == NULL)
  110. {
  111. hr = TrapError(E_INVALIDARG);
  112. goto exit;
  113. }
  114. // Init
  115. *ppv=NULL;
  116. // IID_IUnknown
  117. if (IID_IUnknown == riid)
  118. *ppv = ((IUnknown *)(ISMTPTransport2 *)this);
  119. // IID_IInternetTransport
  120. else if (IID_IInternetTransport == riid)
  121. *ppv = ((IInternetTransport *)(CIxpBase *)this);
  122. // IID_ISMTPTransport
  123. else if (IID_ISMTPTransport == riid)
  124. *ppv = (ISMTPTransport *)this;
  125. // IID_ISMTPTransport2
  126. else if (IID_ISMTPTransport2 == riid)
  127. *ppv = (ISMTPTransport2 *)this;
  128. // If not null, addref it and return
  129. if (NULL != *ppv)
  130. {
  131. ((LPUNKNOWN)*ppv)->AddRef();
  132. goto exit;
  133. }
  134. // No Interface
  135. hr = TrapError(E_NOINTERFACE);
  136. exit:
  137. // Done
  138. return hr;
  139. }
  140. // --------------------------------------------------------------------------------
  141. // CSMTPTransport::AddRef
  142. // --------------------------------------------------------------------------------
  143. STDMETHODIMP_(ULONG) CSMTPTransport::AddRef(void)
  144. {
  145. return ++m_cRef;
  146. }
  147. // --------------------------------------------------------------------------------
  148. // CSMTPTransport::Release
  149. // --------------------------------------------------------------------------------
  150. STDMETHODIMP_(ULONG) CSMTPTransport::Release(void)
  151. {
  152. if (0 != --m_cRef)
  153. return m_cRef;
  154. delete this;
  155. return 0;
  156. }
  157. // --------------------------------------------------------------------------------
  158. // CSMTPTransport::HandsOffCallback
  159. // --------------------------------------------------------------------------------
  160. STDMETHODIMP CSMTPTransport::HandsOffCallback(void)
  161. {
  162. return CIxpBase::HandsOffCallback();
  163. }
  164. // --------------------------------------------------------------------------------
  165. // CSMTPTransport::GetStatus
  166. // --------------------------------------------------------------------------------
  167. STDMETHODIMP CSMTPTransport::GetStatus(IXPSTATUS *pCurrentStatus)
  168. {
  169. return CIxpBase::GetStatus(pCurrentStatus);
  170. }
  171. // --------------------------------------------------------------------------------
  172. // CSMTPTransport::InitNew
  173. // --------------------------------------------------------------------------------
  174. STDMETHODIMP CSMTPTransport::InitNew(LPSTR pszLogFilePath, ISMTPCallback *pCallback)
  175. {
  176. return CIxpBase::OnInitNew("SMTP", pszLogFilePath, FILE_SHARE_READ | FILE_SHARE_WRITE,
  177. (ITransportCallback *)pCallback);
  178. }
  179. // --------------------------------------------------------------------------------
  180. // CSMTPTransport::InetServerFromAccount
  181. // --------------------------------------------------------------------------------
  182. STDMETHODIMP CSMTPTransport::InetServerFromAccount(IImnAccount *pAccount, LPINETSERVER pInetServer)
  183. {
  184. return CIxpBase::InetServerFromAccount(pAccount, pInetServer);
  185. }
  186. // --------------------------------------------------------------------------------
  187. // CSMTPTransport::Connect
  188. // --------------------------------------------------------------------------------
  189. STDMETHODIMP CSMTPTransport::Connect(LPINETSERVER pInetServer, boolean fAuthenticate, boolean fCommandLogging)
  190. {
  191. // Check if user wants us to always prompt for password. Prompt before we connect
  192. // to avoid inactivity disconnections
  193. if (ISFLAGSET(pInetServer->dwFlags, ISF_ALWAYSPROMPTFORPASSWORD))
  194. {
  195. HRESULT hr;
  196. if (NULL != m_pCallback)
  197. hr = m_pCallback->OnLogonPrompt(pInetServer, SMTPTHISIXP);
  198. if (NULL == m_pCallback || S_OK != hr)
  199. return IXP_E_USER_CANCEL;
  200. }
  201. return CIxpBase::Connect(pInetServer, fAuthenticate, fCommandLogging);
  202. }
  203. // --------------------------------------------------------------------------------
  204. // CSMTPTransport::DropConnection
  205. // --------------------------------------------------------------------------------
  206. STDMETHODIMP CSMTPTransport::DropConnection(void)
  207. {
  208. return CIxpBase::DropConnection();
  209. }
  210. // --------------------------------------------------------------------------------
  211. // CSMTPTransport::Disconnect
  212. // --------------------------------------------------------------------------------
  213. STDMETHODIMP CSMTPTransport::Disconnect(void)
  214. {
  215. return CIxpBase::Disconnect();
  216. }
  217. // --------------------------------------------------------------------------------
  218. // CSMTPTransport::IsState
  219. // --------------------------------------------------------------------------------
  220. STDMETHODIMP CSMTPTransport::IsState(IXPISSTATE isstate)
  221. {
  222. return CIxpBase::IsState(isstate);
  223. }
  224. // --------------------------------------------------------------------------------
  225. // CSMTPTransport::GetServerInfo
  226. // --------------------------------------------------------------------------------
  227. STDMETHODIMP CSMTPTransport::GetServerInfo(LPINETSERVER pInetServer)
  228. {
  229. return CIxpBase::GetServerInfo(pInetServer);
  230. }
  231. // --------------------------------------------------------------------------------
  232. // CSMTPTransport::GetIXPType
  233. // --------------------------------------------------------------------------------
  234. STDMETHODIMP_(IXPTYPE) CSMTPTransport::GetIXPType(void)
  235. {
  236. return CIxpBase::GetIXPType();
  237. }
  238. // --------------------------------------------------------------------------------
  239. // CSMTPTransport::SendMessage
  240. // --------------------------------------------------------------------------------
  241. STDMETHODIMP CSMTPTransport::SendMessage(LPSMTPMESSAGE pMessage)
  242. {
  243. SMTPMESSAGE2 pMessage2= {0};
  244. pMessage2.smtpMsg= *pMessage;
  245. return SendMessage2(&pMessage2);
  246. }
  247. // --------------------------------------------------------------------------------
  248. // CSMTPTransport::SendMessage2
  249. // --------------------------------------------------------------------------------
  250. STDMETHODIMP CSMTPTransport::SendMessage2(LPSMTPMESSAGE2 pMessage)
  251. {
  252. // Locals
  253. HRESULT hr=S_OK;
  254. BOOL fDSNAvail= FALSE;
  255. // check params
  256. if (NULL == pMessage || NULL == pMessage->smtpMsg.pstmMsg)
  257. return TrapError(E_INVALIDARG);
  258. // Thread Safety
  259. EnterCriticalSection(&m_cs);
  260. // Enter Busy
  261. CHECKHR(hr = HrEnterBusy());
  262. // Zero Init Current State
  263. fDSNAvail = m_fDSNAvail; // save DSN state!
  264. ResetBase();
  265. m_fDSNAvail = fDSNAvail;
  266. // Special State in this transport
  267. m_fSendMessage = TRUE;
  268. // Copy Mesage
  269. m_rMessage.smtpMsg.pstmMsg = pMessage->smtpMsg.pstmMsg;
  270. m_rMessage.smtpMsg.pstmMsg->AddRef();
  271. // Copy the Address List
  272. m_rMessage.smtpMsg.rAddressList.cAddress = pMessage->smtpMsg.rAddressList.cAddress;
  273. CHECKHR(hr = HrAlloc((LPVOID *)&m_rMessage.smtpMsg.rAddressList.prgAddress, sizeof(INETADDR) * m_rMessage.smtpMsg.rAddressList.cAddress));
  274. CopyMemory(m_rMessage.smtpMsg.rAddressList.prgAddress, pMessage->smtpMsg.rAddressList.prgAddress, sizeof(INETADDR) * m_rMessage.smtpMsg.rAddressList.cAddress);
  275. // Copy the message Size
  276. m_rMessage.smtpMsg.cbSize = pMessage->smtpMsg.cbSize;
  277. // Copy DSN data
  278. if(pMessage->pszDSNENVID)
  279. {
  280. // ENVID max length is 100 characters
  281. ULONG cbAlloc= max(lstrlen(pMessage->pszDSNENVID) + 1, 101);
  282. CHECKALLOC(m_rMessage.pszDSNENVID = (LPSTR)g_pMalloc->Alloc(cbAlloc));
  283. StrCpyN(m_rMessage.pszDSNENVID, pMessage->pszDSNENVID, cbAlloc);
  284. }
  285. m_rMessage.dsnRet = pMessage->dsnRet;
  286. // Send RSET command (this initiates a send)
  287. if (m_fReset)
  288. {
  289. // Send the RSET command
  290. CHECKHR(hr = CommandRSET());
  291. }
  292. // Otherwise, start sending this message
  293. else
  294. {
  295. // Start sending this message
  296. SendMessage_MAIL();
  297. // A reset will be needed
  298. m_fReset = TRUE;
  299. }
  300. // return warning if client requested DSN but it isn't available
  301. if((m_rServer.dwFlags & ISF_QUERYDSNSUPPORT) && !m_fDSNAvail)
  302. hr= IXP_S_SMTP_NO_DSN_SUPPORT;
  303. exit:
  304. // Failure
  305. if (FAILED(hr))
  306. {
  307. ResetBase();
  308. LeaveBusy();
  309. }
  310. // Thread Safety
  311. LeaveCriticalSection(&m_cs);
  312. // Done
  313. return hr;
  314. }
  315. // --------------------------------------------------------------------------------
  316. // CSMTPTransport::OnNotify
  317. // --------------------------------------------------------------------------------
  318. void CSMTPTransport::OnNotify(ASYNCSTATE asOld, ASYNCSTATE asNew, ASYNCEVENT ae)
  319. {
  320. // Enter Critical Section
  321. EnterCriticalSection(&m_cs);
  322. switch(ae)
  323. {
  324. // --------------------------------------------------------------------------------
  325. case AE_RECV:
  326. OnSocketReceive();
  327. break;
  328. // --------------------------------------------------------------------------------
  329. case AE_SENDDONE:
  330. if (SMTP_SEND_STREAM == m_command)
  331. {
  332. // Leave Busy State
  333. LeaveBusy();
  334. // Send Dot Command
  335. HRESULT hr = CommandDOT();
  336. // Failure Causes Send Stream Response to finish
  337. if (FAILED(hr))
  338. SendStreamResponse(TRUE, hr, 0);
  339. }
  340. break;
  341. // --------------------------------------------------------------------------------
  342. case AE_WRITE:
  343. if (SMTP_DOT == m_command || SMTP_SEND_STREAM == m_command)
  344. SendStreamResponse(FALSE, S_OK, m_pSocket->UlGetSendByteCount());
  345. break;
  346. // --------------------------------------------------------------------------------
  347. default:
  348. CIxpBase::OnNotify(asOld, asNew, ae);
  349. break;
  350. }
  351. // Leave Critical Section
  352. LeaveCriticalSection(&m_cs);
  353. }
  354. // --------------------------------------------------------------------------------
  355. // CSMTPTransport::OnEnterBusy
  356. // --------------------------------------------------------------------------------
  357. void CSMTPTransport::OnEnterBusy(void)
  358. {
  359. IxpAssert(m_command == SMTP_NONE);
  360. }
  361. // --------------------------------------------------------------------------------
  362. // CSMTPTransport::OnLeaveBusy
  363. // --------------------------------------------------------------------------------
  364. void CSMTPTransport::OnLeaveBusy(void)
  365. {
  366. m_command = SMTP_NONE;
  367. }
  368. // --------------------------------------------------------------------------------
  369. // CSMTPTransport::OnConnected
  370. // --------------------------------------------------------------------------------
  371. void CSMTPTransport::OnConnected(void)
  372. {
  373. if (FALSE == m_fTLSNegotiation)
  374. {
  375. m_command = SMTP_BANNER;
  376. CIxpBase::OnConnected();
  377. }
  378. else
  379. {
  380. HRESULT hr = S_OK;
  381. CIxpBase::OnConnected();
  382. // Clear out the TLS state
  383. m_fSecured = TRUE;
  384. // Clear out info from the banner
  385. m_fSTARTTLSAvail = FALSE;
  386. FreeAuthInfo(&m_rAuth);
  387. // Performing auth
  388. if (m_fConnectAuth)
  389. {
  390. // If we aren't doing sicily authenication or querying DSN
  391. // then just send a HELO message
  392. if ((FALSE == m_rServer.fTrySicily) &&
  393. (0 == (m_rServer.dwFlags & ISF_QUERYAUTHSUPPORT)) &&
  394. (0 == (m_rServer.dwFlags & ISF_QUERYDSNSUPPORT)))
  395. {
  396. // Issue HELO
  397. hr = CommandHELO();
  398. if (FAILED(hr))
  399. {
  400. OnError(hr);
  401. DropConnection();
  402. }
  403. }
  404. else
  405. {
  406. // Issue EHLO
  407. hr = CommandEHLO();
  408. if (FAILED(hr))
  409. {
  410. OnError(hr);
  411. DropConnection();
  412. }
  413. }
  414. // We've finished doing negotiation
  415. m_fTLSNegotiation = FALSE;
  416. }
  417. // Otherwise, were connected, user can send HELO command
  418. else
  419. {
  420. m_command = SMTP_CONNECTED;
  421. DispatchResponse(S_OK, TRUE);
  422. }
  423. // Were not authenticated yet
  424. m_fAuthenticated = FALSE;
  425. }
  426. return;
  427. }
  428. // --------------------------------------------------------------------------------
  429. // CSMTPTransport::OnDisconnect
  430. // --------------------------------------------------------------------------------
  431. void CSMTPTransport::OnDisconnected(void)
  432. {
  433. ResetBase();
  434. m_fReset = FALSE;
  435. CIxpBase::OnDisconnected();
  436. }
  437. // --------------------------------------------------------------------------------
  438. // CSMTPTransport::OnSocketReceive
  439. // --------------------------------------------------------------------------------
  440. void CSMTPTransport::OnSocketReceive(void)
  441. {
  442. // Locals
  443. HRESULT hr=S_OK;
  444. // Enter Critical Section
  445. EnterCriticalSection(&m_cs);
  446. // Read Server Response...
  447. hr = HrGetResponse();
  448. if (IXP_E_INCOMPLETE == hr)
  449. goto exit;
  450. // Handle smtp state
  451. switch(m_command)
  452. {
  453. // --------------------------------------------------------------------------------
  454. case SMTP_BANNER:
  455. // Dispatch the Response
  456. DispatchResponse(hr, TRUE);
  457. // Failure, were done
  458. if (SUCCEEDED(hr))
  459. {
  460. // Performing auth
  461. if (m_fConnectAuth)
  462. {
  463. // If we aren't doing sicily authenication or
  464. // SSL security via STARTTLS or querying for DSN then just send a HELO message
  465. if ((FALSE == m_rServer.fTrySicily) &&
  466. (0 == (m_rServer.dwFlags & ISF_QUERYAUTHSUPPORT)) &&
  467. (FALSE == m_fConnectTLS) &&
  468. (0 == (m_rServer.dwFlags & ISF_QUERYDSNSUPPORT)))
  469. {
  470. // Issue HELO
  471. hr = CommandHELO();
  472. if (FAILED(hr))
  473. {
  474. OnError(hr);
  475. DropConnection();
  476. }
  477. }
  478. else
  479. {
  480. // Issue EHLO
  481. hr = CommandEHLO();
  482. if (FAILED(hr))
  483. {
  484. OnError(hr);
  485. DropConnection();
  486. }
  487. }
  488. }
  489. // Otherwise, were connected, user can send HELO command
  490. else
  491. {
  492. m_command = SMTP_CONNECTED;
  493. DispatchResponse(S_OK, TRUE);
  494. }
  495. // Were not authenticated yet
  496. m_fAuthenticated = FALSE;
  497. }
  498. // Done
  499. break;
  500. // --------------------------------------------------------------------------------
  501. case SMTP_HELO:
  502. // Dispatch the Response
  503. DispatchResponse(hr, TRUE);
  504. // Failure, were done
  505. if (SUCCEEDED(hr))
  506. {
  507. // Were performing AUTH
  508. if (m_fConnectAuth)
  509. {
  510. // Were authenticated
  511. m_fAuthenticated = TRUE;
  512. // Authorized
  513. OnAuthorized();
  514. }
  515. }
  516. break;
  517. // --------------------------------------------------------------------------------
  518. case SMTP_EHLO:
  519. // Are we just trying to negotiate a SSL connection
  520. // EHLO Response
  521. if (FALSE == m_fTLSNegotiation)
  522. {
  523. OnEHLOResponse(m_pszResponse);
  524. }
  525. // Failure, were done
  526. if (m_fConnectAuth)
  527. {
  528. // Do we need to do STARTTLS?
  529. if ((FALSE != m_fConnectTLS) && (FALSE == m_fSecured))
  530. {
  531. if (SUCCEEDED(hr))
  532. {
  533. if (FALSE == m_fTLSNegotiation)
  534. {
  535. // Start TLS negotiation
  536. StartTLS();
  537. }
  538. else
  539. {
  540. TryNextSecurityPkg();
  541. }
  542. }
  543. else
  544. {
  545. OnError(hr);
  546. DropConnection();
  547. }
  548. }
  549. else
  550. {
  551. // Dispatch Response, always success...
  552. DispatchResponse(S_OK, TRUE);
  553. // Success ?
  554. if (SUCCEEDED(hr))
  555. {
  556. // No Auth Tokens, just try normal authentication
  557. if (m_rAuth.cAuthToken <= 0)
  558. {
  559. // Were authenticated
  560. m_fAuthenticated = TRUE;
  561. // Authorized
  562. OnAuthorized();
  563. }
  564. // Otherwise, start sasl
  565. else
  566. {
  567. // StartLogon
  568. StartLogon();
  569. }
  570. }
  571. // Otherwise, just try the HELO command
  572. else
  573. {
  574. // Issue HELO
  575. hr = CommandHELO();
  576. if (FAILED(hr))
  577. {
  578. OnError(hr);
  579. DropConnection();
  580. }
  581. }
  582. }
  583. }
  584. // Otherwise, just dispatch the Response
  585. else
  586. DispatchResponse(hr, TRUE);
  587. break;
  588. // --------------------------------------------------------------------------------
  589. case SMTP_AUTH:
  590. Assert(m_rAuth.authstate != AUTH_ENUMPACKS_DATA)
  591. // Authenticating
  592. if (m_fConnectAuth)
  593. ResponseAUTH(hr);
  594. else
  595. DispatchResponse(hr, TRUE);
  596. break;
  597. // --------------------------------------------------------------------------------
  598. case SMTP_RSET:
  599. // Dispatch the Response
  600. if (FALSE == m_fConnectAuth)
  601. DispatchResponse(hr, TRUE);
  602. // Failure, were done
  603. if (SUCCEEDED(hr))
  604. {
  605. // If sending message, start it...
  606. if (m_fSendMessage)
  607. SendMessage_MAIL();
  608. }
  609. break;
  610. // --------------------------------------------------------------------------------
  611. case SMTP_MAIL:
  612. // Dispatch the Response
  613. DispatchResponse(hr, TRUE);
  614. if (SUCCEEDED(hr))
  615. {
  616. // Doing a Send Message..
  617. if (m_fSendMessage)
  618. SendMessage_RCPT();
  619. }
  620. break;
  621. // --------------------------------------------------------------------------------
  622. case SMTP_RCPT:
  623. // Dispatch the Response
  624. DispatchResponse(hr, TRUE);
  625. if (SUCCEEDED(hr))
  626. {
  627. // Doing a Send Message..
  628. if (m_fSendMessage)
  629. SendMessage_RCPT();
  630. }
  631. break;
  632. // --------------------------------------------------------------------------------
  633. case SMTP_DATA:
  634. // Dispatch the Response
  635. DispatchResponse(hr, TRUE);
  636. if (SUCCEEDED(hr))
  637. {
  638. // Doing a Send Message..
  639. if (m_fSendMessage)
  640. {
  641. // Send the data stream
  642. hr = SendDataStream(m_rMessage.smtpMsg.pstmMsg, m_rMessage.smtpMsg.cbSize);
  643. if (FAILED(hr))
  644. {
  645. SendMessage_DONE(hr);
  646. }
  647. }
  648. }
  649. break;
  650. // --------------------------------------------------------------------------------
  651. case SMTP_DOT:
  652. // Dispatch the response
  653. DispatchResponse(hr, TRUE);
  654. if (SUCCEEDED(hr))
  655. {
  656. // If doing a send message
  657. if (m_fSendMessage)
  658. SendMessage_DONE(S_OK);
  659. }
  660. break;
  661. // --------------------------------------------------------------------------------
  662. case SMTP_QUIT:
  663. // Doing a Send Message..were not done until disconnected.
  664. DispatchResponse(hr, FALSE);
  665. m_pSocket->Close();
  666. break;
  667. }
  668. exit:
  669. // Enter Critical Section
  670. LeaveCriticalSection(&m_cs);
  671. }
  672. // ------------------------------------------------------------------------------------
  673. // CSMTPTransport::SendMessage_DONE
  674. // ------------------------------------------------------------------------------------
  675. void CSMTPTransport::SendMessage_DONE(HRESULT hrResult, LPSTR pszProblem)
  676. {
  677. m_command = SMTP_SEND_MESSAGE;
  678. m_fSendMessage = FALSE;
  679. m_fReset = TRUE;
  680. SafeRelease(m_rMessage.smtpMsg.pstmMsg);
  681. DispatchResponse(hrResult, TRUE, pszProblem);
  682. SafeMemFree(m_rMessage.smtpMsg.rAddressList.prgAddress);
  683. SafeMemFree(m_rMessage.pszDSNENVID);
  684. ZeroMemory(&m_rMessage, sizeof(m_rMessage));
  685. }
  686. // ------------------------------------------------------------------------------------
  687. // CSMTPTransport::OnEHLOResponse
  688. // ------------------------------------------------------------------------------------
  689. void CSMTPTransport::OnEHLOResponse(LPCSTR pszResponse)
  690. {
  691. // Do we have anything to do?
  692. if (NULL == pszResponse || FALSE != m_fTLSNegotiation)
  693. goto exit;
  694. // DSN support?
  695. if (m_rServer.dwFlags & ISF_QUERYDSNSUPPORT)
  696. {
  697. if (0 == StrCmpNI(pszResponse + 4, g_szSMTPDSN, g_cchSMTPDSN))
  698. {
  699. m_fDSNAvail = TRUE;
  700. }
  701. }
  702. // Searching for: 250 STARTTLS
  703. if (TRUE == m_fConnectTLS)
  704. {
  705. if (0 == StrCmpNI(pszResponse + 4, g_szSMTPSTARTTLS08, g_cchSMTPSTARTTLS08))
  706. {
  707. m_fSTARTTLSAvail = TRUE;
  708. }
  709. }
  710. // Searching for: 250 AUTH=LOGIN NTLM or 250 AUTH LOGIN NTLM
  711. if ((FALSE != m_rServer.fTrySicily) || (0 != (m_rServer.dwFlags & ISF_QUERYAUTHSUPPORT)))
  712. {
  713. if ((0 == StrCmpNI(pszResponse + 4, g_szSMTPAUTH11, g_cchSMTPAUTH11)) ||
  714. (0 == StrCmpNI(pszResponse + 4, g_szSMTPAUTH10, g_cchSMTPAUTH10)))
  715. {
  716. // If we haven't read the tokens yet...
  717. if (0 == m_rAuth.cAuthToken)
  718. {
  719. // Locals
  720. CStringParser cString;
  721. CHAR chToken;
  722. // State Check
  723. Assert(m_rAuth.cAuthToken == 0);
  724. // Set the Members
  725. cString.Init(pszResponse + 9, lstrlen(pszResponse + 9), PSF_NOTRAILWS | PSF_NOFRONTWS);
  726. // Parse tokens
  727. while(1)
  728. {
  729. // Set Parse Tokens
  730. chToken = cString.ChParse(" ");
  731. if (0 == cString.CchValue())
  732. break;
  733. // Can't take any more
  734. if (m_rAuth.cAuthToken == MAX_AUTH_TOKENS)
  735. {
  736. Assert(FALSE);
  737. break;
  738. }
  739. // Store the auth type
  740. m_rAuth.rgpszAuthTokens[m_rAuth.cAuthToken] = PszDupA(cString.PszValue());
  741. if (m_rAuth.rgpszAuthTokens[m_rAuth.cAuthToken])
  742. m_rAuth.cAuthToken++;
  743. }
  744. }
  745. }
  746. }
  747. exit:
  748. return;
  749. }
  750. // ------------------------------------------------------------------------------------
  751. // CSMTPTransport::_PszGetCurrentAddress
  752. // ------------------------------------------------------------------------------------
  753. LPSTR CSMTPTransport::_PszGetCurrentAddress(void)
  754. {
  755. return (*m_szEmail == '\0') ? NULL : m_szEmail;
  756. }
  757. // ------------------------------------------------------------------------------------
  758. // CSMTPTransport::DispatchResponse
  759. // ------------------------------------------------------------------------------------
  760. void CSMTPTransport::DispatchResponse(HRESULT hrResult, BOOL fDone, LPSTR pszProblem)
  761. {
  762. // Locals
  763. SMTPRESPONSE rResponse;
  764. // If not in SendMessage
  765. if (FALSE == m_fSendMessage)
  766. {
  767. // Clear the Response
  768. ZeroMemory(&rResponse, sizeof(SMTPRESPONSE));
  769. // Set the HRESULT
  770. rResponse.command = m_command;
  771. rResponse.fDone = fDone;
  772. rResponse.rIxpResult.pszResponse = m_pszResponse;
  773. rResponse.rIxpResult.hrResult = hrResult;
  774. rResponse.rIxpResult.uiServerError = m_uiResponse;
  775. rResponse.rIxpResult.hrServerError = m_hrResponse;
  776. rResponse.rIxpResult.dwSocketError = m_pSocket->GetLastError();
  777. rResponse.rIxpResult.pszProblem = NULL;
  778. rResponse.pTransport = this;
  779. // Map HRESULT and set problem...
  780. if (FAILED(hrResult))
  781. {
  782. // Handle Rejected Sender
  783. if (SMTP_MAIL == m_command)
  784. {
  785. rResponse.rIxpResult.hrResult = IXP_E_SMTP_REJECTED_SENDER;
  786. rResponse.rIxpResult.pszProblem = _PszGetCurrentAddress();
  787. }
  788. // Handle Rejected Recipient
  789. else if (SMTP_RCPT == m_command)
  790. {
  791. rResponse.rIxpResult.hrResult = IXP_E_SMTP_REJECTED_RECIPIENTS;
  792. rResponse.rIxpResult.pszProblem = _PszGetCurrentAddress();
  793. }
  794. }
  795. // Finished...
  796. if (fDone)
  797. {
  798. // No current command
  799. m_command = SMTP_NONE;
  800. // Leave Busy State
  801. LeaveBusy();
  802. }
  803. // Give the Response to the client
  804. if (m_pCallback)
  805. ((ISMTPCallback *)m_pCallback)->OnResponse(&rResponse);
  806. // Reset Last Response
  807. SafeMemFree(m_pszResponse);
  808. m_hrResponse = S_OK;
  809. m_uiResponse = 0;
  810. }
  811. // Otherwise, if FAILED
  812. else if (FAILED(hrResult))
  813. {
  814. // Handle Rejected Sender
  815. if (SMTP_MAIL == m_command)
  816. SendMessage_DONE(IXP_E_SMTP_REJECTED_SENDER, _PszGetCurrentAddress());
  817. // Handle Rejected Recipient
  818. else if (SMTP_RCPT == m_command)
  819. SendMessage_DONE(IXP_E_SMTP_REJECTED_RECIPIENTS, _PszGetCurrentAddress());
  820. // General Failure
  821. else
  822. SendMessage_DONE(hrResult);
  823. }
  824. }
  825. // ------------------------------------------------------------------------------------
  826. // CSMTPTransport::HrGetResponse
  827. // ------------------------------------------------------------------------------------
  828. HRESULT CSMTPTransport::HrGetResponse(void)
  829. {
  830. // Locals
  831. HRESULT hr = S_OK;
  832. INT cbLine = 0;
  833. BOOL fKnownResponse = TRUE;
  834. BOOL fComplete = FALSE;
  835. BOOL fMoreLinesNeeded = FALSE;
  836. // Clear current response
  837. IxpAssert(m_pszResponse == NULL && m_hrResponse == S_OK);
  838. // We received a line from the host $$ERROR$$ - How do I know if there are more lines
  839. while(1)
  840. {
  841. // Read the line
  842. IxpAssert(m_pszResponse == NULL);
  843. hr = HrReadLine(&m_pszResponse, &cbLine, &fComplete);
  844. if (FAILED(hr))
  845. {
  846. hr = TRAPHR(IXP_E_SOCKET_READ_ERROR);
  847. goto exit;
  848. }
  849. // Not complete
  850. if (!fComplete)
  851. {
  852. if (FALSE != fMoreLinesNeeded)
  853. {
  854. hr = IXP_E_INCOMPLETE;
  855. }
  856. goto exit;
  857. }
  858. // Parse the response code
  859. if ((cbLine < 3) || (m_pszResponse == NULL) ||
  860. (m_pszResponse[0] < '0' || m_pszResponse[0] > '9') ||
  861. (m_pszResponse[1] < '0' || m_pszResponse[1] > '9') ||
  862. (m_pszResponse[2] < '0' || m_pszResponse[2] > '9'))
  863. {
  864. hr = TrapError(IXP_E_SMTP_RESPONSE_ERROR);
  865. if (m_pCallback && m_fCommandLogging)
  866. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, hr, SMTPTHISIXP);
  867. goto exit;
  868. }
  869. // Ignores continuation lines for now
  870. if ((cbLine >= 4) && (m_pszResponse[3] == '-'))
  871. {
  872. // Locals
  873. SMTPRESPONSE rResponse;
  874. // General command
  875. if (m_pCallback && m_fCommandLogging)
  876. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, IXP_S_SMTP_CONTINUE, SMTPTHISIXP);
  877. // Clear the Response
  878. ZeroMemory(&rResponse, sizeof(SMTPRESPONSE));
  879. // Set the HRESULT
  880. rResponse.command = m_command;
  881. rResponse.fDone = FALSE;
  882. rResponse.rIxpResult.pszResponse = m_pszResponse;
  883. rResponse.rIxpResult.hrResult = IXP_S_SMTP_CONTINUE;
  884. rResponse.rIxpResult.uiServerError = 0;
  885. rResponse.rIxpResult.hrServerError = S_OK;
  886. rResponse.rIxpResult.dwSocketError = 0;
  887. rResponse.rIxpResult.pszProblem = NULL;
  888. rResponse.pTransport = this;
  889. // Give the Response to the client
  890. if (m_pCallback)
  891. ((ISMTPCallback *)m_pCallback)->OnResponse(&rResponse);
  892. // EHLO Response
  893. if (SMTP_EHLO == m_command)
  894. OnEHLOResponse(m_pszResponse);
  895. // Reset Last Response
  896. SafeMemFree(m_pszResponse);
  897. m_hrResponse = S_OK;
  898. m_uiResponse = 0;
  899. // We still need to get more lines from the server
  900. fMoreLinesNeeded = TRUE;
  901. // Continue
  902. continue;
  903. }
  904. // Not a valid SMTP response line.
  905. if ((cbLine >= 4) && (m_pszResponse[3] != ' '))
  906. {
  907. hr = TrapError(IXP_E_SMTP_RESPONSE_ERROR);
  908. if (m_pCallback && m_fCommandLogging)
  909. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, hr, SMTPTHISIXP);
  910. goto exit;
  911. }
  912. // Done
  913. break;
  914. }
  915. // Compute Actual Response code
  916. m_uiResponse = (m_pszResponse[0] - '0') * 100 +
  917. (m_pszResponse[1] - '0') * 10 +
  918. (m_pszResponse[2] - '0');
  919. // Assume it is not recognized
  920. switch(m_uiResponse)
  921. {
  922. case 500: hr = IXP_E_SMTP_500_SYNTAX_ERROR; break;
  923. case 501: hr = IXP_E_SMTP_501_PARAM_SYNTAX; break;
  924. case 502: hr = IXP_E_SMTP_502_COMMAND_NOTIMPL; break;
  925. case 503: hr = IXP_E_SMTP_503_COMMAND_SEQ; break;
  926. case 504: hr = IXP_E_SMTP_504_COMMAND_PARAM_NOTIMPL; break;
  927. case 421: hr = IXP_E_SMTP_421_NOT_AVAILABLE; break;
  928. case 450: hr = IXP_E_SMTP_450_MAILBOX_BUSY; break;
  929. case 550: hr = IXP_E_SMTP_550_MAILBOX_NOT_FOUND; break;
  930. case 451: hr = IXP_E_SMTP_451_ERROR_PROCESSING; break;
  931. case 551: hr = IXP_E_SMTP_551_USER_NOT_LOCAL; break;
  932. case 452: hr = IXP_E_SMTP_452_NO_SYSTEM_STORAGE; break;
  933. case 552: hr = IXP_E_SMTP_552_STORAGE_OVERFLOW; break;
  934. case 553: hr = IXP_E_SMTP_553_MAILBOX_NAME_SYNTAX; break;
  935. case 554: hr = IXP_E_SMTP_554_TRANSACT_FAILED; break;
  936. case 211: hr = IXP_S_SMTP_211_SYSTEM_STATUS; break;
  937. case 214: hr = IXP_S_SMTP_214_HELP_MESSAGE; break;
  938. case 220: hr = IXP_S_SMTP_220_READY; break;
  939. case 221: hr = IXP_S_SMTP_221_CLOSING; break;
  940. case 250: hr = IXP_S_SMTP_250_MAIL_ACTION_OKAY; break;
  941. case 251: hr = IXP_S_SMTP_251_FORWARDING_MAIL; break;
  942. case 354: hr = IXP_S_SMTP_354_START_MAIL_INPUT; break;
  943. case 334: hr = IXP_S_SMTP_334_AUTH_READY_RESPONSE; break;
  944. case 235: hr = IXP_S_SMTP_245_AUTH_SUCCESS; break;
  945. case 454: hr = IXP_E_SMTP_454_STARTTLS_FAILED; break;
  946. case 530: hr = IXP_E_SMTP_530_STARTTLS_REQUIRED; break;
  947. default:
  948. hr = IXP_E_SMTP_UNKNOWN_RESPONSE_CODE;
  949. fKnownResponse = FALSE;
  950. break;
  951. }
  952. // Set hr
  953. m_hrResponse = hr;
  954. // Give to callback
  955. if (m_pCallback && m_fCommandLogging)
  956. m_pCallback->OnCommand(CMD_RESP, m_pszResponse, hr, SMTPTHISIXP);
  957. exit:
  958. // Done
  959. return hr;
  960. }
  961. // --------------------------------------------------------------------------------
  962. // CSMTPTransport::_HrFormatAddressString
  963. // --------------------------------------------------------------------------------
  964. HRESULT CSMTPTransport::_HrFormatAddressString(LPCSTR pszEmail, LPCSTR pszExtra, LPSTR *ppszAddress)
  965. {
  966. // Locals
  967. HRESULT hr=S_OK;
  968. ULONG cchAlloc;
  969. // Invalid Arg
  970. Assert(pszEmail && ppszAddress);
  971. cchAlloc= lstrlen(pszEmail) + 3; // length of pszEmail plus <> and a null term
  972. if(pszExtra && pszExtra[0])
  973. cchAlloc += lstrlen(pszExtra) + 1; // length of pszExtra plus a space
  974. // Allocate string
  975. CHECKALLOC(*ppszAddress = (LPSTR)g_pMalloc->Alloc(cchAlloc * sizeof((*ppszAddress)[0])));
  976. // Format the String
  977. wnsprintf(*ppszAddress, cchAlloc, "<%s>", pszEmail);
  978. if(pszExtra && pszExtra[0])
  979. {
  980. StrCatBuff(*ppszAddress, " ", cchAlloc);
  981. StrCatBuff(*ppszAddress, pszExtra, cchAlloc);
  982. }
  983. exit:
  984. // Done
  985. return hr;
  986. }
  987. // --------------------------------------------------------------------------------
  988. // CSMTPTransport::CommandMAIL
  989. // --------------------------------------------------------------------------------
  990. STDMETHODIMP CSMTPTransport::CommandMAIL(LPSTR pszEmailFrom)
  991. {
  992. // Locals
  993. HRESULT hr=S_OK;
  994. LPSTR pszAddress=NULL;
  995. CHAR szDSNData[128];
  996. szDSNData[0]= '\0';
  997. // Check params
  998. if (NULL == pszEmailFrom)
  999. return TrapError(E_INVALIDARG);
  1000. // build DSN parameters if necessary
  1001. if(m_fDSNAvail)
  1002. {
  1003. if(DSNRET_DEFAULT != m_rMessage.dsnRet)
  1004. {
  1005. StrCatBuff(szDSNData, g_szDSNRET, ARRAYSIZE(szDSNData));
  1006. if(m_rMessage.dsnRet == DSNRET_HDRS)
  1007. StrCatBuff(szDSNData, g_szDSNHDRS, ARRAYSIZE(szDSNData));
  1008. else if(DSNRET_FULL == m_rMessage.dsnRet)
  1009. StrCatBuff(szDSNData, g_szDSNFULL, ARRAYSIZE(szDSNData));
  1010. }
  1011. if(m_rMessage.pszDSNENVID)
  1012. {
  1013. if(szDSNData[0])
  1014. StrCatBuff(szDSNData, " ", ARRAYSIZE(szDSNData));
  1015. StrCatBuff(szDSNData, g_szDSNENVID, ARRAYSIZE(szDSNData));
  1016. StrCatBuff(szDSNData, m_rMessage.pszDSNENVID, ARRAYSIZE(szDSNData));
  1017. }
  1018. }
  1019. // Put pszEmailFrom into <pszEmailFrom>
  1020. CHECKHR(hr = _HrFormatAddressString(pszEmailFrom, szDSNData, &pszAddress));
  1021. // Send Command
  1022. hr = HrSendCommand((LPSTR)SMTP_MAIL_STR, pszAddress, !m_fSendMessage);
  1023. if (SUCCEEDED(hr))
  1024. {
  1025. StrCpyN(m_szEmail, pszEmailFrom, ARRAYSIZE(m_szEmail));
  1026. m_command = SMTP_MAIL;
  1027. }
  1028. exit:
  1029. // Cleanup
  1030. SafeMemFree(pszAddress);
  1031. // Done
  1032. return hr;
  1033. }
  1034. // --------------------------------------------------------------------------------
  1035. // CSMTPTransport::CommandRCPT
  1036. // --------------------------------------------------------------------------------
  1037. STDMETHODIMP CSMTPTransport::CommandRCPT(LPSTR pszEmailTo)
  1038. {
  1039. return CommandRCPT2(pszEmailTo, (INETADDRTYPE)0);
  1040. }
  1041. // --------------------------------------------------------------------------------
  1042. // CSMTPTransport::CommandRCPT2
  1043. // --------------------------------------------------------------------------------
  1044. STDMETHODIMP CSMTPTransport::CommandRCPT2(LPSTR pszEmailTo, INETADDRTYPE atDSN)
  1045. {
  1046. // Locals
  1047. HRESULT hr=S_OK;
  1048. LPSTR pszAddress=NULL;
  1049. CHAR szDSNData[32];
  1050. int iatDSN= atDSN;
  1051. szDSNData[0]= '\0';
  1052. // Check params
  1053. if (NULL == pszEmailTo)
  1054. return TrapError(E_INVALIDARG);
  1055. if ((atDSN & ~ADDR_DSN_MASK) ||
  1056. ((atDSN & ADDR_DSN_NEVER) &&
  1057. (atDSN & ~ADDR_DSN_NEVER)))
  1058. return TrapError(E_INVALIDARG);
  1059. // build DSN parameters if necessary
  1060. if(m_fDSNAvail && atDSN)
  1061. {
  1062. StrCatBuff(szDSNData, g_szDSNNOTIFY, ARRAYSIZE(szDSNData));
  1063. if(atDSN & ADDR_DSN_NEVER)
  1064. StrCatBuff(szDSNData, g_szDSNNEVER, ARRAYSIZE(szDSNData));
  1065. else
  1066. {
  1067. bool fPrev= false;
  1068. if(atDSN & ADDR_DSN_SUCCESS)
  1069. {
  1070. StrCatBuff(szDSNData, g_szDSNSUCCESS, ARRAYSIZE(szDSNData));
  1071. fPrev= true;
  1072. }
  1073. if(atDSN & ADDR_DSN_FAILURE)
  1074. {
  1075. if(fPrev)
  1076. StrCatBuff(szDSNData, ",", ARRAYSIZE(szDSNData));
  1077. StrCatBuff(szDSNData, g_szDSNFAILURE, ARRAYSIZE(szDSNData));
  1078. fPrev= true;
  1079. }
  1080. if(atDSN & ADDR_DSN_DELAY)
  1081. {
  1082. if(fPrev)
  1083. StrCatBuff(szDSNData, ",", ARRAYSIZE(szDSNData));
  1084. StrCatBuff(szDSNData, g_szDSNDELAY, ARRAYSIZE(szDSNData));
  1085. }
  1086. }
  1087. }
  1088. // Put pszEmailFrom into <pszEmailFrom>
  1089. CHECKHR(hr = _HrFormatAddressString(pszEmailTo, szDSNData, &pszAddress));
  1090. // Send Command
  1091. hr = HrSendCommand((LPSTR)SMTP_RCPT_STR, pszAddress, !m_fSendMessage);
  1092. if (SUCCEEDED(hr))
  1093. {
  1094. StrCpyN(m_szEmail, pszEmailTo, ARRAYSIZE(m_szEmail));
  1095. m_command = SMTP_RCPT;
  1096. }
  1097. exit:
  1098. // Cleanup
  1099. SafeMemFree(pszAddress);
  1100. // Done
  1101. return hr;
  1102. }
  1103. // --------------------------------------------------------------------------------
  1104. // CSMTPTransport::CommandEHLO
  1105. // --------------------------------------------------------------------------------
  1106. STDMETHODIMP CSMTPTransport::CommandEHLO(void)
  1107. {
  1108. return _HrHELO_Or_EHLO(SMTP_EHLO_STR, SMTP_EHLO);
  1109. }
  1110. // --------------------------------------------------------------------------------
  1111. // CSMTPTransport::CommandHELO
  1112. // --------------------------------------------------------------------------------
  1113. STDMETHODIMP CSMTPTransport::CommandHELO(void)
  1114. {
  1115. return _HrHELO_Or_EHLO(SMTP_HELO_STR, SMTP_HELO);
  1116. }
  1117. // --------------------------------------------------------------------------------
  1118. // CSMTPTransport::_HrHELO_Or_EHLO
  1119. // --------------------------------------------------------------------------------
  1120. HRESULT CSMTPTransport::_HrHELO_Or_EHLO(LPCSTR pszCommand, SMTPCOMMAND eNewCommand)
  1121. {
  1122. // Locals
  1123. HRESULT hr=S_OK;
  1124. // Use an IP address
  1125. if (ISFLAGSET(m_rServer.dwFlags, ISF_SMTP_USEIPFORHELO))
  1126. {
  1127. // Locals
  1128. LPHOSTENT pHost=NULL;
  1129. SOCKADDR_IN sa;
  1130. // Get Host by name
  1131. pHost = gethostbyname(SzGetLocalHostName());
  1132. // Cast ip
  1133. sa.sin_addr.s_addr = (ULONG)(*(DWORD *)pHost->h_addr);
  1134. // Send HELO, quit and die if it fails
  1135. hr = HrSendCommand((LPSTR)pszCommand, inet_ntoa(sa.sin_addr), !m_fSendMessage && !m_fTLSNegotiation);
  1136. if (SUCCEEDED(hr))
  1137. m_command = eNewCommand;
  1138. }
  1139. // Otherwise, this code uses a host name to do the ehlo or helo command
  1140. else
  1141. {
  1142. // Locals
  1143. CHAR szLocalHost[255];
  1144. LPSTR pszHost=SzGetLocalHostName();
  1145. // Get legal local host name
  1146. #ifdef DEBUG
  1147. StripIllegalHostChars("GTE/Athena", szLocalHost, ARRAYSIZE(szLocalHost));
  1148. StripIllegalHostChars("foobar.", szLocalHost, ARRAYSIZE(szLocalHost));
  1149. StripIllegalHostChars("127.256.34.23", szLocalHost, ARRAYSIZE(szLocalHost));
  1150. StripIllegalHostChars("�56foo1", szLocalHost, ARRAYSIZE(szLocalHost));
  1151. #endif
  1152. // Get legal local host name
  1153. StripIllegalHostChars(pszHost, szLocalHost, ARRAYSIZE(szLocalHost));
  1154. // Send HELO, quit and die if it fails
  1155. hr = HrSendCommand((LPSTR)pszCommand, szLocalHost, !m_fSendMessage && !m_fTLSNegotiation);
  1156. if (SUCCEEDED(hr))
  1157. m_command = eNewCommand;
  1158. }
  1159. // Done
  1160. return hr;
  1161. }
  1162. // --------------------------------------------------------------------------------
  1163. // CSMTPTransport::DoQuit
  1164. // --------------------------------------------------------------------------------
  1165. void CSMTPTransport::DoQuit(void)
  1166. {
  1167. CommandQUIT();
  1168. }
  1169. // ------------------------------------------------------------------------------------
  1170. // CSMTPTransport::CommandAUTH
  1171. // ------------------------------------------------------------------------------------
  1172. STDMETHODIMP CSMTPTransport::CommandAUTH(LPSTR pszAuthType)
  1173. {
  1174. // check params
  1175. if (NULL == pszAuthType)
  1176. return TrapError(E_INVALIDARG);
  1177. // Do the command
  1178. HRESULT hr = HrSendCommand((LPSTR)SMTP_AUTH_STR, pszAuthType, !m_fConnectAuth);
  1179. if (SUCCEEDED(hr))
  1180. m_command = SMTP_AUTH;
  1181. // Done
  1182. return hr;
  1183. }
  1184. // --------------------------------------------------------------------------------
  1185. // CSMTPTransport::CommandQUIT
  1186. // --------------------------------------------------------------------------------
  1187. STDMETHODIMP CSMTPTransport::CommandQUIT(void)
  1188. {
  1189. // Send QUIT
  1190. OnStatus(IXP_DISCONNECTING);
  1191. HRESULT hr = HrSendCommand((LPSTR)SMTP_QUIT_STR, NULL, !m_fSendMessage);
  1192. if (SUCCEEDED(hr))
  1193. m_command = SMTP_QUIT;
  1194. return hr;
  1195. }
  1196. // --------------------------------------------------------------------------------
  1197. // CSMTPTransport::CommandRSET
  1198. // --------------------------------------------------------------------------------
  1199. STDMETHODIMP CSMTPTransport::CommandRSET(void)
  1200. {
  1201. // Send Command
  1202. HRESULT hr = HrSendCommand((LPSTR)SMTP_RSET_STR, NULL, !m_fSendMessage);
  1203. if (SUCCEEDED(hr))
  1204. m_command = SMTP_RSET;
  1205. return hr;
  1206. }
  1207. // --------------------------------------------------------------------------------
  1208. // CSMTPTransport::CommandDATA
  1209. // --------------------------------------------------------------------------------
  1210. STDMETHODIMP CSMTPTransport::CommandDATA(void)
  1211. {
  1212. // Send Command
  1213. HRESULT hr = HrSendCommand((LPSTR)SMTP_DATA_STR, NULL, !m_fSendMessage);
  1214. if (SUCCEEDED(hr))
  1215. m_command = SMTP_DATA;
  1216. return hr;
  1217. }
  1218. // --------------------------------------------------------------------------------
  1219. // CSMTPTransport::CommandDOT
  1220. // --------------------------------------------------------------------------------
  1221. STDMETHODIMP CSMTPTransport::CommandDOT(void)
  1222. {
  1223. // Send Command
  1224. HRESULT hr = HrSendCommand((LPSTR)SMTP_END_DATA_STR, NULL, !m_fSendMessage);
  1225. if (SUCCEEDED(hr))
  1226. m_command = SMTP_DOT;
  1227. return hr;
  1228. }
  1229. // ------------------------------------------------------------------------------------
  1230. // CSMTPTransport::CommandSTARTTLS
  1231. // ------------------------------------------------------------------------------------
  1232. HRESULT CSMTPTransport::CommandSTARTTLS(void)
  1233. {
  1234. // Locals
  1235. HRESULT hr=S_OK;
  1236. // Is StartTLS supported?
  1237. if(FALSE == m_fSTARTTLSAvail)
  1238. {
  1239. hr= IXP_E_SMTP_NO_STARTTLS_SUPPORT;
  1240. goto exit;
  1241. }
  1242. // Do the command
  1243. hr = HrSendCommand((LPSTR)SMTP_STARTTLS_STR, NULL, !m_fConnectAuth);
  1244. if (SUCCEEDED(hr))
  1245. m_fTLSNegotiation = TRUE;
  1246. // Done
  1247. exit:
  1248. return hr;
  1249. }
  1250. // --------------------------------------------------------------------------------
  1251. // CSMTPTransport::SendDataStream
  1252. // --------------------------------------------------------------------------------
  1253. STDMETHODIMP CSMTPTransport::SendDataStream(IStream *pStream, ULONG cbSize)
  1254. {
  1255. // Locals
  1256. HRESULT hr=S_OK;
  1257. INT cb;
  1258. // check params
  1259. if (NULL == pStream)
  1260. return TrapError(E_INVALIDARG);
  1261. // Thread Safety
  1262. EnterCriticalSection(&m_cs);
  1263. // Busy...
  1264. if (m_fSendMessage == FALSE)
  1265. {
  1266. CHECKHR(hr = HrEnterBusy());
  1267. }
  1268. // Save Total Size
  1269. m_cbSent = 0;
  1270. m_cbTotal = cbSize;
  1271. // Send the stream, if it fails, move the the next message
  1272. hr = m_pSocket->SendStream(pStream, &cb, TRUE);
  1273. if (FAILED(hr))
  1274. {
  1275. // If this is a blocking situation, enter SMTP_SEND_STREAM_RESP
  1276. if (hr == IXP_E_WOULD_BLOCK)
  1277. {
  1278. m_command = SMTP_SEND_STREAM;
  1279. SendStreamResponse(FALSE, S_OK, cb);
  1280. hr =S_OK;
  1281. goto exit;
  1282. }
  1283. // Otherwise, someother error
  1284. else
  1285. {
  1286. hr = TrapError(IXP_E_SOCKET_WRITE_ERROR);
  1287. goto exit;
  1288. }
  1289. }
  1290. // Give send stream response
  1291. SendStreamResponse(TRUE, S_OK, cb);
  1292. // Not Busy
  1293. if (FALSE == m_fSendMessage)
  1294. LeaveBusy();
  1295. // Send DOT
  1296. CHECKHR(hr = CommandDOT());
  1297. exit:
  1298. // Failure
  1299. if (FALSE == m_fSendMessage && FAILED(hr))
  1300. LeaveBusy();
  1301. // Thread Safety
  1302. LeaveCriticalSection(&m_cs);
  1303. // Done
  1304. return hr;
  1305. }
  1306. // --------------------------------------------------------------------------------
  1307. // CSMTPTransport::SendStreamResponse
  1308. // --------------------------------------------------------------------------------
  1309. void CSMTPTransport::SendStreamResponse(BOOL fDone, HRESULT hrResult, DWORD cbIncrement)
  1310. {
  1311. // Locals
  1312. SMTPRESPONSE rResponse;
  1313. // Increment Current
  1314. m_cbSent += cbIncrement;
  1315. // Set the HRESULT
  1316. rResponse.command = SMTP_SEND_STREAM;
  1317. rResponse.fDone = fDone;
  1318. rResponse.rIxpResult.pszResponse = NULL;
  1319. rResponse.rIxpResult.hrResult = hrResult;
  1320. rResponse.rIxpResult.uiServerError = 0;
  1321. rResponse.rIxpResult.hrServerError = S_OK;
  1322. rResponse.rIxpResult.dwSocketError = m_pSocket->GetLastError();
  1323. rResponse.rIxpResult.pszProblem = NULL;
  1324. rResponse.pTransport = this;
  1325. rResponse.rStreamInfo.cbIncrement = cbIncrement;
  1326. rResponse.rStreamInfo.cbCurrent = m_cbSent;
  1327. rResponse.rStreamInfo.cbTotal = m_cbTotal;
  1328. // Finished...
  1329. if (fDone)
  1330. {
  1331. // No current command
  1332. m_command = SMTP_NONE;
  1333. // Leave Busy State
  1334. LeaveBusy();
  1335. }
  1336. // Give the Response to the client
  1337. if (m_pCallback)
  1338. ((ISMTPCallback *)m_pCallback)->OnResponse(&rResponse);
  1339. }
  1340. // --------------------------------------------------------------------------------
  1341. // CSMTPTransport::SendMAIL
  1342. // --------------------------------------------------------------------------------
  1343. void CSMTPTransport::SendMessage_MAIL(void)
  1344. {
  1345. // Locals
  1346. HRESULT hr=S_OK;
  1347. ULONG i;
  1348. LPINETADDR pInetAddress;
  1349. // Loop address list
  1350. for (i=0; i<m_rMessage.smtpMsg.rAddressList.cAddress; i++)
  1351. {
  1352. // Readability
  1353. pInetAddress = &m_rMessage.smtpMsg.rAddressList.prgAddress[i];
  1354. // From...
  1355. if (ADDR_FROM == (pInetAddress->addrtype & ADDR_TOFROM_MASK))
  1356. {
  1357. // Save index of sender
  1358. m_iAddress = 0;
  1359. // Send Command
  1360. hr = CommandMAIL(pInetAddress->szEmail);
  1361. if (FAILED(hr))
  1362. SendMessage_DONE(hr);
  1363. // Done
  1364. return;
  1365. }
  1366. }
  1367. // No Sender
  1368. SendMessage_DONE(TrapError(IXP_E_SMTP_NO_SENDER));
  1369. }
  1370. // --------------------------------------------------------------------------------
  1371. // CSMTPTransport::SendMessage_RCPT
  1372. // --------------------------------------------------------------------------------
  1373. void CSMTPTransport::SendMessage_RCPT(void)
  1374. {
  1375. // Locals
  1376. HRESULT hr=S_OK;
  1377. ULONG i;
  1378. LPINETADDR pInetAddress;
  1379. // Find next ADDR_TO, starting with m_rCurrent.iRcptAddrList
  1380. IxpAssert(m_iAddress <= m_rMessage.smtpMsg.rAddressList.cAddress);
  1381. for(i=m_iAddress; i<m_rMessage.smtpMsg.rAddressList.cAddress; i++)
  1382. {
  1383. // Readability
  1384. pInetAddress = &m_rMessage.smtpMsg.rAddressList.prgAddress[i];
  1385. // Recipient
  1386. if (ADDR_TO == (pInetAddress->addrtype & ADDR_TOFROM_MASK))
  1387. {
  1388. // Count recipients
  1389. m_cRecipients++;
  1390. // Send Command
  1391. hr = CommandRCPT2(pInetAddress->szEmail, (INETADDRTYPE)(pInetAddress->addrtype & ADDR_DSN_MASK));
  1392. if (FAILED(hr))
  1393. SendMessage_DONE(hr);
  1394. else
  1395. {
  1396. m_iAddress = i + 1;
  1397. m_cRecipients++;
  1398. }
  1399. // Done
  1400. return;
  1401. }
  1402. }
  1403. // If no recipients
  1404. if (0 == m_cRecipients)
  1405. SendMessage_DONE(TrapError(IXP_E_SMTP_NO_RECIPIENTS));
  1406. // Otherwise, were done with rcpt, lets send the message
  1407. else
  1408. {
  1409. hr = CommandDATA();
  1410. if (FAILED(hr))
  1411. SendMessage_DONE(hr);
  1412. }
  1413. }
  1414. // ------------------------------------------------------------------------------------
  1415. // CSMTPTransport::StartLogon
  1416. // ------------------------------------------------------------------------------------
  1417. void CSMTPTransport::StartLogon(void)
  1418. {
  1419. // Locals
  1420. HRESULT hr;
  1421. // Progress
  1422. OnStatus(IXP_AUTHORIZING);
  1423. // Free current packages...
  1424. if (NULL == m_rAuth.pPackages)
  1425. {
  1426. // If Not Using Sicily or its not installed, then send USER command
  1427. SSPIGetPackages(&m_rAuth.pPackages, &m_rAuth.cPackages);
  1428. }
  1429. // ResponseAUTH
  1430. TryNextAuthPackage();
  1431. // Done
  1432. return;
  1433. }
  1434. // ------------------------------------------------------------------------------------
  1435. // CSMTPTransport::LogonRetry
  1436. // ------------------------------------------------------------------------------------
  1437. void CSMTPTransport::LogonRetry(void)
  1438. {
  1439. // Locals
  1440. HRESULT hr=S_OK;
  1441. // Auth Retry
  1442. OnStatus(IXP_AUTHRETRY);
  1443. // Enter Auth Retry State
  1444. m_pSocket->Close();
  1445. // Logon
  1446. if (NULL == m_pCallback || m_pCallback->OnLogonPrompt(&m_rServer, SMTPTHISIXP) != S_OK)
  1447. {
  1448. // Go to terminal state, were done.
  1449. OnDisconnected();
  1450. return;
  1451. }
  1452. // Finding Host Progress
  1453. OnStatus(IXP_FINDINGHOST);
  1454. // Connect to server
  1455. hr = m_pSocket->Connect();
  1456. if (FAILED(hr))
  1457. {
  1458. OnError(TrapError(IXP_E_SOCKET_CONNECT_ERROR));
  1459. OnDisconnected();
  1460. return;
  1461. }
  1462. // Reset the secured state
  1463. m_fSecured = FALSE;
  1464. // Start WatchDog
  1465. m_pSocket->StartWatchDog();
  1466. }
  1467. // ------------------------------------------------------------------------------------
  1468. // CSMTPTransport::TryNextAuthPackage
  1469. // ------------------------------------------------------------------------------------
  1470. void CSMTPTransport::TryNextAuthPackage(void)
  1471. {
  1472. // Locals
  1473. HRESULT hr=S_OK;
  1474. BOOL fPackageInstalled;
  1475. BOOL fLoginMethod=FALSE;
  1476. ULONG i;
  1477. // Set auth state
  1478. m_rAuth.authstate = AUTH_NONE;
  1479. // Loop through the auth tokens, and try to authenticate with each one in order
  1480. for (;m_rAuth.iAuthToken < m_rAuth.cAuthToken; m_rAuth.iAuthToken++)
  1481. {
  1482. // Assume package is not installed
  1483. fPackageInstalled = FALSE;
  1484. // "LOGIN"
  1485. if (lstrcmpi(m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken], "LOGIN") == 0)
  1486. {
  1487. fLoginMethod = TRUE;
  1488. fPackageInstalled = TRUE;
  1489. }
  1490. // Loop through installed packages
  1491. else
  1492. {
  1493. for (i=0; i<m_rAuth.cPackages; i++)
  1494. {
  1495. // Null Package ??
  1496. if (!m_rAuth.pPackages[i].pszName)
  1497. continue;
  1498. // Is this the package I am looking for
  1499. if (lstrcmpi(m_rAuth.pPackages[i].pszName, m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken]) == 0)
  1500. {
  1501. fPackageInstalled = TRUE;
  1502. break;
  1503. }
  1504. }
  1505. }
  1506. // Package not installed ?
  1507. if (!fPackageInstalled)
  1508. continue;
  1509. // We are not retrying the current package
  1510. m_rAuth.fRetryPackage = FALSE;
  1511. // Otherwise, send AUTH enumpacks command
  1512. hr = CommandAUTH(m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken]);
  1513. if (FAILED(hr))
  1514. {
  1515. OnError(hr);
  1516. DropConnection();
  1517. return;
  1518. }
  1519. // We are in the TRYING_PACKAGE state
  1520. m_rAuth.authstate = fLoginMethod ? AUTH_SMTP_LOGIN : AUTH_TRYING_PACKAGE;
  1521. // Done
  1522. break;
  1523. }
  1524. // If auth state is none, try HELO command
  1525. if (AUTH_NONE == m_rAuth.authstate)
  1526. {
  1527. // Were authenticated
  1528. m_fAuthenticated = TRUE;
  1529. // Authorized
  1530. OnAuthorized();
  1531. }
  1532. }
  1533. // ------------------------------------------------------------------------------------
  1534. // CSMTPTransport::ResponseAUTH
  1535. // ------------------------------------------------------------------------------------
  1536. void CSMTPTransport::ResponseAUTH(HRESULT hrResponse)
  1537. {
  1538. // Stop the WatchDog
  1539. m_pSocket->StopWatchDog();
  1540. // I know how to do this
  1541. if (lstrcmpi(m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken], "LOGIN") == 0)
  1542. {
  1543. // DoLogonAuth
  1544. DoLoginAuth(hrResponse);
  1545. }
  1546. // Otherwise, we must have just tryed a package
  1547. else if (m_rAuth.authstate == AUTH_TRYING_PACKAGE)
  1548. {
  1549. // DoPackageAuth
  1550. DoPackageAuth(hrResponse);
  1551. }
  1552. // Otherwise, we got a response from a negotiation string
  1553. else if (m_rAuth.authstate == AUTH_NEGO_RESP)
  1554. {
  1555. // DoAuthNegoResponse
  1556. DoAuthNegoResponse(hrResponse);
  1557. }
  1558. // Otherwise, we got a response from a challenge response string
  1559. else if (m_rAuth.authstate == AUTH_RESP_RESP)
  1560. {
  1561. // DoAuthRespResp
  1562. DoAuthRespResponse(hrResponse);
  1563. }
  1564. // Auth was cancelled, try next package
  1565. else if (m_rAuth.authstate == AUTH_CANCELED)
  1566. {
  1567. // Free Current Context
  1568. SSPIFreeContext(&m_rAuth.rSicInfo);
  1569. // Goto next package
  1570. m_rAuth.iAuthToken++;
  1571. // Try the next package
  1572. TryNextAuthPackage();
  1573. }
  1574. // Free Current Response
  1575. SafeMemFree(m_pszResponse);
  1576. m_hrResponse = S_OK;
  1577. // Start the WatchDog
  1578. m_pSocket->StartWatchDog();
  1579. }
  1580. // ------------------------------------------------------------------------------------
  1581. // CSMTPTransport::DoLoginAuth
  1582. // ------------------------------------------------------------------------------------
  1583. void CSMTPTransport::DoLoginAuth(HRESULT hrResponse)
  1584. {
  1585. // Locals
  1586. SSPIBUFFER Buffer;
  1587. // Failure, retry login
  1588. if (FAILED(hrResponse))
  1589. {
  1590. // I just issued the AUTH LOGIN command, this should not happen
  1591. if (AUTH_SMTP_LOGIN == m_rAuth.authstate)
  1592. {
  1593. // Free Current Context
  1594. SSPIFreeContext(&m_rAuth.rSicInfo);
  1595. // Goto next package
  1596. m_rAuth.iAuthToken++;
  1597. // Try the next package
  1598. TryNextAuthPackage();
  1599. }
  1600. // Otherwise, I just issued the AUTH LOGIN USERNAME
  1601. else if (AUTH_SMTP_LOGIN_USERNAME == m_rAuth.authstate || AUTH_SMTP_LOGIN_PASSWORD == m_rAuth.authstate)
  1602. {
  1603. // Retry the Logon
  1604. LogonRetry();
  1605. }
  1606. else
  1607. Assert(FALSE);
  1608. // Done
  1609. goto exit;
  1610. }
  1611. // Should have a response
  1612. Assert(m_pszResponse);
  1613. // 334
  1614. if ((334 == m_uiResponse) && m_pszResponse)
  1615. {
  1616. // Set the Length
  1617. SSPISetBuffer(m_pszResponse + 4, SSPI_STRING, 0, &Buffer);
  1618. // Base64 Decode
  1619. if (FAILED(SSPIDecodeBuffer(TRUE, &Buffer)))
  1620. {
  1621. OnError(E_FAIL);
  1622. DropConnection();
  1623. goto exit;
  1624. }
  1625. // If the user name is empty, lets retry the login...
  1626. if (FIsEmptyA(m_rServer.szUserName))
  1627. {
  1628. // LogonRetry
  1629. LogonRetry();
  1630. // Done
  1631. goto exit;
  1632. }
  1633. // Handle Next STep
  1634. if (StrCmpNI(Buffer.szBuffer, "username:", lstrlen("username:")) == 0)
  1635. {
  1636. // Set the Buffer
  1637. SSPISetBuffer(m_rServer.szUserName, SSPI_STRING, 0, &Buffer);
  1638. // Encode the User Name
  1639. if (FAILED(SSPIEncodeBuffer(TRUE, &Buffer)))
  1640. {
  1641. OnError(E_FAIL);
  1642. DropConnection();
  1643. goto exit;
  1644. }
  1645. // Send the user name
  1646. if (FSendSicilyString(Buffer.szBuffer))
  1647. m_rAuth.authstate = AUTH_SMTP_LOGIN_USERNAME;
  1648. }
  1649. // Password
  1650. else if (StrCmpNI(Buffer.szBuffer, "password:", lstrlen("password:")) == 0)
  1651. {
  1652. // Set the Buffer
  1653. SSPISetBuffer(m_rServer.szPassword, SSPI_STRING, 0, &Buffer);
  1654. // Encode the password
  1655. if (FAILED(SSPIEncodeBuffer(TRUE, &Buffer)))
  1656. {
  1657. OnError(E_FAIL);
  1658. DropConnection();
  1659. goto exit;
  1660. }
  1661. // Send the password
  1662. if (FSendSicilyString(Buffer.szBuffer))
  1663. m_rAuth.authstate = AUTH_SMTP_LOGIN_PASSWORD;
  1664. }
  1665. // Bad response from the server
  1666. else
  1667. {
  1668. OnError(E_FAIL);
  1669. DropConnection();
  1670. goto exit;
  1671. }
  1672. }
  1673. // Connected
  1674. else if (235 == m_uiResponse)
  1675. {
  1676. // OnAuthorizied
  1677. OnAuthorized();
  1678. }
  1679. // Error Response ?
  1680. else
  1681. {
  1682. OnError(E_FAIL);
  1683. DropConnection();
  1684. goto exit;
  1685. }
  1686. exit:
  1687. return;
  1688. }
  1689. // ------------------------------------------------------------------------------------
  1690. // CSMTPTransport::DoPackageAuth
  1691. // ------------------------------------------------------------------------------------
  1692. void CSMTPTransport::DoPackageAuth(HRESULT hrResponse)
  1693. {
  1694. // Locals
  1695. SSPIBUFFER Negotiate;
  1696. // Failure, retry login
  1697. if (FAILED(hrResponse))
  1698. {
  1699. // Free Current Context
  1700. SSPIFreeContext(&m_rAuth.rSicInfo);
  1701. // Goto next package
  1702. m_rAuth.iAuthToken++;
  1703. // Try the next package
  1704. TryNextAuthPackage();
  1705. // Done
  1706. goto exit;
  1707. }
  1708. // Invalid Arg
  1709. Assert(m_rAuth.iAuthToken < m_rAuth.cAuthToken);
  1710. // Do Sicily Logon
  1711. if (FAILED(SSPILogon(&m_rAuth.rSicInfo, m_rAuth.fRetryPackage, SSPI_BASE64, m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken], &m_rServer, m_pCallback)))
  1712. {
  1713. // Cancel Authentication
  1714. CancelAuthInProg();
  1715. // Done
  1716. goto exit;
  1717. }
  1718. // Retrying current package
  1719. if (m_rAuth.fRetryPackage)
  1720. {
  1721. // Don't retry again
  1722. m_rAuth.fRetryPackage = FALSE;
  1723. }
  1724. // Get negotiation string
  1725. if (FAILED(SSPIGetNegotiate(&m_rAuth.rSicInfo, &Negotiate)))
  1726. {
  1727. // Cancel Authentication
  1728. CancelAuthInProg();
  1729. // Done
  1730. goto exit;
  1731. }
  1732. // Send AUTH Respons
  1733. if (FSendSicilyString(Negotiate.szBuffer))
  1734. m_rAuth.authstate = AUTH_NEGO_RESP;
  1735. exit:
  1736. // Done
  1737. return;
  1738. }
  1739. // ------------------------------------------------------------------------------------
  1740. // CSMTPTransport::DoAuthNegoResponse
  1741. // ------------------------------------------------------------------------------------
  1742. void CSMTPTransport::DoAuthNegoResponse(HRESULT hrResponse)
  1743. {
  1744. // Locals
  1745. HRESULT hr=S_OK;
  1746. SSPIBUFFER Challenge;
  1747. SSPIBUFFER Response;
  1748. if (!m_pszResponse)
  1749. {
  1750. Assert(m_pszResponse);
  1751. return;
  1752. }
  1753. // Invalid Arg
  1754. Assert(m_rAuth.iAuthToken < m_rAuth.cAuthToken);
  1755. // Failure, retry login
  1756. if (FAILED(hrResponse) || (lstrlen(m_pszResponse) < 4))
  1757. {
  1758. // RetryPackage
  1759. RetryPackage();
  1760. // Done
  1761. goto exit;
  1762. }
  1763. // Set Chal String - skip over "+ "
  1764. SSPISetBuffer(m_pszResponse + 4, SSPI_STRING, 0, &Challenge);
  1765. // Get response from challenge
  1766. if (FAILED(SSPIResponseFromChallenge(&m_rAuth.rSicInfo, &Challenge, &Response)))
  1767. {
  1768. // Cancel Authentication
  1769. CancelAuthInProg();
  1770. // Done
  1771. goto exit;
  1772. }
  1773. // Send AUTH Respons
  1774. if (FSendSicilyString(Response.szBuffer))
  1775. {
  1776. // if we need to continue, we keep the state the same
  1777. // else we transition to the AUTH_RESP_RESP state.
  1778. if (!Response.fContinue)
  1779. m_rAuth.authstate = AUTH_RESP_RESP;
  1780. }
  1781. exit:
  1782. // Done
  1783. return;
  1784. }
  1785. // ------------------------------------------------------------------------------------
  1786. // CSMTPTransport::DoAuthRespResponse
  1787. // ------------------------------------------------------------------------------------
  1788. void CSMTPTransport::DoAuthRespResponse(HRESULT hrResponse)
  1789. {
  1790. // Failure
  1791. if (FAILED(hrResponse))
  1792. {
  1793. // RetryPackage
  1794. RetryPackage();
  1795. // Done
  1796. goto exit;
  1797. }
  1798. // We will free the context, but keep the credential handle
  1799. SSPIReleaseContext(&m_rAuth.rSicInfo);
  1800. // OnAuthorized
  1801. OnAuthorized();
  1802. exit:
  1803. // Done
  1804. return;
  1805. }
  1806. // ------------------------------------------------------------------------------------
  1807. // CSMTPTransport::OnAuthorized
  1808. // ------------------------------------------------------------------------------------
  1809. void CSMTPTransport::OnAuthorized(void)
  1810. {
  1811. // Connected (Authorized) state
  1812. OnStatus(IXP_AUTHORIZED);
  1813. // No more authorization
  1814. m_fConnectAuth = FALSE;
  1815. // Send command
  1816. m_command = SMTP_CONNECTED;
  1817. // Dispatch response
  1818. DispatchResponse(S_OK, TRUE);
  1819. }
  1820. // ------------------------------------------------------------------------------------
  1821. // CSMTPTransport::RetryPackage
  1822. // ------------------------------------------------------------------------------------
  1823. void CSMTPTransport::RetryPackage(void)
  1824. {
  1825. // retry current package, with prompt
  1826. m_rAuth.fRetryPackage = TRUE;
  1827. // Send the auth command again
  1828. HRESULT hr = CommandAUTH(m_rAuth.rgpszAuthTokens[m_rAuth.iAuthToken]);
  1829. if (FAILED(hr))
  1830. {
  1831. OnError(hr);
  1832. DropConnection();
  1833. goto exit;
  1834. }
  1835. // New State
  1836. m_rAuth.authstate = AUTH_TRYING_PACKAGE;
  1837. // Free current information
  1838. SSPIFreeContext(&m_rAuth.rSicInfo);
  1839. exit:
  1840. // Done
  1841. return;
  1842. }
  1843. // ------------------------------------------------------------------------------------
  1844. // CSMTPTransport::FSendSicilyString
  1845. // ------------------------------------------------------------------------------------
  1846. BOOL CSMTPTransport::FSendSicilyString(LPSTR pszData)
  1847. {
  1848. // Locals
  1849. LPSTR pszLine=NULL;
  1850. HRESULT hr=S_OK;
  1851. // Check Param
  1852. Assert(pszData);
  1853. // Allocate a line
  1854. DWORD cchSize = (lstrlen(pszData) + 5);
  1855. pszLine = PszAllocA(cchSize * sizeof(pszLine[0]));
  1856. if (NULL == pszLine)
  1857. {
  1858. OnError(E_OUTOFMEMORY);
  1859. DropConnection();
  1860. return FALSE;
  1861. }
  1862. // Make Line
  1863. wnsprintf(pszLine, cchSize, "%s\r\n", pszData);
  1864. // Send the lin
  1865. hr = HrSendLine(pszLine);
  1866. SafeMemFree(pszLine);
  1867. // Failure
  1868. if (FAILED(hr))
  1869. {
  1870. OnError(hr);
  1871. DropConnection();
  1872. return FALSE;
  1873. }
  1874. // Success
  1875. return TRUE;
  1876. }
  1877. // ------------------------------------------------------------------------------------
  1878. // CSMTPTransport::CancelAuthInProg
  1879. // ------------------------------------------------------------------------------------
  1880. void CSMTPTransport::CancelAuthInProg(void)
  1881. {
  1882. // Locals
  1883. HRESULT hr;
  1884. // Send *, quit and die if it fails
  1885. hr = HrSendCommand((LPSTR)SMTP_AUTH_CANCEL_STR, NULL, FALSE);
  1886. if (FAILED(hr))
  1887. {
  1888. OnError(hr);
  1889. DropConnection();
  1890. }
  1891. else
  1892. {
  1893. // New state
  1894. m_command = SMTP_AUTH;
  1895. m_rAuth.authstate = AUTH_CANCELED;
  1896. }
  1897. }
  1898. // ------------------------------------------------------------------------------------
  1899. // CSMTPTransport::StartTLS
  1900. // ------------------------------------------------------------------------------------
  1901. void CSMTPTransport::StartTLS(void)
  1902. {
  1903. // Locals
  1904. HRESULT hr;
  1905. // Progress
  1906. OnStatus(IXP_SECURING);
  1907. hr = CommandSTARTTLS();
  1908. if (FAILED(hr))
  1909. {
  1910. OnError(hr);
  1911. DropConnection();
  1912. }
  1913. return;
  1914. }
  1915. // ------------------------------------------------------------------------------------
  1916. // CSMTPTransport::TryNextSecurityPkg
  1917. // ------------------------------------------------------------------------------------
  1918. void CSMTPTransport::TryNextSecurityPkg(void)
  1919. {
  1920. if (FALSE != FIsSecurityEnabled())
  1921. {
  1922. m_pSocket->TryNextSecurityPkg();
  1923. }
  1924. else
  1925. {
  1926. OnError(E_FAIL);
  1927. DropConnection();
  1928. }
  1929. return;
  1930. }
  1931. //***************************************************************************
  1932. // Function: SetWindow
  1933. //
  1934. // Purpose:
  1935. // This function creates the current window handle for async winsock process.
  1936. //
  1937. // Returns:
  1938. // HRESULT indicating success or failure.
  1939. //***************************************************************************
  1940. STDMETHODIMP CSMTPTransport::SetWindow(void)
  1941. {
  1942. HRESULT hr;
  1943. Assert(NULL != m_pSocket);
  1944. if(m_pSocket)
  1945. hr= m_pSocket->SetWindow();
  1946. else
  1947. hr= E_UNEXPECTED;
  1948. return hr;
  1949. }
  1950. //***************************************************************************
  1951. // Function: ResetWindow
  1952. //
  1953. // Purpose:
  1954. // This function closes the current window handle for async winsock process.
  1955. //
  1956. // Returns:
  1957. // HRESULT indicating success or failure.
  1958. //***************************************************************************
  1959. STDMETHODIMP CSMTPTransport::ResetWindow(void)
  1960. {
  1961. HRESULT hr;
  1962. Assert(NULL != m_pSocket);
  1963. if(m_pSocket)
  1964. hr= m_pSocket->ResetWindow();
  1965. else
  1966. hr= E_UNEXPECTED;
  1967. return hr;
  1968. }