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.

1093 lines
33 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // NT specific routines for loading and configuring the TCP/IPv6 driver.
  14. //
  15. #include <oscfg.h>
  16. #include <ndis.h>
  17. #include <tdi.h>
  18. #include <tdikrnl.h>
  19. #include <tdint.h>
  20. #include <tdistat.h>
  21. #include <tdiinfo.h>
  22. #include <ip6imp.h>
  23. #include <ip6def.h>
  24. #include <ntddip6.h>
  25. #include "queue.h"
  26. #include "transprt.h"
  27. #include "addr.h"
  28. #include "tcp.h"
  29. #include "tcb.h"
  30. #include "tcpconn.h"
  31. #include "tcpcfg.h"
  32. #include <ntddtcp.h>
  33. //
  34. // Global variables.
  35. //
  36. PSECURITY_DESCRIPTOR TcpAdminSecurityDescriptor = NULL;
  37. PDEVICE_OBJECT TCPDeviceObject = NULL;
  38. PDEVICE_OBJECT UDPDeviceObject = NULL;
  39. PDEVICE_OBJECT RawIPDeviceObject = NULL;
  40. extern PDEVICE_OBJECT IPDeviceObject;
  41. HANDLE TCPRegistrationHandle;
  42. HANDLE UDPRegistrationHandle;
  43. HANDLE IPRegistrationHandle;
  44. //
  45. // Set to TRUE when the stack is unloading.
  46. //
  47. int Unloading = FALSE;
  48. //
  49. // External function prototypes.
  50. // REVIEW: These prototypes should be imported via include files.
  51. //
  52. int
  53. TransportLayerInit(void);
  54. void
  55. TransportLayerUnload(void);
  56. NTSTATUS
  57. TCPDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  58. NTSTATUS
  59. TCPDispatchInternalDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  60. NTSTATUS
  61. IPDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
  62. NTSTATUS
  63. IPDriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
  64. NTSTATUS
  65. GetRegMultiSZValue(HANDLE KeyHandle, PWCHAR ValueName,
  66. PUNICODE_STRING ValueData);
  67. PWCHAR
  68. EnumRegMultiSz(IN PWCHAR MszString, IN ULONG MszStringLength,
  69. IN ULONG StringIndex);
  70. //
  71. // Local funcion prototypes.
  72. //
  73. NTSTATUS
  74. DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
  75. VOID
  76. DriverUnload(IN PDRIVER_OBJECT DriverObject);
  77. void
  78. TLRegisterProtocol(uchar Protocol, void *RcvHandler, void *XmitHandler,
  79. void *StatusHandler, void *RcvCmpltHandler);
  80. uchar
  81. TCPGetConfigInfo(void);
  82. NTSTATUS
  83. TCPInitializeParameter(HANDLE KeyHandle, PWCHAR ValueName, PULONG Value);
  84. BOOLEAN
  85. IsRunningOnPersonal(VOID);
  86. BOOLEAN
  87. IsRunningOnWorkstation(VOID);
  88. NTSTATUS
  89. TcpBuildDeviceAcl(OUT PACL *DeviceAcl);
  90. NTSTATUS
  91. TcpCreateAdminSecurityDescriptor(VOID);
  92. NTSTATUS
  93. AddNetAcesToDeviceObject(IN OUT PDEVICE_OBJECT DeviceObject);
  94. #ifdef ALLOC_PRAGMA
  95. #pragma alloc_text(INIT, DriverEntry)
  96. #pragma alloc_text(INIT, TLRegisterProtocol)
  97. #pragma alloc_text(INIT, TCPGetConfigInfo)
  98. #pragma alloc_text(INIT, TCPInitializeParameter)
  99. #pragma alloc_text(INIT, IsRunningOnPersonal)
  100. #pragma alloc_text(PAGE, IsRunningOnWorkstation)
  101. #pragma alloc_text(INIT, TcpBuildDeviceAcl)
  102. #pragma alloc_text(INIT, TcpCreateAdminSecurityDescriptor)
  103. #pragma alloc_text(INIT, AddNetAcesToDeviceObject)
  104. #endif // ALLOC_PRAGMA
  105. //
  106. // Main initialization routine for the TCP/IPv6 driver.
  107. //
  108. // This is the driver entry point, called by NT upon loading us.
  109. //
  110. //
  111. NTSTATUS // Returns: final status from the initialization operation.
  112. DriverEntry(
  113. IN PDRIVER_OBJECT DriverObject, // TCP/IPv6 driver object.
  114. IN PUNICODE_STRING RegistryPath) // Path to our info in the registry.
  115. {
  116. NTSTATUS Status;
  117. UNICODE_STRING deviceName;
  118. USHORT i;
  119. int initStatus;
  120. PIO_ERROR_LOG_PACKET entry;
  121. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  122. "Tcpip6: In DriverEntry routine\n"));
  123. //
  124. // Write a log entry, so that PSS will know
  125. // if this driver has been loaded on the machine.
  126. //
  127. entry = IoAllocateErrorLogEntry(DriverObject, sizeof *entry);
  128. if (entry != NULL) {
  129. RtlZeroMemory(entry, sizeof *entry);
  130. entry->ErrorCode = EVENT_TCPIP6_STARTED;
  131. IoWriteErrorLogEntry(entry);
  132. }
  133. #if COUNTING_MALLOC
  134. InitCountingMalloc();
  135. #endif
  136. TdiInitialize();
  137. //
  138. // Initialize network level protocol: IPv6.
  139. //
  140. Status = IPDriverEntry(DriverObject, RegistryPath);
  141. if (!NT_SUCCESS(Status)) {
  142. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  143. "Tcpip6: IPv6 init failed, status %lx\n", Status));
  144. return(Status);
  145. }
  146. //
  147. // Initialize transport level protocols: TCP, UDP, and RawIP.
  148. //
  149. //
  150. // Create the device objects. IoCreateDevice zeroes the memory
  151. // occupied by the object.
  152. //
  153. RtlInitUnicodeString(&deviceName, DD_TCPV6_DEVICE_NAME);
  154. Status = IoCreateDevice(DriverObject, 0, &deviceName,
  155. FILE_DEVICE_NETWORK,
  156. FILE_DEVICE_SECURE_OPEN,
  157. FALSE, &TCPDeviceObject);
  158. if (!NT_SUCCESS(Status)) {
  159. //
  160. // REVIEW: Write an error log entry here?
  161. //
  162. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  163. "Tcpip6: Failed to create TCP device object, status %lx\n",
  164. Status));
  165. goto init_failed;
  166. }
  167. RtlInitUnicodeString(&deviceName, DD_UDPV6_DEVICE_NAME);
  168. Status = IoCreateDevice(DriverObject, 0, &deviceName,
  169. FILE_DEVICE_NETWORK,
  170. FILE_DEVICE_SECURE_OPEN,
  171. FALSE, &UDPDeviceObject);
  172. if (!NT_SUCCESS(Status)) {
  173. //
  174. // REVIEW: Write an error log entry here?
  175. //
  176. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  177. "Tcpip6: Failed to create UDP device object, status %lx\n",
  178. Status));
  179. goto init_failed;
  180. }
  181. RtlInitUnicodeString(&deviceName, DD_RAW_IPV6_DEVICE_NAME);
  182. Status = IoCreateDevice(DriverObject, 0, &deviceName,
  183. FILE_DEVICE_NETWORK,
  184. FILE_DEVICE_SECURE_OPEN,
  185. FALSE, &RawIPDeviceObject);
  186. if (!NT_SUCCESS(Status)) {
  187. //
  188. // REVIEW: Write an error log entry here?
  189. //
  190. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_NTOS_ERROR,
  191. "Tcpip6: Failed to create Raw IP device object, status %lx\n",
  192. Status));
  193. goto init_failed;
  194. }
  195. //
  196. // Initialize the driver object.
  197. //
  198. DriverObject->DriverUnload = DriverUnload;
  199. DriverObject->FastIoDispatch = NULL;
  200. for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  201. DriverObject->MajorFunction[i] = TCPDispatch;
  202. }
  203. //
  204. // We special case Internal Device Controls because they are the
  205. // hot path for kernel-mode clients.
  206. //
  207. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
  208. TCPDispatchInternalDeviceControl;
  209. //
  210. // Intialize the device objects.
  211. //
  212. TCPDeviceObject->Flags |= DO_DIRECT_IO;
  213. UDPDeviceObject->Flags |= DO_DIRECT_IO;
  214. RawIPDeviceObject->Flags |= DO_DIRECT_IO;
  215. //
  216. // Change the devices and objects to allow access by
  217. // Network Configuration Operators
  218. //
  219. if (!IsRunningOnPersonal()) {
  220. Status = AddNetAcesToDeviceObject(IPDeviceObject);
  221. if (!NT_SUCCESS(Status)) {
  222. goto init_failed;
  223. }
  224. Status = AddNetAcesToDeviceObject(TCPDeviceObject);
  225. if (!NT_SUCCESS(Status)) {
  226. goto init_failed;
  227. }
  228. }
  229. //
  230. // Create the security descriptor used for raw socket access checks.
  231. //
  232. Status = TcpCreateAdminSecurityDescriptor();
  233. if (!NT_SUCCESS(Status)) {
  234. goto init_failed;
  235. }
  236. //
  237. // Finally, initialize the stack.
  238. //
  239. initStatus = TransportLayerInit();
  240. if (initStatus == TRUE) {
  241. RtlInitUnicodeString(&deviceName, DD_TCPV6_DEVICE_NAME);
  242. (void)TdiRegisterDeviceObject(&deviceName, &TCPRegistrationHandle);
  243. RtlInitUnicodeString(&deviceName, DD_UDPV6_DEVICE_NAME);
  244. (void)TdiRegisterDeviceObject(&deviceName, &UDPRegistrationHandle);
  245. RtlInitUnicodeString(&deviceName, DD_RAW_IPV6_DEVICE_NAME);
  246. (void)TdiRegisterDeviceObject(&deviceName, &IPRegistrationHandle);
  247. return(STATUS_SUCCESS);
  248. }
  249. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  250. "Tcpip6: "
  251. "TCP/UDP initialization failed, but IP will be available.\n"));
  252. //
  253. // REVIEW: Write an error log entry here?
  254. //
  255. Status = STATUS_UNSUCCESSFUL;
  256. init_failed:
  257. //
  258. // IP has successfully started, but TCP & UDP failed. Set the
  259. // Dispatch routine to point to IP only, since the TCP and UDP
  260. // devices don't exist.
  261. //
  262. if (TCPDeviceObject != NULL) {
  263. IoDeleteDevice(TCPDeviceObject);
  264. }
  265. if (UDPDeviceObject != NULL) {
  266. IoDeleteDevice(UDPDeviceObject);
  267. }
  268. if (RawIPDeviceObject != NULL) {
  269. IoDeleteDevice(RawIPDeviceObject);
  270. }
  271. for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  272. DriverObject->MajorFunction[i] = IPDispatch;
  273. }
  274. return(STATUS_SUCCESS);
  275. }
  276. VOID
  277. DriverUnload(
  278. IN PDRIVER_OBJECT DriverObject)
  279. {
  280. UNICODE_STRING WinDeviceName;
  281. UNREFERENCED_PARAMETER(DriverObject);
  282. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_STATE,
  283. "IPv6: DriverUnload\n"));
  284. //
  285. // Start the shutdown process by noting our change of state.
  286. // This will inhibit our starting new activities.
  287. // REVIEW - Is this actually needed? Possibly other factors
  288. // prevent new entries into the stack.
  289. //
  290. Unloading = TRUE;
  291. //
  292. // Cleanup our modules.
  293. // This will break connections with NDIS and the v4 stack.
  294. //
  295. TransportLayerUnload();
  296. IPUnload();
  297. LanUnload();
  298. //
  299. // Deregister with TDI.
  300. //
  301. (void) TdiDeregisterDeviceObject(TCPRegistrationHandle);
  302. (void) TdiDeregisterDeviceObject(UDPRegistrationHandle);
  303. (void) TdiDeregisterDeviceObject(IPRegistrationHandle);
  304. //
  305. // Delete Win32 symbolic links.
  306. //
  307. RtlInitUnicodeString(&WinDeviceName, L"\\??\\" WIN_IPV6_BASE_DEVICE_NAME);
  308. (void) IoDeleteSymbolicLink(&WinDeviceName);
  309. //
  310. // Delete our device objects.
  311. //
  312. IoDeleteDevice(TCPDeviceObject);
  313. IoDeleteDevice(UDPDeviceObject);
  314. IoDeleteDevice(RawIPDeviceObject);
  315. IoDeleteDevice(IPDeviceObject);
  316. #if COUNTING_MALLOC
  317. DumpCountingMallocStats();
  318. UnloadCountingMalloc();
  319. #endif
  320. }
  321. //
  322. // Interval in milliseconds between keepalive transmissions until a
  323. // response is received.
  324. //
  325. #define DEFAULT_KEEPALIVE_INTERVAL 1000
  326. //
  327. // Time to first keepalive transmission. 2 hours == 7,200,000 milliseconds
  328. //
  329. #define DEFAULT_KEEPALIVE_TIME 7200000
  330. #if 1
  331. //* TCPGetConfigInfo -
  332. //
  333. // Initializes TCP global configuration parameters.
  334. //
  335. uchar // Returns: Zero on failure, nonzero on success.
  336. TCPGetConfigInfo(void)
  337. {
  338. HANDLE keyHandle;
  339. NTSTATUS status;
  340. OBJECT_ATTRIBUTES objectAttributes;
  341. UNICODE_STRING UKeyName;
  342. ULONG maxConnectRexmits = 0;
  343. ULONG maxDataRexmits = 0;
  344. ULONG pptpmaxDataRexmits = 0;
  345. ULONG useRFC1122UrgentPointer = 0;
  346. MM_SYSTEMSIZE systemSize;
  347. //
  348. // Initialize to the defaults in case an error occurs somewhere.
  349. //
  350. AllowUserRawAccess = FALSE;
  351. KAInterval = DEFAULT_KEEPALIVE_INTERVAL;
  352. KeepAliveTime = DEFAULT_KEEPALIVE_TIME;
  353. PMTUDiscovery = TRUE;
  354. PMTUBHDetect = FALSE;
  355. DefaultRcvWin = 0; // Automagically pick a reasonable one.
  356. MaxConnections = DEFAULT_MAX_CONNECTIONS;
  357. maxConnectRexmits = MAX_CONNECT_REXMIT_CNT;
  358. pptpmaxDataRexmits = maxDataRexmits = MAX_REXMIT_CNT;
  359. BSDUrgent = TRUE;
  360. FinWait2TO = FIN_WAIT2_TO;
  361. NTWMaxConnectCount = NTW_MAX_CONNECT_COUNT;
  362. NTWMaxConnectTime = NTW_MAX_CONNECT_TIME;
  363. MaxUserPort = MAX_USER_PORT;
  364. TcbTableSize = ComputeLargerOrEqualPowerOfTwo(DEFAULT_TCB_TABLE_SIZE);
  365. systemSize = MmQuerySystemSize();
  366. if (MmIsThisAnNtAsSystem()) {
  367. switch (systemSize) {
  368. case MmSmallSystem:
  369. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_AS_SMALL;
  370. break;
  371. case MmMediumSystem:
  372. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_AS_MEDIUM;
  373. break;
  374. case MmLargeSystem:
  375. default:
  376. #if defined(_WIN64)
  377. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_AS_LARGE64;
  378. #else
  379. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_AS_LARGE;
  380. #endif
  381. break;
  382. }
  383. } else {
  384. switch (systemSize) {
  385. case MmSmallSystem:
  386. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_WS_SMALL;
  387. break;
  388. case MmMediumSystem:
  389. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_WS_MEDIUM;
  390. break;
  391. case MmLargeSystem:
  392. default:
  393. MaxConnBlocks = DEFAULT_MAX_CONN_BLOCKS_WS_LARGE;
  394. break;
  395. }
  396. }
  397. //
  398. // Read the TCP optional (hidden) registry parameters.
  399. //
  400. RtlInitUnicodeString(&UKeyName,
  401. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\" TCPIPV6_NAME L"\\Parameters"
  402. );
  403. memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
  404. InitializeObjectAttributes(&objectAttributes, &UKeyName,
  405. OBJ_CASE_INSENSITIVE, NULL, NULL);
  406. status = ZwOpenKey(&keyHandle, KEY_READ, &objectAttributes);
  407. if (NT_SUCCESS(status)) {
  408. TCPInitializeParameter(keyHandle, L"AllowUserRawAccess",
  409. (PULONG)&AllowUserRawAccess);
  410. TCPInitializeParameter(keyHandle, L"IsnStoreSize",
  411. (PULONG)&ISNStoreSize);
  412. TCPInitializeParameter(keyHandle, L"KeepAliveInterval",
  413. (PULONG)&KAInterval);
  414. TCPInitializeParameter(keyHandle, L"KeepAliveTime",
  415. (PULONG)&KeepAliveTime);
  416. TCPInitializeParameter(keyHandle, L"EnablePMTUBHDetect",
  417. (PULONG)&PMTUBHDetect);
  418. TCPInitializeParameter(keyHandle, L"TcpWindowSize",
  419. (PULONG)&DefaultRcvWin);
  420. TCPInitializeParameter(keyHandle, L"TcpNumConnections",
  421. (PULONG)&MaxConnections);
  422. if (MaxConnections != DEFAULT_MAX_CONNECTIONS) {
  423. uint ConnBlocks =
  424. (MaxConnections + MAX_CONN_PER_BLOCK - 1) / MAX_CONN_PER_BLOCK;
  425. if (ConnBlocks > MaxConnBlocks) {
  426. MaxConnBlocks = ConnBlocks;
  427. }
  428. }
  429. TCPInitializeParameter(keyHandle, L"MaxHashTableSize",
  430. (PULONG)&TcbTableSize);
  431. if (TcbTableSize < MIN_TCB_TABLE_SIZE) {
  432. TcbTableSize = MIN_TCB_TABLE_SIZE;
  433. } else if (TcbTableSize > MAX_TCB_TABLE_SIZE) {
  434. TcbTableSize = MAX_TCB_TABLE_SIZE;
  435. } else {
  436. TcbTableSize = ComputeLargerOrEqualPowerOfTwo(TcbTableSize);
  437. }
  438. TCPInitializeParameter(keyHandle, L"TcpMaxConnectRetransmissions",
  439. &maxConnectRexmits);
  440. if (maxConnectRexmits > 255) {
  441. maxConnectRexmits = 255;
  442. }
  443. TCPInitializeParameter(keyHandle, L"TcpMaxDataRetransmissions",
  444. &maxDataRexmits);
  445. if (maxDataRexmits > 255) {
  446. maxDataRexmits = 255;
  447. }
  448. //
  449. // If we fail, then set to same value as maxDataRexmit so that the
  450. // max(pptpmaxDataRexmit,maxDataRexmit) is a decent value
  451. // Need this since TCPInitializeParameter no longer "initializes"
  452. // to a default value.
  453. //
  454. if(TCPInitializeParameter(keyHandle, L"PPTPTcpMaxDataRetransmissions",
  455. &pptpmaxDataRexmits) != STATUS_SUCCESS) {
  456. pptpmaxDataRexmits = maxDataRexmits;
  457. }
  458. if (pptpmaxDataRexmits > 255) {
  459. pptpmaxDataRexmits = 255;
  460. }
  461. TCPInitializeParameter(keyHandle, L"TcpUseRFC1122UrgentPointer",
  462. &useRFC1122UrgentPointer);
  463. if (useRFC1122UrgentPointer) {
  464. BSDUrgent = FALSE;
  465. }
  466. TCPInitializeParameter(keyHandle, L"TcpTimedWaitDelay",
  467. (PULONG)&FinWait2TO);
  468. if (FinWait2TO < 30) {
  469. FinWait2TO = 30;
  470. }
  471. if (FinWait2TO > 300) {
  472. FinWait2TO = 300;
  473. }
  474. FinWait2TO = MS_TO_TICKS(FinWait2TO*1000);
  475. NTWMaxConnectTime = MS_TO_TICKS(NTWMaxConnectTime*1000);
  476. TCPInitializeParameter(keyHandle, L"MaxUserPort", (PULONG)&MaxUserPort);
  477. if (MaxUserPort < 5000) {
  478. MaxUserPort = 5000;
  479. }
  480. if (MaxUserPort > 65534) {
  481. MaxUserPort = 65534;
  482. }
  483. //
  484. // Read a few IP optional (hidden) registry parameters that TCP
  485. // cares about.
  486. //
  487. TCPInitializeParameter(keyHandle, L"EnablePMTUDiscovery",
  488. (PULONG)&PMTUDiscovery);
  489. TCPInitializeParameter(keyHandle, L"SynAttackProtect",
  490. (PULONG)&SynAttackProtect);
  491. ZwClose(keyHandle);
  492. }
  493. MaxConnectRexmitCount = maxConnectRexmits;
  494. //
  495. // Use the greater of the two, hence both values should be valid
  496. //
  497. MaxDataRexmitCount = (maxDataRexmits > pptpmaxDataRexmits ?
  498. maxDataRexmits : pptpmaxDataRexmits);
  499. return(1);
  500. }
  501. #endif
  502. #define WORK_BUFFER_SIZE 256
  503. //* TCPInitializeParameter - Read a value from the registry.
  504. //
  505. // Initializes a ULONG parameter from the registry.
  506. //
  507. NTSTATUS
  508. TCPInitializeParameter(
  509. HANDLE KeyHandle, // An open handle to the registry key for the parameter.
  510. PWCHAR ValueName, // The UNICODE name of the registry value to read.
  511. PULONG Value) // The ULONG into which to put the data.
  512. {
  513. NTSTATUS status;
  514. ULONG resultLength;
  515. PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
  516. UCHAR keybuf[WORK_BUFFER_SIZE];
  517. UNICODE_STRING UValueName;
  518. RtlInitUnicodeString(&UValueName, ValueName);
  519. keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
  520. status = ZwQueryValueKey(KeyHandle, &UValueName, KeyValueFullInformation,
  521. keyValueFullInformation, WORK_BUFFER_SIZE,
  522. &resultLength);
  523. if (status == STATUS_SUCCESS) {
  524. if (keyValueFullInformation->Type == REG_DWORD) {
  525. *Value = *((ULONG UNALIGNED *) ((PCHAR)keyValueFullInformation +
  526. keyValueFullInformation->DataOffset));
  527. }
  528. }
  529. return(status);
  530. }
  531. //* IsRunningOnPersonal - Are we running on the Personal SKU.
  532. //
  533. BOOLEAN
  534. IsRunningOnPersonal(
  535. VOID)
  536. {
  537. OSVERSIONINFOEXW OsVer = {0};
  538. ULONGLONG ConditionMask = 0;
  539. BOOLEAN IsPersonal = TRUE;
  540. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  541. OsVer.wSuiteMask = VER_SUITE_PERSONAL;
  542. OsVer.wProductType = VER_NT_WORKSTATION;
  543. VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  544. VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_AND);
  545. if (RtlVerifyVersionInfo(&OsVer, VER_PRODUCT_TYPE | VER_SUITENAME,
  546. ConditionMask) == STATUS_REVISION_MISMATCH) {
  547. IsPersonal = FALSE;
  548. }
  549. return(IsPersonal);
  550. } // IsRunningOnPersonal
  551. //* IsRunningOnWorkstation - Are we running on any Workstation SKU.
  552. //
  553. BOOLEAN
  554. IsRunningOnWorkstation(
  555. VOID)
  556. {
  557. OSVERSIONINFOEXW OsVer = {0};
  558. ULONGLONG ConditionMask = 0;
  559. BOOLEAN IsWorkstation = TRUE;
  560. OsVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  561. OsVer.wProductType = VER_NT_WORKSTATION;
  562. VER_SET_CONDITION(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
  563. if (RtlVerifyVersionInfo(&OsVer, VER_PRODUCT_TYPE, ConditionMask) ==
  564. STATUS_REVISION_MISMATCH) {
  565. IsWorkstation = FALSE;
  566. }
  567. return(IsWorkstation);
  568. } // IsRunningOnWorkstation
  569. //* TcpBuildDeviceAcl -
  570. //
  571. // (Lifted from AFD - AfdBuildDeviceAcl)
  572. // This routine builds an ACL which gives Administrators and LocalSystem
  573. // principals full access. All other principals have no access.
  574. //
  575. NTSTATUS
  576. TcpBuildDeviceAcl(
  577. OUT PACL *DeviceAcl) // Output pointer to the new ACL.
  578. {
  579. PGENERIC_MAPPING GenericMapping;
  580. PSID AdminsSid;
  581. PSID SystemSid;
  582. PSID NetworkSid;
  583. ULONG AclLength;
  584. NTSTATUS Status;
  585. ACCESS_MASK AccessMask = GENERIC_ALL;
  586. PACL NewAcl;
  587. //
  588. // Enable access to all the globally defined SIDs
  589. //
  590. GenericMapping = IoGetFileObjectGenericMapping();
  591. RtlMapGenericMask(&AccessMask, GenericMapping);
  592. AdminsSid = SeExports->SeAliasAdminsSid;
  593. SystemSid = SeExports->SeLocalSystemSid;
  594. NetworkSid = SeExports->SeNetworkServiceSid;
  595. AclLength = sizeof(ACL) +
  596. 3 * FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) +
  597. RtlLengthSid(AdminsSid) +
  598. RtlLengthSid(SystemSid) +
  599. RtlLengthSid(NetworkSid);
  600. NewAcl = ExAllocatePool(NonPagedPool, AclLength);
  601. if (NewAcl == NULL) {
  602. return(STATUS_INSUFFICIENT_RESOURCES);
  603. }
  604. Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
  605. if (!NT_SUCCESS(Status)) {
  606. ExFreePool(NewAcl);
  607. return(Status);
  608. }
  609. Status = RtlAddAccessAllowedAce(NewAcl,
  610. ACL_REVISION,
  611. AccessMask,
  612. AdminsSid);
  613. ASSERT(NT_SUCCESS(Status));
  614. Status = RtlAddAccessAllowedAce(NewAcl,
  615. ACL_REVISION,
  616. AccessMask,
  617. SystemSid);
  618. ASSERT(NT_SUCCESS(Status));
  619. // Add acl for NetworkSid!
  620. Status = RtlAddAccessAllowedAce(NewAcl,
  621. ACL_REVISION,
  622. AccessMask,
  623. NetworkSid);
  624. ASSERT(NT_SUCCESS(Status));
  625. *DeviceAcl = NewAcl;
  626. return(STATUS_SUCCESS);
  627. } // TcpBuildDeviceAcl
  628. //* TcpCreateAdminSecurityDescriptor -
  629. //
  630. // (Lifted from AFD - AfdCreateAdminSecurityDescriptor)
  631. // This routine creates a security descriptor which gives access
  632. // only to Administrtors and LocalSystem. This descriptor is used
  633. // to access check raw endpoint opens and exclisive access to transport
  634. // addresses.
  635. //
  636. NTSTATUS
  637. TcpCreateAdminSecurityDescriptor(VOID)
  638. {
  639. PACL rawAcl = NULL;
  640. NTSTATUS status;
  641. BOOLEAN memoryAllocated = FALSE;
  642. PSECURITY_DESCRIPTOR tcpSecurityDescriptor;
  643. ULONG tcpSecurityDescriptorLength;
  644. CHAR buffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  645. PSECURITY_DESCRIPTOR localSecurityDescriptor =
  646. (PSECURITY_DESCRIPTOR) buffer;
  647. PSECURITY_DESCRIPTOR localTcpAdminSecurityDescriptor;
  648. SECURITY_INFORMATION securityInformation = DACL_SECURITY_INFORMATION;
  649. //
  650. // Get a pointer to the security descriptor from the TCP device object.
  651. //
  652. status = ObGetObjectSecurity(TCPDeviceObject,
  653. &tcpSecurityDescriptor,
  654. &memoryAllocated);
  655. if (!NT_SUCCESS(status)) {
  656. ASSERT(memoryAllocated == FALSE);
  657. return(status);
  658. }
  659. //
  660. // Build a local security descriptor with an ACL giving only
  661. // administrators and system access.
  662. //
  663. status = TcpBuildDeviceAcl(&rawAcl);
  664. if (!NT_SUCCESS(status)) {
  665. goto error_exit;
  666. }
  667. (VOID) RtlCreateSecurityDescriptor(
  668. localSecurityDescriptor,
  669. SECURITY_DESCRIPTOR_REVISION
  670. );
  671. (VOID) RtlSetDaclSecurityDescriptor(
  672. localSecurityDescriptor,
  673. TRUE,
  674. rawAcl,
  675. FALSE
  676. );
  677. //
  678. // Make a copy of the TCP descriptor. This copy will be the raw descriptor.
  679. //
  680. tcpSecurityDescriptorLength = RtlLengthSecurityDescriptor(tcpSecurityDescriptor);
  681. localTcpAdminSecurityDescriptor = ExAllocatePool(PagedPool,
  682. tcpSecurityDescriptorLength);
  683. if (localTcpAdminSecurityDescriptor == NULL) {
  684. goto error_exit;
  685. }
  686. RtlMoveMemory(localTcpAdminSecurityDescriptor,
  687. tcpSecurityDescriptor,
  688. tcpSecurityDescriptorLength);
  689. TcpAdminSecurityDescriptor = localTcpAdminSecurityDescriptor;
  690. //
  691. // Now apply the local descriptor to the raw descriptor.
  692. //
  693. status = SeSetSecurityDescriptorInfo(NULL,
  694. &securityInformation,
  695. localSecurityDescriptor,
  696. &TcpAdminSecurityDescriptor,
  697. PagedPool,
  698. IoGetFileObjectGenericMapping());
  699. if (!NT_SUCCESS(status)) {
  700. ASSERT(TcpAdminSecurityDescriptor == localTcpAdminSecurityDescriptor);
  701. ExFreePool(TcpAdminSecurityDescriptor);
  702. TcpAdminSecurityDescriptor = NULL;
  703. goto error_exit;
  704. }
  705. if (TcpAdminSecurityDescriptor != localTcpAdminSecurityDescriptor) {
  706. ExFreePool(localTcpAdminSecurityDescriptor);
  707. }
  708. status = STATUS_SUCCESS;
  709. error_exit:
  710. ObReleaseObjectSecurity(tcpSecurityDescriptor,
  711. memoryAllocated);
  712. if (rawAcl != NULL) {
  713. ExFreePool(rawAcl);
  714. }
  715. return(status);
  716. }
  717. //* AddNetAcesToDeviceObject -
  718. //
  719. // This routine adds ACEs that give full access to NetworkService and
  720. // NetConfigOps to the IO manager device object.
  721. //
  722. // Note that if existing ACE's in the DACL deny access to the same
  723. // user/group as ACE's being added, the new ACEs will not take
  724. // affect by the virtue of being placed in the back of the DACL.
  725. //
  726. // This routine statically allocates kernel security structures (on
  727. // the stack). Thus it must be in sync with current kernel headers
  728. // (e.g. once compiled this code may not be binary compatible with
  729. // previous or future OS versions).
  730. //
  731. NTSTATUS
  732. AddNetAcesToDeviceObject(
  733. IN OUT PDEVICE_OBJECT DeviceObject) // Device object to add ACEs to.
  734. {
  735. NTSTATUS status;
  736. BOOLEAN present, defaulted, memoryAllocated;
  737. PSECURITY_DESCRIPTOR sd;
  738. PACL newAcl = NULL, dacl;
  739. ULONG newAclSize;
  740. ULONG aclRevision;
  741. ACCESS_MASK accessMask = GENERIC_ALL;
  742. SECURITY_DESCRIPTOR localSd;
  743. // Provision enough space for IO manager FILE_DEVICE_NETWORK ACL
  744. // which includes ACEs for:
  745. // World (EXECUTE),
  746. // LocalSystem (ALL),
  747. // Administrators(ALL),
  748. // RestrictedUser (EXECUTE)
  749. // plus two ACEs that we need to add:
  750. // NetworkService (ALL)
  751. // NetworkConfigOps (ALL)
  752. union {
  753. CHAR buffer[sizeof (ACL) +
  754. 6 * (FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) +
  755. SECURITY_MAX_SID_SIZE)];
  756. ACL acl;
  757. } acl;
  758. union {
  759. CHAR buffer[SECURITY_MAX_SID_SIZE];
  760. SID sid;
  761. } netOps;
  762. {
  763. //
  764. // Create SID for NetworkConfigOps.
  765. // Should we export this from NDIS as global (e.g. NdisSeExports)?
  766. //
  767. SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_NT_AUTHORITY;
  768. //
  769. // Initialize SID for network operators.
  770. //
  771. status = RtlInitializeSid (&netOps.sid, &sidAuth, 2);
  772. // Nothing to fail - local storage init (see above for
  773. // possible binary incompatibility).
  774. ASSERT (NT_SUCCESS (status));
  775. netOps.sid.SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
  776. netOps.sid.SubAuthority[1] = DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS;
  777. }
  778. //
  779. // Compute the size of ACEs that we want to add.
  780. //
  781. newAclSize = FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) +
  782. RtlLengthSid( SeExports->SeNetworkServiceSid ) +
  783. FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) +
  784. RtlLengthSid( &netOps.sid );
  785. //
  786. // Get the original ACL.
  787. //
  788. status = ObGetObjectSecurity(DeviceObject,
  789. &sd,
  790. &memoryAllocated
  791. );
  792. if (!NT_SUCCESS(status)) {
  793. //
  794. // Object doesn't have security descriptor in the first place
  795. // This shouldn't be possible (unless we are running under some really
  796. // bad memory conditions).
  797. //
  798. return status;
  799. }
  800. status = RtlGetDaclSecurityDescriptor (sd, &present, &dacl, &defaulted);
  801. if (!NT_SUCCESS (status)) {
  802. //
  803. // Malformed SD? Should this be an assert since SD comes from kernel?
  804. //
  805. goto cleanup;
  806. }
  807. if (present && dacl!=NULL) {
  808. USHORT i;
  809. aclRevision = max(dacl->AclRevision, ACL_REVISION);
  810. //
  811. // DeviceObject already had an ACL, copy ACEs from it.
  812. //
  813. newAclSize += dacl->AclSize;
  814. //
  815. // See if it fits into the stack buffer or allocate
  816. // one if it doesn't.
  817. //
  818. if (newAclSize<=sizeof (acl)) {
  819. newAcl = &acl.acl;
  820. } else {
  821. newAcl = ExAllocatePool(PagedPool, newAclSize);
  822. if (newAcl==NULL) {
  823. status = STATUS_INSUFFICIENT_RESOURCES;
  824. goto cleanup;
  825. }
  826. }
  827. status = RtlCreateAcl(newAcl, newAclSize, aclRevision);
  828. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init
  829. //
  830. // Copy ACEs from the original ACL if there are any in there.
  831. //
  832. for (i=0; i<dacl->AceCount; i++) {
  833. PACE_HEADER ace;
  834. status = RtlGetAce (dacl, i, (PVOID)&ace);
  835. ASSERT (NT_SUCCESS (status)); // Nothing to fail - we know
  836. // ACEs are there.
  837. status = RtlAddAce (newAcl, // ACL
  838. aclRevision, // AceRevision
  839. i, // StartingAceIndex
  840. ace, // AceList
  841. ace->AceSize); // AceListLength
  842. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  843. }
  844. } else {
  845. //
  846. // We allocate enough space on stack for ACL
  847. // with two ACEs.
  848. //
  849. C_ASSERT ( sizeof (acl) >=
  850. sizeof (ACL) +
  851. 2 * (FIELD_OFFSET (ACCESS_ALLOWED_ACE, SidStart) +
  852. SECURITY_MAX_SID_SIZE) );
  853. aclRevision = ACL_REVISION;
  854. newAcl = &acl.acl;
  855. newAclSize += sizeof (ACL);
  856. status = RtlCreateAcl(newAcl, newAclSize, aclRevision);
  857. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  858. }
  859. //
  860. // Generic mapping is the same for device and file objects.
  861. //
  862. RtlMapGenericMask(&accessMask, IoGetFileObjectGenericMapping());
  863. status = RtlAddAccessAllowedAce(
  864. newAcl,
  865. aclRevision,
  866. accessMask,
  867. SeExports->SeNetworkServiceSid
  868. );
  869. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  870. status = RtlAddAccessAllowedAce(
  871. newAcl,
  872. aclRevision,
  873. accessMask,
  874. &netOps.sid
  875. );
  876. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  877. status = RtlCreateSecurityDescriptor(
  878. &localSd,
  879. SECURITY_DESCRIPTOR_REVISION
  880. );
  881. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  882. status = RtlSetDaclSecurityDescriptor(
  883. &localSd, // Sd
  884. TRUE, // DaclPresent
  885. newAcl, // Dacl
  886. FALSE // DaclDefaulted
  887. );
  888. ASSERT (NT_SUCCESS (status)); // Nothing to fail - local storage init.
  889. //
  890. // Now apply the local descriptor to the raw descriptor.
  891. //
  892. status = ObSetSecurityObjectByPointer(
  893. DeviceObject,
  894. DACL_SECURITY_INFORMATION,
  895. &localSd);
  896. cleanup:
  897. if (newAcl!=NULL && newAcl!=&acl.acl) {
  898. ExFreePool (newAcl);
  899. }
  900. ObReleaseObjectSecurity(sd, memoryAllocated);
  901. return(status);
  902. }