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.

1367 lines
50 KiB

  1. /************************************************************************************************
  2. Copyright (c) 2001 Microsoft Corporation
  3. File Name: Pop3Context.cpp
  4. Abstract: Implementation of the POP3_CONTEXT Class
  5. Notes:
  6. History: 08/01/2001 Created by Hao Yu (haoyu)
  7. ************************************************************************************************/
  8. #include <stdafx.h>
  9. #include <ThdPool.hxx>
  10. #include <SockPool.hxx>
  11. #include <POP3Context.h>
  12. #ifdef ROCKALL3
  13. void * __cdecl
  14. operator new(size_t cb)
  15. {
  16. void *const pv = g_RockallHeap.New(cb);
  17. return pv;
  18. }
  19. void __cdecl
  20. operator delete(void *pv)
  21. {
  22. g_RockallHeap.Delete(pv);
  23. }
  24. #endif
  25. POP3_CONTEXT::POP3_CONTEXT()
  26. {
  27. Reset();
  28. }
  29. POP3_CONTEXT::~POP3_CONTEXT()
  30. {
  31. }
  32. void POP3_CONTEXT::Reset()
  33. {
  34. m_dwCurrentState=INIT_STATE;
  35. m_bFileTransmitPending=FALSE;
  36. m_bCommandComplete=TRUE;
  37. m_dwCommandSize=0;
  38. m_wszUserName[0]=0;
  39. m_szPassword[0]=0;
  40. m_szDomainName[0]=0;
  41. m_szCommandBuffer[0]=0;
  42. m_cPswdSize=0;
  43. m_dwAuthStatus=0;
  44. m_dwFailedAuthCount=0;
  45. m_AuthServer.Cleanup();
  46. }
  47. void POP3_CONTEXT::TimeOut(IO_CONTEXT *pIoContext)
  48. {
  49. TerminateConnection(pIoContext);
  50. }
  51. void POP3_CONTEXT::ProcessRequest(IO_CONTEXT *pIoContext,OVERLAPPED *pOverlapped,DWORD dwBytesRcvd)
  52. {
  53. POP3_CMD CurrentCmd=CMD_UNKNOWN;
  54. char szGreetingBuffer[MAX_PATH*2];
  55. LONG lTotalMsgSize, lMsgCnt;
  56. char *pEndOfCmd=NULL;
  57. if( ( NULL == pIoContext) ||
  58. ( NULL == pIoContext->m_hAsyncIO) )
  59. {
  60. //This is a rare shutdown case.
  61. //IO completion received after socket is shut down.
  62. if(NULL!=pIoContext)
  63. {
  64. //Signal that the IO Context should be deleted/reused
  65. pIoContext->m_ConType = DELETE_PENDING;
  66. }
  67. return;
  68. }
  69. ASSERT( LOCKED_TO_PROCESS_POP3_CMD == pIoContext->m_lLock);
  70. m_pIoContext=pIoContext;
  71. // BLaPorte - I moved transmit completion handling here to avoid confusion.
  72. // Check if this should be signal of TransmitFile completion
  73. if(m_bFileTransmitPending)
  74. {
  75. m_bFileTransmitPending=FALSE;
  76. //Here we calculate the perf on message size downloaded
  77. g_PerfCounters.AddPerfCntr(e_gcBytesTransmitted, dwBytesRcvd);
  78. g_PerfCounters.AddPerfCntr(e_gcBytesTransmitRate, dwBytesRcvd);
  79. WaitForCommand();
  80. return;
  81. }
  82. if(INIT_STATE == m_dwCurrentState)
  83. {
  84. if(SERVICE_RUNNING!=g_dwServerStatus)
  85. {
  86. //Reject the connection
  87. SendResponse(RESP_SERVER_NOT_AVAILABLE);
  88. TerminateConnection(pIoContext);
  89. return;
  90. }
  91. if( 0 > _snwprintf(m_wszGreeting,
  92. sizeof(m_wszGreeting)/sizeof(WCHAR),
  93. L"<%u@%s>",
  94. GetTickCount(),
  95. g_wszComputerName))
  96. {
  97. //Make sure length of <TimeStamp@Machine> is less than MAX_PATH
  98. m_wszGreeting[sizeof(m_wszGreeting)/sizeof(WCHAR)-1]=0;
  99. m_wszGreeting[sizeof(m_wszGreeting)/sizeof(WCHAR)-2]=L'>';
  100. }
  101. if(L'\0'!=g_wszGreeting[0])
  102. {
  103. _snprintf(szGreetingBuffer,
  104. sizeof(szGreetingBuffer)/sizeof(char),
  105. RESP_SERVER_READY,
  106. g_wszGreeting,
  107. m_wszGreeting);
  108. }
  109. else
  110. {
  111. _snprintf(szGreetingBuffer,
  112. sizeof(szGreetingBuffer)/sizeof(char),
  113. RESP_SERVER_READY,
  114. RESP_SERVER_GREETING,
  115. m_wszGreeting);
  116. }
  117. //Make sure the NULL is there
  118. szGreetingBuffer[sizeof(szGreetingBuffer)/sizeof(char)-1]=0;
  119. m_dwCurrentState=AUTH_STATE;
  120. g_PerfCounters.IncPerfCntr(e_gcAuthStateCnt);
  121. SendResponse(szGreetingBuffer);
  122. if(0==dwBytesRcvd)
  123. {
  124. WaitForCommand();
  125. return;
  126. }
  127. }
  128. // BLaPorte - oversized/undersized data should be rejected immediately.
  129. if(dwBytesRcvd >= POP3_REQUEST_BUF_SIZE ||
  130. dwBytesRcvd == 0)
  131. {
  132. //Error this command is too big or is nil
  133. //Consider this is an attack or
  134. // termination of a connection unexpectedly.
  135. TerminateConnection(pIoContext);
  136. return;
  137. }
  138. if( g_SocketPool.IsMaxSocketUsed() ) //Possible DoS Attack situation
  139. {
  140. DWORD dwTime=GetTickCount();
  141. if(AUTH_STATE==m_dwCurrentState)
  142. {
  143. //The connection is not authenticated for twice the shorted timeout
  144. if(dwTime>m_pIoContext->m_dwConnectionTime+SHORTENED_TIMEOUT) //The connection is not authenticated
  145. {
  146. TerminateConnection(pIoContext);
  147. return; //The connection will be terminated
  148. }
  149. }
  150. }
  151. // BLaPorte - moved the counter increment here since we do it in either case.
  152. g_PerfCounters.AddPerfCntr(e_gcBytesReceived, dwBytesRcvd);
  153. g_PerfCounters.AddPerfCntr(e_gcBytesReceiveRate, dwBytesRcvd);
  154. if(m_bCommandComplete)
  155. {
  156. m_dwCommandSize=dwBytesRcvd;
  157. memcpy(m_szCommandBuffer, m_pIoContext->m_Buffer,dwBytesRcvd);
  158. }
  159. else
  160. {
  161. if(m_dwCommandSize+dwBytesRcvd >= POP3_REQUEST_BUF_SIZE)
  162. {
  163. //Error this command is too big!
  164. //Consider this is an attack.
  165. TerminateConnection(pIoContext);
  166. return;
  167. }
  168. memcpy(m_szCommandBuffer+m_dwCommandSize, m_pIoContext->m_Buffer,dwBytesRcvd);
  169. m_dwCommandSize+=dwBytesRcvd;
  170. }
  171. m_szCommandBuffer[m_dwCommandSize]='\0';
  172. pEndOfCmd=strstr(m_szCommandBuffer,"\r\n");
  173. if(NULL == pEndOfCmd)
  174. {
  175. m_bCommandComplete=FALSE;
  176. WaitForCommand();
  177. return;
  178. }
  179. else
  180. {
  181. m_bCommandComplete=TRUE;
  182. *pEndOfCmd='\0'; //Cut the \r\n
  183. m_dwCommandSize-=2;
  184. }
  185. if(m_dwAuthStatus!=1)
  186. {
  187. CurrentCmd=ParseCommand();
  188. if(CMD_UNKNOWN == CurrentCmd)
  189. {
  190. // Count the bad commands?
  191. SendResponse(RESP_UNKNOWN_COMMAND);
  192. if(!g_SocketPool.IsMaxSocketUsed() )
  193. {
  194. WaitForCommand();
  195. }
  196. else
  197. {
  198. TerminateConnection(pIoContext);
  199. }
  200. return;
  201. }
  202. }
  203. else
  204. {
  205. CurrentCmd=CMD_AUTH;
  206. }
  207. if(AUTH_STATE == m_dwCurrentState)
  208. {
  209. if(!ProcessAuthStateCommands(CurrentCmd,m_dwCommandSize))
  210. {
  211. TerminateConnection(pIoContext);
  212. }
  213. }
  214. else // TRANS_STATE == m_dwCurrentState
  215. {
  216. if(dwBytesRcvd == 0)
  217. {
  218. //Connection terminated
  219. TerminateConnection(pIoContext);
  220. }
  221. if(!ProcessTransStateCommands(CurrentCmd, m_dwCommandSize))
  222. {
  223. TerminateConnection(pIoContext);
  224. }
  225. }
  226. }
  227. void POP3_CONTEXT::WaitForCommand()
  228. {
  229. int iRet;
  230. DWORD cbRevd=0;
  231. DWORD Flags=0;
  232. ASSERT( NULL != m_pIoContext);
  233. ASSERT( NULL != m_pIoContext->m_hAsyncIO);
  234. if(NULL == m_pIoContext->m_hAsyncIO)
  235. {
  236. TerminateConnection(m_pIoContext);
  237. return;
  238. }
  239. WSABUF wsaBuf={POP3_REQUEST_BUF_SIZE, m_pIoContext->m_Buffer};
  240. iRet=WSARecv(m_pIoContext->m_hAsyncIO,
  241. &wsaBuf,
  242. 1,
  243. &cbRevd,
  244. &Flags,
  245. &(m_pIoContext->m_Overlapped),
  246. NULL);
  247. if(SOCKET_ERROR == iRet )
  248. {
  249. iRet=WSAGetLastError();
  250. if(iRet != ERROR_IO_PENDING )
  251. {
  252. //Problem with this connection
  253. //We terminate the connection
  254. TerminateConnection(m_pIoContext);
  255. }
  256. }
  257. }
  258. void POP3_CONTEXT::TerminateConnection(PIO_CONTEXT pIoContext)
  259. {
  260. SOCKET hSocket;
  261. if(NULL!=pIoContext)
  262. {
  263. if(pIoContext->m_ConType != DELETE_PENDING)
  264. {
  265. m_MailBox.QuitAndClose();
  266. hSocket=(SOCKET)InterlockedExchange((LPLONG)( &(pIoContext->m_hAsyncIO)), NULL);
  267. if(NULL != hSocket )
  268. {
  269. closesocket(hSocket);
  270. g_SocketPool.DecrementTotalSocketCount();
  271. switch (m_dwCurrentState)
  272. {
  273. case UPDATE_STATE:
  274. break;
  275. case TRANS_STATE:
  276. g_PerfCounters.DecPerfCntr(e_gcTransStateCnt);
  277. break;
  278. case AUTH_STATE:
  279. g_PerfCounters.DecPerfCntr(e_gcAuthStateCnt);
  280. break;
  281. }
  282. g_PerfCounters.DecPerfCntr(e_gcConnectedSocketCnt);
  283. }
  284. if(!m_bFileTransmitPending)
  285. {
  286. pIoContext->m_ConType = DELETE_PENDING;
  287. }
  288. }
  289. }
  290. }
  291. POP3_CMD POP3_CONTEXT::ParseCommand()
  292. {
  293. int i=0;
  294. if(strlen(m_szCommandBuffer) < COMMAND_SIZE-1)
  295. {
  296. return CMD_UNKNOWN;
  297. }
  298. //Check if any invalid characters
  299. for(i=0; i< m_dwCommandSize; i++)
  300. {
  301. if(!isprint(m_szCommandBuffer[i]))
  302. {
  303. return CMD_UNKNOWN;
  304. }
  305. }
  306. for(i=0; i< CMD_UNKNOWN; i++)
  307. {
  308. if( 0 == _strnicmp(m_szCommandBuffer, cszCommands[i], ciCommandSize[i]) )
  309. {
  310. return (POP3_CMD)i;
  311. }
  312. }
  313. return CMD_UNKNOWN;
  314. }
  315. BOOL POP3_CONTEXT::ProcessAuthStateCommands(POP3_CMD CurrentCmd,
  316. DWORD dwBytesRcvd)
  317. {
  318. BOOL bRetVal=FALSE;
  319. char szBuf[POP3_RESPONSE_BUF_SIZE];
  320. char szUserName[POP3_MAX_ADDRESS_LENGTH];
  321. BSTR bstrUserName=NULL;
  322. szBuf[POP3_RESPONSE_BUF_SIZE-1]='\0';
  323. // BLaPorte - wszPassword could potentially be used to concatenate 2 strings of length MAX_PATH + change.
  324. WCHAR wszPassword[2*MAX_PATH+32];
  325. HRESULT hr=E_FAIL;
  326. VARIANT vPassword;
  327. VariantInit(&vPassword);
  328. switch (CurrentCmd)
  329. {
  330. case CMD_USER: if( (m_szCommandBuffer[COMMAND_SIZE]!=' ') &&
  331. (m_szCommandBuffer[COMMAND_SIZE]!='\0') )
  332. {
  333. SendResponse(RESP_UNKNOWN_COMMAND);
  334. }
  335. else if(g_dwRequireSPA)
  336. {
  337. SendResponse(RESP_SPA_REQUIRED);
  338. bRetVal=TRUE;
  339. }
  340. else if(m_wszUserName[0] != 0 )
  341. {
  342. SendResponse(RESP_CMD_NOT_SUPPORTED);
  343. }
  344. else
  345. {
  346. if(GetNextStringParameter(
  347. &(m_szCommandBuffer[COMMAND_SIZE]),
  348. szUserName,
  349. sizeof(szUserName)/sizeof(char)))
  350. {
  351. AnsiToUnicode(szUserName, -1, m_wszUserName, sizeof(m_wszUserName)/sizeof(WCHAR));
  352. SendResponse(RESP_OK);
  353. bRetVal=TRUE;
  354. }
  355. else
  356. {
  357. SendResponse(RESP_CMD_NOT_VALID);
  358. }
  359. }
  360. if(! g_SocketPool.IsMaxSocketUsed() )
  361. {
  362. bRetVal=TRUE;
  363. }
  364. break;
  365. case CMD_PASS:
  366. //
  367. // BLaPorte - make sure the password is cleared from the receive buffer.
  368. //
  369. SecureZeroMemory(m_pIoContext->m_Buffer,sizeof(m_pIoContext->m_Buffer));
  370. if(m_wszUserName[0] == 0)
  371. {
  372. SendResponse(RESP_CMD_NOT_SUPPORTED);
  373. if(! g_SocketPool.IsMaxSocketUsed() )
  374. {
  375. bRetVal=TRUE;
  376. }
  377. break;
  378. }
  379. else //USER command alread issued
  380. {
  381. if( (m_dwCommandSize == COMMAND_SIZE ) ||
  382. ((m_dwCommandSize == COMMAND_SIZE +1) &&
  383. (' '==m_szCommandBuffer[COMMAND_SIZE] )) )
  384. {
  385. //No password
  386. m_cPswdSize=0;
  387. }
  388. else
  389. {
  390. m_cPswdSize=m_dwCommandSize-COMMAND_SIZE-1;
  391. if( (m_cPswdSize >= sizeof(m_szPassword)/sizeof(char)) ||
  392. (' '!=m_szCommandBuffer[COMMAND_SIZE]) )
  393. {
  394. SendResponse(RESP_CMD_NOT_VALID);
  395. m_wszUserName[0] = 0;
  396. //
  397. // BLaPorte - Zero out command buffer so cleartext password isn't
  398. // lying around in memory.
  399. //
  400. SecureZeroMemory(m_szCommandBuffer,m_dwCommandSize);
  401. if(! g_SocketPool.IsMaxSocketUsed() )
  402. {
  403. bRetVal=TRUE;
  404. }
  405. break;
  406. }
  407. strncpy(m_szPassword, &(m_szCommandBuffer[COMMAND_SIZE+1]), sizeof(m_szPassword)/sizeof(char)-1);
  408. m_szPassword[sizeof(m_szPassword)/sizeof(char)-1]=0;
  409. SecureZeroMemory(m_szCommandBuffer,m_dwCommandSize);
  410. }
  411. }
  412. //Do Authentication here
  413. bstrUserName=SysAllocString(m_wszUserName);
  414. AnsiToUnicode(m_szPassword, -1, wszPassword, sizeof(wszPassword)/sizeof(WCHAR));
  415. //
  416. // BLaPorte - clear the password.
  417. //
  418. SecureZeroMemory(m_szPassword,sizeof(m_szPassword));
  419. vPassword.vt=VT_BSTR;
  420. if(0==m_cPswdSize)
  421. {
  422. vPassword.bstrVal=NULL;
  423. }
  424. else
  425. {
  426. vPassword.bstrVal=SysAllocString(wszPassword);
  427. SecureZeroMemory(wszPassword,sizeof(wszPassword));
  428. }
  429. if(NULL != bstrUserName)
  430. {
  431. if(S_OK == ( hr= g_pAuthMethod->Authenticate(bstrUserName, vPassword)))
  432. {
  433. bRetVal=TRUE;
  434. }
  435. else if(E_ACCESSDENIED == hr )
  436. {
  437. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  438. POP3SVR_MAILROOT_ACCESS_DENIED,
  439. m_wszUserName,
  440. 1);
  441. }
  442. }
  443. SysFreeString(bstrUserName);
  444. if(NULL != vPassword.bstrVal)
  445. {
  446. SecureZeroMemory(vPassword.bstrVal,SysStringByteLen(vPassword.bstrVal));
  447. SysFreeString(vPassword.bstrVal);
  448. }
  449. //Open the mailbox
  450. if(bRetVal)
  451. {
  452. bRetVal=m_MailBox.OpenMailBox(m_wszUserName);
  453. }
  454. if (bRetVal)
  455. {
  456. bRetVal=m_MailBox.LockMailBox();
  457. if(bRetVal)
  458. {
  459. bRetVal=m_MailBox.EnumerateMailBox(g_dwMaxMsgPerDnld);
  460. if(!bRetVal)
  461. {
  462. m_MailBox.UnlockMailBox();
  463. }
  464. }
  465. }
  466. else
  467. {
  468. //Open mailbox failed
  469. if(ERROR_ACCESS_DENIED==GetLastError())
  470. { //Log the event
  471. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  472. POP3SVR_MAILROOT_ACCESS_DENIED,
  473. m_wszUserName,
  474. 1);
  475. }
  476. }
  477. if (!bRetVal)
  478. {
  479. g_PerfCounters.IncPerfCntr(e_gcFailedLogonCnt);
  480. m_dwFailedAuthCount++;
  481. if( MAX_FAILED_AUTH<=m_dwFailedAuthCount )
  482. {
  483. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  484. POP3SVR_MAX_LOGON_FAILURES,
  485. m_wszUserName,
  486. 1);
  487. }
  488. else
  489. {
  490. if(! g_SocketPool.IsMaxSocketUsed() )
  491. {
  492. bRetVal=TRUE; //Don't disconnect
  493. }
  494. }
  495. SendResponse(RESP_ACCOUNT_ERROR);
  496. m_wszUserName[0] = 0;
  497. }
  498. else
  499. {
  500. m_dwCurrentState=TRANS_STATE;
  501. g_PerfCounters.DecPerfCntr(e_gcAuthStateCnt);
  502. g_PerfCounters.IncPerfCntr(e_gcTransStateCnt);
  503. SendResponse(RESP_AUTH_DONE);
  504. }
  505. break;
  506. case CMD_APOP: char *pPswd;
  507. //
  508. // BLaPorte - Clear the receive buffer.
  509. //
  510. SecureZeroMemory(m_pIoContext->m_Buffer,sizeof(m_pIoContext->m_Buffer));
  511. pPswd=strchr( &(m_szCommandBuffer[COMMAND_SIZE+1]), ' ');
  512. if(NULL == pPswd)
  513. {
  514. SecureZeroMemory(m_szCommandBuffer,m_dwCommandSize);
  515. SendResponse(RESP_ACCOUNT_ERROR);
  516. if(! g_SocketPool.IsMaxSocketUsed() )
  517. {
  518. bRetVal=TRUE;
  519. }
  520. break;
  521. }
  522. *pPswd='\0';
  523. strncpy(szUserName, &(m_szCommandBuffer[COMMAND_SIZE+1]), sizeof(szUserName)/sizeof(char)-1);
  524. szUserName[sizeof(szUserName)/sizeof(char)-1]=0;
  525. pPswd++;
  526. strncpy(m_szPassword, pPswd, sizeof(m_szPassword)/sizeof(char)-1);
  527. m_szPassword[sizeof(m_szPassword)/sizeof(char)-1]=0;
  528. SecureZeroMemory(m_szCommandBuffer,m_dwCommandSize);
  529. if(strlen(m_szPassword) != MD5_HASH_SIZE )
  530. {
  531. SecureZeroMemory(m_szPassword,sizeof(m_szPassword));
  532. SendResponse(RESP_ACCOUNT_ERROR);
  533. if(! g_SocketPool.IsMaxSocketUsed() )
  534. {
  535. bRetVal=TRUE;
  536. }
  537. break;
  538. }
  539. //Do the authentication
  540. AnsiToUnicode(szUserName, -1,m_wszUserName, sizeof(m_wszUserName)/sizeof(WCHAR));
  541. bstrUserName=SysAllocString(m_wszUserName);
  542. AnsiToUnicode(m_szPassword, -1, wszPassword, sizeof(wszPassword)/sizeof(WCHAR));
  543. SecureZeroMemory(m_szPassword,sizeof(m_szPassword));
  544. wcscat(wszPassword, m_wszGreeting);
  545. vPassword.vt=VT_BSTR;
  546. vPassword.bstrVal=SysAllocString(wszPassword);
  547. SecureZeroMemory(wszPassword,sizeof(wszPassword));
  548. if(NULL != bstrUserName &&
  549. NULL != vPassword.bstrVal)
  550. {
  551. if(S_OK == (hr= g_pAuthMethod->Authenticate(bstrUserName, vPassword)))
  552. {
  553. bRetVal=TRUE;
  554. }
  555. else if(E_ACCESSDENIED == hr )
  556. {
  557. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  558. POP3SVR_MAILROOT_ACCESS_DENIED,
  559. m_wszUserName,
  560. 1);
  561. }
  562. }
  563. SysFreeString(bstrUserName);
  564. SecureZeroMemory(vPassword.bstrVal,SysStringByteLen(vPassword.bstrVal));
  565. SysFreeString(vPassword.bstrVal);
  566. //Open the mailbox
  567. if(bRetVal)
  568. {
  569. bRetVal=m_MailBox.OpenMailBox(m_wszUserName);
  570. }
  571. if (bRetVal)
  572. {
  573. bRetVal=m_MailBox.LockMailBox();
  574. if(bRetVal)
  575. {
  576. bRetVal=m_MailBox.EnumerateMailBox(g_dwMaxMsgPerDnld);
  577. if(!bRetVal)
  578. {
  579. m_MailBox.UnlockMailBox();
  580. }
  581. }
  582. }
  583. else
  584. {
  585. //Open mailbox failed
  586. if(ERROR_ACCESS_DENIED==GetLastError())
  587. { //Log the event
  588. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  589. POP3SVR_MAILROOT_ACCESS_DENIED,
  590. m_wszUserName,
  591. 1);
  592. }
  593. }
  594. if (!bRetVal)
  595. {
  596. g_PerfCounters.IncPerfCntr(e_gcFailedLogonCnt);
  597. m_dwFailedAuthCount++;
  598. if( MAX_FAILED_AUTH<=m_dwFailedAuthCount )
  599. {
  600. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  601. POP3SVR_MAX_LOGON_FAILURES,
  602. m_wszUserName,
  603. 1);
  604. }
  605. else
  606. {
  607. if(! g_SocketPool.IsMaxSocketUsed() )
  608. {
  609. bRetVal=TRUE; //Don't disconnect
  610. }
  611. }
  612. SendResponse(RESP_ACCOUNT_ERROR);
  613. }
  614. else
  615. {
  616. m_dwCurrentState=TRANS_STATE;
  617. g_PerfCounters.DecPerfCntr(e_gcAuthStateCnt);
  618. g_PerfCounters.IncPerfCntr(e_gcTransStateCnt);
  619. SendResponse(RESP_AUTH_DONE);
  620. }
  621. break;
  622. case CMD_AUTH: if(0==m_dwAuthStatus)
  623. {
  624. //First time AUTH command
  625. //Only when AD/Local SAM Auth is used,
  626. //we support NTLM
  627. if(AUTH_OTHER==g_dwAuthMethod)
  628. {
  629. SendResponse(RESP_CMD_NOT_SUPPORTED);
  630. bRetVal=TRUE;
  631. }
  632. else
  633. {
  634. if(IsEndOfCommand(&(m_szCommandBuffer[COMMAND_SIZE])))
  635. {
  636. SendResponse(RESP_AUTH_METHODS);
  637. bRetVal=TRUE;
  638. }
  639. else
  640. {
  641. szBuf[0]='\0';
  642. if((GetNextStringParameter( &(m_szCommandBuffer[COMMAND_SIZE]),
  643. szBuf,
  644. POP3_RESPONSE_BUF_SIZE) ) &&
  645. (0==_stricmp(szBuf, SZ_NTLM)) )
  646. {
  647. SendResponse(RESP_OK);
  648. m_dwAuthStatus=1;
  649. bRetVal=TRUE;
  650. }
  651. else
  652. {
  653. SendResponse(RESP_CMD_NOT_VALID);
  654. }
  655. }
  656. }
  657. }
  658. else // This is specific to auth protocol
  659. {
  660. char OutBuf[AUTH_BUF_SIZE];
  661. DWORD dwOutBufSize=AUTH_BUF_SIZE;
  662. SecureZeroMemory(OutBuf, AUTH_BUF_SIZE);
  663. hr=m_AuthServer.HandShake((LPBYTE)m_szCommandBuffer,
  664. dwBytesRcvd,
  665. (LPBYTE)OutBuf,
  666. &dwOutBufSize);
  667. if(S_FALSE==hr)
  668. {
  669. SendResponse(OutBuf);
  670. bRetVal=TRUE;
  671. }
  672. else if(S_OK==hr)
  673. {
  674. m_dwAuthStatus=0;
  675. //Authentication Done!
  676. if(S_OK==m_AuthServer.GetUserName(m_wszUserName))
  677. {
  678. bRetVal=TRUE;
  679. }
  680. else
  681. {
  682. bRetVal=FALSE;
  683. }
  684. //Now open the mailbox
  685. if(bRetVal)
  686. {
  687. bRetVal=m_MailBox.OpenMailBox(m_wszUserName);
  688. }
  689. if (bRetVal)
  690. {
  691. bRetVal=m_MailBox.LockMailBox();
  692. if(bRetVal)
  693. {
  694. bRetVal=m_MailBox.EnumerateMailBox(g_dwMaxMsgPerDnld);
  695. if(!bRetVal)
  696. {
  697. m_MailBox.UnlockMailBox();
  698. }
  699. }
  700. }
  701. else
  702. {
  703. //Open mailbox failed
  704. if(ERROR_ACCESS_DENIED==GetLastError())
  705. { //Log the event
  706. g_EventLogger.LogEvent(LOGTYPE_ERR_WARNING,
  707. POP3SVR_MAILROOT_ACCESS_DENIED,
  708. m_wszUserName,
  709. 1);
  710. }
  711. }
  712. if (!bRetVal)
  713. {
  714. m_dwAuthStatus=0;
  715. m_AuthServer.Cleanup();
  716. g_PerfCounters.IncPerfCntr(e_gcFailedLogonCnt);
  717. m_dwFailedAuthCount++;
  718. SendResponse(RESP_ACCOUNT_ERROR);
  719. if( (MAX_FAILED_AUTH>m_dwFailedAuthCount) &&
  720. (! g_SocketPool.IsMaxSocketUsed() ) )
  721. {
  722. bRetVal=TRUE; //Don't disconnect
  723. }
  724. }
  725. else
  726. {
  727. m_dwCurrentState=TRANS_STATE;
  728. g_PerfCounters.DecPerfCntr(e_gcAuthStateCnt);
  729. g_PerfCounters.IncPerfCntr(e_gcTransStateCnt);
  730. SendResponse(RESP_AUTH_DONE);
  731. bRetVal=TRUE;
  732. }
  733. }
  734. else // Failed Auth
  735. {
  736. m_dwAuthStatus=0;
  737. m_AuthServer.Cleanup();
  738. g_PerfCounters.IncPerfCntr(e_gcFailedLogonCnt);
  739. m_dwFailedAuthCount++;
  740. SendResponse(RESP_CMD_NOT_VALID);
  741. if( (MAX_FAILED_AUTH>m_dwFailedAuthCount) &&
  742. (! g_SocketPool.IsMaxSocketUsed() ) )
  743. {
  744. bRetVal=TRUE; //Don't disconnect
  745. }
  746. }
  747. }
  748. break;
  749. case CMD_QUIT: if(IsEndOfCommand(&(m_szCommandBuffer[COMMAND_SIZE])))
  750. {
  751. g_PerfCounters.DecPerfCntr(e_gcAuthStateCnt);
  752. m_dwCurrentState=UPDATE_STATE;
  753. if(L'\0'!=g_wszGreeting[0])
  754. {
  755. _snprintf(szBuf,
  756. POP3_RESPONSE_BUF_SIZE-1,
  757. RESP_SERVER_QUIT,
  758. g_wszGreeting,
  759. m_wszGreeting);
  760. }
  761. else
  762. {
  763. _snprintf(szBuf,
  764. POP3_RESPONSE_BUF_SIZE-1,
  765. RESP_SERVER_QUIT,
  766. RESP_SERVER_GREETING,
  767. m_wszGreeting);
  768. }
  769. szBuf[POP3_RESPONSE_BUF_SIZE-1]=0;
  770. SendResponse(szBuf);
  771. }
  772. else
  773. {
  774. SendResponse(RESP_CMD_NOT_VALID);
  775. if(! g_SocketPool.IsMaxSocketUsed() )
  776. {
  777. bRetVal=TRUE;
  778. }
  779. }
  780. break;
  781. case CMD_STAT:
  782. case CMD_LIST:
  783. case CMD_RETR:
  784. case CMD_DELE:
  785. case CMD_UIDL:
  786. case CMD_RSET:
  787. case CMD_TOP: SendResponse(RESP_CMD_NOT_SUPPORTED);
  788. if(! g_SocketPool.IsMaxSocketUsed() )
  789. {
  790. bRetVal=TRUE;
  791. }
  792. break;
  793. default: //CountUnknownCommand?
  794. SendResponse(RESP_UNKNOWN_COMMAND);
  795. if(! g_SocketPool.IsMaxSocketUsed() )
  796. {
  797. bRetVal=TRUE;// Still allow client to send another command
  798. }
  799. }
  800. if(bRetVal)
  801. {
  802. WaitForCommand();
  803. }
  804. return bRetVal;
  805. }
  806. BOOL POP3_CONTEXT::ProcessTransStateCommands(POP3_CMD CurrentCmd,
  807. DWORD dwBytesRcvd)
  808. {
  809. char szReBuf[POP3_RESPONSE_BUF_SIZE];
  810. char szReHelpBuf[POP3_RESPONSE_BUF_SIZE];
  811. DWORD dwLen=0;
  812. DWORD dwCurLen;
  813. BOOL bRetVal=TRUE;
  814. int iArg=-1;
  815. int iArg2=-1;
  816. int iMailCount=0;
  817. DWORD dwResult;
  818. char *pCur=NULL;
  819. //The buffer will always be NULL terminated
  820. szReBuf[POP3_RESPONSE_BUF_SIZE-1]='\0';
  821. switch (CurrentCmd)
  822. {
  823. case CMD_STAT:if(!IsEndOfCommand(&(m_szCommandBuffer[COMMAND_SIZE])))
  824. {
  825. SendResponse(RESP_CMD_NOT_VALID);
  826. }
  827. else if(0 >_snprintf(szReBuf,
  828. POP3_RESPONSE_BUF_SIZE-1,
  829. "+OK %d %d\r\n",
  830. m_MailBox.GetCurrentMailCount(),
  831. m_MailBox.GetTotalSize()))
  832. {
  833. //This should not happen
  834. //EventLog??
  835. SendResponse(RESP_SERVER_ERROR);
  836. }
  837. else
  838. {
  839. szReBuf[POP3_RESPONSE_BUF_SIZE-1]=0;
  840. SendResponse(szReBuf);
  841. }
  842. WaitForCommand();
  843. break;
  844. case CMD_LIST:pCur=&(m_szCommandBuffer[COMMAND_SIZE]);
  845. if(!IsEndOfCommand(pCur))
  846. {
  847. if( (GetNextNumParameter(&pCur, &iArg)) &&
  848. (IsEndOfCommand(pCur)) )
  849. {
  850. dwResult=m_MailBox.ListMail(iArg-1, szReBuf, sizeof(szReBuf)/sizeof(char));
  851. SendResponse(dwResult, szReBuf);
  852. }
  853. else
  854. {
  855. SendResponse(RESP_CMD_NOT_VALID);
  856. }
  857. }
  858. else
  859. {
  860. if(0> _snprintf(szReBuf,
  861. POP3_RESPONSE_BUF_SIZE-1,
  862. "+OK %d messages (%d octets)\r\n",
  863. m_MailBox.GetCurrentMailCount(),
  864. m_MailBox.GetTotalSize()))
  865. {
  866. //This should not happen
  867. //EventLog??
  868. SendResponse(RESP_SERVER_ERROR);
  869. }
  870. else
  871. {
  872. iMailCount=m_MailBox.GetMailCount();
  873. dwLen=strlen(szReBuf);
  874. for(iArg=0; iArg<iMailCount; iArg++)
  875. {
  876. if(ERROR_SUCCESS==m_MailBox.ListMail(iArg,
  877. szReHelpBuf,
  878. sizeof(szReHelpBuf)/sizeof(char)))
  879. {
  880. dwCurLen=strlen(szReHelpBuf);
  881. if(dwLen+dwCurLen< POP3_RESPONSE_BUF_SIZE )
  882. {
  883. strcat(szReBuf, szReHelpBuf);
  884. dwLen+=dwCurLen;
  885. }
  886. else
  887. {
  888. SendResponse(szReBuf);
  889. strcpy(szReBuf, szReHelpBuf);
  890. dwLen=dwCurLen;
  891. }
  892. }
  893. }
  894. if(dwLen+sizeof(RESP_END_OF_LIST)<POP3_RESPONSE_BUF_SIZE)
  895. {
  896. strcat(szReBuf, RESP_END_OF_LIST);
  897. SendResponse(szReBuf);
  898. }
  899. else
  900. {
  901. if(dwLen)
  902. {
  903. SendResponse(szReBuf);
  904. }
  905. SendResponse(RESP_END_OF_LIST);
  906. }
  907. }
  908. }
  909. WaitForCommand();
  910. break;
  911. case CMD_UIDL:pCur=&(m_szCommandBuffer[COMMAND_SIZE]);
  912. if(!IsEndOfCommand(pCur))
  913. {
  914. if( (GetNextNumParameter(&pCur, &iArg)) &&
  915. (IsEndOfCommand(pCur)) )
  916. {
  917. dwResult=m_MailBox.UidlMail(iArg-1, szReBuf, sizeof(szReBuf)/sizeof(char));
  918. SendResponse(dwResult, szReBuf);
  919. }
  920. else
  921. {
  922. SendResponse(RESP_CMD_NOT_VALID);
  923. }
  924. }
  925. else
  926. {
  927. if(0> _snprintf(szReBuf,
  928. POP3_RESPONSE_BUF_SIZE-1,
  929. "+OK %d messages (%d octets)\r\n",
  930. m_MailBox.GetCurrentMailCount(),
  931. m_MailBox.GetTotalSize()))
  932. {
  933. //This should not happen
  934. //EventLog??
  935. SendResponse(RESP_SERVER_ERROR);
  936. }
  937. else
  938. {
  939. iMailCount=m_MailBox.GetMailCount();
  940. dwLen=strlen(szReBuf);
  941. for(iArg=0; iArg<iMailCount; iArg++)
  942. {
  943. if(ERROR_SUCCESS==m_MailBox.UidlMail(iArg,
  944. szReHelpBuf,
  945. sizeof(szReBuf)/sizeof(char)))
  946. {
  947. dwCurLen=strlen(szReHelpBuf);
  948. if(dwLen+dwCurLen< POP3_RESPONSE_BUF_SIZE )
  949. {
  950. strcat(szReBuf, szReHelpBuf);
  951. dwLen+=dwCurLen;
  952. }
  953. else
  954. {
  955. SendResponse(szReBuf);
  956. strcpy(szReBuf, szReHelpBuf);
  957. dwLen=dwCurLen;
  958. }
  959. }
  960. }
  961. if(dwLen+sizeof(RESP_END_OF_LIST)<POP3_RESPONSE_BUF_SIZE)
  962. {
  963. strcat(szReBuf, RESP_END_OF_LIST);
  964. SendResponse(szReBuf);
  965. }
  966. else
  967. {
  968. if(dwLen)
  969. {
  970. SendResponse(szReBuf);
  971. }
  972. SendResponse(RESP_END_OF_LIST);
  973. }
  974. }
  975. }
  976. WaitForCommand();
  977. break;
  978. case CMD_RETR://RETR must hava one argument
  979. pCur=&(m_szCommandBuffer[COMMAND_SIZE]);
  980. if( (GetNextNumParameter(&pCur, &iArg)) &&
  981. (IsEndOfCommand(pCur)) )
  982. {
  983. m_bFileTransmitPending=TRUE;
  984. dwResult=m_MailBox.TransmitMail(m_pIoContext, iArg-1);
  985. if(ERROR_SUCCESS != dwResult)
  986. {
  987. m_bFileTransmitPending=FALSE;
  988. SendResponse(RESP_INVALID_MAIL_NUMBER);
  989. WaitForCommand();
  990. }
  991. else
  992. {
  993. g_PerfCounters.IncPerfCntr(e_gcTotMsgDnldCnt);
  994. g_PerfCounters.IncPerfCntr(e_gcMsgDnldRate);
  995. }
  996. }
  997. else
  998. {
  999. SendResponse(RESP_CMD_NOT_VALID);
  1000. WaitForCommand();
  1001. }
  1002. break;
  1003. case CMD_TOP: //TOP must have two parameters
  1004. pCur=&(m_szCommandBuffer[COMMAND_SIZE-1]);
  1005. if( IsEndOfCommand(pCur) )
  1006. {
  1007. SendResponse(RESP_CMD_NOT_VALID);
  1008. }
  1009. else
  1010. {
  1011. if( (GetNextNumParameter(&pCur, &iArg)) &&
  1012. !(IsEndOfCommand(pCur)) )
  1013. {
  1014. if((GetNextNumParameter(&pCur, &iArg2)) &&
  1015. (IsEndOfCommand(pCur)) )
  1016. {
  1017. m_bFileTransmitPending=TRUE;
  1018. dwResult=m_MailBox.TransmitMail(m_pIoContext, iArg-1, iArg2);
  1019. if(ERROR_SUCCESS !=dwResult)
  1020. {
  1021. m_bFileTransmitPending=FALSE;
  1022. SendResponse(RESP_INVALID_MAIL_NUMBER);
  1023. }
  1024. else
  1025. {
  1026. g_PerfCounters.IncPerfCntr(e_gcTotMsgDnldCnt);
  1027. g_PerfCounters.IncPerfCntr(e_gcMsgDnldRate);
  1028. //
  1029. // BLaPorte - do not call WaitForCommand in success case. This
  1030. // avoids the situation where we have two pending async
  1031. // completions.
  1032. //
  1033. break;
  1034. }
  1035. }
  1036. else
  1037. {
  1038. SendResponse(RESP_CMD_NOT_VALID);
  1039. }
  1040. }
  1041. else
  1042. {
  1043. SendResponse(RESP_CMD_NOT_VALID);
  1044. }
  1045. }
  1046. WaitForCommand();
  1047. break;
  1048. case CMD_DELE://DELE must have one argument
  1049. pCur=&(m_szCommandBuffer[COMMAND_SIZE]);
  1050. if( (GetNextNumParameter(&pCur, &iArg)) &&
  1051. (IsEndOfCommand(pCur)) )
  1052. {
  1053. dwResult=m_MailBox.DeleteMail(iArg-1);
  1054. if(ERROR_SUCCESS == dwResult)
  1055. {
  1056. SendResponse(RESP_MSG_MARKED_DELETED);
  1057. }
  1058. else
  1059. {
  1060. SendResponse(RESP_INVALID_MAIL_NUMBER);
  1061. }
  1062. }
  1063. else
  1064. {
  1065. SendResponse(RESP_CMD_NOT_VALID);
  1066. }
  1067. WaitForCommand();
  1068. break;
  1069. case CMD_NOOP://NOOP has no argument
  1070. if(!IsEndOfCommand(&(m_szCommandBuffer[COMMAND_SIZE])))
  1071. {
  1072. SendResponse(RESP_CMD_NOT_VALID);
  1073. }
  1074. else
  1075. {
  1076. SendResponse(RESP_OK);
  1077. }
  1078. WaitForCommand();
  1079. break;
  1080. case CMD_RSET://RSET has no argument
  1081. if(!IsEndOfCommand(&(m_szCommandBuffer[COMMAND_SIZE])))
  1082. {
  1083. SendResponse(RESP_CMD_NOT_VALID);
  1084. }
  1085. else
  1086. {
  1087. m_MailBox.Reset();
  1088. SendResponse(RESP_RESET);
  1089. }
  1090. WaitForCommand();
  1091. break;
  1092. case CMD_QUIT://QUIT has no argument
  1093. //Commit all changes to the mailbox and close the connection
  1094. if( m_MailBox.CommitAndClose())
  1095. {
  1096. g_PerfCounters.DecPerfCntr(e_gcTransStateCnt);
  1097. m_dwCurrentState=UPDATE_STATE;
  1098. if(L'\0'!=g_wszGreeting[0])
  1099. {
  1100. _snprintf(szReBuf,
  1101. POP3_RESPONSE_BUF_SIZE-1,
  1102. RESP_SERVER_QUIT,
  1103. g_wszGreeting,
  1104. m_wszGreeting);
  1105. }
  1106. else
  1107. {
  1108. _snprintf(szReBuf,
  1109. POP3_RESPONSE_BUF_SIZE-1,
  1110. RESP_SERVER_QUIT,
  1111. RESP_SERVER_GREETING,
  1112. m_wszGreeting);
  1113. }
  1114. szReBuf[POP3_RESPONSE_BUF_SIZE-1]=0;
  1115. SendResponse(szReBuf);
  1116. bRetVal=FALSE;
  1117. }
  1118. else
  1119. {
  1120. SendResponse(RESP_SERVER_ERROR);
  1121. bRetVal=FALSE; // In this case terminate the connection
  1122. }
  1123. break;
  1124. case CMD_USER:
  1125. case CMD_APOP:
  1126. case CMD_AUTH:
  1127. case CMD_PASS:SendResponse(RESP_CMD_NOT_SUPPORTED);
  1128. WaitForCommand();
  1129. break;
  1130. default:
  1131. SendResponse(RESP_UNKNOWN_COMMAND);
  1132. WaitForCommand();
  1133. }
  1134. return bRetVal;
  1135. }
  1136. void POP3_CONTEXT::SendResponse(char *szBuf)
  1137. {
  1138. int iErr;
  1139. ASSERT(m_pIoContext!=NULL);
  1140. ASSERT(m_pIoContext->m_hAsyncIO!=NULL);
  1141. if(SOCKET_ERROR == send(m_pIoContext->m_hAsyncIO,
  1142. szBuf,
  1143. strlen(szBuf),
  1144. 0))
  1145. {
  1146. iErr=WSAGetLastError();
  1147. //Can not send through the socket
  1148. //The connection will be terminated later
  1149. //in the WaitForCommand call.
  1150. }
  1151. }
  1152. void POP3_CONTEXT::SendResponse(DWORD dwResult, char *szBuf)
  1153. {
  1154. char szResp[POP3_RESPONSE_BUF_SIZE];
  1155. if(ERROR_SUCCESS == dwResult)
  1156. {
  1157. if( 0 > _snprintf(szResp,
  1158. POP3_RESPONSE_BUF_SIZE-1,
  1159. "+OK %s",
  1160. szBuf))
  1161. {
  1162. SendResponse(RESP_SERVER_ERROR);
  1163. }
  1164. else
  1165. {
  1166. szResp[POP3_RESPONSE_BUF_SIZE-1]=0;
  1167. SendResponse(szResp);
  1168. }
  1169. }
  1170. else
  1171. {
  1172. SendResponse(RESP_INVALID_MAIL_NUMBER);
  1173. }
  1174. }
  1175. BOOL POP3_CONTEXT::GetNextStringParameter(char *szInput, char *szOutput, DWORD dwOutputSize)
  1176. {
  1177. ASSERT(szInput!=NULL);
  1178. ASSERT(szOutput!=NULL);
  1179. //Must have at lease one space
  1180. if(!isspace(*szInput))
  1181. {
  1182. return FALSE;
  1183. }
  1184. do
  1185. {
  1186. szInput++;
  1187. }while(isspace(*szInput));
  1188. if('\0'==*szInput)
  1189. {
  1190. return FALSE;
  1191. }
  1192. //
  1193. // BLaPorte - added output size parameter to prevent buffer overflow.
  1194. //
  1195. if (strlen(szInput) >= dwOutputSize) {
  1196. return FALSE;
  1197. }
  1198. strcpy(szOutput,szInput);
  1199. return TRUE;
  1200. }
  1201. BOOL POP3_CONTEXT::GetNextNumParameter(char **pszInput, int *piOutput)
  1202. {
  1203. ASSERT(pszInput!=NULL);
  1204. ASSERT(*pszInput!=NULL);
  1205. char *szInput=*pszInput;
  1206. char *szEndInput=NULL;
  1207. if(!isspace(*szInput))
  1208. {
  1209. return FALSE;
  1210. }
  1211. do
  1212. {
  1213. szInput++;
  1214. }while(isspace(*szInput));
  1215. szEndInput=szInput;
  1216. if(!isdigit(*szEndInput))
  1217. {
  1218. return FALSE;
  1219. }
  1220. do
  1221. {
  1222. szEndInput++;
  1223. }while(isdigit(*szEndInput));
  1224. if((szEndInput-szInput) > MAX_INT_LEN )
  1225. {
  1226. return FALSE;
  1227. }
  1228. *piOutput=atoi(szInput);
  1229. *pszInput=szEndInput;
  1230. return TRUE;
  1231. }
  1232. BOOL POP3_CONTEXT::IsEndOfCommand(char *szInput)
  1233. {
  1234. ASSERT(szInput!=NULL);
  1235. while(isspace(*szInput))
  1236. {
  1237. szInput++;
  1238. }
  1239. if('\0'==*szInput)
  1240. {
  1241. return TRUE;
  1242. }
  1243. else
  1244. {
  1245. return FALSE;
  1246. }
  1247. }
  1248. BOOL POP3_CONTEXT::Unauthenticated()
  1249. {
  1250. return ( m_dwCurrentState==AUTH_STATE );
  1251. }