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

743 lines
20 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. connect.cxx
  7. This module contains the main function for handling new connections.
  8. After receiving a new connection this module creates a new USER_DATA
  9. object to contain the information about a connection for processing.
  10. Functions exported by this module:
  11. FtpdNewConnction
  12. FtpdNewConnectionEx
  13. FILE HISTORY:
  14. KeithMo 08-Mar-1993 Created.
  15. MuraliK 03-April-1995
  16. Rewrote to separate the notion of one thread/control connection +
  17. other mods.
  18. MuraliK 11-Oct-1995
  19. Completely rewrote to support AcceptEx connections
  20. */
  21. #include "ftpdp.hxx"
  22. static CHAR PSZ_SERVICE_NOT_AVAILABLE[] =
  23. "Service not available, closing control connection.";
  24. //
  25. // Private prototypes.
  26. //
  27. VOID
  28. FtpReqResolveCallback(
  29. ADDRCHECKARG pArg,
  30. BOOL fSt,
  31. LPSTR pName
  32. )
  33. {
  34. // ignore fSt : DNS name is simply unavailable
  35. //((LPUSER_DATA)pArg)->Reference();
  36. if ( !AtqPostCompletionStatus( ((LPUSER_DATA)pArg)->QueryControlAio()->QueryAtqContext(),
  37. 0 ))
  38. {
  39. DereferenceUserDataAndKill( ((LPUSER_DATA)pArg) );
  40. }
  41. }
  42. BOOL
  43. ProcessNewClient(
  44. IN SOCKET sNew,
  45. IN PVOID EndpointObject,
  46. IN FTP_SERVER_INSTANCE *pInstance,
  47. IN BOOL fMaxConnExceeded,
  48. IN PSOCKADDR_IN psockAddrRemote,
  49. IN PSOCKADDR_IN psockAddrLocal = NULL,
  50. IN PATQ_CONTEXT patqContext = NULL,
  51. IN PVOID pvBuff = NULL,
  52. IN DWORD cbWritten = 0,
  53. OUT LPBOOL pfAtqToBeFreed = NULL
  54. )
  55. {
  56. LPUSER_DATA pUserData = NULL;
  57. DWORD err = NO_ERROR;
  58. BOOL fReturn = FALSE;
  59. DBG_CODE( CHAR pchAddr[32];);
  60. BOOL fSockToBeFreed = TRUE;
  61. BOOL fDereferenceInstance = FALSE;
  62. AC_RESULT acIpAccess;
  63. BOOL fNeedDnsCheck = FALSE;
  64. BOOL fValid;
  65. BOOL fUnbindOnFail;
  66. DBG_CODE( InetNtoa( psockAddrRemote->sin_addr, pchAddr));
  67. if ( pfAtqToBeFreed != NULL) {
  68. *pfAtqToBeFreed = TRUE;
  69. }
  70. //
  71. // Create a new connection object
  72. //
  73. if ( !fMaxConnExceeded ) {
  74. pUserData = pInstance->AllocNewConnection();
  75. }
  76. if ( pUserData != NULL) {
  77. pUserData->QueryAccessCheck()->BindAddr( (PSOCKADDR)psockAddrRemote );
  78. if ( !pUserData->BindInstanceAccessCheck() ) {
  79. fValid = FALSE;
  80. fUnbindOnFail = FALSE;
  81. }
  82. else {
  83. fUnbindOnFail = TRUE;
  84. acIpAccess = pUserData->QueryAccessCheck()->CheckIpAccess( &fNeedDnsCheck );
  85. if ( (acIpAccess == AC_IN_DENY_LIST) ||
  86. ((acIpAccess == AC_NOT_IN_GRANT_LIST) && !fNeedDnsCheck) ) {
  87. SockPrintf2(
  88. NULL,
  89. sNew,
  90. "%u Connection refused, unknown IP address.",
  91. REPLY_NOT_LOGGED_IN
  92. );
  93. fValid = FALSE;
  94. }
  95. else {
  96. fValid = TRUE;
  97. }
  98. }
  99. //
  100. // Start off processing this client connection.
  101. //
  102. // Once we make a reset call, the USER_DATA object is created
  103. // with the socket and atq context.
  104. // From now on USER_DATA will take care of freeing
  105. // ATQ context & socket
  106. //
  107. fSockToBeFreed = FALSE;
  108. if ( fValid && pUserData->Reset(sNew,
  109. EndpointObject,
  110. psockAddrRemote->sin_addr,
  111. psockAddrLocal,
  112. patqContext,
  113. pvBuff,
  114. cbWritten,
  115. acIpAccess )
  116. ) {
  117. #ifndef _NO_TRACING_
  118. IF_CHKDEBUG( CLIENT) {
  119. CHKINFO( ( DBG_CONTEXT,
  120. " Established a new connection to %s"
  121. " ( Socket = %d)\n",
  122. pchAddr,
  123. sNew));
  124. #else
  125. IF_DEBUG( CLIENT) {
  126. DBGPRINTF( ( DBG_CONTEXT,
  127. " Established a new connection to %s"
  128. " ( Socket = %d)\n",
  129. pchAddr,
  130. sNew));
  131. #endif
  132. }
  133. //
  134. // At this point we have the context for the AcceptExed socket.
  135. // Set the context in the AtqContext if need be.
  136. //
  137. if ( patqContext != NULL) {
  138. //
  139. // Associate client connection object with this control socket
  140. // handle for future completions.
  141. //
  142. AtqContextSetInfo(patqContext,
  143. ATQ_INFO_COMPLETION_CONTEXT,
  144. (ULONG_PTR) pUserData->QueryControlAio());
  145. }
  146. if ( fNeedDnsCheck )
  147. {
  148. if ( !pUserData->QueryAccessCheck()->IsDnsResolved() ) {
  149. BOOL fSync;
  150. LPSTR pDns;
  151. pUserData->SetNeedDnsCheck( TRUE );
  152. if ( pUserData->QueryAccessCheck()->QueryDnsName( &fSync,
  153. (ADDRCHECKFUNCEX)FtpReqResolveCallback,
  154. (ADDRCHECKARG)pUserData,
  155. &pDns )
  156. && !fSync ) {
  157. return TRUE;
  158. }
  159. }
  160. }
  161. else {
  162. pUserData->UnbindInstanceAccessCheck();
  163. }
  164. DBG_REQUIRE( pUserData->Reference() > 0);
  165. fReturn = pUserData->ProcessAsyncIoCompletion(0, NO_ERROR,
  166. pUserData->
  167. QueryControlAio()
  168. );
  169. if ( !fReturn) {
  170. err = GetLastError();
  171. #ifndef _NO_TRACING_
  172. IF_CHKDEBUG( ERROR) {
  173. CHKINFO(( DBG_CONTEXT,
  174. " Unable to start off a read to client(%s,%d)."
  175. " Error = %lu\n",
  176. pchAddr,
  177. sNew,
  178. err ));
  179. #else
  180. IF_DEBUG( ERROR) {
  181. DBGPRINTF(( DBG_CONTEXT,
  182. " Unable to start off a read to client(%s,%d)."
  183. " Error = %lu\n",
  184. pchAddr,
  185. sNew,
  186. err ));
  187. #endif
  188. }
  189. }
  190. //
  191. // Decrement the ref count and free the connection.
  192. //
  193. DBG_ASSERT( (err == NO_ERROR) || pUserData->QueryReference() == 1);
  194. DereferenceUserDataAndKill( pUserData);
  195. } else {
  196. if ( fUnbindOnFail )
  197. {
  198. pUserData->UnbindInstanceAccessCheck();
  199. }
  200. // reset operation failed. relase memory and exit.
  201. err = GetLastError();
  202. pUserData->Cleanup();
  203. pInstance->RemoveConnection( pUserData);
  204. pUserData = NULL;
  205. }
  206. } else {
  207. err = GetLastError();
  208. fDereferenceInstance = TRUE;
  209. }
  210. if ( (pUserData == NULL) || (err != NO_ERROR) ) {
  211. //
  212. // Failed to allocate new connection
  213. // Reasons:
  214. // 1) Max connecitons might have been exceeded.
  215. // 2) Not enough memory is available.
  216. // 3) Access check failed
  217. //
  218. // handle the failures and notify client.
  219. //
  220. if ( fMaxConnExceeded) {
  221. CHAR rgchBuffer[MAX_REPLY_LENGTH];
  222. DWORD len;
  223. //
  224. // Unable to insert new connection.
  225. // The maxConnections may have exceeded.
  226. // Destroy the client connection object and return.
  227. // Possibly need to send an error message.
  228. //
  229. #ifndef _NO_TRACING_
  230. IF_CHKDEBUG( ERROR) {
  231. CHKINFO( ( DBG_CONTEXT,
  232. " MaxConnections Exceeded. "
  233. " Connection from %s refused at socket %d\n",
  234. pchAddr, sNew));
  235. #else
  236. IF_DEBUG( ERROR) {
  237. DBGPRINTF( ( DBG_CONTEXT,
  238. " MaxConnections Exceeded. "
  239. " Connection from %s refused at socket %d\n",
  240. pchAddr, sNew));
  241. #endif
  242. }
  243. // Format a message to send for the error case.
  244. pInstance->LockConfig();
  245. LPCSTR pszMsg = pInstance->QueryMaxClientsMsg();
  246. pszMsg = (pszMsg == NULL) ? PSZ_SERVICE_NOT_AVAILABLE : pszMsg;
  247. len = FtpFormatResponseMessage(REPLY_SERVICE_NOT_AVAILABLE,
  248. pszMsg,
  249. rgchBuffer,
  250. MAX_REPLY_LENGTH);
  251. pInstance->UnLockConfig();
  252. DBG_ASSERT( len < MAX_REPLY_LENGTH);
  253. // Send the formatted message
  254. // Ignore error in sending this message.
  255. SockSend( NULL, sNew, rgchBuffer, len);
  256. } else {
  257. // not enough memory for running this client connection
  258. const CHAR * apszSubStrings[1];
  259. CHAR pchAddr2[32];
  260. InetNtoa( psockAddrRemote->sin_addr, pchAddr2 );
  261. apszSubStrings[0] = pchAddr2;
  262. g_pInetSvc->LogEvent(FTPD_EVENT_CANNOT_CREATE_CLIENT_THREAD,
  263. 1,
  264. apszSubStrings,
  265. err );
  266. #ifndef _NO_TRACING_
  267. IF_CHKDEBUG( ERROR) {
  268. CHKINFO(( DBG_CONTEXT,
  269. "Cannot create Client Connection for %s,"
  270. " Error %lu\n",
  271. pchAddr,
  272. err ));
  273. #else
  274. IF_DEBUG( ERROR) {
  275. DBGPRINTF(( DBG_CONTEXT,
  276. "Cannot create Client Connection for %s,"
  277. " Error %lu\n",
  278. pchAddr,
  279. err ));
  280. #endif
  281. }
  282. //
  283. // Send a message to client if the socket is to be freed.
  284. // If it is already freed, then we cannot send message
  285. //
  286. if ( fSockToBeFreed) {
  287. SockPrintf2(NULL, sNew,
  288. "%u Service not available,"
  289. " closing control connection.",
  290. REPLY_SERVICE_NOT_AVAILABLE );
  291. } else {
  292. IF_DEBUG( CLIENT) {
  293. DBGPRINTF( ( DBG_CONTEXT,
  294. " Unable to send closed error message to "
  295. " %s (%d)\n",
  296. pchAddr2, sNew
  297. ));
  298. }
  299. }
  300. }
  301. //
  302. // Unable to create a new connection object.
  303. // Report error and shut this.
  304. //
  305. #ifndef _NO_TRACING_
  306. IF_CHKDEBUG( ERROR) {
  307. CHKINFO( ( DBG_CONTEXT,
  308. "Cannot create new FTP Request object to %s."
  309. " Error= %u\n",
  310. pchAddr,
  311. err));
  312. #else
  313. IF_DEBUG( ERROR) {
  314. DBGPRINTF( ( DBG_CONTEXT,
  315. "Cannot create new FTP Request object to %s."
  316. " Error= %u\n",
  317. pchAddr,
  318. err));
  319. #endif
  320. }
  321. if ( fSockToBeFreed ) {
  322. if ( patqContext != NULL) {
  323. // ensure that socket is shut down.
  324. DBG_REQUIRE( AtqCloseSocket( patqContext, TRUE));
  325. } else {
  326. CloseSocket( sNew);
  327. }
  328. }
  329. fReturn = (FALSE);
  330. } // if ( pcc == NULL)
  331. if ( pfAtqToBeFreed != NULL) {
  332. *pfAtqToBeFreed = fSockToBeFreed;
  333. }
  334. if ( fDereferenceInstance ) {
  335. pInstance->DecrementCurrentConnections();
  336. pInstance->Dereference();
  337. }
  338. return (fReturn);
  339. } // ProcessNewClient()
  340. //
  341. // Public functions.
  342. //
  343. VOID
  344. FtpdNewConnection(
  345. IN SOCKET sNew,
  346. IN SOCKADDR_IN * psockaddr,
  347. IN PVOID EndpointContext,
  348. IN PVOID EndpointObject
  349. )
  350. /*++
  351. Call back function for processing the connections from clients.
  352. This function creates a new UserData object if permitted for the new
  353. client request and starts off a receive for the given connection
  354. using Async read on control channel established.
  355. Arguments:
  356. sNew control socket for the new client connection
  357. psockAddr pointer to the client's address.
  358. Returns:
  359. None
  360. History:
  361. KeithMo 08-Mar-1993 Created.
  362. MuraliK 04-April-1995
  363. ReCreated for using async Io threading model.
  364. --*/
  365. {
  366. SOCKERR serr;
  367. BOOL fProcessed;
  368. BOOL fMaxConnExceeded;
  369. INT cbAddr = sizeof(SOCKADDR);
  370. SOCKADDR_IN sockaddr;
  371. FTP_SERVER_INSTANCE *pInstance;
  372. DBG_ASSERT( sNew != INVALID_SOCKET );
  373. DBG_ASSERT( psockaddr != NULL );
  374. DBG_ASSERT( psockaddr->sin_family == AF_INET ); // temporary
  375. g_pFTPStats->IncrConnectionAttempts();
  376. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING ) {
  377. #ifndef _NO_TRACING_
  378. IF_CHKDEBUG( ERROR) {
  379. #else
  380. IF_DEBUG( ERROR) {
  381. #endif
  382. DBG_CODE( CHAR pchAddr[32];);
  383. DBG_CODE( InetNtoa(((SOCKADDR_IN *) psockaddr)->sin_addr,
  384. pchAddr));
  385. #ifndef _NO_TRACING_
  386. CHKINFO( ( DBG_CONTEXT,
  387. "Service is not running or AccessCheck failed for"
  388. " Connection from %s\n",
  389. pchAddr));
  390. #else
  391. DBGPRINTF( ( DBG_CONTEXT,
  392. "Service is not running or AccessCheck failed for"
  393. " Connection from %s\n",
  394. pchAddr));
  395. #endif
  396. }
  397. SockPrintf2(NULL,
  398. sNew,
  399. "%u %s", // the blank after %u is essential
  400. REPLY_SERVICE_NOT_AVAILABLE,
  401. "Service not available, closing control connection." );
  402. goto error_exit;
  403. }
  404. if (getsockname( sNew, (PSOCKADDR)&sockaddr, &cbAddr ) != 0) {
  405. goto error_exit;
  406. }
  407. //
  408. // Find Instance
  409. //
  410. pInstance = (FTP_SERVER_INSTANCE *)
  411. ((PIIS_ENDPOINT)EndpointContext)->FindAndReferenceInstance(
  412. (LPCSTR)NULL,
  413. sockaddr.sin_addr.s_addr,
  414. &fMaxConnExceeded
  415. );
  416. if ( pInstance == NULL ) {
  417. //
  418. // Site is not permitted to access this server.
  419. // Dont establish this connection. We should send a message.
  420. //
  421. SockPrintf2(NULL, sNew,
  422. "%u Connection refused, unknown IP address.",
  423. REPLY_NOT_LOGGED_IN);
  424. goto error_exit;
  425. }
  426. fProcessed = ProcessNewClient( sNew,
  427. EndpointObject,
  428. pInstance,
  429. fMaxConnExceeded,
  430. psockaddr);
  431. if ( fProcessed) {
  432. pInstance->QueryStatsObj()->CheckAndSetMaxConnections();
  433. }
  434. return;
  435. error_exit:
  436. CloseSocket( sNew);
  437. return;
  438. } // FtpdNewConnection()
  439. VOID
  440. FtpdNewConnectionEx(
  441. IN VOID * patqContext,
  442. IN DWORD cbWritten,
  443. IN DWORD dwError,
  444. IN OVERLAPPED * lpo
  445. )
  446. /*++
  447. Description:
  448. Callback function for new connections when using AcceptEx.
  449. This function verifies if this is a valid connection
  450. ( maybe using IP level authentication)
  451. and creates a new connection object
  452. The connection object is added to list of active connections.
  453. If the max number of connections permitted is exceeded,
  454. the client connection object is destroyed and
  455. connection is rejected.
  456. Arguments:
  457. patqContext: pointer to ATQ context for the IO operation
  458. cbWritten: count of bytes available from first read operation
  459. dwError: error if any from initial operation
  460. lpo: indicates if this function was called as a result
  461. of IO completion or due to some error.
  462. Returns:
  463. None.
  464. --*/
  465. {
  466. DWORD err = NO_ERROR;
  467. BOOL fProcessed = FALSE;
  468. BOOL fAtqContextToBeFreed = TRUE;
  469. BOOL fMaxConnExceeded;
  470. PSOCKADDR_IN psockAddrLocal = NULL;
  471. PSOCKADDR_IN psockAddrRemote = NULL;
  472. SOCKET sNew = INVALID_SOCKET;
  473. PVOID pvBuff = NULL;
  474. PIIS_ENDPOINT pEndpoint;
  475. FTP_SERVER_INSTANCE *pInstance;
  476. if ( (dwError != NO_ERROR) || !lpo) {
  477. DBGPRINTF(( DBG_CONTEXT, "FtpdNewConnectionEx() completion failed."
  478. " Error = %d. AtqContext=%08x\n",
  479. dwError, patqContext));
  480. //
  481. // For now free up the resources.
  482. //
  483. goto exit;
  484. }
  485. g_pFTPStats->IncrConnectionAttempts();
  486. DBG_ASSERT( patqContext != NULL);
  487. AtqGetAcceptExAddrs( (PATQ_CONTEXT ) patqContext,
  488. &sNew,
  489. &pvBuff,
  490. (PVOID*)&pEndpoint,
  491. (PSOCKADDR *)&psockAddrLocal,
  492. (PSOCKADDR *)&psockAddrRemote);
  493. DBG_ASSERT( pEndpoint != NULL );
  494. IF_DEBUG( CONNECTION ) {
  495. DBGPRINTF(( DBG_CONTEXT,
  496. " New connection. AtqCont=%08x, buff=%08x, cb=%d\n",
  497. patqContext, pvBuff, cbWritten));
  498. }
  499. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING ) {
  500. DBGPRINTF((DBG_CONTEXT,"Connection attempt on inactive service\n"));
  501. SockPrintf2(NULL,
  502. sNew,
  503. "%u %s", // the blank after %u is essential
  504. REPLY_SERVICE_NOT_AVAILABLE,
  505. "Service not available, closing control connection." );
  506. goto exit;
  507. }
  508. //
  509. // Find Instance
  510. //
  511. pInstance = (FTP_SERVER_INSTANCE*)pEndpoint->FindAndReferenceInstance(
  512. (LPCSTR)NULL,
  513. psockAddrLocal->sin_addr.s_addr,
  514. &fMaxConnExceeded
  515. );
  516. if (pInstance == NULL ) {
  517. //
  518. // Site is not permitted to access this server.
  519. // Dont establish this connection. We should send a message.
  520. //
  521. DBGPRINTF((DBG_CONTEXT,
  522. "Unable to find instance [err %d]\n",GetLastError()));
  523. goto exit;
  524. }
  525. //
  526. // Set the timeout for future IOs on this context
  527. //
  528. AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
  529. ATQ_INFO_TIMEOUT,
  530. (ULONG_PTR) pInstance->QueryConnectionTimeout()
  531. );
  532. if ( pInstance->QueryBandwidthInfo() )
  533. {
  534. AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
  535. ATQ_INFO_BANDWIDTH_INFO,
  536. (ULONG_PTR) pInstance->QueryBandwidthInfo() );
  537. }
  538. fProcessed = ProcessNewClient( sNew,
  539. NULL,
  540. pInstance,
  541. fMaxConnExceeded,
  542. psockAddrRemote,
  543. psockAddrLocal,
  544. (PATQ_CONTEXT ) patqContext,
  545. pvBuff,
  546. cbWritten,
  547. &fAtqContextToBeFreed);
  548. if ( fProcessed) {
  549. pInstance->QueryStatsObj()->CheckAndSetMaxConnections();
  550. }
  551. exit:
  552. if ( !fProcessed && fAtqContextToBeFreed ) {
  553. //
  554. // We failed to process this connection. Free up resources properly
  555. //
  556. DBG_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT )patqContext, FALSE));
  557. AtqFreeContext( (PATQ_CONTEXT ) patqContext, TRUE );
  558. }
  559. return;
  560. } // FtpdNewConnectionEx