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.

762 lines
18 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1994 **/
  4. /**********************************************************************/
  5. /*
  6. connect.cxx
  7. This module contains the connection accept routine called by the connection
  8. thread.
  9. FILE HISTORY:
  10. Johnl 08-Aug-1994 Lifted from FTP server
  11. */
  12. #define INCL_INETSRV_INCS
  13. #include "smtpinc.h"
  14. #include <rdns.hxx>
  15. #include "smtpcli.hxx"
  16. //
  17. // Private prototypes.
  18. //
  19. VOID
  20. SmtpCompletion(
  21. PVOID pvContext,
  22. DWORD cbWritten,
  23. DWORD dwCompletionStatus,
  24. OVERLAPPED * lpo
  25. );
  26. SOCKERR CloseSocket( SOCKET sock );
  27. BOOL
  28. SendError(
  29. SOCKET socket,
  30. DWORD ids
  31. );
  32. //
  33. // Private functions.
  34. //
  35. /*++
  36. This function dereferences User data and kills the UserData object if the
  37. reference count hits 0. Before killing the user data, it also removes
  38. the connection from the list of active connections.
  39. --*/
  40. VOID DereferenceUserDataAndKill(IN OUT CLIENT_CONNECTION * pUserData)
  41. {
  42. pUserData->DisconnectClient();
  43. ((SMTP_CONNECTION*)pUserData)->QuerySmtpInstance()->RemoveConnection(pUserData);
  44. delete pUserData;
  45. } // DereferenceUserDataAndKill()
  46. void HandleErrorCondition(SOCKET sock, SMTP_SERVER_INSTANCE *pInstance, DWORD dwError, PSOCKADDR_IN pSockAddr)
  47. {
  48. char ErrorBuf[4 *MAX_PATH];
  49. const CHAR * apszSubStrings[2];
  50. CHAR pchAddr1[50] = "";
  51. CHAR pchAddr2[50] = "";
  52. DWORD SendSize;
  53. _ASSERT(pSockAddr != NULL);
  54. _ASSERT(pInstance != NULL);
  55. _ASSERT(sock != INVALID_SOCKET);
  56. SendSize = wsprintf (ErrorBuf, "%d-%s %s\r\n",
  57. SMTP_RESP_SRV_UNAVAIL,
  58. pInstance->GetConnectResponse(),
  59. SMTP_SRV_UNAVAIL_MSG);
  60. CLIENT_CONNECTION::WriteSocket(sock, ErrorBuf, SendSize );
  61. if(dwError == ERROR_REMOTE_SESSION_LIMIT_EXCEEDED)
  62. {
  63. _itoa(pInstance->QueryInstanceId(), pchAddr1, 10);
  64. InetNtoa(pSockAddr->sin_addr, pchAddr2 );
  65. apszSubStrings[0] = pchAddr1;
  66. apszSubStrings[1] = pchAddr2;
  67. SmtpLogEvent(SMTP_MAX_CONNECTION_REACHED,
  68. 2,
  69. apszSubStrings,
  70. NO_ERROR );
  71. }
  72. }
  73. BOOL VerifyClient(SMTP_CONNECTION * pNewClient, PSOCKADDR_IN psockAddrRemote)
  74. {
  75. AC_RESULT acIpAccess;
  76. BOOL fNeedDnsCheck = FALSE;
  77. BOOL fRet = TRUE;
  78. struct hostent* pH = NULL;
  79. pNewClient->QueryAccessCheck()->BindAddr( (PSOCKADDR)psockAddrRemote );
  80. if ( pNewClient->BindInstanceAccessCheck() )
  81. {
  82. acIpAccess = pNewClient->QueryAccessCheck()->CheckIpAccess( &fNeedDnsCheck);
  83. if ( (acIpAccess == AC_IN_DENY_LIST) ||
  84. ((acIpAccess == AC_NOT_IN_GRANT_LIST) && !fNeedDnsCheck) )
  85. {
  86. fRet = FALSE;
  87. }
  88. else if (fNeedDnsCheck)
  89. {
  90. pH = gethostbyaddr( (char*)(&((PSOCKADDR_IN)psockAddrRemote)->sin_addr),
  91. 4, PF_INET );
  92. if(pH != NULL)
  93. {
  94. acIpAccess = pNewClient->QueryAccessCheck()->CheckName(pH->h_name);
  95. }
  96. else
  97. {
  98. acIpAccess = AC_IN_DENY_LIST;
  99. }
  100. }
  101. if ( (acIpAccess == AC_IN_DENY_LIST) ||
  102. (acIpAccess == AC_NOT_IN_GRANT_LIST))
  103. {
  104. fRet = FALSE;
  105. }
  106. pNewClient->UnbindInstanceAccessCheck();
  107. }
  108. if(!fRet)
  109. {
  110. SetLastError(ERROR_ACCESS_DENIED);
  111. }
  112. return fRet;
  113. }
  114. BOOL
  115. ProcessNewClient(
  116. IN SOCKET sNew,
  117. IN PVOID EndpointObject,
  118. IN SMTP_SERVER_INSTANCE *pInstance,
  119. IN BOOL fMaxConnExceeded,
  120. IN PSOCKADDR_IN psockAddrRemote,
  121. IN PSOCKADDR_IN psockAddrLocal = NULL,
  122. IN PATQ_CONTEXT patqContext = NULL,
  123. IN PVOID pvBuff = NULL,
  124. IN DWORD cbWritten = 0,
  125. OUT LPBOOL pfAtqToBeFreed = NULL
  126. )
  127. {
  128. SMTP_CONNECTION * pNewClient = NULL;
  129. DWORD err = NO_ERROR;
  130. BOOL fReturn = FALSE;
  131. BOOL fMaxExceeded = FALSE;
  132. DBG_CODE( CHAR pchAddr[32];);
  133. BOOL fSockToBeFreed = TRUE;
  134. BOOL fDereferenceInstance = FALSE;
  135. BOOL fSupressErrorResponse = FALSE;
  136. CLIENT_CONN_PARAMS clientParams;
  137. TraceFunctEnterEx((LPARAM) NULL, "ProcessNewClient");
  138. DBG_CODE( InetNtoa( psockAddrRemote->sin_addr, pchAddr));
  139. if ( pfAtqToBeFreed != NULL)
  140. {
  141. *pfAtqToBeFreed = TRUE;
  142. }
  143. clientParams.sClient = sNew;
  144. clientParams.pAtqContext = patqContext;
  145. clientParams.pAddrLocal = (PSOCKADDR) psockAddrLocal;
  146. clientParams.pAddrRemote = (PSOCKADDR)psockAddrRemote;
  147. clientParams.pvInitialBuff = pvBuff;
  148. clientParams.cbInitialBuff = cbWritten ;
  149. clientParams.pEndpoint = (PIIS_ENDPOINT)EndpointObject;
  150. if( pInstance && (pInstance->IsShuttingDown() || (pInstance->QueryServerState( ) != MD_SERVER_STATE_STARTED)))
  151. {
  152. DBGPRINTF((DBG_CONTEXT," Service instance is shutting down\n"));
  153. }
  154. else if ( !fMaxConnExceeded)
  155. {
  156. // DBGPRINTF((DBG_CONTEXT,"Getting a connection object\n"));
  157. pNewClient = (SMTP_CONNECTION *) pInstance->CreateNewConnection( &clientParams);
  158. if(pNewClient)
  159. {
  160. if(!VerifyClient(pNewClient, psockAddrRemote))
  161. {
  162. //
  163. // Depending on metabase configuration, either require clients
  164. // whose IPs are blocked to authenticate, or drop the connection.
  165. //
  166. if(pInstance->GetDeniedIpAction() == SMTPDENIEDIP_REQAUTH)
  167. pNewClient->RequireAuth();
  168. else
  169. {
  170. _ASSERT(pInstance->GetDeniedIpAction() == SMTPDENIEDIP_DROPCONN);
  171. DereferenceUserDataAndKill(pNewClient);
  172. pNewClient = NULL;
  173. fSockToBeFreed = FALSE;
  174. fDereferenceInstance = FALSE;
  175. SetLastError(ERROR_ACCESS_DENIED);
  176. //
  177. // We have closed the socket... don't write to it!!!
  178. //
  179. fSupressErrorResponse = TRUE;
  180. }
  181. }
  182. }
  183. }
  184. else
  185. {
  186. err = ERROR_REMOTE_SESSION_LIMIT_EXCEEDED;
  187. SetLastError(err);
  188. }
  189. if( pNewClient != NULL)
  190. {
  191. //DBGPRINTF((DBG_CONTEXT,"New connection object is non-null\n"));
  192. //
  193. // Start off processing this client connection.
  194. //
  195. // Once we make a reset call, the USER_DATA object is created
  196. // with the socket and atq context.
  197. // From now on USER_DATA will take care of freeing
  198. // ATQ context & socket
  199. //
  200. fSockToBeFreed = FALSE;
  201. //
  202. // At this point we have the context for the AcceptExed socket.
  203. // Set the context in the AtqContext if need be.
  204. //
  205. if ( patqContext != NULL)
  206. {
  207. //DBGPRINTF((DBG_CONTEXT,"AtqContext is not NULL\n"));
  208. //
  209. // Associate client connection object with this control socket
  210. // handle for future completions.
  211. //
  212. AtqContextSetInfo(patqContext,
  213. ATQ_INFO_COMPLETION_CONTEXT,
  214. (UINT_PTR) pNewClient);
  215. }
  216. else
  217. {
  218. //DBGPRINTF((DBG_CONTEXT,"AtqContext is NULL\n"));
  219. if(!pNewClient->AddToAtqHandles((HANDLE) sNew,EndpointObject, pInstance->QueryConnectionTimeout(),
  220. SmtpCompletion))
  221. {
  222. err = GetLastError();
  223. DBGPRINTF((DBG_CONTEXT,"AddToAtqHandles() failed- err= %d\n", err));
  224. DebugTrace((LPARAM) NULL, "pNewClient->AddToAtqHandles failed- err = %d", err);
  225. DereferenceUserDataAndKill(pNewClient);
  226. fDereferenceInstance = FALSE;
  227. fSockToBeFreed = FALSE;
  228. pNewClient = NULL;
  229. }
  230. }
  231. }
  232. else
  233. {
  234. err = GetLastError();
  235. if(err != ERROR_ACCESS_DENIED)
  236. fDereferenceInstance = TRUE;
  237. }
  238. if ( (pNewClient == NULL) || (err != NO_ERROR) )
  239. {
  240. // DBGPRINTF((DBG_CONTEXT,"New connection object is NULL\n"));
  241. //
  242. // Failed to allocate new connection
  243. // Reasons:
  244. // 1) Max connections might have been exceeded.
  245. // 2) Not enough memory is available.
  246. //
  247. // handle the failures and notify client.
  248. //
  249. if (!fSupressErrorResponse)
  250. HandleErrorCondition(sNew, pInstance, err, psockAddrRemote);
  251. }
  252. else
  253. {
  254. //DBGPRINTF((DBG_CONTEXT,"Calling StartSession()\n"));
  255. if(!pNewClient->StartSession())
  256. {
  257. err = GetLastError();
  258. DBGPRINTF((DBG_CONTEXT,"StartSession() failed - err= %d\n", err));
  259. DebugTrace((LPARAM) NULL, "pNewClient->StartSession() failed- err = %d", err);
  260. DereferenceUserDataAndKill(pNewClient);
  261. pNewClient = NULL;
  262. fSockToBeFreed = FALSE;
  263. fDereferenceInstance = FALSE;
  264. }
  265. else
  266. {
  267. fReturn = TRUE;
  268. }
  269. }
  270. if ( fSockToBeFreed )
  271. {
  272. if ( patqContext != NULL)
  273. {
  274. // ensure that socket is shut down.
  275. DBG_REQUIRE( AtqCloseSocket( patqContext, TRUE));
  276. }
  277. else
  278. {
  279. CloseSocket( sNew);
  280. }
  281. }
  282. if ( pfAtqToBeFreed != NULL)
  283. {
  284. *pfAtqToBeFreed = fSockToBeFreed;
  285. }
  286. if (pInstance && fDereferenceInstance )
  287. {
  288. pInstance->DecrementCurrentConnections();
  289. pInstance->Dereference();
  290. }
  291. TraceFunctLeaveEx((LPARAM) NULL);
  292. return (fReturn);
  293. } // ProcessNewClient()
  294. /*******************************************************************
  295. NAME: SmtpOnConnect
  296. SYNOPSIS: Handles the incoming connection indication from the
  297. connection thread
  298. ENTRY: sNew - New client socket
  299. HISTORY:
  300. KeithMo 09-Mar-1993 Created.
  301. Johnl 02-Aug-1994 Reworked from FTP server
  302. ********************************************************************/
  303. VOID SmtpOnConnect( IN SOCKET sNew,
  304. IN SOCKADDR_IN * psockaddr, //Should be SOCKADDR *
  305. IN PVOID pEndpointContext,
  306. IN PVOID pEndpointObject )
  307. {
  308. PIIS_ENDPOINT pEndpoint = (PIIS_ENDPOINT)pEndpointContext;
  309. INT cbAddr = sizeof( sockaddr );
  310. SOCKADDR_IN sockaddr;
  311. SMTP_SERVER_INSTANCE *pInstance;
  312. BOOL fProcessed;
  313. BOOL fMaxConnExceeded;
  314. DBG_ASSERT( sNew != INVALID_SOCKET );
  315. DBG_ASSERT( psockaddr != NULL );
  316. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING )
  317. {
  318. DBGPRINTF((DBG_CONTEXT,"Connection attempt on inactive service\n"));
  319. goto error_exit;
  320. }
  321. if ( getsockname( sNew, (PSOCKADDR) &sockaddr, &cbAddr ) != 0 )
  322. {
  323. goto error_exit;
  324. }
  325. //
  326. // Find Instance
  327. //
  328. pInstance = (SMTP_SERVER_INSTANCE *)
  329. ((PIIS_ENDPOINT)pEndpointContext)->FindAndReferenceInstance(
  330. (LPCSTR)NULL,
  331. sockaddr.sin_addr.s_addr,
  332. &fMaxConnExceeded);
  333. if ( pInstance == NULL )
  334. {
  335. //
  336. // Site is not permitted to access this server.
  337. // Dont establish this connection. We should send a message.
  338. //
  339. goto error_exit;
  340. }
  341. fProcessed = ProcessNewClient( sNew,
  342. pEndpointObject,
  343. pInstance,
  344. fMaxConnExceeded,
  345. psockaddr);
  346. if ( fProcessed)
  347. {
  348. //StatCheckAndSetMaxConnections();
  349. }
  350. return;
  351. error_exit:
  352. CloseSocket( sNew );
  353. return;
  354. } // SmtpOnConnect
  355. VOID
  356. SmtpOnConnectEx(
  357. VOID * patqContext,
  358. DWORD cbWritten,
  359. DWORD err,
  360. OVERLAPPED * lpo
  361. )
  362. {
  363. BOOL fAllowConnection = FALSE;
  364. PVOID pvBuff = NULL;
  365. PSOCKADDR_IN psockAddrLocal = NULL;
  366. PSOCKADDR_IN psockAddrRemote = NULL;
  367. SOCKET sNew;
  368. PIIS_ENDPOINT pEndpoint;
  369. PSMTP_SERVER_INSTANCE pInstance;
  370. BOOL fProcessed = FALSE;
  371. BOOL fAtqContextToBeFreed = TRUE;
  372. BOOL fMaxConnExceeded;
  373. if ( err || !lpo || g_IsShuttingDown)
  374. {
  375. if(g_IsShuttingDown)
  376. {
  377. DBGPRINTF(( DBG_CONTEXT,
  378. "[SmtpOnConnectEx] Completion failed because of shutdown %d, Atq context %lx\n",
  379. err,
  380. patqContext ));
  381. }
  382. else
  383. {
  384. DBGPRINTF(( DBG_CONTEXT,
  385. "[SmtpOnConnectEx] Completion failed with error %d, Atq context %lx\n",
  386. err,
  387. patqContext ));
  388. }
  389. goto exit;
  390. }
  391. //
  392. // Get AcceptEx parameters
  393. //
  394. AtqGetAcceptExAddrs( (PATQ_CONTEXT) patqContext,
  395. &sNew,
  396. &pvBuff,
  397. (PVOID*)&pEndpoint,
  398. (PSOCKADDR *) &psockAddrLocal,
  399. (PSOCKADDR *) &psockAddrRemote );
  400. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING )
  401. {
  402. DBGPRINTF((DBG_CONTEXT,"Connection attempt on inactive service\n"));
  403. goto exit ;
  404. }
  405. //
  406. // Find Instance
  407. //
  408. pInstance = (SMTP_SERVER_INSTANCE *)
  409. ((PIIS_ENDPOINT)pEndpoint)->FindAndReferenceInstance(
  410. (LPCSTR)NULL,
  411. psockAddrLocal->sin_addr.s_addr,
  412. &fMaxConnExceeded
  413. );
  414. if(pInstance == NULL)
  415. {
  416. //
  417. // Site is not permitted to access this server.
  418. // Dont establish this connection. We should send a message.
  419. //
  420. // DBGPRINTF((DBG_CONTEXT,
  421. // "Unable to find instance [err %d]\n",GetLastError()));
  422. goto exit;
  423. }
  424. //
  425. // Set the timeout for future IOs on this context
  426. //
  427. AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
  428. ATQ_INFO_TIMEOUT,
  429. (UINT_PTR) pInstance->QueryConnectionTimeout());
  430. fProcessed = ProcessNewClient( sNew,
  431. pEndpoint,
  432. pInstance,
  433. fMaxConnExceeded,
  434. psockAddrRemote,
  435. psockAddrLocal,
  436. (PATQ_CONTEXT ) patqContext,
  437. pvBuff,
  438. cbWritten,
  439. &fAtqContextToBeFreed);
  440. exit:
  441. if ( !fProcessed && fAtqContextToBeFreed )
  442. {
  443. // DBGPRINTF((DBG_CONTEXT,
  444. // "ProcessNewClient returned false\n"));
  445. //
  446. // We failed to process this connection. Free up resources properly
  447. //
  448. DBG_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT )patqContext, FALSE));
  449. AtqFreeContext( (PATQ_CONTEXT ) patqContext, TRUE );
  450. }
  451. return;
  452. } // SmtpOnConnectEx
  453. #if 0
  454. BOOL
  455. SendError(
  456. SOCKET socket,
  457. DWORD ids
  458. )
  459. {
  460. STR strResponse;
  461. if ( !strResponse.Resize( 512 ) ||
  462. !HTTP_REQ_BASE::BuildExtendedStatus( &strResponse,
  463. HT_FORBIDDEN,
  464. NO_ERROR,
  465. ids ))
  466. {
  467. DBGPRINTF((DBG_CONTEXT,
  468. "[SendError] Failed to build status (error %d)\n",
  469. GetLastError()));
  470. return FALSE;
  471. }
  472. //
  473. // Do a synchronous send
  474. //
  475. send( socket,
  476. strResponse.QueryStr(),
  477. strResponse.QueryCB(),
  478. 0 );
  479. return TRUE ;
  480. } // SendError
  481. #endif
  482. /*******************************************************************
  483. NAME: CloseSocket
  484. SYNOPSIS: Closes the specified socket. This is just a thin
  485. wrapper around the "real" closesocket() API.
  486. ENTRY: sock - The socket to close.
  487. RETURNS: SOCKERR - 0 if successful, !0 if not.
  488. HISTORY:
  489. KeithMo 26-Apr-1993 Created.
  490. ********************************************************************/
  491. SOCKERR CloseSocket( SOCKET sock )
  492. {
  493. SOCKERR serr = 0;
  494. //
  495. // Close the socket.
  496. //
  497. #if 0
  498. shutdown( sock, 1 ); // Davidtr sez not needed
  499. #endif
  500. if( closesocket( sock ) != 0 )
  501. {
  502. serr = WSAGetLastError();
  503. }
  504. if( serr == 0 )
  505. {
  506. // DBGPRINTF(( DBG_CONTEXT,
  507. // "closed socket %d\n",
  508. // sock ));
  509. }
  510. else
  511. {
  512. DBGPRINTF(( DBG_CONTEXT,
  513. "cannot close socket %d, error %d\n",
  514. sock,
  515. serr ));
  516. }
  517. return serr;
  518. } // CloseSocket
  519. /*++
  520. Description:
  521. Handles a completed IO.
  522. Arguments:
  523. pvContext: the context pointer specified in the initial IO
  524. cbWritten: the number of bytes sent
  525. dwCompletionStatus: the status of the completion (usually NO_ERROR)
  526. lpo: the overlapped structure associated with the IO
  527. Returns:
  528. nothing.
  529. --*/
  530. VOID
  531. SmtpCompletion(
  532. PVOID pvContext,
  533. DWORD cbWritten,
  534. DWORD dwCompletionStatus,
  535. OVERLAPPED * lpo
  536. )
  537. {
  538. BOOL WasProcessed;
  539. SMTP_CONNECTION *pCC = (SMTP_CONNECTION *) pvContext;
  540. _ASSERT(pCC);
  541. _ASSERT(pCC->IsValid());
  542. _ASSERT(pCC->QuerySmtpInstance() != NULL);
  543. //
  544. // if we could not process a command, or we were
  545. // told to destroy this object, close the connection.
  546. //
  547. WasProcessed = pCC->ProcessClient(cbWritten, dwCompletionStatus, lpo);
  548. }
  549. /*++
  550. Description:
  551. Handles a completed IO.
  552. Arguments:
  553. pvContext: the context pointer specified in the initial IO
  554. cbWritten: the number of bytes sent
  555. dwCompletionStatus: the status of the completion (usually NO_ERROR)
  556. lpo: the overlapped structure associated with the IO
  557. Returns:
  558. nothing.
  559. --*/
  560. VOID
  561. SmtpCompletionFIO(
  562. PFIO_CONTEXT pFIOContext,
  563. FH_OVERLAPPED *pOverlapped,
  564. DWORD cbWritten,
  565. DWORD dwCompletionStatus)
  566. {
  567. BOOL WasProcessed;
  568. SMTP_CONNECTION *pCC = (SMTP_CONNECTION *) (((SERVEREVENT_OVERLAPPED *) pOverlapped)->ThisPtr);
  569. _ASSERT(pCC);
  570. _ASSERT(pCC->IsValid());
  571. _ASSERT(pCC->QuerySmtpInstance() != NULL);
  572. //
  573. // if we could not process a command, or we were
  574. // told to destroy this object, close the connection.
  575. //
  576. WasProcessed = pCC->ProcessClient(cbWritten, dwCompletionStatus, (OVERLAPPED *) pOverlapped);
  577. }
  578. #if 0
  579. VOID
  580. ServerEventCompletion(
  581. PVOID pvContext,
  582. DWORD cbWritten,
  583. DWORD dwCompletionStatus,
  584. OVERLAPPED * lpo
  585. )
  586. {
  587. SERVEREVENT_OVERLAPPED * Ov = (SERVEREVENT_OVERLAPPED *) lpo;
  588. _ASSERT(pvContext);
  589. Ov->Overlapped.pfnCompletion(Ov->ThisPtr, cbWritten, dwCompletionStatus, lpo);
  590. }
  591. #endif