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.

1488 lines
42 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. RxInit.c
  5. Abstract:
  6. This module implements the DRIVER_INITIALIZATION routine for the RDBSS.
  7. Also, the routines for pagingio resource selection/allocation are here; since
  8. we have to delete the resources when we unload, having them here simply centralizes
  9. all the pagingio resource stuff.
  10. Finally, the routines that are here that implement the wrapper's version of
  11. network provider order. Basically, the wrapper MUST implement the same concept of
  12. network provider order as the MUP so that the UI will work as expected. So, we
  13. read the provider order from the registry at init time and memorize the order. Then,
  14. we can assign the correct order when minirdrs register. Obviously, provider order is
  15. not an issue in MONOLITHIC mode.
  16. Author:
  17. Joe Linn [JoeLinn] 20-jul-1994
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. #pragma hdrstop
  22. #include "ntverp.h"
  23. #include "NtDdNfs2.h"
  24. #include "netevent.h"
  25. //
  26. // The local debug trace level
  27. //
  28. #define Dbg (0)
  29. ULONG RxBuildNumber = VER_PRODUCTBUILD;
  30. #ifdef RX_PRIVATE_BUILD
  31. ULONG RxPrivateBuild = 1;
  32. #else
  33. ULONG RxPrivateBuild = 0;
  34. #endif
  35. #ifdef MONOLITHIC_MINIRDR
  36. RDBSS_DEVICE_OBJECT RxSpaceForTheWrappersDeviceObject;
  37. #endif
  38. #define LANMAN_WORKSTATION_PARAMETERS \
  39. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters"
  40. BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
  41. VOID
  42. RxReadRegistryParameters (
  43. VOID
  44. );
  45. NPAGED_LOOKASIDE_LIST RxContextLookasideList;
  46. VOID
  47. RxGetRegistryParameters(
  48. IN PUNICODE_STRING RegistryPath
  49. );
  50. NTSTATUS
  51. RxInitializeRegistrationStructures (
  52. VOID
  53. );
  54. VOID
  55. RxUninitializeRegistrationStructures (
  56. VOID
  57. );
  58. NTSTATUS
  59. RxGetStringRegistryParameter (
  60. HANDLE ParametersHandle,
  61. PWCHAR ParameterName,
  62. PUNICODE_STRING ParamString,
  63. PKEY_VALUE_PARTIAL_INFORMATION Value,
  64. ULONG ValueSize,
  65. BOOLEAN LogFailure
  66. );
  67. NTSTATUS
  68. RxGetUlongRegistryParameter (
  69. HANDLE ParametersHandle,
  70. PWCHAR ParameterName,
  71. PULONG ParamUlong,
  72. PKEY_VALUE_PARTIAL_INFORMATION Value,
  73. ULONG ValueSize,
  74. BOOLEAN LogFailure
  75. );
  76. //
  77. // this type and variable are used for unwinding the initialization so that stuff doesn't go thru the cracks
  78. // the way that this works is that stuff is done in the reverse order of the enumeration. that way i can just
  79. // use a switch-no-break to unwind.
  80. //
  81. typedef enum _RX_INIT_STATES {
  82. RXINIT_ALL_INITIALIZATION_COMPLETED,
  83. RXINIT_CONSTRUCTED_PROVIDERORDER,
  84. RXINIT_CREATED_LOG,
  85. RXINIT_CREATED_DEVICE_OBJECT,
  86. RXINIT_CREATED_FIRST_LINK,
  87. RXINIT_START
  88. } RX_INIT_STATES;
  89. VOID
  90. RxInitUnwind (
  91. IN PDRIVER_OBJECT DriverObject,
  92. IN RX_INIT_STATES RxInitState
  93. );
  94. #ifdef ALLOC_PRAGMA
  95. #pragma alloc_text(INIT, RxDriverEntry)
  96. #pragma alloc_text(INIT, RxGetRegistryParameters)
  97. #pragma alloc_text(INIT, RxGetStringRegistryParameter)
  98. #pragma alloc_text(INIT, RxGetUlongRegistryParameter)
  99. #pragma alloc_text(PAGE, RxUnload)
  100. #pragma alloc_text(PAGE, RxInitUnwind)
  101. #pragma alloc_text(PAGE, RxGetNetworkProviderPriority)
  102. #pragma alloc_text(PAGE, RxInitializeRegistrationStructures)
  103. #pragma alloc_text(PAGE, RxUninitializeRegistrationStructures)
  104. #pragma alloc_text(PAGE, RxInitializeMinirdrDispatchTable)
  105. #pragma alloc_text(PAGE, __RxFillAndInstallFastIoDispatch)
  106. #pragma alloc_text(PAGE, RxReadRegistryParameters)
  107. #endif
  108. #define RX_SYMLINK_NAME L"\\??\\fsWrap"
  109. BOOLEAN EnableWmiLog = FALSE;
  110. NTSTATUS
  111. RxDriverEntry (
  112. IN PDRIVER_OBJECT DriverObject,
  113. IN PUNICODE_STRING RegistryPath
  114. )
  115. /*++
  116. Routine Description:
  117. This is the initialization routine for the Rx file system
  118. device driver. This routine creates the device object for the FileSystem
  119. device and performs all other driver initialization.
  120. Arguments:
  121. DriverObject - Pointer to driver object created by the system.
  122. Return Value:
  123. RXSTATUS - The function value is the final status from the initialization
  124. operation.
  125. --*/
  126. {
  127. NTSTATUS Status;
  128. RX_INIT_STATES RxInitState = 0;
  129. #ifndef MONOLITHIC_MINIRDR
  130. UNICODE_STRING UnicodeString,LinkName;
  131. #endif
  132. //
  133. // this will bugcheck if things are bad
  134. //
  135. RxCheckFcbStructuresForAlignment();
  136. //
  137. // Initialize the global data structures
  138. //
  139. ZeroAndInitializeNodeType( &RxData, RDBSS_NTC_DATA_HEADER, sizeof( RDBSS_DATA ) );
  140. RxData.DriverObject = DriverObject;
  141. ZeroAndInitializeNodeType( &RxDeviceFCB, RDBSS_NTC_DEVICE_FCB, sizeof( FCB ) );
  142. KeInitializeSpinLock( &RxStrucSupSpinLock );
  143. RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
  144. RxInitializeDebugSupport();
  145. try {
  146. Status = RXINIT_START;
  147. #ifndef MONOLITHIC_MINIRDR
  148. //
  149. // Create a symbolic link from \\dosdevices\fswrap to the rdbss device object name
  150. //
  151. RtlInitUnicodeString( &LinkName, RX_SYMLINK_NAME );
  152. RtlInitUnicodeString( &UnicodeString, DD_NFS2_DEVICE_NAME_U );
  153. IoDeleteSymbolicLink( &LinkName );
  154. Status = IoCreateSymbolicLink( &LinkName, &UnicodeString );
  155. if (!NT_SUCCESS( Status )) {
  156. try_return( Status );
  157. }
  158. RxInitState = RXINIT_CREATED_FIRST_LINK;
  159. //
  160. // Create the device object.
  161. //
  162. Status = IoCreateDevice( DriverObject,
  163. sizeof(RDBSS_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
  164. &UnicodeString,
  165. FILE_DEVICE_NETWORK_FILE_SYSTEM,
  166. FILE_REMOTE_DEVICE,
  167. FALSE,
  168. (PDEVICE_OBJECT *)(&RxFileSystemDeviceObject) );
  169. if (!NT_SUCCESS( Status )) {
  170. try_return( Status );
  171. }
  172. RxInitState = RXINIT_CREATED_DEVICE_OBJECT;
  173. #else
  174. //
  175. // in monolithic mode, the wrapper doesn't really need a device object but
  176. // we allocate stuff in the wrapper's device object in order to appropriately throttle
  177. // thread usage per device object.
  178. //
  179. RxFileSystemDeviceObject = &RxSpaceForTheWrappersDeviceObject;
  180. RtlZeroMemory( RxFileSystemDeviceObject, sizeof( RxSpaceForTheWrappersDeviceObject ) );
  181. #endif
  182. //
  183. // Initialize the trace and logging facilities. loginit is a big allocation.
  184. //
  185. RxInitializeDebugTrace();
  186. RxInitializeLog();
  187. RxInitState = RXINIT_CREATED_LOG;
  188. RxGetRegistryParameters( RegistryPath );
  189. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("Constants %08lx %08lx\n", RX_CONTEXT_FLAG_WAIT, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH ));
  190. RxReadRegistryParameters();
  191. //
  192. // Initialize the minirdr registration facilities.
  193. //
  194. Status = RxInitializeRegistrationStructures();
  195. if (!NT_SUCCESS( Status )) {
  196. try_return( Status );
  197. }
  198. RxInitState = RXINIT_CONSTRUCTED_PROVIDERORDER;
  199. #ifndef MONOLITHIC_MINIRDR
  200. //
  201. // We allocate an IoWorkItem to queue the requests to the FSP in the
  202. // RxAddToWorkque function. We only do this when the DeviceObject
  203. // RxFileSystemDeviceObject created to make sure that the RDBSS
  204. // DeviceObject doesn't get unloaded while a request is being queued
  205. // to the FSP.
  206. //
  207. RxIoWorkItem = IoAllocateWorkItem( (PDEVICE_OBJECT) RxFileSystemDeviceObject );
  208. if (!NT_SUCCESS( Status )) {
  209. try_return( Status );
  210. }
  211. #endif
  212. try_exit: NOTHING;
  213. } finally {
  214. if (Status != STATUS_SUCCESS) {
  215. RxLogFailure ( RxFileSystemDeviceObject, NULL, EVENT_RDR_UNEXPECTED_ERROR, Status );
  216. RxInitUnwind( DriverObject, RxInitState );
  217. }
  218. }
  219. if (Status != STATUS_SUCCESS) {
  220. return Status;
  221. }
  222. //
  223. //
  224. //
  225. //
  226. // ##### ## # # #### ###### #####
  227. // # # # # ## # # # # # #
  228. // # # # # # # # # ##### # #
  229. // # # ###### # # # # ### # #####
  230. // # # # # # ## # # # # #
  231. // ##### # # # # #### ###### # #
  232. //
  233. //
  234. //
  235. // EVERYTHING FROM HERE DOWN BETTER WORK BECAUSE THERE IS NO MORE UNWINDING!!!
  236. //
  237. //
  238. RxInitializeDispatcher();
  239. RxInitializeBackoffPackage();
  240. //
  241. // Initialize the look aside list for RxContext allocation
  242. //
  243. ExInitializeNPagedLookasideList( &RxContextLookasideList,
  244. ExAllocatePoolWithTag,
  245. ExFreePool,
  246. 0,
  247. sizeof( RX_CONTEXT ),
  248. RX_IRPC_POOLTAG,
  249. 4 );
  250. //
  251. // Initialize the list of transport Irps to an empty list
  252. //
  253. InitializeListHead( &RxIrpsList );
  254. KeInitializeSpinLock( &RxIrpsListSpinLock );
  255. //
  256. // Initialize the list of active contexts to an empty list
  257. //
  258. InitializeListHead( &RxActiveContexts );
  259. //
  260. // Initialize the list of srv call downs active
  261. //
  262. InitializeListHead( &RxSrvCalldownList );
  263. //
  264. // a fastmutex is used to serialize access to the Qs that serialize blocking pipe operations
  265. //
  266. ExInitializeFastMutex( &RxContextPerFileSerializationMutex );
  267. //
  268. // and to serialize access to the Qs that serialize some pagingio operations
  269. //
  270. ExInitializeFastMutex( &RxLowIoPagingIoSyncMutex );
  271. //
  272. // Initialize the scavenger mutex
  273. //
  274. KeInitializeMutex( &RxScavengerMutex, 1 );
  275. //
  276. // Initialize the global serialization Mutex.
  277. //
  278. KeInitializeMutex( &RxSerializationMutex, 1 );
  279. //
  280. // Initialize the wrapper's overflow queue
  281. //
  282. {
  283. PRDBSS_DEVICE_OBJECT MyDo = (PRDBSS_DEVICE_OBJECT)RxFileSystemDeviceObject;
  284. LONG Index;
  285. for (Index = 0; Index < MaximumWorkQueue; Index++) {
  286. MyDo->OverflowQueueCount[Index] = 0;
  287. InitializeListHead( &MyDo->OverflowQueue[Index] );
  288. MyDo->PostedRequestCount[Index] = 0;
  289. }
  290. KeInitializeSpinLock( &MyDo->OverflowQueueSpinLock );
  291. }
  292. //
  293. // Initialize dispatch vector for driver object AND ALSO FOR the devicefcb
  294. //
  295. RxInitializeDispatchVectors( DriverObject );
  296. ExInitializeResourceLite( &RxData.Resource );
  297. //
  298. // Initialize devfcb context2
  299. //
  300. RxDeviceFCB.Context2 = (PVOID) &RxData;
  301. //
  302. // Set up global pointer to our process.
  303. //
  304. RxData.OurProcess = PsGetCurrentProcess();
  305. //
  306. // Put in a bunch of sanity checks about various structures...hey, it's init code!
  307. //
  308. IF_DEBUG {
  309. ULONG FcbStateBufferingMask = FCB_STATE_BUFFERING_STATE_MASK;
  310. ULONG MinirdrBufStateCommandMask = MINIRDR_BUFSTATE_COMMAND_MASK;
  311. USHORT EightBitsPerChar = 8;
  312. //
  313. // we could put in defines for the ULONG/USHORTS here...but they don't change often
  314. //
  315. ASSERT( MRDRBUFSTCMD_MAXXX == (sizeof( ULONG )*EightBitsPerChar) );
  316. ASSERT( !(FcbStateBufferingMask&MinirdrBufStateCommandMask) );
  317. }
  318. //
  319. // Setup the timer subsystem
  320. //
  321. RxInitializeRxTimer();
  322. #ifndef MONOLITHIC_MINIRDR
  323. Status = IoWMIRegistrationControl( (PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_REGISTER );
  324. if (Status != STATUS_SUCCESS) {
  325. DbgPrint( "Rdbss fails to register WMI %lx\n", Status );
  326. } else {
  327. EnableWmiLog = TRUE;
  328. }
  329. #endif
  330. return STATUS_SUCCESS;
  331. }
  332. //
  333. // Unload routine
  334. //
  335. VOID
  336. RxUnload (
  337. IN PDRIVER_OBJECT DriverObject
  338. )
  339. /*++
  340. Routine Description:
  341. This is the unload routine for the RDBSS.
  342. Arguments:
  343. DriverObject - pointer to the driver object for the RDBSS
  344. Return Value:
  345. None
  346. --*/
  347. {
  348. PAGED_CODE();
  349. RxTearDownRxTimer();
  350. RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxUnload: DriverObject =%08lx\n", DriverObject ) );
  351. ExDeleteResourceLite( &RxData.Resource );
  352. RxUninitializeBackoffPackage();
  353. RxTearDownDispatcher();
  354. RxTearDownDebugSupport();
  355. ExDeleteNPagedLookasideList( &RxContextLookasideList );
  356. RxInitUnwind( DriverObject, RXINIT_ALL_INITIALIZATION_COMPLETED );
  357. if (EnableWmiLog) {
  358. NTSTATUS Status;
  359. Status = IoWMIRegistrationControl( (PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_DEREGISTER );
  360. if (Status != STATUS_SUCCESS) {
  361. DbgPrint( "Rdbss fails to deregister WMI %lx\n", Status );
  362. }
  363. }
  364. #ifndef MONOLITHIC_MINIRDR
  365. IoFreeWorkItem(RxIoWorkItem);
  366. #endif
  367. return;
  368. }
  369. #if DBG
  370. PCHAR RxUnwindFollower = NULL;
  371. #endif
  372. VOID
  373. RxInitUnwind (
  374. IN PDRIVER_OBJECT DriverObject,
  375. IN RX_INIT_STATES RxInitState
  376. )
  377. /*++
  378. Routine Description:
  379. This routine does the common uninit work for unwinding from a bad driver entry or for unloading.
  380. Arguments:
  381. RxInitState - tells how far we got into the intialization
  382. Return Value:
  383. None
  384. --*/
  385. {
  386. #ifndef MONOLITHIC_MINIRDR
  387. UNICODE_STRING LinkName;
  388. #endif
  389. PAGED_CODE();
  390. switch (RxInitState) {
  391. case RXINIT_ALL_INITIALIZATION_COMPLETED:
  392. //
  393. // Nothing extra to do...this is just so that the constant in RxUnload doesn't change.......
  394. // lack of break intentional
  395. //
  396. #if DBG
  397. RxUnwindFollower = "RXINIT_ALL_INITIALIZATION_COMPLETED";
  398. #endif
  399. case RXINIT_CONSTRUCTED_PROVIDERORDER:
  400. #if DBG
  401. RxUnwindFollower = "RXINIT_CONSTRUCTED_PROVIDERORDER";
  402. #endif
  403. RxUninitializeRegistrationStructures();
  404. //
  405. // lack of break intentional
  406. //
  407. case RXINIT_CREATED_LOG:
  408. #if DBG
  409. RxUnwindFollower = "RXINIT_CREATED_LOG";
  410. #endif
  411. RxUninitializeLog();
  412. //
  413. // lack of break intentional
  414. //
  415. case RXINIT_CREATED_DEVICE_OBJECT:
  416. #if DBG
  417. RxUnwindFollower = "RXINIT_CREATED_DEVICE_OBJECT";
  418. #endif
  419. #ifndef MONOLITHIC_MINIRDR
  420. IoDeleteDevice( (PDEVICE_OBJECT)RxFileSystemDeviceObject );
  421. #endif
  422. //
  423. // lack of break intentional
  424. //
  425. case RXINIT_CREATED_FIRST_LINK:
  426. #if DBG
  427. RxUnwindFollower = "RXINIT_CREATED_FIRST_LINK";
  428. #endif
  429. #ifndef MONOLITHIC_MINIRDR
  430. RtlInitUnicodeString( &LinkName, L"\\??\\fsWrap" );
  431. IoDeleteSymbolicLink( &LinkName );
  432. #endif
  433. //
  434. // lack of break intentional
  435. //
  436. case RXINIT_START:
  437. #if DBG
  438. RxUnwindFollower = "RXINIT_START";
  439. #endif
  440. break;
  441. }
  442. }
  443. VOID
  444. RxGetRegistryParameters (
  445. PUNICODE_STRING RegistryPath
  446. )
  447. {
  448. ULONG Storage[256];
  449. UNICODE_STRING UnicodeString;
  450. HANDLE ConfigHandle;
  451. HANDLE ParametersHandle;
  452. NTSTATUS Status;
  453. OBJECT_ATTRIBUTES ObjectAttributes;
  454. PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;
  455. PAGED_CODE();
  456. InitializeObjectAttributes( &ObjectAttributes,
  457. RegistryPath, // name
  458. OBJ_CASE_INSENSITIVE, // attributes
  459. NULL, // root
  460. NULL // security descriptor
  461. );
  462. Status = ZwOpenKey( &ConfigHandle, KEY_READ, &ObjectAttributes );
  463. if (!NT_SUCCESS(Status)) {
  464. return;
  465. }
  466. RtlInitUnicodeString( &UnicodeString, L"Parameters" );
  467. InitializeObjectAttributes( &ObjectAttributes,
  468. &UnicodeString,
  469. OBJ_CASE_INSENSITIVE,
  470. ConfigHandle,
  471. NULL );
  472. Status = ZwOpenKey( &ParametersHandle, KEY_READ, &ObjectAttributes );
  473. if (!NT_SUCCESS(Status)) {
  474. ZwClose(ConfigHandle);
  475. return;
  476. }
  477. #ifdef RDBSSLOG
  478. RxGetStringRegistryParameter( ParametersHandle,
  479. L"InitialDebugString",
  480. &UnicodeString,
  481. (PKEY_VALUE_PARTIAL_INFORMATION) Storage,
  482. sizeof( Storage ),
  483. FALSE );
  484. if (UnicodeString.Length && UnicodeString.Length<320) {
  485. PWCH u = UnicodeString.Buffer;
  486. ULONG l;
  487. PCH p = (PCH)u;
  488. for (l=0; l<UnicodeString.Length; l++) {
  489. *p++ = (CHAR)*u++;
  490. *p = 0;
  491. }
  492. DbgPrint( "InitialDebugString From Registry as singlebytestring: <%s>\n", UnicodeString.Buffer );
  493. RxDebugControlCommand( (PCH)UnicodeString.Buffer );
  494. }
  495. #endif // RDBSSLOG
  496. ZwClose( ParametersHandle );
  497. ZwClose( ConfigHandle );
  498. }
  499. NTSTATUS
  500. RxGetStringRegistryParameter (
  501. HANDLE ParametersHandle,
  502. PWCHAR ParameterName,
  503. PUNICODE_STRING ParamString,
  504. PKEY_VALUE_PARTIAL_INFORMATION Value,
  505. ULONG ValueSize,
  506. BOOLEAN LogFailure
  507. )
  508. {
  509. UNICODE_STRING UnicodeString;
  510. NTSTATUS Status;
  511. ULONG BytesRead;
  512. PAGED_CODE();
  513. RtlInitUnicodeString( &UnicodeString, ParameterName );
  514. Status = ZwQueryValueKey( ParametersHandle,
  515. &UnicodeString,
  516. KeyValuePartialInformation,
  517. Value,
  518. ValueSize,
  519. &BytesRead );
  520. ParamString->Length = 0;
  521. ParamString->Buffer = NULL;
  522. if (NT_SUCCESS(Status)) {
  523. ParamString->Buffer = (PWCH)(&Value->Data[0]);
  524. //
  525. // the datalength actually accounts for the trailing null
  526. //
  527. ParamString->Length = ((USHORT)Value->DataLength) - sizeof( WCHAR );
  528. ParamString->MaximumLength = ParamString->Length;
  529. return STATUS_SUCCESS;
  530. }
  531. if (!LogFailure) {
  532. return Status;
  533. }
  534. RxLogFailure ( RxFileSystemDeviceObject, NULL, EVENT_RDR_CANT_READ_REGISTRY, Status );
  535. return Status;
  536. }
  537. NTSTATUS
  538. RxGetUlongRegistryParameter (
  539. HANDLE ParametersHandle,
  540. PWCHAR ParameterName,
  541. PULONG ParamUlong,
  542. PKEY_VALUE_PARTIAL_INFORMATION Value,
  543. ULONG ValueSize,
  544. BOOLEAN LogFailure
  545. )
  546. {
  547. UNICODE_STRING UnicodeString;
  548. NTSTATUS Status;
  549. ULONG BytesRead;
  550. PAGED_CODE();
  551. RtlInitUnicodeString( &UnicodeString, ParameterName );
  552. Status = ZwQueryValueKey( ParametersHandle,
  553. &UnicodeString,
  554. KeyValuePartialInformation,
  555. Value,
  556. ValueSize,
  557. &BytesRead );
  558. if (NT_SUCCESS(Status)) {
  559. if (Value->Type == REG_DWORD) {
  560. PULONG ConfigValue = (PULONG)&Value->Data[0];
  561. *ParamUlong = *((PULONG)ConfigValue);
  562. DbgPrint( "readRegistryvalue %wZ = %08lx\n", &UnicodeString, *ParamUlong );
  563. return(STATUS_SUCCESS);
  564. } else {
  565. Status = STATUS_INVALID_PARAMETER;
  566. }
  567. }
  568. if (!LogFailure) {
  569. return Status;
  570. }
  571. RxLogFailureWithBuffer ( RxFileSystemDeviceObject,
  572. NULL,
  573. EVENT_RDR_CANT_READ_REGISTRY,
  574. Status,
  575. ParameterName,
  576. (USHORT)(wcslen( ParameterName )* sizeof( WCHAR ) ) );
  577. return Status;
  578. }
  579. /*-------------------------------
  580. This set of routines implements the network provider order in the wrapper.
  581. The way that this works is somewhat complicated. First, we go to the registry
  582. to get the provider order; it is stored at key=PROVIDERORDER_REGISTRY_KEY and
  583. value=L"ProviderOrder". This is a list of service providers whereas what we need
  584. are the device names. So, for each ServiceProverName, we go to the registry to
  585. get the device name at key=SERVICE_REGISTRY_KEY, subkey=ServiceProverName,
  586. subsubkey=NETWORK_PROVIDER_SUBKEY, and value=L"Devicename".
  587. We build a linked list of these guys. Later when a minirdr registers, we look
  588. on this list for the corresponding device name and that gives us the priority.
  589. ----------------------------------*/
  590. #ifndef MONOLITHIC_MINIRDR
  591. NTSTATUS
  592. RxAccrueProviderFromServiceName (
  593. HANDLE ServicesHandle,
  594. PUNICODE_STRING ServiceName,
  595. ULONG Priority,
  596. PWCHAR ProviderInfoNameBuffer,
  597. ULONG ProviderInfoNameBufferLength
  598. );
  599. NTSTATUS
  600. RxConstructProviderOrder (
  601. VOID
  602. );
  603. VOID
  604. RxDestructProviderOrder (
  605. VOID
  606. );
  607. #ifdef ALLOC_PRAGMA
  608. #pragma alloc_text(INIT, RxAccrueProviderFromServiceName)
  609. #pragma alloc_text(INIT, RxConstructProviderOrder)
  610. #pragma alloc_text(PAGE, RxDestructProviderOrder)
  611. #endif
  612. #define PROVIDERORDER_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order"
  613. #define SERVICE_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
  614. #define NETWORK_PROVIDER_SUBKEY L"\\networkprovider"
  615. typedef struct _RX_UNC_PROVIDER_HEADER {
  616. union {
  617. LIST_ENTRY;
  618. LIST_ENTRY Links;
  619. };
  620. ULONG Priority;
  621. union {
  622. UNICODE_STRING;
  623. UNICODE_STRING DeviceName;
  624. };
  625. } RX_UNC_PROVIDER_HEADER;
  626. typedef struct _RX_UNC_PROVIDER {
  627. RX_UNC_PROVIDER_HEADER;
  628. KEY_VALUE_PARTIAL_INFORMATION Info;
  629. } RX_UNC_PROVIDER, *PRX_UNC_PROVIDER;
  630. LIST_ENTRY RxUncProviders;
  631. ULONG
  632. RxGetNetworkProviderPriority (
  633. IN PUNICODE_STRING DeviceName
  634. )
  635. /*++
  636. Routine Description:
  637. This routine is called at minirdr registration time to find out the priority
  638. of the provider with the given DeviceName. It simply looks it up on a list.
  639. Arguments:
  640. DeviceName - name of the device whose priority is to be found
  641. Return Value:
  642. the network provider priority that the MUP will use.
  643. --*/
  644. {
  645. PLIST_ENTRY Entry;
  646. PAGED_CODE();
  647. RxLog(( "FindUncProvider %wZ \n", DeviceName ));
  648. RxWmiLog( LOG,
  649. RxGetNetworkProviderPriority,
  650. LOGUSTR( *DeviceName ));
  651. for (Entry = RxUncProviders.Flink; Entry != &RxUncProviders;) {
  652. PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
  653. Entry = Entry->Flink;
  654. if (RtlEqualUnicodeString( DeviceName, &UncProvider->DeviceName, TRUE )) {
  655. return UncProvider->Priority;
  656. }
  657. }
  658. //
  659. // no corresponding entry was found
  660. //
  661. return 0x7effffff; // got this constant from the MUP........
  662. }
  663. NTSTATUS
  664. RxAccrueProviderFromServiceName (
  665. HANDLE ServicesHandle,
  666. PUNICODE_STRING ServiceName,
  667. ULONG Priority,
  668. PWCHAR ProviderInfoNameBuffer,
  669. ULONG ProviderInfoNameBufferLength
  670. )
  671. /*++
  672. Routine Description:
  673. This routine has the responsibility to look up the device name corresponding
  674. to a particular provider name; if successful, the device name and the corresponding
  675. priority are recorded on the UncProvider List.
  676. Arguments:
  677. HANDLE ServicesHandle - a handle to the services root in the registry
  678. PUNICODE_STRING ServiceName - the name of the service relative to the servicehandle
  679. ULONG Priority, - the priority of this provider
  680. PWCHAR ProviderInfoNameBuffer, - a buffer that can be used to accrue the subkey name
  681. ULONG ProviderInfoNameBufferLength - and the length
  682. Return Value:
  683. STATUS_SUCCESS if everything worked elsewise an error status.
  684. --*/
  685. {
  686. NTSTATUS Status;
  687. OBJECT_ATTRIBUTES ObjectAttributes;
  688. UNICODE_STRING ProviderInfoName,ProviderInfoKey,ParameterDeviceName;
  689. HANDLE NetworkProviderInfoHandle = INVALID_HANDLE_VALUE;
  690. KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
  691. ULONG DummyBytesRead,ProviderLength;
  692. PRX_UNC_PROVIDER UncProvider = NULL;
  693. PAGED_CODE();
  694. RxLog(( "SvcNm %wZ", ServiceName ));
  695. RxWmiLog( LOG,
  696. RxAccrueProviderFromServiceName_1,
  697. LOGUSTR( *ServiceName ) );
  698. //
  699. // Form the correct keyname using the bufferspace provided
  700. //
  701. ProviderInfoName.Buffer = ProviderInfoNameBuffer;
  702. ProviderInfoName.Length = 0;
  703. ProviderInfoName.MaximumLength = (USHORT)ProviderInfoNameBufferLength;
  704. try {
  705. Status = RtlAppendUnicodeStringToString( &ProviderInfoName, ServiceName );
  706. if (Status != STATUS_SUCCESS) {
  707. DbgPrint( "Could append1: %08lx %wZ\n", Status, &ProviderInfoName );
  708. leave;
  709. }
  710. RtlInitUnicodeString( &ProviderInfoKey, NETWORK_PROVIDER_SUBKEY );
  711. Status = RtlAppendUnicodeStringToString( &ProviderInfoName, &ProviderInfoKey );
  712. if (Status != STATUS_SUCCESS) {
  713. DbgPrint( "Could append2: %08lx %wZ\n", Status, &ProviderInfoName );
  714. leave;
  715. }
  716. //
  717. // Open the key in preparation for reeading the devicename value
  718. //
  719. InitializeObjectAttributes( &ObjectAttributes,
  720. &ProviderInfoName, // name
  721. OBJ_CASE_INSENSITIVE, // attributes
  722. ServicesHandle, // root
  723. NULL ); // security descriptor
  724. Status = ZwOpenKey( &NetworkProviderInfoHandle, KEY_READ, &ObjectAttributes );
  725. if (!NT_SUCCESS(Status )) {
  726. DbgPrint( "NetWorkProviderInfoFailed: %08lx %wZ\n", Status, &ProviderInfoName );
  727. leave;
  728. }
  729. //
  730. // Read the devicename. we do this in two steps. first, we do a partial read to find out
  731. // how big the name really is. Then, we allocate a UncProviderEntry of the correctsize and make
  732. // a second call to fill it in.
  733. //
  734. RtlInitUnicodeString( &ParameterDeviceName, L"DeviceName" );
  735. Status = ZwQueryValueKey( NetworkProviderInfoHandle,
  736. &ParameterDeviceName,
  737. KeyValuePartialInformation,
  738. &InitialValuePartialInformation,
  739. sizeof(InitialValuePartialInformation),
  740. &DummyBytesRead );
  741. if (Status == STATUS_BUFFER_OVERFLOW) {
  742. Status = STATUS_SUCCESS;
  743. }
  744. if (Status != STATUS_SUCCESS) {
  745. leave;
  746. }
  747. ProviderLength = sizeof( RX_UNC_PROVIDER) + InitialValuePartialInformation.DataLength;
  748. UncProvider = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, ProviderLength, RX_MRX_POOLTAG );
  749. if (UncProvider == NULL) {
  750. Status = STATUS_INSUFFICIENT_RESOURCES;
  751. DbgPrint( "UncProviderAllocationFailed: %08lx %wZ\n", Status, &ProviderInfoName );
  752. leave;
  753. }
  754. Status = ZwQueryValueKey( NetworkProviderInfoHandle,
  755. &ParameterDeviceName,
  756. KeyValuePartialInformation,
  757. &UncProvider->Info,
  758. ProviderLength,
  759. &DummyBytesRead );
  760. if (Status != STATUS_SUCCESS) {
  761. leave;
  762. }
  763. //
  764. // Finish filling in the UncProviderEntry and link it in
  765. //
  766. UncProvider->Buffer = (PWCHAR)(&UncProvider->Info.Data[0]);
  767. UncProvider->Length = (USHORT)(UncProvider->Info.DataLength - sizeof( WCHAR )); // dont include trailing NULL
  768. UncProvider->MaximumLength = UncProvider->Length;
  769. UncProvider->Priority = Priority;
  770. InsertTailList( &RxUncProviders, &UncProvider->Links );
  771. RxLog(( "Dvc p=%lx Nm %wZ",UncProvider->Priority, &UncProvider->DeviceName ));
  772. RxWmiLog( LOG,
  773. RxAccrueProviderFromServiceName_2,
  774. LOGULONG( UncProvider->Priority )
  775. LOGUSTR( UncProvider->DeviceName ) );
  776. UncProvider = NULL;
  777. } finally {
  778. //
  779. // if we obtained a handle to ...\\services\<sevicename>\providerinfo then close it
  780. //
  781. if (NetworkProviderInfoHandle != INVALID_HANDLE_VALUE) {
  782. ZwClose( NetworkProviderInfoHandle );
  783. }
  784. if (UncProvider != NULL) {
  785. RxFreePool(UncProvider);
  786. }
  787. }
  788. return Status;
  789. }
  790. NTSTATUS
  791. RxConstructProviderOrder (
  792. VOID
  793. )
  794. /*++
  795. Routine Description:
  796. This routine has the responsibility to build the list of network providers
  797. that is used to look up provider priority at minirdr registration time. It does this
  798. by first reading the providerorder string fron the registry; then for each provider
  799. listed in the string, a helper routine is called to lookup the corresponding device
  800. name and insert an entry on the provider list.
  801. Arguments:
  802. none.
  803. Return Value:
  804. STATUS_SUCCESS if everything worked elsewise an error status.
  805. --*/
  806. {
  807. KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
  808. UNICODE_STRING ProviderOrderValueName;
  809. ULONG DummyBytesRead;
  810. PBYTE ProviderOrderStringBuffer;
  811. PBYTE ServiceNameStringBuffer = NULL;
  812. ULONG ProviderOrderStringLength,ServiceNameStringLength,AllocationLength;
  813. UNICODE_STRING UnicodeString;
  814. UNICODE_STRING ProviderOrder;
  815. PWCHAR ScanPtr,FinalScanPtr;
  816. HANDLE NPOrderHandle = INVALID_HANDLE_VALUE;
  817. HANDLE ServiceRootHandle = INVALID_HANDLE_VALUE;
  818. NTSTATUS Status;
  819. OBJECT_ATTRIBUTES ObjectAttributes;
  820. ULONG Priority = 0;
  821. PAGED_CODE();
  822. RxLog(( "RxConstructProviderOrder" ));
  823. RxWmiLog( LOG,
  824. RxConstructProviderOrder_1,
  825. LOGULONG( Priority ) );
  826. InitializeListHead( &RxUncProviders );
  827. try {
  828. //
  829. // Start by opening the service registry key. This is the root key of all services
  830. // and is used for relative opens by the helper routine so that string manipulation
  831. // is reduced.
  832. //
  833. RtlInitUnicodeString( &UnicodeString, SERVICE_REGISTRY_KEY );
  834. InitializeObjectAttributes( &ObjectAttributes,
  835. &UnicodeString, // name
  836. OBJ_CASE_INSENSITIVE, // attributes
  837. NULL, // root
  838. NULL ); // security descriptor
  839. Status = ZwOpenKey( &ServiceRootHandle, KEY_READ, &ObjectAttributes );
  840. if (!NT_SUCCESS( Status )) {
  841. DbgPrint( "ServiceRootOpenFailed: %08lx %wZ\n", Status, &UnicodeString );
  842. leave;
  843. }
  844. //
  845. // Now open up the key where we find the provider order string
  846. //
  847. RtlInitUnicodeString( &UnicodeString, PROVIDERORDER_REGISTRY_KEY );
  848. InitializeObjectAttributes( &ObjectAttributes,
  849. &UnicodeString, // name
  850. OBJ_CASE_INSENSITIVE, // attributes
  851. NULL, // root
  852. NULL ); // security descriptor
  853. Status = ZwOpenKey( &NPOrderHandle, KEY_READ, &ObjectAttributes );
  854. if (!NT_SUCCESS( Status )) {
  855. DbgPrint( "NetProviderOpenFailed: %08lx %wZ\n", Status, &UnicodeString );
  856. leave;
  857. }
  858. //
  859. // Find out how long the provider order string is
  860. //
  861. RtlInitUnicodeString( &ProviderOrderValueName, L"ProviderOrder" );
  862. Status = ZwQueryValueKey( NPOrderHandle,
  863. &ProviderOrderValueName,
  864. KeyValuePartialInformation,
  865. &InitialValuePartialInformation,
  866. sizeof( InitialValuePartialInformation ),
  867. &DummyBytesRead );
  868. if (Status == STATUS_BUFFER_OVERFLOW) {
  869. Status = STATUS_SUCCESS;
  870. }
  871. if (Status != STATUS_SUCCESS) {
  872. DbgPrint( "ProviderOrderStringPartialInfoFailed: %08lx %wZ\n", Status, &ProviderOrderValueName );
  873. leave;
  874. }
  875. //
  876. // allocate two buffers: one buffer will hold the provider string -- ProviderOrderStringBuffer.
  877. // it has to be as long as the providerorder string plus enough extra for the registry
  878. // structure used in the call. the second buffer is used to hold the servicename key--it has
  879. // to be as long as any element of the provider string plus enough extra to hold the suffix
  880. // NETWORK_PROVIDER_SUBKEY. in order to only parse the string once, we just allocate for a complete
  881. // additional copy of the provider string. we actually combine these into a single allocation.
  882. //
  883. ProviderOrderStringLength = sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + InitialValuePartialInformation.DataLength;
  884. ProviderOrderStringLength = QuadAlign( ProviderOrderStringLength + 2*sizeof( WCHAR ) ); // chars added below
  885. ServiceNameStringLength = sizeof( NETWORK_PROVIDER_SUBKEY ) + InitialValuePartialInformation.DataLength;
  886. ServiceNameStringLength = QuadAlign( ServiceNameStringLength );
  887. AllocationLength = ProviderOrderStringLength + ServiceNameStringLength;
  888. RxLog(( "prov string=%lx,alloc=%lx\n", InitialValuePartialInformation.DataLength, AllocationLength ));
  889. RxWmiLog( LOG,
  890. RxConstructProviderOrder_2,
  891. LOGULONG( InitialValuePartialInformation.DataLength )
  892. LOGULONG( AllocationLength ) );
  893. ServiceNameStringBuffer = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, AllocationLength, RX_MRX_POOLTAG );
  894. if (ServiceNameStringBuffer == NULL) {
  895. Status = STATUS_INSUFFICIENT_RESOURCES;
  896. leave;
  897. }
  898. ProviderOrderStringBuffer = ServiceNameStringBuffer+ServiceNameStringLength;
  899. //
  900. // now do the final read to get the providerorder string
  901. //
  902. RxGetStringRegistryParameter( NPOrderHandle,
  903. L"ProviderOrder",
  904. &ProviderOrder,
  905. (PKEY_VALUE_PARTIAL_INFORMATION) ProviderOrderStringBuffer,
  906. ProviderOrderStringLength,
  907. FALSE );
  908. if (ProviderOrder.Buffer == NULL) {
  909. Status = STATUS_UNSUCCESSFUL;
  910. leave;
  911. }
  912. //
  913. // comma-terminate the string for easier living. then scan down the string
  914. // looking for comma terminated entries. for each entry found, try to accrue
  915. // it to the list
  916. //
  917. ProviderOrder.Buffer[ProviderOrder.Length / sizeof( WCHAR )] = L',';
  918. ScanPtr = ProviderOrder.Buffer;
  919. FinalScanPtr = ScanPtr+(ProviderOrder.Length / sizeof( WCHAR ));
  920. for (;;) {
  921. UNICODE_STRING ServiceName;
  922. //
  923. // check for loop termination
  924. //
  925. if (ScanPtr >= FinalScanPtr) { break; }
  926. if (*ScanPtr==L',') { ScanPtr++; continue; }
  927. //
  928. // parse for a servicename
  929. //
  930. ServiceName.Buffer = ScanPtr;
  931. for (; *ScanPtr != L','; ScanPtr++) {}
  932. ASSERT( *ScanPtr==L',' );
  933. ServiceName.Length = (USHORT)(sizeof( WCHAR )* (ScanPtr - ServiceName.Buffer));
  934. //
  935. // accrue it to the list
  936. //
  937. Priority += 1;
  938. Status = RxAccrueProviderFromServiceName( ServiceRootHandle,
  939. &ServiceName,
  940. Priority,
  941. (PWCHAR)ServiceNameStringBuffer,
  942. ServiceNameStringLength );
  943. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  944. leave; // a log entry has already been generated
  945. } else {
  946. Status = STATUS_SUCCESS;
  947. }
  948. }
  949. } finally {
  950. //
  951. // give back anything that we got in this procedure
  952. //
  953. if (NPOrderHandle != INVALID_HANDLE_VALUE) ZwClose( NPOrderHandle );
  954. if (ServiceRootHandle != INVALID_HANDLE_VALUE) ZwClose( ServiceRootHandle );
  955. if (ServiceNameStringBuffer != NULL) RxFreePool( ServiceNameStringBuffer );
  956. //
  957. // if things didn't work, then we won't start....so give back
  958. // the stuff that we have
  959. //
  960. if (!NT_SUCCESS( Status )) {
  961. RxDestructProviderOrder();
  962. }
  963. }
  964. return Status;
  965. }
  966. VOID
  967. RxDestructProviderOrder (
  968. VOID
  969. )
  970. {
  971. PLIST_ENTRY Entry;
  972. PAGED_CODE();
  973. for (Entry = RxUncProviders.Flink; Entry != &RxUncProviders;) {
  974. PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
  975. Entry = Entry->Flink;
  976. RxFreePool( UncProvider );
  977. }
  978. return;
  979. }
  980. #else
  981. ULONG
  982. RxGetNetworkProviderPriority (
  983. PUNICODE_STRING DeviceName
  984. )
  985. {
  986. PAGED_CODE();
  987. return 1; //this number is irrelevant for monolithic
  988. }
  989. #endif //#ifndef MONOLITHIC_MINIRDR
  990. NTSTATUS
  991. RxInitializeRegistrationStructures (
  992. VOID
  993. )
  994. {
  995. NTSTATUS Status = STATUS_SUCCESS;
  996. PAGED_CODE();
  997. ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
  998. RxData.NumberOfMinirdrsRegistered = 0;
  999. RxData.NumberOfMinirdrsStarted = 0;
  1000. InitializeListHead( &RxData.RegisteredMiniRdrs );
  1001. #ifndef MONOLITHIC_MINIRDR
  1002. Status = RxConstructProviderOrder();
  1003. #endif
  1004. return(Status);
  1005. }
  1006. VOID
  1007. RxUninitializeRegistrationStructures(
  1008. VOID
  1009. )
  1010. {
  1011. PAGED_CODE();
  1012. #ifndef MONOLITHIC_MINIRDR
  1013. RxDestructProviderOrder();
  1014. #endif
  1015. }
  1016. VOID
  1017. RxInitializeMinirdrDispatchTable (
  1018. IN PDRIVER_OBJECT DriverObject
  1019. )
  1020. {
  1021. #ifndef MONOLITHIC_MINIRDR
  1022. ULONG i;
  1023. PAGED_CODE();
  1024. //
  1025. // finally, fill in the dispatch tables for normal guys.........
  1026. //
  1027. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  1028. DriverObject->MajorFunction[i] = RxData.DriverObject->MajorFunction[i];
  1029. }
  1030. DriverObject->FastIoDispatch = RxData.DriverObject->FastIoDispatch;
  1031. #else
  1032. PAGED_CODE();
  1033. #endif
  1034. }
  1035. VOID
  1036. NTAPI
  1037. __RxFillAndInstallFastIoDispatch(
  1038. IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
  1039. IN OUT PFAST_IO_DISPATCH FastIoDispatch,
  1040. IN ULONG FastIoDispatchSize
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. This routine fills out a fastiodispatch vector to be identical with
  1045. that normal one and installs it into the driver object associated with
  1046. the device object passed.
  1047. Arguments:
  1048. RxDeviceObject - the device object that is to have its driver's fastiodispatch changed
  1049. FastIoDispatch - the fastiodispatch table to fill in and use
  1050. FastIoDispatchSize - the size of the table passed
  1051. Return Value:
  1052. NONE
  1053. --*/
  1054. {
  1055. ULONG TableSize = min(FastIoDispatchSize, RxFastIoDispatch.SizeOfFastIoDispatch );
  1056. PAGED_CODE();
  1057. #ifndef MONOLITHIC_MINIRDR
  1058. RtlCopyMemory( FastIoDispatch, &RxFastIoDispatch, TableSize );
  1059. FastIoDispatch->SizeOfFastIoDispatch = TableSize;
  1060. RxDeviceObject->DriverObject->FastIoDispatch = FastIoDispatch;
  1061. return;
  1062. #endif
  1063. }
  1064. VOID
  1065. RxReadRegistryParameters(
  1066. VOID
  1067. )
  1068. {
  1069. ULONG Storage[16];
  1070. UNICODE_STRING UnicodeString;
  1071. HANDLE ParametersHandle;
  1072. NTSTATUS Status;
  1073. OBJECT_ATTRIBUTES ObjectAttributes;
  1074. UNICODE_STRING WorkStationParametersRegistryKeyName;
  1075. PKEY_VALUE_PARTIAL_INFORMATION Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
  1076. ULONG ValueSize;
  1077. ULONG BytesRead;
  1078. PAGED_CODE();
  1079. RtlInitUnicodeString( &WorkStationParametersRegistryKeyName, LANMAN_WORKSTATION_PARAMETERS );
  1080. ValueSize = sizeof( Storage );
  1081. InitializeObjectAttributes( &ObjectAttributes,
  1082. &WorkStationParametersRegistryKeyName, // name
  1083. OBJ_CASE_INSENSITIVE, // attributes
  1084. NULL, // root
  1085. NULL ); // security descriptor
  1086. Status = ZwOpenKey( &ParametersHandle, KEY_READ, &ObjectAttributes );
  1087. if (!NT_SUCCESS( Status )) {
  1088. return;
  1089. }
  1090. RtlInitUnicodeString( &UnicodeString, L"DisableByteRangeLockingOnReadOnlyFiles" );
  1091. Status = ZwQueryValueKey( ParametersHandle,
  1092. &UnicodeString,
  1093. KeyValuePartialInformation,
  1094. Value,
  1095. ValueSize,
  1096. &BytesRead );
  1097. if (NT_SUCCESS( Status ) && (Value->Type == REG_DWORD)) {
  1098. PULONG ConfigValue = (PULONG)&Value->Data[0];
  1099. DisableByteRangeLockingOnReadOnlyFiles = (BOOLEAN)(*((PULONG)ConfigValue) != 0);
  1100. }
  1101. ZwClose( ParametersHandle );
  1102. }
  1103.