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.

1624 lines
36 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. ftpif.c
  5. Abstract:
  6. This module contains code for the FTP transparent proxy's interface
  7. management.
  8. Author:
  9. Qiang Wang (qiangw) 10-April-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <ipnatapi.h>
  15. //
  16. // GLOBAL DATA DEFINITIONS
  17. //
  18. LIST_ENTRY FtpInterfaceList;
  19. CRITICAL_SECTION FtpInterfaceLock;
  20. ULONG FtpFirewallIfCount;
  21. ULONG
  22. FtpAcceptConnectionInterface(
  23. IN PFTP_INTERFACE Interfacep,
  24. IN SOCKET ListeningSocket,
  25. IN SOCKET AcceptedSocket OPTIONAL,
  26. IN PNH_BUFFER Bufferp OPTIONAL,
  27. OUT PHANDLE DynamicRedirectHandlep OPTIONAL
  28. )
  29. /*++
  30. Routine Description:
  31. This routine is called to accept a connection on an interface. It issues
  32. an accept-request on the socket and optionally issues a redirect to cause
  33. FTP control-channel connection-requests to be sent to the listening
  34. socket.
  35. Arguments:
  36. Interfacep - the interface on which to accept a connection
  37. ListeningSocket - the socket on which to listen for a connection
  38. AcceptedSocket - optionally specifies the socket with which to accept
  39. a connection.
  40. Bufferp - optionally supplies a buffer to be used for accept-data
  41. DynamicRedirectHandlep - on output, optionally receives a handle to a
  42. dynamic redirect created for the interface. The dynamic redirect
  43. is only created if the caller specifies this parameter.
  44. Return Value:
  45. ULONG - Win32/Winsock2 status code.
  46. Notes:
  47. Invoked with the interface's lock held by the caller and with a reference
  48. made to the interface on behalf of the accept-completion routine. It is
  49. this routine's responsibility to release that reference in the event of a
  50. failure.
  51. --*/
  52. {
  53. ULONG Address;
  54. ULONG Error;
  55. USHORT Port;
  56. PROFILE("FtpAcceptConnectionInterface");
  57. Error =
  58. NhAcceptStreamSocket(
  59. &FtpComponentReference,
  60. ListeningSocket,
  61. AcceptedSocket,
  62. Bufferp,
  63. FtpAcceptCompletionRoutine,
  64. Interfacep,
  65. (PVOID)ListeningSocket
  66. );
  67. if (Error) {
  68. FTP_DEREFERENCE_INTERFACE(Interfacep);
  69. NhTrace(
  70. TRACE_FLAG_FTP,
  71. "FtpAcceptConnectionInterface: error %d accepting connection",
  72. Error
  73. );
  74. } else if (DynamicRedirectHandlep) {
  75. //
  76. // From here onward, failures do not require us to drop our reference
  77. // to the interface, since it is now guaranteed that the accept-
  78. // completion routine will be invoked.
  79. //
  80. // Create the dynamic redirect which will cause all FTP control
  81. // channel connections to our listening socket.
  82. //
  83. Error = NhQueryLocalEndpointSocket(ListeningSocket, &Address, &Port);
  84. if (Error) {
  85. NhTrace(
  86. TRACE_FLAG_FTP,
  87. "FtpAcceptConnectionInterface: error %d querying endpoint",
  88. Error
  89. );
  90. } else {
  91. //
  92. // Install redirect(s).
  93. //
  94. if (NAT_IFC_PRIVATE(Interfacep->Characteristics) ||
  95. FTP_INTERFACE_MAPPED(Interfacep)) {
  96. ASSERT(!FTP_INTERFACE_MAPPED(Interfacep) ||
  97. NAT_IFC_BOUNDARY(Interfacep->Characteristics));
  98. Error =
  99. NatCreateDynamicAdapterRestrictedPortRedirect(
  100. NatRedirectFlagReceiveOnly,
  101. NAT_PROTOCOL_TCP,
  102. FTP_PORT_CONTROL,
  103. Address,
  104. Port,
  105. Interfacep->AdapterIndex,
  106. 0,
  107. &DynamicRedirectHandlep[0]
  108. );
  109. NhTrace(
  110. TRACE_FLAG_FTP,
  111. "FtpAcceptConnectionInterface:"
  112. " redirect installed for adapter 0x%08x [%d]",
  113. Interfacep->AdapterIndex,
  114. Error
  115. );
  116. }
  117. if (!Error && NAT_IFC_FW(Interfacep->Characteristics)) {
  118. Error =
  119. NatCreateDynamicAdapterRestrictedPortRedirect(
  120. NatRedirectFlagSendOnly,
  121. NAT_PROTOCOL_TCP,
  122. FTP_PORT_CONTROL,
  123. Address,
  124. Port,
  125. Interfacep->AdapterIndex,
  126. 0,
  127. &DynamicRedirectHandlep[1]
  128. );
  129. NhTrace(
  130. TRACE_FLAG_FTP,
  131. "FtpAcceptConnectionInterface:"
  132. " redirect installed for firewalled adapter 0x%08x [%d]",
  133. Interfacep->AdapterIndex,
  134. Error
  135. );
  136. }
  137. }
  138. }
  139. return Error;
  140. } // FtpAcceptConnectionInterface
  141. ULONG
  142. FtpActivateInterface(
  143. PFTP_INTERFACE Interfacep
  144. )
  145. /*++
  146. Routine Description:
  147. This routine is called to activate an interface, when the interface
  148. becomes both enabled and bound.
  149. Activation involves
  150. (a) creating sockets for each binding of the interface
  151. (b) initiating connection-acceptance on each created socket
  152. (c) initiating session-redirection for the FTP port, if necessary.
  153. Arguments:
  154. Interfacep - the interface to be activated
  155. Return Value:
  156. ULONG - Win32 status code indicating success or failure.
  157. Notes:
  158. Always invoked locally, with 'Interfacep' referenced by caller and/or
  159. 'FtpInterfaceLock' held by caller.
  160. --*/
  161. {
  162. ULONG Error;
  163. ULONG i;
  164. BOOLEAN IsNatInterface;
  165. PROFILE("FtpActivateInterface");
  166. EnterCriticalSection(&FtpInterfaceLock);
  167. if (FTP_INTERFACE_ADMIN_DISABLED(Interfacep)) {
  168. LeaveCriticalSection(&FtpInterfaceLock);
  169. return NO_ERROR;
  170. }
  171. Interfacep->Characteristics
  172. = NatGetInterfaceCharacteristics(Interfacep->Index);
  173. if (!Interfacep->Characteristics) {
  174. LeaveCriticalSection(&FtpInterfaceLock);
  175. NhTrace(
  176. TRACE_FLAG_FTP,
  177. "FtpActivateInterface: ignoring non-NAT interface %d",
  178. Interfacep->Index
  179. );
  180. return NO_ERROR;
  181. }
  182. if (NAT_IFC_BOUNDARY(Interfacep->Characteristics)) {
  183. for (i = 0; i < Interfacep->BindingCount; i++) {
  184. Error = NatLookupPortMappingAdapter(
  185. Interfacep->AdapterIndex,
  186. NAT_PROTOCOL_TCP,
  187. Interfacep->BindingArray[i].Address,
  188. FTP_PORT_CONTROL,
  189. &Interfacep->PortMapping
  190. );
  191. if (!Error) {
  192. Interfacep->Flags |= FTP_INTERFACE_FLAG_MAPPED;
  193. break;
  194. }
  195. }
  196. if (Error && !NAT_IFC_FW(Interfacep->Characteristics)) {
  197. LeaveCriticalSection(&FtpInterfaceLock);
  198. NhTrace(
  199. TRACE_FLAG_FTP,
  200. "FtpActivateInterface:"
  201. " ignoring non-FW and non-mapped NAT boundary interface %d",
  202. Interfacep->Index
  203. );
  204. NhWarningLog(
  205. IP_FTP_LOG_NAT_INTERFACE_IGNORED,
  206. 0,
  207. "%d",
  208. Interfacep->Index
  209. );
  210. return NO_ERROR;
  211. }
  212. }
  213. if (NAT_IFC_FW(Interfacep->Characteristics)) {
  214. InterlockedIncrement(reinterpret_cast<LPLONG>(&FtpFirewallIfCount));
  215. }
  216. //
  217. // Create stream sockets that listen for connection-requests on each
  218. // logical network, and datagram sockets that process incoming messages.
  219. //
  220. Error = NO_ERROR;
  221. ACQUIRE_LOCK(Interfacep);
  222. for (i = 0; i < Interfacep->BindingCount; i++) {
  223. Error =
  224. NhCreateStreamSocket(
  225. Interfacep->BindingArray[i].Address,
  226. 0,
  227. &Interfacep->BindingArray[i].ListeningSocket
  228. );
  229. if (Error) { break; }
  230. Error = listen(Interfacep->BindingArray[i].ListeningSocket, SOMAXCONN);
  231. if (Error == SOCKET_ERROR) { break; }
  232. }
  233. //
  234. // If an error occurred, roll back all work done so far and fail.
  235. //
  236. if (Error) {
  237. ULONG FailedAddress = i;
  238. for (--i; (LONG)i >= 0; i--) {
  239. NhDeleteStreamSocket(
  240. Interfacep->BindingArray[i].ListeningSocket
  241. );
  242. Interfacep->BindingArray[i].ListeningSocket = INVALID_SOCKET;
  243. }
  244. NhErrorLog(
  245. IP_FTP_LOG_ACTIVATE_FAILED,
  246. Error,
  247. "%I",
  248. Interfacep->BindingArray[FailedAddress].Address
  249. );
  250. RELEASE_LOCK(Interfacep);
  251. LeaveCriticalSection(&FtpInterfaceLock);
  252. return Error;
  253. }
  254. //
  255. // Initiate connection-acceptance and message-redirection on each socket
  256. //
  257. for (i = 0; i < Interfacep->BindingCount; i++) {
  258. if (!FTP_REFERENCE_INTERFACE(Interfacep)) { break; }
  259. Error =
  260. FtpAcceptConnectionInterface(
  261. Interfacep,
  262. Interfacep->BindingArray[i].ListeningSocket,
  263. INVALID_SOCKET,
  264. NULL,
  265. &Interfacep->BindingArray[i].ListeningRedirectHandle[0]
  266. );
  267. if (Error) {
  268. NhErrorLog(
  269. IP_FTP_LOG_ACCEPT_FAILED,
  270. Error,
  271. "%I",
  272. Interfacep->BindingArray[i].Address
  273. );
  274. Error = NO_ERROR;
  275. }
  276. }
  277. RELEASE_LOCK(Interfacep);
  278. LeaveCriticalSection(&FtpInterfaceLock);
  279. return NO_ERROR;
  280. } // FtpActivateInterface
  281. ULONG
  282. FtpBindInterface(
  283. ULONG Index,
  284. PIP_ADAPTER_BINDING_INFO BindingInfo
  285. )
  286. /*++
  287. Routine Description:
  288. This routine is invoked to supply the binding for an interface.
  289. It records the binding information received, and if necessary,
  290. it activates the interface.
  291. Arguments:
  292. Index - the index of the interface to be bound
  293. BindingInfo - the binding-information for the interface
  294. Return Value:
  295. ULONG - Win32 status code.
  296. Notes:
  297. Invoked internally in the context of an IP router-manager thread.
  298. (See 'RMFTP.C').
  299. --*/
  300. {
  301. ULONG i;
  302. ULONG Error = NO_ERROR;
  303. PFTP_INTERFACE Interfacep;
  304. PROFILE("FtpBindInterface");
  305. EnterCriticalSection(&FtpInterfaceLock);
  306. //
  307. // Retrieve the interface to be bound
  308. //
  309. Interfacep = FtpLookupInterface(Index, NULL);
  310. if (Interfacep == NULL) {
  311. LeaveCriticalSection(&FtpInterfaceLock);
  312. NhTrace(
  313. TRACE_FLAG_IF,
  314. "FtpBindInterface: interface %d not found",
  315. Index
  316. );
  317. return ERROR_NO_SUCH_INTERFACE;
  318. }
  319. //
  320. // Make sure the interface isn't already bound
  321. //
  322. if (FTP_INTERFACE_BOUND(Interfacep)) {
  323. LeaveCriticalSection(&FtpInterfaceLock);
  324. NhTrace(
  325. TRACE_FLAG_IF,
  326. "FtpBindInterface: interface %d is already bound",
  327. Index
  328. );
  329. return ERROR_ADDRESS_ALREADY_ASSOCIATED;
  330. }
  331. //
  332. // Reference the interface
  333. //
  334. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  335. LeaveCriticalSection(&FtpInterfaceLock);
  336. NhTrace(
  337. TRACE_FLAG_IF,
  338. "FtpBindInterface: interface %d cannot be referenced",
  339. Index
  340. );
  341. return ERROR_INTERFACE_DISABLED;
  342. }
  343. //
  344. // Update the interface's flags
  345. //
  346. Interfacep->Flags |= FTP_INTERFACE_FLAG_BOUND;
  347. LeaveCriticalSection(&FtpInterfaceLock);
  348. ACQUIRE_LOCK(Interfacep);
  349. //
  350. // Allocate space for the binding
  351. //
  352. if (!BindingInfo->AddressCount) {
  353. Interfacep->BindingCount = 0;
  354. Interfacep->BindingArray = NULL;
  355. } else {
  356. Interfacep->BindingArray =
  357. reinterpret_cast<PFTP_BINDING>(
  358. NH_ALLOCATE(BindingInfo->AddressCount * sizeof(FTP_BINDING))
  359. );
  360. if (!Interfacep->BindingArray) {
  361. RELEASE_LOCK(Interfacep);
  362. FTP_DEREFERENCE_INTERFACE(Interfacep);
  363. NhTrace(
  364. TRACE_FLAG_IF,
  365. "FtpBindInterface: allocation failed for interface %d binding",
  366. Index
  367. );
  368. NhErrorLog(
  369. IP_FTP_LOG_ALLOCATION_FAILED,
  370. 0,
  371. "%d",
  372. BindingInfo->AddressCount * sizeof(FTP_BINDING)
  373. );
  374. return ERROR_NOT_ENOUGH_MEMORY;
  375. }
  376. ZeroMemory(
  377. Interfacep->BindingArray,
  378. BindingInfo->AddressCount * sizeof(FTP_BINDING)
  379. );
  380. Interfacep->BindingCount = BindingInfo->AddressCount;
  381. }
  382. //
  383. // Copy the binding
  384. //
  385. for (i = 0; i < BindingInfo->AddressCount; i++) {
  386. Interfacep->BindingArray[i].Address = BindingInfo->Address[i].Address;
  387. Interfacep->BindingArray[i].Mask = BindingInfo->Address[i].Mask;
  388. Interfacep->BindingArray[i].ListeningSocket = INVALID_SOCKET;
  389. }
  390. //
  391. // Figure out our IP Adapter Index, if we have a valid binding
  392. //
  393. if (Interfacep->BindingCount) {
  394. Interfacep->AdapterIndex =
  395. NhMapAddressToAdapter(BindingInfo->Address[0].Address);
  396. }
  397. RELEASE_LOCK(Interfacep);
  398. //
  399. // Activate the interface if necessary
  400. //
  401. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  402. Error = FtpActivateInterface(Interfacep);
  403. }
  404. FTP_DEREFERENCE_INTERFACE(Interfacep);
  405. return Error;
  406. } // FtpBindInterface
  407. VOID
  408. FtpCleanupInterface(
  409. PFTP_INTERFACE Interfacep
  410. )
  411. /*++
  412. Routine Description:
  413. This routine is invoked when the very last reference to an interface
  414. is released, and the interface must be destroyed.
  415. Arguments:
  416. Interfacep - the interface to be destroyed
  417. Return Value:
  418. none.
  419. Notes:
  420. Invoked internally from an arbitrary context, with no references
  421. to the interface.
  422. --*/
  423. {
  424. PROFILE("FtpCleanupInterface");
  425. if (Interfacep->BindingArray) {
  426. NH_FREE(Interfacep->BindingArray);
  427. Interfacep->BindingArray = NULL;
  428. }
  429. DeleteCriticalSection(&Interfacep->Lock);
  430. NH_FREE(Interfacep);
  431. } // FtpCleanupInterface
  432. ULONG
  433. FtpConfigureInterface(
  434. ULONG Index,
  435. PIP_FTP_INTERFACE_INFO InterfaceInfo
  436. )
  437. /*++
  438. Routine Description:
  439. This routine is called to set the configuration for an interface.
  440. Arguments:
  441. Index - the interface to be configured
  442. InterfaceInfo - the new configuration
  443. Return Value:
  444. ULONG - Win32 status code
  445. Notes:
  446. Invoked internally in the context of a IP router-manager thread.
  447. (See 'RMFTP.C').
  448. --*/
  449. {
  450. ULONG Error;
  451. PFTP_INTERFACE Interfacep;
  452. ULONG NewFlags;
  453. ULONG OldFlags;
  454. PROFILE("FtpConfigureInterface");
  455. //
  456. // Retrieve the interface to be configured
  457. //
  458. EnterCriticalSection(&FtpInterfaceLock);
  459. Interfacep = FtpLookupInterface(Index, NULL);
  460. if (Interfacep == NULL) {
  461. LeaveCriticalSection(&FtpInterfaceLock);
  462. NhTrace(
  463. TRACE_FLAG_IF,
  464. "FtpConfigureInterface: interface %d not found",
  465. Index
  466. );
  467. return ERROR_NO_SUCH_INTERFACE;
  468. }
  469. //
  470. // Reference the interface
  471. //
  472. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  473. LeaveCriticalSection(&FtpInterfaceLock);
  474. NhTrace(
  475. TRACE_FLAG_IF,
  476. "FtpConfigureInterface: interface %d cannot be referenced",
  477. Index
  478. );
  479. return ERROR_INTERFACE_DISABLED;
  480. }
  481. LeaveCriticalSection(&FtpInterfaceLock);
  482. Error = NO_ERROR;
  483. ACQUIRE_LOCK(Interfacep);
  484. //
  485. // Compare the interface's current and new configuration
  486. //
  487. OldFlags = Interfacep->Info.Flags;
  488. NewFlags =
  489. (InterfaceInfo
  490. ? (InterfaceInfo->Flags|FTP_INTERFACE_FLAG_CONFIGURED) : 0);
  491. Interfacep->Flags &= ~OldFlags;
  492. Interfacep->Flags |= NewFlags;
  493. if (!InterfaceInfo) {
  494. ZeroMemory(&Interfacep->Info, sizeof(*InterfaceInfo));
  495. //
  496. // The interface no longer has any information;
  497. // default to being enabled.
  498. //
  499. if (OldFlags & IP_FTP_INTERFACE_FLAG_DISABLED) {
  500. //
  501. // Activate the interface if necessary
  502. //
  503. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  504. RELEASE_LOCK(Interfacep);
  505. Error = FtpActivateInterface(Interfacep);
  506. ACQUIRE_LOCK(Interfacep);
  507. }
  508. }
  509. } else {
  510. CopyMemory(&Interfacep->Info, InterfaceInfo, sizeof(*InterfaceInfo));
  511. //
  512. // Activate or deactivate the interface if its status changed
  513. //
  514. if ((OldFlags & IP_FTP_INTERFACE_FLAG_DISABLED) &&
  515. !(NewFlags & IP_FTP_INTERFACE_FLAG_DISABLED)) {
  516. //
  517. // Activate the interface
  518. //
  519. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  520. RELEASE_LOCK(Interfacep);
  521. Error = FtpActivateInterface(Interfacep);
  522. ACQUIRE_LOCK(Interfacep);
  523. }
  524. } else if (!(OldFlags & IP_FTP_INTERFACE_FLAG_DISABLED) &&
  525. (NewFlags & IP_FTP_INTERFACE_FLAG_DISABLED)) {
  526. //
  527. // Deactivate the interface if necessary
  528. //
  529. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  530. RELEASE_LOCK(Interfacep);
  531. FtpDeactivateInterface(Interfacep);
  532. ACQUIRE_LOCK(Interfacep);
  533. }
  534. }
  535. }
  536. RELEASE_LOCK(Interfacep);
  537. FTP_DEREFERENCE_INTERFACE(Interfacep);
  538. return Error;
  539. } // FtpConfigureInterface
  540. ULONG
  541. FtpCreateInterface(
  542. ULONG Index,
  543. NET_INTERFACE_TYPE Type,
  544. PIP_FTP_INTERFACE_INFO InterfaceInfo,
  545. OUT PFTP_INTERFACE* InterfaceCreated
  546. )
  547. /*++
  548. Routine Description:
  549. This routine is invoked by the router-manager to add a new interface
  550. to the FTP transparent proxy.
  551. Arguments:
  552. Index - the index of the new interface
  553. Type - the media type of the new interface
  554. InterfaceInfo - the interface's configuration
  555. Interfacep - receives the interface created
  556. Return Value:
  557. ULONG - Win32 error code
  558. Notes:
  559. Invoked internally in the context of an IP router-manager thread.
  560. (See 'RMFTP.C').
  561. --*/
  562. {
  563. PLIST_ENTRY InsertionPoint;
  564. PFTP_INTERFACE Interfacep;
  565. PROFILE("FtpCreateInterface");
  566. EnterCriticalSection(&FtpInterfaceLock);
  567. //
  568. // See if the interface already exists;
  569. // If not, this obtains the insertion point
  570. //
  571. if (FtpLookupInterface(Index, &InsertionPoint)) {
  572. LeaveCriticalSection(&FtpInterfaceLock);
  573. NhTrace(
  574. TRACE_FLAG_IF,
  575. "FtpCreateInterface: duplicate index found for %d",
  576. Index
  577. );
  578. return ERROR_INTERFACE_ALREADY_EXISTS;
  579. }
  580. //
  581. // Allocate a new interface
  582. //
  583. Interfacep =
  584. reinterpret_cast<PFTP_INTERFACE>(NH_ALLOCATE(sizeof(FTP_INTERFACE)));
  585. if (!Interfacep) {
  586. LeaveCriticalSection(&FtpInterfaceLock);
  587. NhTrace(
  588. TRACE_FLAG_IF, "FtpCreateInterface: error allocating interface"
  589. );
  590. NhErrorLog(
  591. IP_FTP_LOG_ALLOCATION_FAILED,
  592. 0,
  593. "%d",
  594. sizeof(FTP_INTERFACE)
  595. );
  596. return ERROR_NOT_ENOUGH_MEMORY;
  597. }
  598. //
  599. // Initialize the new interface
  600. //
  601. ZeroMemory(Interfacep, sizeof(*Interfacep));
  602. __try {
  603. InitializeCriticalSection(&Interfacep->Lock);
  604. } __except(EXCEPTION_EXECUTE_HANDLER) {
  605. LeaveCriticalSection(&FtpInterfaceLock);
  606. NH_FREE(Interfacep);
  607. return GetExceptionCode();
  608. }
  609. Interfacep->Index = Index;
  610. Interfacep->Type = Type;
  611. if (InterfaceInfo) {
  612. Interfacep->Flags = InterfaceInfo->Flags|FTP_INTERFACE_FLAG_CONFIGURED;
  613. CopyMemory(&Interfacep->Info, InterfaceInfo, sizeof(*InterfaceInfo));
  614. }
  615. Interfacep->ReferenceCount = 1;
  616. InitializeListHead(&Interfacep->ConnectionList);
  617. InitializeListHead(&Interfacep->EndpointList);
  618. InsertTailList(InsertionPoint, &Interfacep->Link);
  619. LeaveCriticalSection(&FtpInterfaceLock);
  620. if (InterfaceCreated) { *InterfaceCreated = Interfacep; }
  621. return NO_ERROR;
  622. } // FtpCreateInterface
  623. VOID
  624. FtpDeactivateInterface(
  625. PFTP_INTERFACE Interfacep
  626. )
  627. /*++
  628. Routine Description:
  629. This routine is called to deactivate an interface.
  630. It closes all sockets on the interface's bindings (if any).
  631. Arguments:
  632. Interfacep - the interface to be deactivated
  633. Return Value:
  634. none.
  635. Notes:
  636. Always invoked locally, with 'Interfacep' referenced by caller and/or
  637. 'FtpInterfaceLock' held by caller.
  638. --*/
  639. {
  640. ULONG i;
  641. ULONG j;
  642. PLIST_ENTRY Link;
  643. PFTP_CONNECTION Connectionp;
  644. PROFILE("FtpDeactivateInterface");
  645. ACQUIRE_LOCK(Interfacep);
  646. //
  647. // Stop all network I/O on the interface's logical networks
  648. //
  649. for (i = 0; i < Interfacep->BindingCount; i++) {
  650. if (Interfacep->BindingArray[i].ListeningSocket != INVALID_SOCKET) {
  651. NhDeleteStreamSocket(Interfacep->BindingArray[i].ListeningSocket);
  652. Interfacep->BindingArray[i].ListeningSocket = INVALID_SOCKET;
  653. }
  654. for (j = 0; j < 2; j++) {
  655. if (Interfacep->BindingArray[i].ListeningRedirectHandle[j]) {
  656. NatCancelDynamicPortRedirect(
  657. Interfacep->BindingArray[i].ListeningRedirectHandle[j]
  658. );
  659. Interfacep->BindingArray[i].ListeningRedirectHandle[j] = NULL;
  660. }
  661. }
  662. }
  663. //
  664. // Eliminate all connections
  665. //
  666. while (!IsListEmpty(&Interfacep->ConnectionList)) {
  667. Link = RemoveHeadList(&Interfacep->ConnectionList);
  668. Connectionp = CONTAINING_RECORD(Link, FTP_CONNECTION, Link);
  669. FtpDeleteConnection(Connectionp);
  670. }
  671. ASSERT(IsListEmpty(&Interfacep->EndpointList));
  672. //
  673. // If this interface is firewalled, decrement the global count.
  674. //
  675. if (NAT_IFC_FW(Interfacep->Characteristics)) {
  676. InterlockedDecrement(reinterpret_cast<LPLONG>(&FtpFirewallIfCount));
  677. }
  678. RELEASE_LOCK(Interfacep);
  679. } // FtpDeactivateInterface
  680. ULONG
  681. FtpDeleteInterface(
  682. ULONG Index
  683. )
  684. /*++
  685. Routine Description:
  686. This routine is called to delete an interface.
  687. It drops the reference count on the interface so that the last
  688. dereferencer will delete the interface, and sets the 'deleted' flag
  689. so that further references to the interface will fail.
  690. Arguments:
  691. Index - the index of the interface to be deleted
  692. Return Value:
  693. ULONG - Win32 status code.
  694. Notes:
  695. Invoked internally in the context of an IP router-manager thread.
  696. (See 'RMFTP.C').
  697. --*/
  698. {
  699. PFTP_INTERFACE Interfacep;
  700. PROFILE("FtpDeleteInterface");
  701. //
  702. // Retrieve the interface to be deleted
  703. //
  704. EnterCriticalSection(&FtpInterfaceLock);
  705. Interfacep = FtpLookupInterface(Index, NULL);
  706. if (Interfacep == NULL) {
  707. LeaveCriticalSection(&FtpInterfaceLock);
  708. NhTrace(
  709. TRACE_FLAG_IF,
  710. "FtpDeleteInterface: interface %d not found",
  711. Index
  712. );
  713. return ERROR_NO_SUCH_INTERFACE;
  714. }
  715. //
  716. // Deactivate the interface
  717. //
  718. FtpDeactivateInterface(Interfacep);
  719. //
  720. // Mark the interface as deleted and take it off the interface list
  721. //
  722. Interfacep->Flags |= FTP_INTERFACE_FLAG_DELETED;
  723. Interfacep->Flags &= ~FTP_INTERFACE_FLAG_ENABLED;
  724. RemoveEntryList(&Interfacep->Link);
  725. //
  726. // Drop the reference count; if it is non-zero,
  727. // the deletion will complete later.
  728. //
  729. if (--Interfacep->ReferenceCount) {
  730. LeaveCriticalSection(&FtpInterfaceLock);
  731. NhTrace(
  732. TRACE_FLAG_IF,
  733. "FtpDeleteInterface: interface %d deletion pending",
  734. Index
  735. );
  736. return NO_ERROR;
  737. }
  738. //
  739. // The reference count is zero, so perform final cleanup
  740. //
  741. FtpCleanupInterface(Interfacep);
  742. LeaveCriticalSection(&FtpInterfaceLock);
  743. return NO_ERROR;
  744. } // FtpDeleteInterface
  745. ULONG
  746. FtpDisableInterface(
  747. ULONG Index
  748. )
  749. /*++
  750. Routine Description:
  751. This routine is called to disable I/O on an interface.
  752. If the interface is active, it is deactivated.
  753. Arguments:
  754. Index - the index of the interface to be disabled.
  755. Return Value:
  756. none.
  757. Notes:
  758. Invoked internally in the context of an IP router-manager thread.
  759. (See 'RMFTP.C').
  760. --*/
  761. {
  762. PFTP_INTERFACE Interfacep;
  763. PROFILE("FtpDisableInterface");
  764. //
  765. // Retrieve the interface to be disabled
  766. //
  767. EnterCriticalSection(&FtpInterfaceLock);
  768. Interfacep = FtpLookupInterface(Index, NULL);
  769. if (Interfacep == NULL) {
  770. LeaveCriticalSection(&FtpInterfaceLock);
  771. NhTrace(
  772. TRACE_FLAG_IF,
  773. "FtpDisableInterface: interface %d not found",
  774. Index
  775. );
  776. return ERROR_NO_SUCH_INTERFACE;
  777. }
  778. //
  779. // Make sure the interface is not already disabled
  780. //
  781. if (!FTP_INTERFACE_ENABLED(Interfacep)) {
  782. LeaveCriticalSection(&FtpInterfaceLock);
  783. NhTrace(
  784. TRACE_FLAG_IF,
  785. "FtpDisableInterface: interface %d already disabled",
  786. Index
  787. );
  788. return ERROR_INTERFACE_DISABLED;
  789. }
  790. //
  791. // Reference the interface
  792. //
  793. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  794. LeaveCriticalSection(&FtpInterfaceLock);
  795. NhTrace(
  796. TRACE_FLAG_IF,
  797. "FtpDisableInterface: interface %d cannot be referenced",
  798. Index
  799. );
  800. return ERROR_INTERFACE_DISABLED;
  801. }
  802. //
  803. // Clear the 'enabled' flag
  804. //
  805. Interfacep->Flags &= ~FTP_INTERFACE_FLAG_ENABLED;
  806. //
  807. // Deactivate the interface, if necessary
  808. //
  809. if (FTP_INTERFACE_BOUND(Interfacep)) {
  810. FtpDeactivateInterface(Interfacep);
  811. }
  812. LeaveCriticalSection(&FtpInterfaceLock);
  813. FTP_DEREFERENCE_INTERFACE(Interfacep);
  814. return NO_ERROR;
  815. } // FtpDisableInterface
  816. ULONG
  817. FtpEnableInterface(
  818. ULONG Index
  819. )
  820. /*++
  821. Routine Description:
  822. This routine is called to enable I/O on an interface.
  823. If the interface is already bound, this enabling activates it.
  824. Arguments:
  825. Index - the index of the interfaec to be enabled
  826. Return Value:
  827. ULONG - Win32 status code.
  828. Notes:
  829. Invoked internally in the context of an IP router-manager thread.
  830. (See 'RMFTP.C').
  831. --*/
  832. {
  833. ULONG Error = NO_ERROR;
  834. PFTP_INTERFACE Interfacep;
  835. PROFILE("FtpEnableInterface");
  836. //
  837. // Retrieve the interface to be enabled
  838. //
  839. EnterCriticalSection(&FtpInterfaceLock);
  840. Interfacep = FtpLookupInterface(Index, NULL);
  841. if (Interfacep == NULL) {
  842. LeaveCriticalSection(&FtpInterfaceLock);
  843. NhTrace(
  844. TRACE_FLAG_IF,
  845. "FtpEnableInterface: interface %d not found",
  846. Index
  847. );
  848. return ERROR_NO_SUCH_INTERFACE;
  849. }
  850. //
  851. // Make sure the interface is not already enabled
  852. //
  853. if (FTP_INTERFACE_ENABLED(Interfacep)) {
  854. LeaveCriticalSection(&FtpInterfaceLock);
  855. NhTrace(
  856. TRACE_FLAG_IF,
  857. "FtpEnableInterface: interface %d already enabled",
  858. Index
  859. );
  860. return ERROR_INTERFACE_ALREADY_EXISTS;
  861. }
  862. //
  863. // Reference the interface
  864. //
  865. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  866. LeaveCriticalSection(&FtpInterfaceLock);
  867. NhTrace(
  868. TRACE_FLAG_IF,
  869. "FtpEnableInterface: interface %d cannot be referenced",
  870. Index
  871. );
  872. return ERROR_INTERFACE_DISABLED;
  873. }
  874. //
  875. // Set the 'enabled' flag
  876. //
  877. Interfacep->Flags |= FTP_INTERFACE_FLAG_ENABLED;
  878. //
  879. // Activate the interface, if necessary
  880. //
  881. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  882. Error = FtpActivateInterface(Interfacep);
  883. }
  884. LeaveCriticalSection(&FtpInterfaceLock);
  885. FTP_DEREFERENCE_INTERFACE(Interfacep);
  886. return Error;
  887. } // FtpEnableInterface
  888. ULONG
  889. FtpInitializeInterfaceManagement(
  890. VOID
  891. )
  892. /*++
  893. Routine Description:
  894. This routine is called to initialize the interface-management module.
  895. Arguments:
  896. none.
  897. Return Value:
  898. ULONG - Win32 status code.
  899. Notes:
  900. Invoked internally in the context of an IP router-manager thread.
  901. (See 'RMFTP.C').
  902. --*/
  903. {
  904. ULONG Error = NO_ERROR;
  905. PROFILE("FtpInitializeInterfaceManagement");
  906. InitializeListHead(&FtpInterfaceList);
  907. __try {
  908. InitializeCriticalSection(&FtpInterfaceLock);
  909. } __except(EXCEPTION_EXECUTE_HANDLER) {
  910. NhTrace(
  911. TRACE_FLAG_IF,
  912. "FtpInitializeInterfaceManagement: exception %d creating lock",
  913. Error = GetExceptionCode()
  914. );
  915. }
  916. FtpFirewallIfCount = 0;
  917. return Error;
  918. } // FtpInitializeInterfaceManagement
  919. PFTP_INTERFACE
  920. FtpLookupInterface(
  921. ULONG Index,
  922. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  923. )
  924. /*++
  925. Routine Description:
  926. This routine is called to retrieve an interface given its index.
  927. Arguments:
  928. Index - the index of the interface to be retrieved
  929. InsertionPoint - if the interface is not found, optionally receives
  930. the point where the interface would be inserted in the interface list
  931. Return Value:
  932. PFTP_INTERFACE - the interface, if found; otherwise, NULL.
  933. Notes:
  934. Invoked internally from an arbitrary context, with 'FtpInterfaceLock'
  935. held by caller.
  936. --*/
  937. {
  938. PFTP_INTERFACE Interfacep;
  939. PLIST_ENTRY Link;
  940. PROFILE("FtpLookupInterface");
  941. for (Link = FtpInterfaceList.Flink; Link != &FtpInterfaceList;
  942. Link = Link->Flink) {
  943. Interfacep = CONTAINING_RECORD(Link, FTP_INTERFACE, Link);
  944. if (Index > Interfacep->Index) {
  945. continue;
  946. } else if (Index < Interfacep->Index) {
  947. break;
  948. }
  949. return Interfacep;
  950. }
  951. if (InsertionPoint) { *InsertionPoint = Link; }
  952. return NULL;
  953. } // FtpLookupInterface
  954. ULONG
  955. FtpQueryInterface(
  956. ULONG Index,
  957. PVOID InterfaceInfo,
  958. PULONG InterfaceInfoSize
  959. )
  960. /*++
  961. Routine Description:
  962. This routine is invoked to retrieve the configuration for an interface.
  963. Arguments:
  964. Index - the interface to be queried
  965. InterfaceInfo - receives the retrieved information
  966. InterfaceInfoSize - receives the (required) size of the information
  967. Return Value:
  968. ULONG - Win32 status code.
  969. --*/
  970. {
  971. PFTP_INTERFACE Interfacep;
  972. PROFILE("FtpQueryInterface");
  973. //
  974. // Check the caller's buffer size
  975. //
  976. if (!InterfaceInfoSize) { return ERROR_INVALID_PARAMETER; }
  977. //
  978. // Retrieve the interface to be configured
  979. //
  980. EnterCriticalSection(&FtpInterfaceLock);
  981. Interfacep = FtpLookupInterface(Index, NULL);
  982. if (Interfacep == NULL) {
  983. LeaveCriticalSection(&FtpInterfaceLock);
  984. NhTrace(
  985. TRACE_FLAG_IF,
  986. "FtpQueryInterface: interface %d not found",
  987. Index
  988. );
  989. return ERROR_NO_SUCH_INTERFACE;
  990. }
  991. //
  992. // Reference the interface
  993. //
  994. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  995. LeaveCriticalSection(&FtpInterfaceLock);
  996. NhTrace(
  997. TRACE_FLAG_IF,
  998. "FtpQueryInterface: interface %d cannot be referenced",
  999. Index
  1000. );
  1001. return ERROR_INTERFACE_DISABLED;
  1002. }
  1003. //
  1004. // See if there is any explicit config on this interface
  1005. //
  1006. if (!FTP_INTERFACE_CONFIGURED(Interfacep)) {
  1007. LeaveCriticalSection(&FtpInterfaceLock);
  1008. FTP_DEREFERENCE_INTERFACE(Interfacep);
  1009. NhTrace(
  1010. TRACE_FLAG_IF,
  1011. "FtpQueryInterface: interface %d has no configuration",
  1012. Index
  1013. );
  1014. *InterfaceInfoSize = 0;
  1015. return NO_ERROR;
  1016. }
  1017. //
  1018. // See if there is enough buffer space
  1019. //
  1020. if (*InterfaceInfoSize < sizeof(IP_FTP_INTERFACE_INFO)) {
  1021. LeaveCriticalSection(&FtpInterfaceLock);
  1022. FTP_DEREFERENCE_INTERFACE(Interfacep);
  1023. *InterfaceInfoSize = sizeof(IP_FTP_INTERFACE_INFO);
  1024. return ERROR_INSUFFICIENT_BUFFER;
  1025. }
  1026. //
  1027. // Copy the requested data
  1028. //
  1029. CopyMemory(
  1030. InterfaceInfo,
  1031. &Interfacep->Info,
  1032. sizeof(IP_FTP_INTERFACE_INFO)
  1033. );
  1034. *InterfaceInfoSize = sizeof(IP_FTP_INTERFACE_INFO);
  1035. LeaveCriticalSection(&FtpInterfaceLock);
  1036. FTP_DEREFERENCE_INTERFACE(Interfacep);
  1037. return NO_ERROR;
  1038. } // FtpQueryInterface
  1039. VOID
  1040. FtpShutdownInterfaceManagement(
  1041. VOID
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. This routine is called to shutdown the interface-management module.
  1046. Arguments:
  1047. none.
  1048. Return Value:
  1049. none.
  1050. Notes:
  1051. Invoked in an arbitrary thread context, after all references
  1052. to all interfaces have been released.
  1053. --*/
  1054. {
  1055. PFTP_INTERFACE Interfacep;
  1056. PLIST_ENTRY Link;
  1057. PROFILE("FtpShutdownInterfaceManagement");
  1058. while (!IsListEmpty(&FtpInterfaceList)) {
  1059. Link = RemoveHeadList(&FtpInterfaceList);
  1060. Interfacep = CONTAINING_RECORD(Link, FTP_INTERFACE, Link);
  1061. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  1062. FtpDeactivateInterface(Interfacep);
  1063. }
  1064. FtpCleanupInterface(Interfacep);
  1065. }
  1066. DeleteCriticalSection(&FtpInterfaceLock);
  1067. } // FtpShutdownInterfaceManagement
  1068. VOID
  1069. FtpSignalNatInterface(
  1070. ULONG Index,
  1071. BOOLEAN Boundary
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. This routine is invoked upon reconfiguration of a NAT interface.
  1076. Note that this routine may be invoked even when the FTP transparent
  1077. proxy is neither installed nor running; it operates as expected,
  1078. since the global information and lock are always initialized.
  1079. Upon invocation, the routine activates or deactivates the interface
  1080. depending on whether the NAT is not or is running on the interface,
  1081. respectively.
  1082. Arguments:
  1083. Index - the reconfigured interface
  1084. Boundary - indicates whether the interface is now a boundary interface
  1085. Return Value:
  1086. none.
  1087. Notes:
  1088. Invoked from an arbitrary context.
  1089. --*/
  1090. {
  1091. PFTP_INTERFACE Interfacep;
  1092. PROFILE("FtpSignalNatInterface");
  1093. EnterCriticalSection(&FtpGlobalInfoLock);
  1094. if (!FtpGlobalInfo) {
  1095. LeaveCriticalSection(&FtpGlobalInfoLock);
  1096. return;
  1097. }
  1098. LeaveCriticalSection(&FtpGlobalInfoLock);
  1099. EnterCriticalSection(&FtpInterfaceLock);
  1100. Interfacep = FtpLookupInterface(Index, NULL);
  1101. if (Interfacep == NULL) {
  1102. LeaveCriticalSection(&FtpInterfaceLock);
  1103. return;
  1104. }
  1105. FtpDeactivateInterface(Interfacep);
  1106. if (FTP_INTERFACE_ACTIVE(Interfacep)) {
  1107. FtpActivateInterface(Interfacep);
  1108. }
  1109. LeaveCriticalSection(&FtpInterfaceLock);
  1110. } // FtpSignalNatInterface
  1111. ULONG
  1112. FtpUnbindInterface(
  1113. ULONG Index
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This routine is invoked to revoke the binding on an interface.
  1118. This involves deactivating the interface if it is active.
  1119. Arguments:
  1120. Index - the index of the interface to be unbound
  1121. Return Value:
  1122. none.
  1123. Notes:
  1124. Invoked internally in the context of an IP router-manager thread.
  1125. (See 'RMFTP.C').
  1126. --*/
  1127. {
  1128. PFTP_INTERFACE Interfacep;
  1129. PROFILE("FtpUnbindInterface");
  1130. //
  1131. // Retrieve the interface to be unbound
  1132. //
  1133. EnterCriticalSection(&FtpInterfaceLock);
  1134. Interfacep = FtpLookupInterface(Index, NULL);
  1135. if (Interfacep == NULL) {
  1136. LeaveCriticalSection(&FtpInterfaceLock);
  1137. NhTrace(
  1138. TRACE_FLAG_IF,
  1139. "FtpUnbindInterface: interface %d not found",
  1140. Index
  1141. );
  1142. return ERROR_NO_SUCH_INTERFACE;
  1143. }
  1144. //
  1145. // Make sure the interface is not already unbound
  1146. //
  1147. if (!FTP_INTERFACE_BOUND(Interfacep)) {
  1148. LeaveCriticalSection(&FtpInterfaceLock);
  1149. NhTrace(
  1150. TRACE_FLAG_IF,
  1151. "FtpUnbindInterface: interface %d already unbound",
  1152. Index
  1153. );
  1154. return ERROR_ADDRESS_NOT_ASSOCIATED;
  1155. }
  1156. //
  1157. // Reference the interface
  1158. //
  1159. if (!FTP_REFERENCE_INTERFACE(Interfacep)) {
  1160. LeaveCriticalSection(&FtpInterfaceLock);
  1161. NhTrace(
  1162. TRACE_FLAG_IF,
  1163. "FtpUnbindInterface: interface %d cannot be referenced",
  1164. Index
  1165. );
  1166. return ERROR_INTERFACE_DISABLED;
  1167. }
  1168. //
  1169. // Clear the 'bound' and 'mapped' flag
  1170. //
  1171. Interfacep->Flags &=
  1172. ~(FTP_INTERFACE_FLAG_BOUND | FTP_INTERFACE_FLAG_MAPPED);
  1173. //
  1174. // Deactivate the interface, if necessary
  1175. //
  1176. if (FTP_INTERFACE_ENABLED(Interfacep)) {
  1177. FtpDeactivateInterface(Interfacep);
  1178. }
  1179. LeaveCriticalSection(&FtpInterfaceLock);
  1180. //
  1181. // Destroy the interface's binding
  1182. //
  1183. ACQUIRE_LOCK(Interfacep);
  1184. NH_FREE(Interfacep->BindingArray);
  1185. Interfacep->BindingArray = NULL;
  1186. Interfacep->BindingCount = 0;
  1187. RELEASE_LOCK(Interfacep);
  1188. FTP_DEREFERENCE_INTERFACE(Interfacep);
  1189. return NO_ERROR;
  1190. } // FtpUnbindInterface