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.

2317 lines
60 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. natapi.c
  5. Abstract:
  6. This module contains code for API routines which provide translation
  7. functionality to user-mode clients of the NAT. This functionality
  8. differs from the 'normal' mode, in which a boundary-interface is designated
  9. and packets are transparently modified as they cross the boundary.
  10. This module instead allows an application to stipulate that certain
  11. modifications be made to a packet on any interface it is received.
  12. Author:
  13. Abolade Gbadegesin (aboladeg) 08-May-1998
  14. Revision History:
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <ipnatapi.h>
  19. C_ASSERT(NAT_INVALID_IF_INDEX == INVALID_IF_INDEX);
  20. //
  21. // PRIVATE STRUCTURE DECLARATIONS
  22. //
  23. //
  24. // Structure: NAT_REDIRECT
  25. //
  26. // Encapsulates information about an outstanding redirect-instance.
  27. // For a normal redirect, the structure holds the caller-specified
  28. // completion-parameters and output statistics.
  29. // For a dynamic redirect instance, the structure links this instance
  30. // into the dynamic redirect's instance-list, and contains the notification
  31. // event for the instance.
  32. //
  33. typedef struct _NAT_REDIRECT {
  34. union {
  35. struct _NAT_REDIRECT_TAIL {
  36. IO_STATUS_BLOCK IoStatus;
  37. PNAT_COMPLETION_ROUTINE CompletionRoutine;
  38. PVOID CompletionContext;
  39. IP_NAT_REDIRECT_STATISTICS Statistics;
  40. };
  41. struct _NAT_DYNAMIC_REDIRECT_TAIL {
  42. LIST_ENTRY Link;
  43. ULONG InstanceId;
  44. HANDLE Event;
  45. HANDLE WaitHandle;
  46. struct _NAT_DYNAMIC_REDIRECT_CONTEXT* Context;
  47. };
  48. };
  49. } NAT_REDIRECT, *PNAT_REDIRECT;
  50. //
  51. // Structure: NAT_DYNAMIC_REDIRECT
  52. //
  53. // Encapsulates information about an outstanding dynamic redirect.
  54. // A dynamic redirect is automatically reissued using the caller's original
  55. // parameters whenever the number of instances drops below a given minimum
  56. // specified by the creator. We maintain a list of all instances of a dynamic
  57. // redirect, and we replenish the list whenever an instance is activated
  58. // or terminated without being activated.
  59. //
  60. // For each dynamic redirect, we maintain a reference-count which is used
  61. // to control its lifetime. We make references to the dynamic redirect when
  62. // * the redirect is initially created, on behalf of its existence,
  63. // * an additional instance is issued, on behalf of the notification routine
  64. // for the instance.
  65. //
  66. // The usual rules for synchronization apply, to wit, to access any fields
  67. // a reference must be held, and to add a reference the lock must be held,
  68. // except at creation-time when the initial reference is made.
  69. //
  70. typedef struct _NAT_DYNAMIC_REDIRECT {
  71. CRITICAL_SECTION Lock;
  72. ULONG ReferenceCount;
  73. ULONG Flags;
  74. HANDLE TranslatorHandle;
  75. ULONG MinimumBacklog;
  76. LIST_ENTRY InstanceList;
  77. IP_NAT_CREATE_REDIRECT_EX CreateRedirect;
  78. } NAT_DYNAMIC_REDIRECT, *PNAT_DYNAMIC_REDIRECT;
  79. #define NAT_DYNAMIC_REDIRECT_FLAG_DELETED 0x80000000
  80. #define NAT_DYNAMIC_REDIRECT_DELETED(d) \
  81. ((d)->Flags & NAT_DYNAMIC_REDIRECT_FLAG_DELETED)
  82. #define NAT_REFERENCE_DYNAMIC_REDIRECT(d) \
  83. REFERENCE_OBJECT(d, NAT_DYNAMIC_REDIRECT_DELETED)
  84. #define NAT_DEREFERENCE_DYNAMIC_REDIRECT(d) \
  85. DEREFERENCE_OBJECT(d, NatpCleanupDynamicRedirect)
  86. #define DEFAULT_DYNAMIC_REDIRECT_BACKLOG 5
  87. //
  88. // Structure: NAT_DYNAMIC_REDIRECT_CONTEXT
  89. //
  90. // Used as the context-parameter for the notification and completion routines
  91. // of each instance of a dynamic redirect.
  92. //
  93. typedef struct _NAT_DYNAMIC_REDIRECT_CONTEXT {
  94. PNAT_DYNAMIC_REDIRECT DynamicRedirectp;
  95. ULONG InstanceId;
  96. } NAT_DYNAMIC_REDIRECT_CONTEXT, *PNAT_DYNAMIC_REDIRECT_CONTEXT;
  97. //
  98. // GLOBAL DATA DEFINITIONS
  99. //
  100. const WCHAR NatpServicePath[] =
  101. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\IPNAT";
  102. ULONG NextRedirectInstanceId = 0;
  103. IO_STATUS_BLOCK UnusedIoStatus;
  104. IP_NAT_REDIRECT_STATISTICS UnusedStatistics;
  105. //
  106. // FORWARD DECLARATIONS
  107. //
  108. VOID
  109. NatCloseDriver(
  110. HANDLE FileHandle
  111. );
  112. ULONG
  113. NatLoadDriver(
  114. OUT PHANDLE FileHandle,
  115. PIP_NAT_GLOBAL_INFO GlobalInfo
  116. );
  117. ULONG
  118. NatOpenDriver(
  119. OUT PHANDLE FileHandle
  120. );
  121. VOID
  122. NatpCleanupDynamicRedirect(
  123. PNAT_DYNAMIC_REDIRECT DynamicRedirectp
  124. );
  125. VOID
  126. NatpDisableLoadDriverPrivilege(
  127. PBOOLEAN WasEnabled
  128. );
  129. VOID NTAPI
  130. NatpDynamicRedirectNotificationRoutine(
  131. PVOID Context,
  132. BOOLEAN WaitCompleted
  133. );
  134. BOOLEAN
  135. NatpEnableLoadDriverPrivilege(
  136. PBOOLEAN WasEnabled
  137. );
  138. VOID NTAPI
  139. NatpRedirectCompletionRoutine(
  140. PVOID Context,
  141. PIO_STATUS_BLOCK IoStatus,
  142. ULONG Reserved
  143. );
  144. VOID
  145. NatpCreateDynamicRedirectInstance(
  146. PNAT_DYNAMIC_REDIRECT DynamicRedirectp
  147. );
  148. VOID
  149. NatpDeleteDynamicRedirectInstance(
  150. PNAT_DYNAMIC_REDIRECT DynamicRedirectp,
  151. PNAT_REDIRECT Redirectp
  152. );
  153. BOOLEAN
  154. NatpValidateRedirectParameters(
  155. ULONG Flags,
  156. UCHAR Protocol,
  157. ULONG DestinationAddress,
  158. USHORT DestinationPort,
  159. ULONG SourceAddress,
  160. USHORT SourcePort,
  161. ULONG NewDestinationAddress,
  162. USHORT NewDestinationPort,
  163. ULONG NewSourceAddress,
  164. USHORT NewSourcePort,
  165. ULONG RestrictAdapterIndex OPTIONAL
  166. );
  167. ULONG
  168. NatUnloadDriver(
  169. HANDLE FileHandle
  170. );
  171. ULONG
  172. NatCancelDynamicRedirect(
  173. HANDLE DynamicRedirectHandle
  174. )
  175. /*++
  176. Routine Description:
  177. This routine is called to cancel the given dynamic redirect.
  178. It cancels all instances of the dynamic redirect and releases the initial
  179. reference to the dynamic redirect, thus causing cleanup to occur as soon
  180. as all active references are released.
  181. Arguments:
  182. DynamicRedirectHandle - the handle to the dynamic redirect to be cancelled
  183. Return Value:
  184. ULONG - Win32 status code.
  185. --*/
  186. {
  187. PNAT_DYNAMIC_REDIRECT DynamicRedirectp =
  188. (PNAT_DYNAMIC_REDIRECT)DynamicRedirectHandle;
  189. //
  190. // Lock the dynamic redirect, mark it 'deleted' to ensure that
  191. // no more instances are created by our notification routines,
  192. // and delete all outstanding instances.
  193. //
  194. EnterCriticalSection(&DynamicRedirectp->Lock);
  195. if (NAT_DYNAMIC_REDIRECT_DELETED(DynamicRedirectp)) {
  196. LeaveCriticalSection(&DynamicRedirectp->Lock);
  197. return ERROR_INVALID_PARAMETER;
  198. }
  199. DynamicRedirectp->Flags |= NAT_DYNAMIC_REDIRECT_FLAG_DELETED;
  200. while (!IsListEmpty(&DynamicRedirectp->InstanceList)) {
  201. PNAT_REDIRECT Redirectp =
  202. CONTAINING_RECORD(
  203. DynamicRedirectp->InstanceList.Flink,
  204. NAT_REDIRECT,
  205. Link
  206. );
  207. NatpDeleteDynamicRedirectInstance(DynamicRedirectp, Redirectp);
  208. }
  209. LeaveCriticalSection(&DynamicRedirectp->Lock);
  210. //
  211. // Release the initial reference to the dynamic redirect and return.
  212. //
  213. NAT_DEREFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp);
  214. return NO_ERROR;
  215. } // NatCancelDynamicRedirect
  216. ULONG
  217. NatCancelRedirect(
  218. HANDLE TranslatorHandle,
  219. UCHAR Protocol,
  220. ULONG DestinationAddress,
  221. USHORT DestinationPort,
  222. ULONG SourceAddress,
  223. USHORT SourcePort,
  224. ULONG NewDestinationAddress,
  225. USHORT NewDestinationPort,
  226. ULONG NewSourceAddress,
  227. USHORT NewSourcePort
  228. )
  229. /*++
  230. Routine Description:
  231. This routine is invoked to cancel a redirect for a session.
  232. Arguments:
  233. TranslatorHandle - handle supplied by 'NatInitializeTranslator'
  234. * - specify the redirect to be cancelled
  235. Return Value:
  236. ULONG - Win32 status code.
  237. --*/
  238. {
  239. IP_NAT_LOOKUP_REDIRECT CancelRedirect;
  240. IO_STATUS_BLOCK IoStatus;
  241. NTSTATUS status;
  242. HANDLE WaitEvent;
  243. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  244. if (WaitEvent == NULL) {
  245. return ERROR_NOT_ENOUGH_MEMORY;
  246. }
  247. CancelRedirect.Flags = 0;
  248. CancelRedirect.RedirectApcContext = NULL;
  249. CancelRedirect.Protocol = Protocol;
  250. CancelRedirect.DestinationAddress = DestinationAddress;
  251. CancelRedirect.DestinationPort = DestinationPort;
  252. CancelRedirect.SourceAddress = SourceAddress;
  253. CancelRedirect.SourcePort = SourcePort;
  254. CancelRedirect.NewDestinationAddress = NewDestinationAddress;
  255. CancelRedirect.NewDestinationPort = NewDestinationPort;
  256. CancelRedirect.NewSourceAddress = NewSourceAddress;
  257. CancelRedirect.NewSourcePort = NewSourcePort;
  258. status =
  259. NtDeviceIoControlFile(
  260. TranslatorHandle,
  261. WaitEvent,
  262. NULL,
  263. NULL,
  264. &IoStatus,
  265. IOCTL_IP_NAT_CANCEL_REDIRECT,
  266. (PVOID)&CancelRedirect,
  267. sizeof(CancelRedirect),
  268. NULL,
  269. 0
  270. );
  271. if (status == STATUS_PENDING) {
  272. WaitForSingleObject(WaitEvent, INFINITE);
  273. status = IoStatus.Status;
  274. }
  275. CloseHandle(WaitEvent);
  276. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  277. } // NatCancelRedirect
  278. VOID
  279. NatCloseDriver(
  280. HANDLE FileHandle
  281. )
  282. /*++
  283. Routine Description:
  284. This routine is called to close a handle to the NAT driver's device-object.
  285. Arguments:
  286. FileHandle - the handle to be closed.
  287. Return Value:
  288. none.
  289. --*/
  290. {
  291. NtClose(FileHandle);
  292. } // NatCloseDriver
  293. ULONG
  294. NatCreateDynamicFullRedirect(
  295. ULONG Flags,
  296. UCHAR Protocol,
  297. ULONG DestinationAddress,
  298. USHORT DestinationPort,
  299. ULONG SourceAddress,
  300. USHORT SourcePort,
  301. ULONG NewDestinationAddress,
  302. USHORT NewDestinationPort,
  303. ULONG NewSourceAddress,
  304. USHORT NewSourcePort,
  305. ULONG RestrictSourceAddress OPTIONAL,
  306. ULONG RestrictAdapterIndex OPTIONAL,
  307. ULONG MinimumBacklog OPTIONAL,
  308. OUT PHANDLE DynamicRedirectHandlep
  309. )
  310. /*++
  311. Routine Description:
  312. This routine is invoked to create a redirect which is dynamically
  313. managed to ensure that there are always at least a specified minimum
  314. number of instances active. It is suitable for use by transparent proxies,
  315. which require assurance that all sessions matching a given description
  316. will be redirected by the kernel-mode translation module.
  317. The routine creates and initializes a structure which encapsulates all the
  318. information required to establish an instance of the caller's redirect.
  319. It then creates a series of instances of the redirect, and returns.
  320. We rely on notification routines to replace each instance that is
  321. activated or terminated.
  322. Arguments:
  323. Flags - specifies options for the redirect
  324. Protocol - IP protocol of the session to be redirected
  325. Destination* - destination endpoint of the session to be redirected
  326. Source* - source endpoint of the session to be redirected
  327. NewDestination* - replacement destination endpoint for the session
  328. NewSource* - replacement source endpoint for the session
  329. RestrictSourceAddress - optionally specifies the source address to which
  330. the redirect should be applied
  331. RestrictAdapterIndex - optionally specifies the adapter index that this
  332. redirect should be restricted to
  333. MinimumBacklog - optionally specifies the number of pending redirect
  334. instances to leave as a backlog
  335. DynamicRedirectHandlep - on output, receives a handle to the newly-created
  336. dynamic redirect.
  337. Return Value:
  338. ULONG - Win32 status code.
  339. --*/
  340. {
  341. PNAT_DYNAMIC_REDIRECT DynamicRedirectp;
  342. ULONG Error;
  343. ULONG i;
  344. if (!DynamicRedirectHandlep ||
  345. !NatpValidateRedirectParameters(
  346. Flags,
  347. Protocol,
  348. DestinationAddress,
  349. DestinationPort,
  350. (Flags & NatRedirectFlagRestrictSource) ? RestrictSourceAddress : SourceAddress,
  351. SourcePort,
  352. NewDestinationAddress,
  353. NewDestinationPort,
  354. NewSourceAddress,
  355. NewSourcePort,
  356. RestrictAdapterIndex
  357. )) {
  358. return ERROR_INVALID_PARAMETER;
  359. }
  360. //
  361. // Create and initialize the new dynamic redirect.
  362. //
  363. DynamicRedirectp = MALLOC(sizeof(*DynamicRedirectp));
  364. if (!DynamicRedirectp) {
  365. return ERROR_NOT_ENOUGH_MEMORY;
  366. }
  367. ZeroMemory(DynamicRedirectp, sizeof(*DynamicRedirectp));
  368. __try {
  369. InitializeCriticalSection(&DynamicRedirectp->Lock);
  370. } __except(EXCEPTION_EXECUTE_HANDLER) {
  371. Error = GetExceptionCode();
  372. FREE(DynamicRedirectp);
  373. return Error;
  374. }
  375. DynamicRedirectp->ReferenceCount = 1;
  376. InitializeListHead(&DynamicRedirectp->InstanceList);
  377. DynamicRedirectp->TranslatorHandle = NULL;
  378. DynamicRedirectp->MinimumBacklog =
  379. (MinimumBacklog ? MinimumBacklog : DEFAULT_DYNAMIC_REDIRECT_BACKLOG);
  380. DynamicRedirectp->CreateRedirect.Flags =
  381. Flags | IP_NAT_REDIRECT_FLAG_ASYNCHRONOUS;
  382. DynamicRedirectp->CreateRedirect.Protocol = Protocol;
  383. DynamicRedirectp->CreateRedirect.DestinationAddress = DestinationAddress;
  384. DynamicRedirectp->CreateRedirect.DestinationPort = DestinationPort;
  385. DynamicRedirectp->CreateRedirect.SourceAddress = SourceAddress;
  386. DynamicRedirectp->CreateRedirect.SourcePort = SourcePort;
  387. DynamicRedirectp->CreateRedirect.NewDestinationAddress =
  388. NewDestinationAddress;
  389. DynamicRedirectp->CreateRedirect.NewDestinationPort = NewDestinationPort;
  390. DynamicRedirectp->CreateRedirect.NewSourceAddress = NewSourceAddress;
  391. DynamicRedirectp->CreateRedirect.NewSourcePort = NewSourcePort;
  392. DynamicRedirectp->CreateRedirect.RestrictSourceAddress =
  393. RestrictSourceAddress;
  394. DynamicRedirectp->CreateRedirect.RestrictAdapterIndex =
  395. ((Flags & NatRedirectFlagRestrictAdapter)
  396. ? RestrictAdapterIndex
  397. : NAT_INVALID_IF_INDEX);
  398. //
  399. // Obtain a private handle to the kernel-mode translation module.
  400. // It is important that this handle be private because, as noted
  401. // in 'NatpDeleteDynamicRedirectInstance', we may mistakenly cancel
  402. // redirects during normal execution, and they had better belong to us.
  403. //
  404. if (Error = NatOpenDriver(&DynamicRedirectp->TranslatorHandle)) {
  405. NatpCleanupDynamicRedirect(DynamicRedirectp);
  406. return Error;
  407. }
  408. //
  409. // Issue the first set of redirects for the caller's minimum backlog.
  410. //
  411. EnterCriticalSection(&DynamicRedirectp->Lock);
  412. for (i = 0; i < DynamicRedirectp->MinimumBacklog; i++) {
  413. NatpCreateDynamicRedirectInstance(DynamicRedirectp);
  414. }
  415. LeaveCriticalSection(&DynamicRedirectp->Lock);
  416. *DynamicRedirectHandlep = (HANDLE)DynamicRedirectp;
  417. return NO_ERROR;
  418. } // NatCreateDynamicFullRedirect
  419. ULONG
  420. NatCreateDynamicRedirect(
  421. ULONG Flags,
  422. UCHAR Protocol,
  423. ULONG DestinationAddress,
  424. USHORT DestinationPort,
  425. ULONG NewDestinationAddress,
  426. USHORT NewDestinationPort,
  427. ULONG RestrictSourceAddress OPTIONAL,
  428. ULONG MinimumBacklog OPTIONAL,
  429. OUT PHANDLE DynamicRedirectHandlep
  430. )
  431. {
  432. return
  433. NatCreateDynamicFullRedirect(
  434. Flags,
  435. Protocol,
  436. DestinationAddress,
  437. DestinationPort,
  438. 0,
  439. 0,
  440. NewDestinationAddress,
  441. NewDestinationPort,
  442. 0,
  443. 0,
  444. RestrictSourceAddress,
  445. 0,
  446. MinimumBacklog,
  447. DynamicRedirectHandlep
  448. );
  449. }
  450. ULONG
  451. NatCreateDynamicRedirectEx(
  452. ULONG Flags,
  453. UCHAR Protocol,
  454. ULONG DestinationAddress,
  455. USHORT DestinationPort,
  456. ULONG NewDestinationAddress,
  457. USHORT NewDestinationPort,
  458. ULONG RestrictSourceAddress OPTIONAL,
  459. ULONG RestrictAdapterIndex OPTIONAL,
  460. ULONG MinimumBacklog OPTIONAL,
  461. OUT PHANDLE DynamicRedirectHandlep
  462. )
  463. {
  464. return
  465. NatCreateDynamicFullRedirect(
  466. Flags,
  467. Protocol,
  468. DestinationAddress,
  469. DestinationPort,
  470. 0,
  471. 0,
  472. NewDestinationAddress,
  473. NewDestinationPort,
  474. 0,
  475. 0,
  476. RestrictSourceAddress,
  477. RestrictAdapterIndex,
  478. MinimumBacklog,
  479. DynamicRedirectHandlep
  480. );
  481. }
  482. ULONG
  483. NatCreateRedirect(
  484. HANDLE TranslatorHandle,
  485. ULONG Flags,
  486. UCHAR Protocol,
  487. ULONG DestinationAddress,
  488. USHORT DestinationPort,
  489. ULONG SourceAddress,
  490. USHORT SourcePort,
  491. ULONG NewDestinationAddress,
  492. USHORT NewDestinationPort,
  493. ULONG NewSourceAddress,
  494. USHORT NewSourcePort,
  495. PNAT_COMPLETION_ROUTINE CompletionRoutine,
  496. PVOID CompletionContext,
  497. HANDLE NotifyEvent OPTIONAL
  498. )
  499. {
  500. return NatCreateRedirectEx(
  501. TranslatorHandle,
  502. Flags,
  503. Protocol,
  504. DestinationAddress,
  505. DestinationPort,
  506. SourceAddress,
  507. SourcePort,
  508. NewDestinationAddress,
  509. NewDestinationPort,
  510. NewSourceAddress,
  511. NewSourcePort,
  512. 0,
  513. CompletionRoutine,
  514. CompletionContext,
  515. NotifyEvent
  516. );
  517. }
  518. ULONG
  519. NatCreateRedirectEx(
  520. HANDLE TranslatorHandle,
  521. ULONG Flags,
  522. UCHAR Protocol,
  523. ULONG DestinationAddress,
  524. USHORT DestinationPort,
  525. ULONG SourceAddress,
  526. USHORT SourcePort,
  527. ULONG NewDestinationAddress,
  528. USHORT NewDestinationPort,
  529. ULONG NewSourceAddress,
  530. USHORT NewSourcePort,
  531. ULONG RestrictAdapterIndex OPTIONAL,
  532. PNAT_COMPLETION_ROUTINE CompletionRoutine,
  533. PVOID CompletionContext,
  534. HANDLE NotifyEvent OPTIONAL
  535. )
  536. /*++
  537. Routine Description:
  538. This routine is invoked to install a redirect for a session.
  539. Arguments:
  540. TranslatorHandle - handle supplied by 'NatInitializeTranslator'
  541. Flags - specifies options for the redirect
  542. Protocol - IP protocol of the session to be redirected
  543. Destination* - destination endpoint of the session to be redirected
  544. Source* - source endpoint of the session to be redirected
  545. NewDestination* - replacement destination endpoint for the session
  546. NewSource* - replacement source endpoint for the session
  547. RestrictAdapterIndex - optionally specifies the adapter index that this
  548. redirect should be restricted to
  549. Completion* - specifies routine invoked on completion of the session,
  550. and the context to be passed to the routine
  551. NotifyEvent - optionally specifies an event to be signalled
  552. when a session matches the redirect.
  553. Return Value:
  554. ULONG - Win32 status code.
  555. --*/
  556. {
  557. IP_NAT_CREATE_REDIRECT_EX CreateRedirect;
  558. PNAT_REDIRECT Redirectp;
  559. PIO_STATUS_BLOCK IoStatus;
  560. NTSTATUS status;
  561. HANDLE CompletionEvent;
  562. if (!NatpValidateRedirectParameters(
  563. Flags,
  564. Protocol,
  565. DestinationAddress,
  566. DestinationPort,
  567. SourceAddress,
  568. SourcePort,
  569. NewDestinationAddress,
  570. NewDestinationPort,
  571. NewSourceAddress,
  572. NewSourcePort,
  573. RestrictAdapterIndex
  574. )) {
  575. return ERROR_INVALID_PARAMETER;
  576. }
  577. if (!CompletionRoutine) {
  578. Redirectp = NULL;
  579. IoStatus = &UnusedIoStatus;
  580. CompletionEvent = NULL;
  581. } else if (IPNATAPI_SET_EVENT_ON_COMPLETION == CompletionRoutine) {
  582. Redirectp = NULL;
  583. IoStatus = &UnusedIoStatus;
  584. CompletionEvent = (HANDLE)CompletionContext;
  585. } else {
  586. Redirectp = (PNAT_REDIRECT)MALLOC(sizeof(*Redirectp));
  587. if (!Redirectp) { return ERROR_NOT_ENOUGH_MEMORY; }
  588. Redirectp->CompletionRoutine = CompletionRoutine;
  589. Redirectp->CompletionContext = CompletionContext;
  590. IoStatus = &Redirectp->IoStatus;
  591. }
  592. if (Flags & NatRedirectFlagRestrictSource) {
  593. CreateRedirect.RestrictSourceAddress = SourceAddress;
  594. SourceAddress = 0;
  595. } else {
  596. CreateRedirect.RestrictSourceAddress = 0;
  597. }
  598. CreateRedirect.Flags = Flags;
  599. CreateRedirect.Protocol = Protocol;
  600. CreateRedirect.DestinationAddress = DestinationAddress;
  601. CreateRedirect.DestinationPort = DestinationPort;
  602. CreateRedirect.SourceAddress = SourceAddress;
  603. CreateRedirect.SourcePort = SourcePort;
  604. CreateRedirect.NewDestinationAddress = NewDestinationAddress;
  605. CreateRedirect.NewDestinationPort = NewDestinationPort;
  606. CreateRedirect.NewSourceAddress = NewSourceAddress;
  607. CreateRedirect.NewSourcePort = NewSourcePort;
  608. CreateRedirect.NotifyEvent = NotifyEvent;
  609. CreateRedirect.RestrictAdapterIndex =
  610. ((Flags & NatRedirectFlagRestrictAdapter)
  611. ? RestrictAdapterIndex
  612. : NAT_INVALID_IF_INDEX);
  613. if (!CompletionRoutine
  614. || IPNATAPI_SET_EVENT_ON_COMPLETION == CompletionRoutine ) {
  615. status =
  616. NtDeviceIoControlFile(
  617. TranslatorHandle,
  618. CompletionEvent,
  619. NULL,
  620. NULL,
  621. IoStatus,
  622. IOCTL_IP_NAT_CREATE_REDIRECT_EX,
  623. (PVOID)&CreateRedirect,
  624. sizeof(CreateRedirect),
  625. (PVOID)&UnusedStatistics,
  626. sizeof(UnusedStatistics)
  627. );
  628. } else {
  629. status =
  630. NtDeviceIoControlFile(
  631. TranslatorHandle,
  632. NULL,
  633. NatpRedirectCompletionRoutine,
  634. Redirectp,
  635. IoStatus,
  636. IOCTL_IP_NAT_CREATE_REDIRECT_EX,
  637. (PVOID)&CreateRedirect,
  638. sizeof(CreateRedirect),
  639. (PVOID)&Redirectp->Statistics,
  640. sizeof(Redirectp->Statistics)
  641. );
  642. }
  643. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  644. } // NatCreateRedirect
  645. ULONG
  646. NatInitializeTranslator(
  647. PHANDLE TranslatorHandle
  648. )
  649. /*++
  650. Routine Description:
  651. This routine is invoked to prepare for translation by loading the NAT
  652. and installing all local adapters as interfaces.
  653. Arguments:
  654. TranslatorHandle - receives the file handle of the NAT driver
  655. Return Value:
  656. ULONG - Win32 status code.
  657. --*/
  658. {
  659. ULONG Error;
  660. IP_NAT_GLOBAL_INFO GlobalInfo;
  661. //
  662. // Initialize the NAT's global configuration
  663. //
  664. ZeroMemory(&GlobalInfo, sizeof(GlobalInfo));
  665. GlobalInfo.Header.Version = IP_NAT_VERSION;
  666. GlobalInfo.Header.Size = FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry);
  667. //
  668. // Start the NAT module.
  669. // This step causes the driver to be loaded.
  670. //
  671. Error = NatLoadDriver(TranslatorHandle, &GlobalInfo);
  672. if (Error) {
  673. return Error;
  674. }
  675. return NO_ERROR;
  676. } // NatInitializeTranslator
  677. ULONG
  678. NatLoadDriver(
  679. PHANDLE FileHandle,
  680. PIP_NAT_GLOBAL_INFO GlobalInfo
  681. )
  682. /*++
  683. Routine Description:
  684. This routine is invoked to initialize the NAT's data and start the driver.
  685. Arguments:
  686. FileHandle - receives the handle for the NAT's file-object
  687. GlobalInfo - the global information for the NAT.
  688. Return Value:
  689. ULONG - Win32 status code.
  690. --*/
  691. {
  692. UNICODE_STRING DeviceName;
  693. ULONG Error;
  694. IO_STATUS_BLOCK IoStatus;
  695. OBJECT_ATTRIBUTES ObjectAttributes;
  696. NTSTATUS status;
  697. HANDLE WaitEvent;
  698. #if 0
  699. {
  700. SC_HANDLE ScmHandle;
  701. SC_HANDLE ServiceHandle;
  702. SERVICE_STATUS ServiceStatus;
  703. //
  704. // Request that the service controller load the driver.
  705. // Note that this will either succeed immediately or fail immediately;
  706. // there is no 'checkpoint' processing for starting drivers.
  707. //
  708. if (!(ScmHandle = OpenSCManager(NULL, NULL, GENERIC_READ))) {
  709. Error = GetLastError();
  710. } else {
  711. if (!(ServiceHandle =
  712. OpenServiceA(ScmHandle, IP_NAT_SERVICE_NAME, GENERIC_EXECUTE))) {
  713. Error = GetLastError();
  714. } else {
  715. if (!StartService(ServiceHandle, 0, NULL) &&
  716. (Error = GetLastError()) != ERROR_SERVICE_ALREADY_RUNNING) {
  717. } else {
  718. Error = NO_ERROR;
  719. }
  720. CloseServiceHandle(ServiceHandle);
  721. }
  722. CloseServiceHandle(ScmHandle);
  723. }
  724. if (Error) {
  725. return Error;
  726. }
  727. }
  728. #else
  729. {
  730. UNICODE_STRING ServicePath;
  731. BOOLEAN WasEnabled;
  732. //
  733. // Turn on our driver-loading ability
  734. //
  735. if (!NatpEnableLoadDriverPrivilege(&WasEnabled)) {
  736. return ERROR_ACCESS_DENIED;
  737. }
  738. RtlInitUnicodeString(&ServicePath, NatpServicePath);
  739. //
  740. // Load the driver
  741. //
  742. status = NtLoadDriver(&ServicePath);
  743. //
  744. // Turn off the privilege
  745. //
  746. NatpDisableLoadDriverPrivilege(&WasEnabled);
  747. //
  748. // See if the load-attempt succeeded
  749. //
  750. if (!NT_SUCCESS(status) && status != STATUS_IMAGE_ALREADY_LOADED) {
  751. Error = RtlNtStatusToDosError(status);
  752. return Error;
  753. }
  754. }
  755. #endif
  756. //
  757. // Obtain a handle to the NAT's device-object.
  758. //
  759. Error = NatOpenDriver(FileHandle);
  760. if (Error) {
  761. return Error;
  762. }
  763. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  764. if (WaitEvent == NULL) {
  765. return ERROR_NOT_ENOUGH_MEMORY;
  766. }
  767. //
  768. // Set the global configuration of the NAT
  769. //
  770. status =
  771. NtDeviceIoControlFile(
  772. *FileHandle,
  773. WaitEvent,
  774. NULL,
  775. NULL,
  776. &IoStatus,
  777. IOCTL_IP_NAT_SET_GLOBAL_INFO,
  778. (PVOID)GlobalInfo,
  779. FIELD_OFFSET(IP_NAT_GLOBAL_INFO, Header) + GlobalInfo->Header.Size,
  780. NULL,
  781. 0
  782. );
  783. if (status == STATUS_PENDING) {
  784. WaitForSingleObject(WaitEvent, INFINITE);
  785. status = IoStatus.Status;
  786. }
  787. CloseHandle(WaitEvent);
  788. if (!NT_SUCCESS(status)) {
  789. Error = RtlNtStatusToDosError(status);
  790. return Error;
  791. }
  792. return NO_ERROR;
  793. } // NatLoadDriver
  794. ULONG
  795. NatLookupAndQueryInformationSessionMapping(
  796. HANDLE TranslatorHandle,
  797. UCHAR Protocol,
  798. ULONG DestinationAddress,
  799. USHORT DestinationPort,
  800. ULONG SourceAddress,
  801. USHORT SourcePort,
  802. OUT PVOID Information,
  803. IN OUT PULONG InformationLength,
  804. NAT_SESSION_MAPPING_INFORMATION_CLASS InformationClass
  805. )
  806. /*++
  807. Routine Description:
  808. This routine attempts to locate a particular session mapping using either
  809. its forward key or reverse key, and to query information for the mapping,
  810. if found.
  811. Arguments:
  812. TranslatorHandle - handle supplied by 'NatInitializeTranslator'
  813. Protocol - the IP protocol for the mapping to be located
  814. Destination* - the destination endpoint for the mapping
  815. Source* - the source endpoint for the mapping
  816. Information - on output, receives the requested information
  817. InformationLength - on input, contains the length of the buffer
  818. at 'Information'; on output, receives the length of the information
  819. stored in 'Information', or the length of the buffer required.
  820. InformationClass - specifies
  821. Return Value:
  822. ULONG - Win32 status code.
  823. --*/
  824. {
  825. IO_STATUS_BLOCK IoStatus;
  826. IP_NAT_LOOKUP_SESSION_MAPPING LookupMapping;
  827. NTSTATUS status;
  828. HANDLE WaitEvent;
  829. if (!InformationLength ||
  830. InformationClass >= NatMaximumSessionMappingInformation) {
  831. return ERROR_INVALID_PARAMETER;
  832. }
  833. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  834. if (WaitEvent == NULL) {
  835. return ERROR_NOT_ENOUGH_MEMORY;
  836. }
  837. LookupMapping.Protocol = Protocol;
  838. LookupMapping.DestinationAddress = DestinationAddress;
  839. LookupMapping.DestinationPort = DestinationPort;
  840. LookupMapping.SourceAddress = SourceAddress;
  841. LookupMapping.SourcePort = SourcePort;
  842. if (InformationClass == NatKeySessionMappingInformation) {
  843. status =
  844. NtDeviceIoControlFile(
  845. TranslatorHandle,
  846. WaitEvent,
  847. NULL,
  848. NULL,
  849. &IoStatus,
  850. IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_KEY,
  851. (PVOID)&LookupMapping,
  852. sizeof(LookupMapping),
  853. (PVOID)Information,
  854. *InformationLength
  855. );
  856. if (status == STATUS_PENDING) {
  857. WaitForSingleObject(WaitEvent, INFINITE);
  858. status = IoStatus.Status;
  859. }
  860. } else if (InformationClass == NatStatisticsSessionMappingInformation) {
  861. status =
  862. NtDeviceIoControlFile(
  863. TranslatorHandle,
  864. WaitEvent,
  865. NULL,
  866. NULL,
  867. &IoStatus,
  868. IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_STATISTICS,
  869. (PVOID)&LookupMapping,
  870. sizeof(LookupMapping),
  871. (PVOID)Information,
  872. *InformationLength
  873. );
  874. if (status == STATUS_PENDING) {
  875. WaitForSingleObject(WaitEvent, INFINITE);
  876. status = IoStatus.Status;
  877. }
  878. } else if (InformationClass == NatKeySessionMappingExInformation) {
  879. status =
  880. NtDeviceIoControlFile(
  881. TranslatorHandle,
  882. WaitEvent,
  883. NULL,
  884. NULL,
  885. &IoStatus,
  886. IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_KEY_EX,
  887. (PVOID)&LookupMapping,
  888. sizeof(LookupMapping),
  889. (PVOID)Information,
  890. *InformationLength
  891. );
  892. if (status == STATUS_PENDING) {
  893. WaitForSingleObject(WaitEvent, INFINITE);
  894. status = IoStatus.Status;
  895. }
  896. } else {
  897. CloseHandle(WaitEvent);
  898. return ERROR_INVALID_PARAMETER;
  899. }
  900. CloseHandle(WaitEvent);
  901. if (!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); }
  902. switch(InformationClass) {
  903. case NatKeySessionMappingInformation: {
  904. *InformationLength = sizeof(NAT_KEY_SESSION_MAPPING_INFORMATION);
  905. break;
  906. }
  907. case NatStatisticsSessionMappingInformation: {
  908. *InformationLength =
  909. sizeof(NAT_STATISTICS_SESSION_MAPPING_INFORMATION);
  910. break;
  911. }
  912. case NatKeySessionMappingExInformation: {
  913. *InformationLength =
  914. sizeof(NAT_KEY_SESSION_MAPPING_EX_INFORMATION);
  915. break;
  916. }
  917. default: {
  918. return ERROR_INVALID_PARAMETER;
  919. }
  920. }
  921. return NO_ERROR;
  922. } // NatLookupAndQueryInformationSessionMapping
  923. ULONG
  924. NatOpenDriver(
  925. OUT PHANDLE FileHandle
  926. )
  927. /*++
  928. Routine Description:
  929. This routine is called to open the NAT driver's device-object.
  930. It assumes that the caller has loaded the driver already.
  931. Arguments:
  932. FileHandle - on output, receives the new handle
  933. Return Value:
  934. ULONG - Win32 status code.
  935. --*/
  936. {
  937. UNICODE_STRING DeviceName;
  938. IO_STATUS_BLOCK IoStatus;
  939. OBJECT_ATTRIBUTES ObjectAttributes;
  940. NTSTATUS status;
  941. //
  942. // Obtain a handle to the NAT's device-object.
  943. //
  944. RtlInitUnicodeString(&DeviceName, DD_IP_NAT_DEVICE_NAME);
  945. InitializeObjectAttributes(
  946. &ObjectAttributes,
  947. &DeviceName,
  948. OBJ_CASE_INSENSITIVE,
  949. NULL,
  950. NULL
  951. );
  952. status =
  953. NtOpenFile(
  954. FileHandle,
  955. SYNCHRONIZE|FILE_READ_DATA|FILE_WRITE_DATA,
  956. &ObjectAttributes,
  957. &IoStatus,
  958. FILE_SHARE_READ|FILE_SHARE_WRITE,
  959. 0
  960. );
  961. if (!NT_SUCCESS(status)) {
  962. return RtlNtStatusToDosError(status);
  963. }
  964. return NO_ERROR;
  965. } // NatOpenDriver
  966. VOID
  967. NatpCleanupDynamicRedirect(
  968. PNAT_DYNAMIC_REDIRECT DynamicRedirectp
  969. )
  970. /*++
  971. Routine Description:
  972. This routine is invoked when the last reference to a dynamic redirect
  973. is released. It is responsible for cleaning up all resources in use
  974. by the redirect.
  975. Arguments:
  976. DynamicRedirectp - the dynamic redirect to be cleaned up.
  977. Return Value:
  978. none.
  979. Environment:
  980. Invoked from an arbitrary context.
  981. --*/
  982. {
  983. ASSERT(IsListEmpty(&DynamicRedirectp->InstanceList));
  984. if (DynamicRedirectp->TranslatorHandle) {
  985. NatCloseDriver(DynamicRedirectp->TranslatorHandle);
  986. }
  987. DeleteCriticalSection(&DynamicRedirectp->Lock);
  988. FREE(DynamicRedirectp);
  989. } // NatpCleanupDynamicRedirect
  990. VOID
  991. NatpCreateDynamicRedirectInstance(
  992. PNAT_DYNAMIC_REDIRECT DynamicRedirectp
  993. )
  994. /*++
  995. Routine Description:
  996. This routine is invoked to submit an additional instance of the given
  997. dynamic redirect. The redirect is associated with a notification event
  998. so that this module is notified when the redirect is either activated
  999. or terminated. In either case, another instance of the redirect will be
  1000. created.
  1001. Arguments:
  1002. DynamicRedirectp - the dynamic redirect to be reissued
  1003. Return Value:
  1004. none.
  1005. Environment:
  1006. Invoked with the dynamic-redirect's lock held by the caller.
  1007. --*/
  1008. {
  1009. PNAT_REDIRECT Redirectp = NULL;
  1010. NTSTATUS status;
  1011. do {
  1012. //
  1013. // Allocate and initialize a new redirect-instance
  1014. //
  1015. if (!NAT_REFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp)) { break; }
  1016. Redirectp = MALLOC(sizeof(*Redirectp));
  1017. if (!Redirectp) {
  1018. NAT_DEREFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp);
  1019. break;
  1020. }
  1021. ZeroMemory(Redirectp, sizeof(*Redirectp));
  1022. Redirectp->InstanceId = InterlockedIncrement(&NextRedirectInstanceId);
  1023. InsertTailList(&DynamicRedirectp->InstanceList, &Redirectp->Link);
  1024. //
  1025. // Create an event on which to receive notification of the redirect's
  1026. // activation or termination, allocate a notification context block,
  1027. // and register our notification routine for the event.
  1028. //
  1029. if (!(Redirectp->Event = CreateEvent(NULL, FALSE, FALSE, NULL))) {
  1030. break;
  1031. } else if (!(Redirectp->Context =
  1032. MALLOC(sizeof(*Redirectp->Context)))) {
  1033. break;
  1034. } else {
  1035. Redirectp->Context->DynamicRedirectp = DynamicRedirectp;
  1036. Redirectp->Context->InstanceId = Redirectp->InstanceId;
  1037. if (!RegisterWaitForSingleObject(
  1038. &Redirectp->WaitHandle,
  1039. Redirectp->Event,
  1040. NatpDynamicRedirectNotificationRoutine,
  1041. Redirectp->Context,
  1042. INFINITE,
  1043. WT_EXECUTEINIOTHREAD | WT_EXECUTEONLYONCE
  1044. )) {
  1045. break;
  1046. }
  1047. }
  1048. //
  1049. // Issue the actual redirect request.
  1050. // Now we will notified either by the kernel-mode translation module
  1051. // when the instance is activated, or by the I/O manager when the
  1052. // I/O control completes or is cancelled.
  1053. //
  1054. DynamicRedirectp->CreateRedirect.NotifyEvent = Redirectp->Event;
  1055. status =
  1056. NtDeviceIoControlFile(
  1057. DynamicRedirectp->TranslatorHandle,
  1058. Redirectp->Event,
  1059. NULL,
  1060. NULL,
  1061. &UnusedIoStatus,
  1062. IOCTL_IP_NAT_CREATE_REDIRECT_EX,
  1063. (PVOID)&DynamicRedirectp->CreateRedirect,
  1064. sizeof(DynamicRedirectp->CreateRedirect),
  1065. (PVOID)&UnusedStatistics,
  1066. sizeof(UnusedStatistics)
  1067. );
  1068. if (!NT_SUCCESS(status)) {
  1069. if (UnregisterWait(Redirectp->WaitHandle)) {
  1070. FREE(Redirectp->Context);
  1071. NAT_DEREFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp);
  1072. }
  1073. Redirectp->WaitHandle = NULL;
  1074. break;
  1075. }
  1076. return;
  1077. } while(FALSE);
  1078. if (Redirectp) {
  1079. NatpDeleteDynamicRedirectInstance(DynamicRedirectp, Redirectp);
  1080. }
  1081. } // NatpCreateDynamicRedirectInstance
  1082. VOID
  1083. NatpDeleteDynamicRedirectInstance(
  1084. PNAT_DYNAMIC_REDIRECT DynamicRedirectp,
  1085. PNAT_REDIRECT Redirectp
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This routine is invoked to delete a given instance of a dynamic redirect.
  1090. The redirect is cancelled, synchronizing with the notification-routine
  1091. for the instance.
  1092. Arguments:
  1093. DynamicRedirectp - the dynamic redirect whose instance is to be deleted
  1094. Redirectp - the dynamic redirect instance to be deleted
  1095. Return Value:
  1096. none.
  1097. Environment:
  1098. Invoked with the dynamic redirect's lock held by the caller.
  1099. --*/
  1100. {
  1101. //
  1102. // We need to cancel the outstanding redirect, which will have been created
  1103. // if the wait-handle is non-NULL. However, when we issue the cancellation
  1104. // we have no way to know if the instance in question is already being
  1105. // completed by the kernel-mode translation module. If that is the case,
  1106. // our cancellation may affect some other instance issued on this
  1107. // translator-handle. It will not affect any instance issued on any other
  1108. // translator-handle since the kernel-mode translator will not allow
  1109. // redirects issued on one file-object to be cancelled from another
  1110. // file-object.
  1111. //
  1112. // Since we own the translation-handle, though, it is alright for us to
  1113. // erroneously cancel instances in this manner. The notification routine
  1114. // for the cancelled instance will just create a replacement.
  1115. //
  1116. // There is additional point of synchronization to be noted.
  1117. // If the notification routine runs, it is responsible for deleting
  1118. // the notification context and releasing the reference to the dynamic
  1119. // redirect. However, if we unregister our wait and the notification
  1120. // routine never runs, we are responsible for both tasks.
  1121. // The return code from 'UnregisterWait' is therefore used below as an
  1122. // indication of whether the two tasks should be performed here or left
  1123. // for the notification routine to perform.
  1124. //
  1125. // Finally, the instance only needs to be cancelled if its wait-handle
  1126. // is valid, since otherwise the instance must have never been issued.
  1127. //
  1128. if (Redirectp->WaitHandle) {
  1129. if (UnregisterWait(Redirectp->WaitHandle)) {
  1130. FREE(Redirectp->Context);
  1131. NAT_DEREFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp);
  1132. }
  1133. Redirectp->WaitHandle = NULL;
  1134. NatCancelRedirect(
  1135. DynamicRedirectp->TranslatorHandle,
  1136. DynamicRedirectp->CreateRedirect.Protocol,
  1137. DynamicRedirectp->CreateRedirect.DestinationAddress,
  1138. DynamicRedirectp->CreateRedirect.DestinationPort,
  1139. DynamicRedirectp->CreateRedirect.SourceAddress,
  1140. DynamicRedirectp->CreateRedirect.SourcePort,
  1141. DynamicRedirectp->CreateRedirect.NewDestinationAddress,
  1142. DynamicRedirectp->CreateRedirect.NewDestinationPort,
  1143. DynamicRedirectp->CreateRedirect.NewSourceAddress,
  1144. DynamicRedirectp->CreateRedirect.NewSourcePort
  1145. );
  1146. }
  1147. if (Redirectp->Event) {
  1148. CloseHandle(Redirectp->Event); Redirectp->Event = NULL;
  1149. }
  1150. RemoveEntryList(&Redirectp->Link);
  1151. FREE(Redirectp);
  1152. } // NatpDeleteDynamicRedirectInstance
  1153. VOID
  1154. NatpDisableLoadDriverPrivilege(
  1155. PBOOLEAN WasEnabled
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine is invoked to disable the previously-enable 'LoadDriver'
  1160. privilege for the calling thread.
  1161. Arguments:
  1162. WasEnabled - on input, indicates whether the privilege was already enabled.
  1163. Return Value:
  1164. none.
  1165. --*/
  1166. {
  1167. NTSTATUS Status;
  1168. //
  1169. // See if we had to enable SE_LOAD_DRIVER_PRIVILEGE
  1170. //
  1171. if (!*WasEnabled) {
  1172. //
  1173. // relinquish "Load-Driver" privileges for this thread
  1174. //
  1175. Status =
  1176. RtlAdjustPrivilege(
  1177. SE_LOAD_DRIVER_PRIVILEGE,
  1178. FALSE,
  1179. TRUE,
  1180. WasEnabled
  1181. );
  1182. }
  1183. //
  1184. // return the thread to its previous access token
  1185. //
  1186. RevertToSelf();
  1187. } // NatpDisableLoadDriverPrivilege
  1188. VOID NTAPI
  1189. NatpDynamicRedirectNotificationRoutine(
  1190. PVOID Context,
  1191. BOOLEAN WaitCompleted
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. This routine is invoked upon activation or termination of one of a
  1196. dynamic redirect's instantiated redirects by an incoming session.
  1197. It attempts to locate the corresponding instance and, if successful,
  1198. closes the wait-handle and event for the instance, and adds another
  1199. instance of the dynamic redirect to replace the one which has been
  1200. activated or terminated.
  1201. Arguments:
  1202. Context - contains context information for the notification
  1203. WaitCompleted - indicates whether the wait completed or timed out
  1204. Return Value:
  1205. none.
  1206. Environment:
  1207. Invoked in the context of a system wait thread.
  1208. --*/
  1209. {
  1210. PNAT_DYNAMIC_REDIRECT_CONTEXT Contextp =
  1211. (PNAT_DYNAMIC_REDIRECT_CONTEXT)Context;
  1212. PNAT_DYNAMIC_REDIRECT DynamicRedirectp = Contextp->DynamicRedirectp;
  1213. PLIST_ENTRY Link;
  1214. PNAT_REDIRECT Redirectp;
  1215. //
  1216. // Search the dynamic redirect's list of instances for the instance
  1217. // whose event has been signalled, and remove it after clearing the
  1218. // wait-handle to ensure that the deletion-routine does not attempt
  1219. // to cancel the redirect.
  1220. //
  1221. EnterCriticalSection(&DynamicRedirectp->Lock);
  1222. for (Link = DynamicRedirectp->InstanceList.Flink;
  1223. Link != &DynamicRedirectp->InstanceList; Link = Link->Flink) {
  1224. Redirectp = CONTAINING_RECORD(Link, NAT_REDIRECT, Link);
  1225. if (Redirectp->InstanceId == Contextp->InstanceId) {
  1226. UnregisterWait(Redirectp->WaitHandle);
  1227. Redirectp->WaitHandle = NULL;
  1228. NatpDeleteDynamicRedirectInstance(DynamicRedirectp, Redirectp);
  1229. break;
  1230. }
  1231. }
  1232. FREE(Contextp);
  1233. //
  1234. // If the dynamic redirect has not been deleted,
  1235. // replace the instance deleted above, if any.
  1236. //
  1237. if (!NAT_DYNAMIC_REDIRECT_DELETED(DynamicRedirectp)) {
  1238. NatpCreateDynamicRedirectInstance(DynamicRedirectp);
  1239. }
  1240. LeaveCriticalSection(&DynamicRedirectp->Lock);
  1241. //
  1242. // Drop the original reference to the dynamic redirect, and return.
  1243. //
  1244. NAT_DEREFERENCE_DYNAMIC_REDIRECT(DynamicRedirectp);
  1245. } // NatpDynamicRedirectNotificationRoutine
  1246. BOOLEAN
  1247. NatpEnableLoadDriverPrivilege(
  1248. PBOOLEAN WasEnabled
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. This routine is invoked to enable the 'LoadDriver' privilege
  1253. of the calling thread.
  1254. Arguments:
  1255. WasEnabled - on output indicates whether the privilege was already enabled
  1256. Return Value:
  1257. BOOLEAN - TRUE if successful, FALSE otherwise.
  1258. --*/
  1259. {
  1260. NTSTATUS Status;
  1261. //
  1262. // Obtain the process' access token for the current thread
  1263. //
  1264. Status = RtlImpersonateSelf(SecurityImpersonation);
  1265. if (!NT_SUCCESS(Status)) {
  1266. return FALSE;
  1267. }
  1268. //
  1269. // request "Load-Driver" privileges for this thread
  1270. //
  1271. Status =
  1272. RtlAdjustPrivilege(
  1273. SE_LOAD_DRIVER_PRIVILEGE,
  1274. TRUE,
  1275. TRUE,
  1276. WasEnabled
  1277. );
  1278. if (!NT_SUCCESS(Status)) {
  1279. RevertToSelf();
  1280. return FALSE;
  1281. }
  1282. return TRUE;
  1283. } // NatpEnableLoadDriverPrivilege
  1284. VOID NTAPI
  1285. NatpRedirectCompletionRoutine(
  1286. PVOID Context,
  1287. PIO_STATUS_BLOCK IoStatus,
  1288. ULONG Reserved
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. This routine is invoked upon completion of a redirect-IRP.
  1293. Arguments:
  1294. Context - indicates the redirect which was completed
  1295. IoStatus - contains the final status of the request
  1296. Reserved - unused
  1297. Return Value:
  1298. none.
  1299. --*/
  1300. {
  1301. PNAT_REDIRECT Redirectp = (PNAT_REDIRECT)Context;
  1302. if (Redirectp->CompletionRoutine) {
  1303. Redirectp->CompletionRoutine(
  1304. (HANDLE)Redirectp,
  1305. (BOOLEAN)((IoStatus->Status == STATUS_CANCELLED) ? TRUE : FALSE),
  1306. Redirectp->CompletionContext
  1307. );
  1308. }
  1309. FREE(Redirectp);
  1310. } // NatpRedirectCompletionRoutine
  1311. BOOLEAN
  1312. NatpValidateRedirectParameters(
  1313. ULONG Flags,
  1314. UCHAR Protocol,
  1315. ULONG DestinationAddress,
  1316. USHORT DestinationPort,
  1317. ULONG SourceAddress,
  1318. USHORT SourcePort,
  1319. ULONG NewDestinationAddress,
  1320. USHORT NewDestinationPort,
  1321. ULONG NewSourceAddress,
  1322. USHORT NewSourcePort,
  1323. ULONG RestrictAdapterIndex OPTIONAL
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. This routine validates redirect parameters
  1328. Arguments:
  1329. Flags - specifies options for the redirect
  1330. Protocol - IP protocol of the session to be redirected
  1331. Destination* - destination endpoint of the session to be redirected
  1332. Source* - source endpoint of the session to be redirected
  1333. NewDestination* - replacement destination endpoint for the session
  1334. NewSource* - replacement source endpoint for the session
  1335. Return Value:
  1336. BOOLEAN: TRUE if parameters are OK; FALSE otherwise
  1337. --*/
  1338. {
  1339. //
  1340. // Make sure no invalid flags are specified
  1341. //
  1342. if (Flags & ~NatRedirectFlagsAll)
  1343. {
  1344. return FALSE;
  1345. }
  1346. //
  1347. // TCP and UDP are the only valid protocols
  1348. //
  1349. if (Protocol != NAT_PROTOCOL_TCP && Protocol != NAT_PROTOCOL_UDP)
  1350. {
  1351. return FALSE;
  1352. }
  1353. //
  1354. // Validate endpoint information. There are two different sets of
  1355. // behavior, based on the presence of NatRedirectFlagSourceRedirect
  1356. //
  1357. if (!(Flags & NatRedirectFlagSourceRedirect))
  1358. {
  1359. //
  1360. // A destination address must be specified, unless
  1361. // NatRedirectFlagPortRedirect is set
  1362. //
  1363. if (!DestinationAddress & !(Flags & NatRedirectFlagPortRedirect))
  1364. {
  1365. return FALSE;
  1366. }
  1367. //
  1368. // There must be a destination port
  1369. //
  1370. if (!DestinationPort)
  1371. {
  1372. return FALSE;
  1373. }
  1374. //
  1375. // Both the replacement destination address and port must be specified
  1376. //
  1377. if (!NewDestinationAddress || !NewDestinationPort)
  1378. {
  1379. return FALSE;
  1380. }
  1381. //
  1382. // The replacement source address and port are both specified or
  1383. // unspecified
  1384. //
  1385. if (!!NewSourceAddress ^ !!NewSourcePort)
  1386. {
  1387. return FALSE;
  1388. }
  1389. //
  1390. // The source port must be unspecified if the source address
  1391. // is unspecified
  1392. //
  1393. if (!SourceAddress && SourcePort)
  1394. {
  1395. return FALSE;
  1396. }
  1397. //
  1398. // The replacement source is unspecified then the source port
  1399. // is also unspecified.
  1400. //
  1401. if (!NewSourceAddress && SourcePort)
  1402. {
  1403. return FALSE;
  1404. }
  1405. //
  1406. // If the source address is specified w/o a replacement source,
  1407. // the caller must specify the restrict-source flag indicating
  1408. // that this is a partial redirect restricted to a particular source.
  1409. //
  1410. if (!NewSourceAddress && SourceAddress
  1411. && !(Flags & NatRedirectFlagRestrictSource))
  1412. {
  1413. return FALSE;
  1414. }
  1415. //
  1416. // If the restrict-source flag is specified, the caller is specifiying
  1417. // a partial redirect w/ a source address
  1418. //
  1419. if ((Flags & NatRedirectFlagRestrictSource)
  1420. && (NewSourceAddress || !SourceAddress))
  1421. {
  1422. return FALSE;
  1423. }
  1424. //
  1425. // If the port-redirect flag is specified, the caller is specifying
  1426. // only the destination port, replacement destination address, and
  1427. // replacement destination port
  1428. //
  1429. if ((Flags & NatRedirectFlagPortRedirect)
  1430. && (DestinationAddress || SourceAddress || SourcePort
  1431. || NewSourceAddress || NewSourcePort))
  1432. {
  1433. return FALSE;
  1434. }
  1435. }
  1436. else
  1437. {
  1438. //
  1439. // The source address must be specified, unless
  1440. // NatRedirectFlagPortRedirect is specified
  1441. //
  1442. if (!SourceAddress && !(Flags & NatRedirectFlagPortRedirect))
  1443. {
  1444. return FALSE;
  1445. }
  1446. //
  1447. // The source port must be specified
  1448. //
  1449. if (!SourcePort)
  1450. {
  1451. return FALSE;
  1452. }
  1453. //
  1454. // No destination information may be specified
  1455. //
  1456. if (DestinationAddress || DestinationPort)
  1457. {
  1458. return FALSE;
  1459. }
  1460. //
  1461. // The replacement destination address and port are both specified
  1462. // or unspecified
  1463. //
  1464. if (!!NewDestinationAddress ^ !!NewDestinationPort)
  1465. {
  1466. return FALSE;
  1467. }
  1468. //
  1469. // The replacement source address and port must be specified,
  1470. // unless the port-redirect flag is set
  1471. //
  1472. if ((!NewSourceAddress || !NewSourcePort)
  1473. && !(Flags & NatRedirectFlagPortRedirect))
  1474. {
  1475. return FALSE;
  1476. }
  1477. //
  1478. // If the port-redirect flag is specified, the caller is specifying
  1479. // only the source port, replacement destination address, and
  1480. // replacement destination port
  1481. //
  1482. if ((Flags & NatRedirectFlagPortRedirect)
  1483. && (SourceAddress || DestinationAddress || DestinationPort
  1484. || NewSourceAddress || NewSourcePort))
  1485. {
  1486. return FALSE;
  1487. }
  1488. //
  1489. // The restrict-source-address flag is invalid
  1490. //
  1491. if (Flags & NatRedirectFlagRestrictSource)
  1492. {
  1493. return FALSE;
  1494. }
  1495. }
  1496. //
  1497. // The unidirectional flag is specified only for UDP redirects
  1498. //
  1499. if (Flags & NatRedirectFlagUnidirectional
  1500. && Protocol != NAT_PROTOCOL_UDP)
  1501. {
  1502. return FALSE;
  1503. }
  1504. //
  1505. // If the restrict-adapter-index flag is specified, the caller
  1506. // has given a valid, non-zero (i.e., local) interface index
  1507. //
  1508. if ((Flags & NatRedirectFlagRestrictAdapter)
  1509. && (NAT_INVALID_IF_INDEX == RestrictAdapterIndex
  1510. || LOCAL_IF_INDEX == RestrictAdapterIndex))
  1511. {
  1512. return FALSE;
  1513. }
  1514. return TRUE;
  1515. }
  1516. ULONG
  1517. NatQueryInformationRedirect(
  1518. HANDLE TranslatorHandle,
  1519. UCHAR Protocol,
  1520. ULONG DestinationAddress,
  1521. USHORT DestinationPort,
  1522. ULONG SourceAddress,
  1523. USHORT SourcePort,
  1524. ULONG NewDestinationAddress,
  1525. USHORT NewDestinationPort,
  1526. ULONG NewSourceAddress,
  1527. USHORT NewSourcePort,
  1528. OUT PVOID Information,
  1529. IN OUT PULONG InformationLength,
  1530. NAT_REDIRECT_INFORMATION_CLASS InformationClass
  1531. )
  1532. /*++
  1533. Routine Description:
  1534. This routine is called to obtain information about the session
  1535. for a completed redirect.
  1536. Arguments:
  1537. TranslatorHandle - handle supplied by 'NatInitializeTranslator'
  1538. * - specify the redirect to be queried
  1539. Information - receives the retrieved information
  1540. InformationLength - specifies the size of 'Information' on input;
  1541. contains the required size on output
  1542. InformationClass - indicates the class of information requested
  1543. Return Value:
  1544. ULONG - Win32 status code.
  1545. --*/
  1546. {
  1547. ULONG Error = NO_ERROR;
  1548. IO_STATUS_BLOCK IoStatus;
  1549. ULONG Length;
  1550. IP_NAT_LOOKUP_REDIRECT QueryRedirect;
  1551. IP_NAT_REDIRECT_STATISTICS RedirectStatistics;
  1552. IP_NAT_REDIRECT_SOURCE_MAPPING RedirectSourceMapping;
  1553. IP_NAT_REDIRECT_DESTINATION_MAPPING RedirectDestinationMapping;
  1554. NTSTATUS status;
  1555. HANDLE WaitEvent;
  1556. if (!InformationLength ||
  1557. InformationClass >= NatMaximumRedirectInformation) {
  1558. return ERROR_INVALID_PARAMETER;
  1559. }
  1560. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1561. if (WaitEvent== NULL) {
  1562. return ERROR_NOT_ENOUGH_MEMORY;
  1563. }
  1564. QueryRedirect.Flags = 0;
  1565. QueryRedirect.RedirectApcContext = NULL;
  1566. QueryRedirect.Protocol = Protocol;
  1567. QueryRedirect.DestinationAddress = DestinationAddress;
  1568. QueryRedirect.DestinationPort = DestinationPort;
  1569. QueryRedirect.SourceAddress = SourceAddress;
  1570. QueryRedirect.SourcePort = SourcePort;
  1571. QueryRedirect.NewDestinationAddress = NewDestinationAddress;
  1572. QueryRedirect.NewDestinationPort = NewDestinationPort;
  1573. QueryRedirect.NewSourceAddress = NewSourceAddress;
  1574. QueryRedirect.NewSourcePort = NewSourcePort;
  1575. if (InformationClass == NatDestinationMappingRedirectInformation) {
  1576. status =
  1577. NtDeviceIoControlFile(
  1578. TranslatorHandle,
  1579. WaitEvent,
  1580. NULL,
  1581. NULL,
  1582. &IoStatus,
  1583. IOCTL_IP_NAT_GET_REDIRECT_DESTINATION_MAPPING,
  1584. (PVOID)&QueryRedirect,
  1585. sizeof(QueryRedirect),
  1586. (PVOID)&RedirectDestinationMapping,
  1587. sizeof(RedirectDestinationMapping)
  1588. );
  1589. } else if (InformationClass == NatSourceMappingRedirectInformation) {
  1590. status =
  1591. NtDeviceIoControlFile(
  1592. TranslatorHandle,
  1593. WaitEvent,
  1594. NULL,
  1595. NULL,
  1596. &IoStatus,
  1597. IOCTL_IP_NAT_GET_REDIRECT_SOURCE_MAPPING,
  1598. (PVOID)&QueryRedirect,
  1599. sizeof(QueryRedirect),
  1600. (PVOID)&RedirectSourceMapping,
  1601. sizeof(RedirectSourceMapping)
  1602. );
  1603. } else {
  1604. status =
  1605. NtDeviceIoControlFile(
  1606. TranslatorHandle,
  1607. WaitEvent,
  1608. NULL,
  1609. NULL,
  1610. &IoStatus,
  1611. IOCTL_IP_NAT_GET_REDIRECT_STATISTICS,
  1612. (PVOID)&QueryRedirect,
  1613. sizeof(QueryRedirect),
  1614. (PVOID)&RedirectStatistics,
  1615. sizeof(RedirectStatistics)
  1616. );
  1617. }
  1618. if (status == STATUS_PENDING) {
  1619. WaitForSingleObject(WaitEvent, INFINITE);
  1620. status = IoStatus.Status;
  1621. }
  1622. CloseHandle(WaitEvent);
  1623. if (!NT_SUCCESS(status)) { return RtlNtStatusToDosError(status); }
  1624. switch (InformationClass) {
  1625. case NatByteCountRedirectInformation: {
  1626. PNAT_BYTE_COUNT_REDIRECT_INFORMATION ByteCount =
  1627. (PNAT_BYTE_COUNT_REDIRECT_INFORMATION)Information;
  1628. if (*InformationLength < sizeof(*ByteCount)) {
  1629. Error = ERROR_INSUFFICIENT_BUFFER;
  1630. } else {
  1631. ByteCount->BytesForward = RedirectStatistics.BytesForward;
  1632. ByteCount->BytesReverse = RedirectStatistics.BytesReverse;
  1633. }
  1634. *InformationLength = sizeof(*ByteCount);
  1635. break;
  1636. }
  1637. case NatRejectRedirectInformation: {
  1638. PNAT_REJECT_REDIRECT_INFORMATION Reject =
  1639. (PNAT_REJECT_REDIRECT_INFORMATION)Information;
  1640. if (*InformationLength < sizeof(*Reject)) {
  1641. Error = ERROR_INSUFFICIENT_BUFFER;
  1642. } else {
  1643. Reject->RejectsForward = RedirectStatistics.RejectsForward;
  1644. Reject->RejectsReverse = RedirectStatistics.RejectsReverse;
  1645. }
  1646. *InformationLength = sizeof(*Reject);
  1647. break;
  1648. }
  1649. case NatDestinationMappingRedirectInformation: {
  1650. PNAT_DESTINATION_MAPPING_REDIRECT_INFORMATION DestinationMapping =
  1651. (PNAT_DESTINATION_MAPPING_REDIRECT_INFORMATION)Information;
  1652. if (*InformationLength < sizeof(*DestinationMapping)) {
  1653. Error = ERROR_INSUFFICIENT_BUFFER;
  1654. } else {
  1655. DestinationMapping->DestinationAddress =
  1656. RedirectDestinationMapping.DestinationAddress;
  1657. DestinationMapping->DestinationPort =
  1658. RedirectDestinationMapping.DestinationPort;
  1659. DestinationMapping->NewDestinationAddress =
  1660. RedirectDestinationMapping.NewDestinationAddress;
  1661. DestinationMapping->NewDestinationPort =
  1662. RedirectDestinationMapping.NewDestinationPort;
  1663. }
  1664. *InformationLength = sizeof(*DestinationMapping);
  1665. break;
  1666. }
  1667. case NatSourceMappingRedirectInformation: {
  1668. PNAT_SOURCE_MAPPING_REDIRECT_INFORMATION SourceMapping =
  1669. (PNAT_SOURCE_MAPPING_REDIRECT_INFORMATION)Information;
  1670. if (*InformationLength < sizeof(*SourceMapping)) {
  1671. Error = ERROR_INSUFFICIENT_BUFFER;
  1672. } else {
  1673. SourceMapping->SourceAddress =
  1674. RedirectSourceMapping.SourceAddress;
  1675. SourceMapping->SourcePort =
  1676. RedirectSourceMapping.SourcePort;
  1677. SourceMapping->NewSourceAddress =
  1678. RedirectSourceMapping.NewSourceAddress;
  1679. SourceMapping->NewSourcePort =
  1680. RedirectSourceMapping.NewSourcePort;
  1681. }
  1682. *InformationLength = sizeof(*SourceMapping);
  1683. break;
  1684. }
  1685. default:
  1686. return ERROR_INVALID_PARAMETER;
  1687. }
  1688. return Error;
  1689. } // NatQueryInformationRedirect
  1690. ULONG
  1691. NatQueryInformationRedirectHandle(
  1692. HANDLE RedirectHandle,
  1693. OUT PVOID Information,
  1694. IN OUT PULONG InformationLength,
  1695. NAT_REDIRECT_INFORMATION_CLASS InformationClass
  1696. )
  1697. /*++
  1698. Routine Description:
  1699. This routine is invoked to retrieve information about a redirect upon
  1700. completion of the associated I/O request. At this point, the kernel-mode
  1701. driver is no longer aware of the redirect, and hence we read the requested
  1702. information from the output-buffer for the redirect.
  1703. Arguments:
  1704. RedirectHandle - identifies the redirect to be queried
  1705. Information - receives the retrieved information
  1706. InformationLength - specifies the size of 'Information' on input;
  1707. contains the required size on output
  1708. InformationClass - indicates the class of information requested
  1709. Return Value:
  1710. ULONG - Win32 status code.
  1711. --*/
  1712. {
  1713. ULONG Error = NO_ERROR;
  1714. ULONG Length;
  1715. PNAT_REDIRECT Redirectp;
  1716. if (!InformationLength) { return ERROR_INVALID_PARAMETER; }
  1717. Redirectp = (PNAT_REDIRECT)RedirectHandle;
  1718. switch (InformationClass) {
  1719. case NatByteCountRedirectInformation: {
  1720. PNAT_BYTE_COUNT_REDIRECT_INFORMATION ByteCount =
  1721. (PNAT_BYTE_COUNT_REDIRECT_INFORMATION)Information;
  1722. Length = sizeof(*ByteCount);
  1723. if (*InformationLength < Length) {
  1724. Error = ERROR_INSUFFICIENT_BUFFER;
  1725. } else {
  1726. ByteCount->BytesForward = Redirectp->Statistics.BytesForward;
  1727. ByteCount->BytesReverse = Redirectp->Statistics.BytesReverse;
  1728. }
  1729. *InformationLength = Length;
  1730. break;
  1731. }
  1732. case NatRejectRedirectInformation: {
  1733. PNAT_REJECT_REDIRECT_INFORMATION Reject =
  1734. (PNAT_REJECT_REDIRECT_INFORMATION)Information;
  1735. Length = sizeof(*Reject);
  1736. if (*InformationLength < Length) {
  1737. Error = ERROR_INSUFFICIENT_BUFFER;
  1738. } else {
  1739. Reject->RejectsForward = Redirectp->Statistics.RejectsForward;
  1740. Reject->RejectsReverse = Redirectp->Statistics.RejectsReverse;
  1741. }
  1742. *InformationLength = Length;
  1743. break;
  1744. }
  1745. default:
  1746. return ERROR_INVALID_PARAMETER;
  1747. }
  1748. return Error;
  1749. } // NatQueryInformationRedirectHandle
  1750. VOID
  1751. NatShutdownTranslator(
  1752. HANDLE TranslatorHandle
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. This routine is invoked to shut down the NAT.
  1757. Arguments:
  1758. TranslatorHandle - handle supplied by 'NatInitializeTranslator'
  1759. Return Value:
  1760. none.
  1761. --*/
  1762. {
  1763. NatUnloadDriver(TranslatorHandle);
  1764. } // NatShutdownTranslator
  1765. ULONG
  1766. NatUnloadDriver(
  1767. HANDLE FileHandle
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. This routine is invoked to unload the NAT driver as the protocol stops.
  1772. Arguments:
  1773. FileHandle - identifies the file-object for the NAT driver
  1774. Return Value:
  1775. ULONG - Win32 status code.
  1776. --*/
  1777. {
  1778. ULONG Error;
  1779. //
  1780. // Close our file-handle to the driver
  1781. //
  1782. if (FileHandle) { NtClose(FileHandle); }
  1783. #if 0
  1784. {
  1785. SC_HANDLE ScmHandle;
  1786. SC_HANDLE ServiceHandle;
  1787. SERVICE_STATUS ServiceStatus;
  1788. //
  1789. // Notify the service controller that the driver should be stopped.
  1790. // If other processes are using the driver, this control will be ignored.
  1791. //
  1792. ScmHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
  1793. if (ScmHandle) {
  1794. ServiceHandle =
  1795. OpenServiceA(ScmHandle, IP_NAT_SERVICE_NAME, GENERIC_EXECUTE);
  1796. if (ServiceHandle) {
  1797. ControlService(ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus);
  1798. CloseServiceHandle(ServiceHandle);
  1799. }
  1800. CloseServiceHandle(ScmHandle);
  1801. }
  1802. }
  1803. #else
  1804. {
  1805. UNICODE_STRING ServicePath;
  1806. NTSTATUS status;
  1807. BOOLEAN WasEnabled;
  1808. //
  1809. // Turn on our driver-unloading ability
  1810. //
  1811. if (!NatpEnableLoadDriverPrivilege(&WasEnabled)) {
  1812. return ERROR_ACCESS_DENIED;
  1813. }
  1814. RtlInitUnicodeString(&ServicePath, NatpServicePath);
  1815. //
  1816. // Load the driver
  1817. //
  1818. status = NtUnloadDriver(&ServicePath);
  1819. //
  1820. // Turn off the privilege
  1821. //
  1822. NatpDisableLoadDriverPrivilege(&WasEnabled);
  1823. //
  1824. // See if the unload-attempt succeeded
  1825. //
  1826. if (!NT_SUCCESS(status)) {
  1827. Error = RtlNtStatusToDosError(status);
  1828. return Error;
  1829. }
  1830. }
  1831. #endif
  1832. return NO_ERROR;
  1833. } // NatUnloadDriver