Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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