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.

686 lines
19 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. FtpdNewConnection
  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. if (fValid) {
  108. fSockToBeFreed = FALSE;
  109. fValid = pUserData->Reset(sNew,
  110. EndpointObject,
  111. psockAddrRemote->sin_addr,
  112. psockAddrLocal,
  113. patqContext,
  114. pvBuff,
  115. cbWritten,
  116. acIpAccess );
  117. }
  118. if ( fValid ) {
  119. IF_DEBUG( CLIENT) {
  120. CHKINFO( ( DBG_CONTEXT,
  121. " Established a new connection to %s"
  122. " ( Socket = %d)\n",
  123. pchAddr,
  124. sNew));
  125. }
  126. //
  127. // At this point we have the context for the AcceptExed socket.
  128. // Set the context in the AtqContext if need be.
  129. //
  130. if ( patqContext != NULL) {
  131. //
  132. // Associate client connection object with this control socket
  133. // handle for future completions.
  134. //
  135. AtqContextSetInfo(patqContext,
  136. ATQ_INFO_COMPLETION_CONTEXT,
  137. (ULONG_PTR) pUserData->QueryControlAio());
  138. }
  139. if ( fNeedDnsCheck )
  140. {
  141. if ( !pUserData->QueryAccessCheck()->IsDnsResolved() ) {
  142. BOOL fSync;
  143. LPSTR pDns;
  144. pUserData->SetNeedDnsCheck( TRUE );
  145. if ( pUserData->QueryAccessCheck()->QueryDnsName( &fSync,
  146. (ADDRCHECKFUNCEX)FtpReqResolveCallback,
  147. (ADDRCHECKARG)pUserData,
  148. &pDns )
  149. && !fSync ) {
  150. return TRUE;
  151. }
  152. }
  153. }
  154. else {
  155. pUserData->UnbindInstanceAccessCheck();
  156. }
  157. DBG_REQUIRE( pUserData->Reference() > 0);
  158. fReturn = pUserData->ProcessAsyncIoCompletion(0, NO_ERROR,
  159. pUserData->
  160. QueryControlAio()
  161. );
  162. if ( !fReturn) {
  163. err = GetLastError();
  164. IF_DEBUG( ERROR) {
  165. CHKINFO(( DBG_CONTEXT,
  166. " Unable to start off a read to client(%s,%d)."
  167. " Error = %lu\n",
  168. pchAddr,
  169. sNew,
  170. err ));
  171. }
  172. }
  173. //
  174. // Decrement the ref count and free the connection.
  175. //
  176. DBG_ASSERT( (err == NO_ERROR) || pUserData->QueryReference() == 1);
  177. DereferenceUserDataAndKill( pUserData);
  178. } else {
  179. if ( fUnbindOnFail )
  180. {
  181. pUserData->UnbindInstanceAccessCheck();
  182. }
  183. // reset operation failed. relase memory and exit.
  184. err = GetLastError();
  185. pUserData->Cleanup();
  186. pInstance->RemoveConnection( pUserData);
  187. pUserData = NULL;
  188. }
  189. } else {
  190. err = GetLastError();
  191. fDereferenceInstance = TRUE;
  192. }
  193. if ( (pUserData == NULL) || (err != NO_ERROR) ) {
  194. //
  195. // Failed to allocate new connection
  196. // Reasons:
  197. // 1) Max connecitons might have been exceeded.
  198. // 2) Not enough memory is available.
  199. // 3) Access check failed
  200. //
  201. // handle the failures and notify client.
  202. //
  203. if ( fMaxConnExceeded) {
  204. CHAR rgchBuffer[MAX_REPLY_LENGTH];
  205. DWORD len;
  206. //
  207. // Unable to insert new connection.
  208. // The maxConnections may have exceeded.
  209. // Destroy the client connection object and return.
  210. // Possibly need to send an error message.
  211. //
  212. IF_DEBUG( ERROR) {
  213. CHKINFO( ( DBG_CONTEXT,
  214. " MaxConnections Exceeded. "
  215. " Connection from %s refused at socket %d\n",
  216. pchAddr, sNew));
  217. }
  218. // Format a message to send for the error case.
  219. pInstance->LockConfig();
  220. LPCSTR pszMsg = pInstance->QueryMaxClientsMsg();
  221. pszMsg = (pszMsg == NULL) ? PSZ_SERVICE_NOT_AVAILABLE : pszMsg;
  222. len = FtpFormatResponseMessage(REPLY_SERVICE_NOT_AVAILABLE,
  223. pszMsg,
  224. rgchBuffer,
  225. MAX_REPLY_LENGTH);
  226. pInstance->UnLockConfig();
  227. DBG_ASSERT( len < MAX_REPLY_LENGTH);
  228. // Send the formatted message
  229. // Ignore error in sending this message.
  230. SockSend( NULL, sNew, rgchBuffer, len);
  231. } else {
  232. // not enough memory for running this client connection
  233. const CHAR * apszSubStrings[1];
  234. CHAR pchAddr2[32];
  235. InetNtoa( psockAddrRemote->sin_addr, pchAddr2 );
  236. apszSubStrings[0] = pchAddr2;
  237. g_pInetSvc->LogEvent(FTPD_EVENT_CANNOT_CREATE_CLIENT_THREAD,
  238. 1,
  239. apszSubStrings,
  240. err );
  241. IF_DEBUG( ERROR) {
  242. CHKINFO(( DBG_CONTEXT,
  243. "Cannot create Client Connection for %s,"
  244. " Error %lu\n",
  245. pchAddr,
  246. err ));
  247. }
  248. //
  249. // Send a message to client if the socket is to be freed.
  250. // If it is already freed, then we cannot send message
  251. //
  252. if ( fSockToBeFreed) {
  253. SockPrintf2(NULL, sNew,
  254. "%u Service not available,"
  255. " closing control connection.",
  256. REPLY_SERVICE_NOT_AVAILABLE );
  257. } else {
  258. IF_DEBUG( CLIENT) {
  259. DBGPRINTF( ( DBG_CONTEXT,
  260. " Unable to send closed error message to "
  261. " %s (%d)\n",
  262. pchAddr2, sNew
  263. ));
  264. }
  265. }
  266. }
  267. //
  268. // Unable to create a new connection object.
  269. // Report error and shut this.
  270. //
  271. IF_DEBUG( ERROR) {
  272. CHKINFO( ( DBG_CONTEXT,
  273. "Cannot create new FTP Request object to %s."
  274. " Error= %u\n",
  275. pchAddr,
  276. err));
  277. }
  278. if ( fSockToBeFreed ) {
  279. if ( patqContext != NULL) {
  280. // ensure that socket is shut down.
  281. DBG_REQUIRE( AtqCloseSocket( patqContext, TRUE));
  282. } else {
  283. CloseSocket( sNew);
  284. }
  285. }
  286. fReturn = (FALSE);
  287. } // if ( pcc == NULL)
  288. if ( pfAtqToBeFreed != NULL) {
  289. *pfAtqToBeFreed = fSockToBeFreed;
  290. }
  291. if ( fDereferenceInstance ) {
  292. pInstance->DecrementCurrentConnections();
  293. pInstance->Dereference();
  294. }
  295. return (fReturn);
  296. } // ProcessNewClient()
  297. //
  298. // Public functions.
  299. //
  300. VOID
  301. FtpdNewConnection(
  302. IN SOCKET sNew,
  303. IN SOCKADDR_IN * psockaddr,
  304. IN PVOID EndpointContext,
  305. IN PVOID EndpointObject
  306. )
  307. /*++
  308. Call back function for processing the connections from clients.
  309. This function creates a new UserData object if permitted for the new
  310. client request and starts off a receive for the given connection
  311. using Async read on control channel established.
  312. Arguments:
  313. sNew control socket for the new client connection
  314. psockAddr pointer to the client's address.
  315. Returns:
  316. None
  317. History:
  318. KeithMo 08-Mar-1993 Created.
  319. MuraliK 04-April-1995
  320. ReCreated for using async Io threading model.
  321. --*/
  322. {
  323. BOOL fProcessed;
  324. BOOL fMaxConnExceeded;
  325. INT cbAddr = sizeof(SOCKADDR);
  326. SOCKADDR_IN sockaddr;
  327. FTP_SERVER_INSTANCE *pInstance;
  328. DBG_ASSERT( sNew != INVALID_SOCKET );
  329. DBG_ASSERT( psockaddr != NULL );
  330. DBG_ASSERT( psockaddr->sin_family == AF_INET ); // temporary
  331. g_pFTPStats->IncrConnectionAttempts();
  332. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING ) {
  333. IF_DEBUG( ERROR) {
  334. DBG_CODE( CHAR pchAddr[32];);
  335. DBG_CODE( InetNtoa(((SOCKADDR_IN *) psockaddr)->sin_addr,
  336. pchAddr));
  337. CHKINFO( ( DBG_CONTEXT,
  338. "Service is not running or AccessCheck failed for"
  339. " Connection from %s\n",
  340. pchAddr));
  341. }
  342. SockPrintf2(NULL,
  343. sNew,
  344. "%u %s", // the blank after %u is essential
  345. REPLY_SERVICE_NOT_AVAILABLE,
  346. "Service not available, closing control connection." );
  347. goto error_exit;
  348. }
  349. if (getsockname( sNew, (PSOCKADDR)&sockaddr, &cbAddr ) != 0) {
  350. goto error_exit;
  351. }
  352. //
  353. // Find Instance
  354. //
  355. pInstance = (FTP_SERVER_INSTANCE *)
  356. ((PIIS_ENDPOINT)EndpointContext)->FindAndReferenceInstance(
  357. (LPCSTR)NULL,
  358. sockaddr.sin_addr.s_addr,
  359. &fMaxConnExceeded
  360. );
  361. if ( pInstance == NULL ) {
  362. //
  363. // Site is not permitted to access this server.
  364. // Dont establish this connection. We should send a message.
  365. //
  366. SockPrintf2(NULL, sNew,
  367. "%u Connection refused, unknown IP address.",
  368. REPLY_NOT_LOGGED_IN);
  369. goto error_exit;
  370. }
  371. fProcessed = ProcessNewClient( sNew,
  372. EndpointObject,
  373. pInstance,
  374. fMaxConnExceeded,
  375. psockaddr);
  376. if ( fProcessed) {
  377. pInstance->QueryStatsObj()->CheckAndSetMaxConnections();
  378. }
  379. return;
  380. error_exit:
  381. CloseSocket( sNew);
  382. return;
  383. } // FtpdNewConnection()
  384. VOID
  385. FtpdNewConnectionEx(
  386. IN VOID * patqContext,
  387. IN DWORD cbWritten,
  388. IN DWORD dwError,
  389. IN OVERLAPPED * lpo
  390. )
  391. /*++
  392. Description:
  393. Callback function for new connections when using AcceptEx.
  394. This function verifies if this is a valid connection
  395. ( maybe using IP level authentication)
  396. and creates a new connection object
  397. The connection object is added to list of active connections.
  398. If the max number of connections permitted is exceeded,
  399. the client connection object is destroyed and
  400. connection is rejected.
  401. Arguments:
  402. patqContext: pointer to ATQ context for the IO operation
  403. cbWritten: count of bytes available from first read operation
  404. dwError: error if any from initial operation
  405. lpo: indicates if this function was called as a result
  406. of IO completion or due to some error.
  407. Returns:
  408. None.
  409. --*/
  410. {
  411. BOOL fProcessed = FALSE;
  412. BOOL fAtqContextToBeFreed = TRUE;
  413. BOOL fMaxConnExceeded;
  414. PSOCKADDR_IN psockAddrLocal = NULL;
  415. PSOCKADDR_IN psockAddrRemote = NULL;
  416. SOCKET sNew = INVALID_SOCKET;
  417. PVOID pvBuff = NULL;
  418. PIIS_ENDPOINT pEndpoint;
  419. FTP_SERVER_INSTANCE *pInstance;
  420. if ( (dwError != NO_ERROR) || !lpo) {
  421. DBGPRINTF(( DBG_CONTEXT, "FtpdNewConnectionEx() completion failed."
  422. " Error = %d. AtqContext=%08x\n",
  423. dwError, patqContext));
  424. //
  425. // For now free up the resources.
  426. //
  427. goto exit;
  428. }
  429. g_pFTPStats->IncrConnectionAttempts();
  430. DBG_ASSERT( patqContext != NULL);
  431. AtqGetAcceptExAddrs( (PATQ_CONTEXT ) patqContext,
  432. &sNew,
  433. &pvBuff,
  434. (PVOID*)&pEndpoint,
  435. (PSOCKADDR *)&psockAddrLocal,
  436. (PSOCKADDR *)&psockAddrRemote);
  437. DBG_ASSERT( pEndpoint != NULL );
  438. IF_DEBUG( CONNECTION ) {
  439. DBGPRINTF(( DBG_CONTEXT,
  440. " New connection. AtqCont=%08x, buff=%08x, cb=%d\n",
  441. patqContext, pvBuff, cbWritten));
  442. }
  443. if ( g_pInetSvc->QueryCurrentServiceState() != SERVICE_RUNNING ) {
  444. DBGPRINTF((DBG_CONTEXT,"Connection attempt on inactive service\n"));
  445. SockPrintf2(NULL,
  446. sNew,
  447. "%u %s", // the blank after %u is essential
  448. REPLY_SERVICE_NOT_AVAILABLE,
  449. "Service not available, closing control connection." );
  450. goto exit;
  451. }
  452. //
  453. // Find Instance
  454. //
  455. pInstance = (FTP_SERVER_INSTANCE*)pEndpoint->FindAndReferenceInstance(
  456. (LPCSTR)NULL,
  457. psockAddrLocal->sin_addr.s_addr,
  458. &fMaxConnExceeded
  459. );
  460. if (pInstance == NULL ) {
  461. //
  462. // Site is not permitted to access this server.
  463. // Dont establish this connection. We should send a message.
  464. //
  465. DBGPRINTF((DBG_CONTEXT,
  466. "Unable to find instance [err %d]\n",GetLastError()));
  467. goto exit;
  468. }
  469. //
  470. // Set the timeout for future IOs on this context
  471. //
  472. AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
  473. ATQ_INFO_TIMEOUT,
  474. (ULONG_PTR) pInstance->QueryConnectionTimeout()
  475. );
  476. if ( pInstance->QueryBandwidthInfo() )
  477. {
  478. AtqContextSetInfo( (PATQ_CONTEXT) patqContext,
  479. ATQ_INFO_BANDWIDTH_INFO,
  480. (ULONG_PTR) pInstance->QueryBandwidthInfo() );
  481. }
  482. fProcessed = ProcessNewClient( sNew,
  483. NULL,
  484. pInstance,
  485. fMaxConnExceeded,
  486. psockAddrRemote,
  487. psockAddrLocal,
  488. (PATQ_CONTEXT ) patqContext,
  489. pvBuff,
  490. cbWritten,
  491. &fAtqContextToBeFreed);
  492. if ( fProcessed) {
  493. pInstance->QueryStatsObj()->CheckAndSetMaxConnections();
  494. }
  495. exit:
  496. if ( !fProcessed && fAtqContextToBeFreed ) {
  497. //
  498. // We failed to process this connection. Free up resources properly
  499. //
  500. DBG_REQUIRE( AtqCloseSocket( (PATQ_CONTEXT )patqContext, FALSE));
  501. AtqFreeContext( (PATQ_CONTEXT ) patqContext, TRUE );
  502. }
  503. return;
  504. } // FtpdNewConnectionEx