Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

657 lines
13 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This module performs initialization for the SPUD device driver.
  7. Author:
  8. John Ballard (jballard) 21-Oct-1996
  9. Revision History:
  10. Keith Moore (keithmo) 04-Feb-1998
  11. Cleanup, added much needed comments.
  12. --*/
  13. #include "spudp.h"
  14. //
  15. // Private constants.
  16. //
  17. #define REGISTRY_SPUD_INFORMATION L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Spud"
  18. #define REGISTRY_PARAMETERS L"Parameters"
  19. #define REGISTRY_DO_NOT_LOAD L"DoNotLoad"
  20. #if DBG
  21. #define REGISTRY_BREAK_ON_STARTUP L"BreakOnStartup"
  22. #define REGISTRY_USE_PRIVATE_ASSERT L"UsePrivateAssert"
  23. #endif
  24. #if ALLOW_UNLOAD
  25. #define REGISTRY_ENABLE_UNLOAD L"EnableUnload"
  26. #endif
  27. //
  28. // Private globals.
  29. //
  30. BOOLEAN SpudpFailLoad;
  31. #if ALLOW_UNLOAD
  32. BOOLEAN SpudpEnableUnload;
  33. #endif
  34. //
  35. // Private prototypes.
  36. //
  37. VOID
  38. SpudpReadRegistry(
  39. VOID
  40. );
  41. NTSTATUS
  42. SpudpOpenRegistry(
  43. IN PUNICODE_STRING BaseName,
  44. OUT PHANDLE ParametersHandle
  45. );
  46. ULONG
  47. SpudpReadSingleParameter(
  48. IN HANDLE ParametersHandle,
  49. IN PWCHAR ValueName,
  50. IN LONG DefaultValue
  51. );
  52. #if ALLOW_UNLOAD
  53. VOID
  54. SpudpUnload(
  55. IN PDRIVER_OBJECT DriverObject
  56. );
  57. #endif
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text( INIT, DriverEntry )
  60. #pragma alloc_text( INIT, SpudpReadRegistry )
  61. #pragma alloc_text( INIT, SpudpOpenRegistry )
  62. #pragma alloc_text( INIT, SpudpReadSingleParameter )
  63. #if ALLOW_UNLOAD
  64. #pragma alloc_text( PAGE, SpudpUnload )
  65. #endif
  66. #endif
  67. //
  68. // Public functions.
  69. //
  70. NTSTATUS
  71. DriverEntry(
  72. IN PDRIVER_OBJECT DriverObject,
  73. IN PUNICODE_STRING RegistryPath
  74. )
  75. /*++
  76. Routine Description:
  77. This is the initialization routine for the SPUD driver.
  78. Arguments:
  79. DriverObject - Pointer to driver object created by the system.
  80. Return Value:
  81. The function value is the final status from the initialization operation.
  82. --*/
  83. {
  84. NTSTATUS status;
  85. UNICODE_STRING deviceName;
  86. //
  87. // Sanity check.
  88. //
  89. PAGED_CODE();
  90. //
  91. // Read any configuration information from the registry.
  92. //
  93. SpudpReadRegistry();
  94. //
  95. // If we're configured to fail the load, then bail.
  96. //
  97. if( SpudpFailLoad ) {
  98. return STATUS_INVALID_DEVICE_REQUEST;
  99. }
  100. //
  101. // Create and initialize our device object.
  102. //
  103. RtlInitUnicodeString(
  104. &deviceName,
  105. SPUD_DEVICE_NAME
  106. );
  107. status = IoCreateDevice(
  108. DriverObject, // DriverObject
  109. 0, // DeviceExtension
  110. &deviceName, // DeviceName
  111. FILE_DEVICE_NAMED_PIPE, // DeviceType
  112. 0, // DeviceCharacteristics
  113. TRUE, // Exclusive
  114. &SpudSelfDeviceObject // DeviceObject
  115. );
  116. if( !NT_SUCCESS(status) ) {
  117. KdPrint(( "SPUD DriverEntry: unable to create device object: %X\n", status ));
  118. return status;
  119. }
  120. DriverObject->MajorFunction[IRP_MJ_CREATE] = SpudIrpCreate;
  121. DriverObject->MajorFunction[IRP_MJ_CLOSE] = SpudIrpClose;
  122. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SpudIrpCleanup;
  123. DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SpudIrpQuery;
  124. #if ALLOW_UNLOAD
  125. if( SpudpEnableUnload ) {
  126. DriverObject->DriverUnload = SpudpUnload;
  127. KdPrint(( "SPUD DriverEntry: unload enabled\n" ));
  128. }
  129. #endif
  130. //
  131. // Initialize the context manager.
  132. //
  133. status = SpudInitializeContextManager();
  134. if( !NT_SUCCESS(status) ) {
  135. IoDeleteDevice( SpudSelfDeviceObject );
  136. return status;
  137. }
  138. //
  139. // Initialize other global data.
  140. //
  141. status = SpudInitializeData();
  142. if( !NT_SUCCESS(status) ) {
  143. SpudTerminateContextManager();
  144. IoDeleteDevice( SpudSelfDeviceObject );
  145. return status;
  146. }
  147. //
  148. // Add our service table to the system.
  149. //
  150. if( !KeAddSystemServiceTable(
  151. SpudServiceTable, // Base
  152. NULL, // Count
  153. SpudServiceLimit, // Limit
  154. SpudArgumentTable, // Number
  155. IIS_SERVICE_INDEX // Index
  156. ) ) {
  157. SpudTerminateContextManager();
  158. IoDeleteDevice( SpudSelfDeviceObject );
  159. return STATUS_INSUFFICIENT_RESOURCES;
  160. }
  161. return status;
  162. } // DriverEntry
  163. //
  164. // Private functions.
  165. //
  166. VOID
  167. SpudpReadRegistry(
  168. VOID
  169. )
  170. /*++
  171. Routine Description:
  172. Reads the SPUD section of the registry. Any values listed in the
  173. registry override defaults.
  174. Arguments:
  175. None.
  176. Return Value:
  177. None -- if anything fails, the default value is used.
  178. --*/
  179. {
  180. HANDLE parametersHandle;
  181. NTSTATUS status;
  182. UNICODE_STRING registryPath;
  183. CLONG i;
  184. //
  185. // Sanity check.
  186. //
  187. PAGED_CODE();
  188. //
  189. // Open the registry.
  190. //
  191. RtlInitUnicodeString(
  192. &registryPath,
  193. REGISTRY_SPUD_INFORMATION
  194. );
  195. status = SpudpOpenRegistry( &registryPath, &parametersHandle );
  196. if( status != STATUS_SUCCESS ) {
  197. return;
  198. }
  199. #if DBG
  200. //
  201. // Force a breakpoint if so requested.
  202. //
  203. if( SpudpReadSingleParameter(
  204. parametersHandle,
  205. REGISTRY_BREAK_ON_STARTUP,
  206. 0 ) != 0 ) {
  207. DbgBreakPoint();
  208. }
  209. //
  210. // Enable private assert function if requested. Note that the
  211. // default value is TRUE for free builds and FALSE for checked
  212. // builds.
  213. //
  214. SpudUsePrivateAssert = ( *(PULONG)&NtBuildNumber & 0xF0000000 ) == 0xF0000000;
  215. SpudUsePrivateAssert = SpudpReadSingleParameter(
  216. parametersHandle,
  217. REGISTRY_USE_PRIVATE_ASSERT,
  218. (LONG)SpudUsePrivateAssert
  219. ) != 0;
  220. #endif
  221. #if ALLOW_UNLOAD
  222. //
  223. // Enable driver unload on checked builds only if the proper
  224. // value is in the registry. NEVER enable driver unload on free
  225. // builds.
  226. //
  227. SpudpEnableUnload = SpudpReadSingleParameter(
  228. parametersHandle,
  229. REGISTRY_ENABLE_UNLOAD,
  230. (LONG)SpudpEnableUnload
  231. ) != 0;
  232. #endif
  233. //
  234. // Fail Load if so requested.
  235. //
  236. if( SpudpReadSingleParameter(
  237. parametersHandle,
  238. REGISTRY_DO_NOT_LOAD,
  239. 0 ) != 0 ) {
  240. SpudpFailLoad = TRUE;
  241. KdPrint(("Spud.sys load aborted! DoNotLoad is configured in the registry.\n"));
  242. } else {
  243. SpudpFailLoad = FALSE;
  244. KdPrint(("Spud.sys load enabled! DoNotLoad is configured in the registry.\n"));
  245. }
  246. //
  247. // Cleanup.
  248. //
  249. ZwClose( parametersHandle );
  250. } // SpudpReadRegistry
  251. NTSTATUS
  252. SpudpOpenRegistry(
  253. IN PUNICODE_STRING BaseName,
  254. OUT PHANDLE ParametersHandle
  255. )
  256. /*++
  257. Routine Description:
  258. This routine is called by SPUD to open the registry. If the registry
  259. tree exists, then it opens it and returns STATUS_SUCCESS.
  260. Arguments:
  261. BaseName - Where in the registry to start looking for the information.
  262. LinkageHandle - Returns the handle used to read linkage information.
  263. ParametersHandle - Returns the handle used to read other
  264. parameters.
  265. Return Value:
  266. The status of the request.
  267. --*/
  268. {
  269. HANDLE configHandle;
  270. NTSTATUS status;
  271. PWSTR parametersString = REGISTRY_PARAMETERS;
  272. UNICODE_STRING parametersKeyName;
  273. OBJECT_ATTRIBUTES objectAttributes;
  274. ULONG disposition;
  275. //
  276. // Sanity check.
  277. //
  278. PAGED_CODE();
  279. //
  280. // Open the registry for the initial string.
  281. //
  282. InitializeObjectAttributes(
  283. &objectAttributes,
  284. BaseName, // name
  285. OBJ_CASE_INSENSITIVE, // attributes
  286. NULL, // root
  287. NULL // security descriptor
  288. );
  289. status = ZwOpenKey(
  290. &configHandle,
  291. KEY_READ,
  292. &objectAttributes
  293. );
  294. if( !NT_SUCCESS(status) ) {
  295. return STATUS_UNSUCCESSFUL;
  296. }
  297. //
  298. // Now open the parameters key.
  299. //
  300. RtlInitUnicodeString(
  301. &parametersKeyName,
  302. parametersString
  303. );
  304. InitializeObjectAttributes(
  305. &objectAttributes,
  306. &parametersKeyName, // name
  307. OBJ_CASE_INSENSITIVE, // attributes
  308. configHandle, // root
  309. NULL // security descriptor
  310. );
  311. status = ZwOpenKey(
  312. ParametersHandle,
  313. KEY_READ,
  314. &objectAttributes
  315. );
  316. if( !NT_SUCCESS(status) ) {
  317. ZwClose( configHandle );
  318. return status;
  319. }
  320. //
  321. // All keys successfully opened.
  322. //
  323. ZwClose( configHandle );
  324. return STATUS_SUCCESS;
  325. } // SpudpOpenRegistry
  326. ULONG
  327. SpudpReadSingleParameter(
  328. IN HANDLE ParametersHandle,
  329. IN PWCHAR ValueName,
  330. IN LONG DefaultValue
  331. )
  332. /*++
  333. Routine Description:
  334. This routine is called by SPUD to read a single parameter
  335. from the registry. If the parameter is found it is stored
  336. in Data.
  337. Arguments:
  338. ParametersHandle - A pointer to the open registry.
  339. ValueName - The name of the value to search for.
  340. DefaultValue - The default value.
  341. Return Value:
  342. The value to use; will be the default if the value is not
  343. found or is not in the correct range.
  344. --*/
  345. {
  346. static ULONG informationBuffer[32]; // declare ULONG to get it aligned
  347. PKEY_VALUE_FULL_INFORMATION information =
  348. (PKEY_VALUE_FULL_INFORMATION)informationBuffer;
  349. UNICODE_STRING valueKeyName;
  350. ULONG informationLength;
  351. LONG returnValue;
  352. NTSTATUS status;
  353. //
  354. // Sanity check.
  355. //
  356. PAGED_CODE();
  357. //
  358. // Read the registry value.
  359. //
  360. RtlInitUnicodeString(
  361. &valueKeyName,
  362. ValueName
  363. );
  364. status = ZwQueryValueKey(
  365. ParametersHandle,
  366. &valueKeyName,
  367. KeyValueFullInformation,
  368. (PVOID)information,
  369. sizeof (informationBuffer),
  370. &informationLength
  371. );
  372. if( (status == STATUS_SUCCESS) && (information->DataLength == sizeof(ULONG)) ) {
  373. RtlMoveMemory(
  374. (PVOID)&returnValue,
  375. ((PUCHAR)information) + information->DataOffset,
  376. sizeof(ULONG)
  377. );
  378. if (returnValue < 0) {
  379. returnValue = DefaultValue;
  380. }
  381. } else {
  382. returnValue = DefaultValue;
  383. }
  384. return returnValue;
  385. } // SpudpReadSingleParameter
  386. #if ALLOW_UNLOAD
  387. VOID
  388. SpudpUnload(
  389. IN PDRIVER_OBJECT DriverObject
  390. )
  391. /*++
  392. Routine Description:
  393. Unload routine.
  394. Arguments:
  395. DriverObject - Pointer to target driver object.
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. PKSERVICE_TABLE_DESCRIPTOR serviceTable;
  401. ULONG i;
  402. //
  403. // Sanity check.
  404. //
  405. PAGED_CODE();
  406. UNREFERENCED_PARAMETER( DriverObject );
  407. //
  408. // Yank the system service table. What a hack.
  409. //
  410. // Note that this can never be perfectly synchronized, and you
  411. // risk a blue-screen everytime you unload the driver. Only
  412. // initiate an unload if you're absolutely sure the server is
  413. // idle. This is the reason this code is conditionally compiled
  414. // and will never see the light of day in a public, retail build.
  415. //
  416. serviceTable = *KeServiceDescriptorTable;
  417. serviceTable[IIS_SERVICE_INDEX].Base = NULL;
  418. serviceTable[IIS_SERVICE_INDEX].Count = NULL;
  419. serviceTable[IIS_SERVICE_INDEX].Limit = 0;
  420. serviceTable[IIS_SERVICE_INDEX].Number = NULL;
  421. try {
  422. serviceTable += NUMBER_SERVICE_TABLES;
  423. for( i = 0 ; i < 1000 ; i++ ) {
  424. if( serviceTable->Base == SpudServiceTable &&
  425. serviceTable->Count == NULL &&
  426. serviceTable->Limit == SpudServiceLimit &&
  427. serviceTable->Number == SpudArgumentTable
  428. ) {
  429. serviceTable->Base = NULL;
  430. serviceTable->Count = NULL;
  431. serviceTable->Limit = 0;
  432. serviceTable->Number = NULL;
  433. break;
  434. }
  435. serviceTable = (PKSERVICE_TABLE_DESCRIPTOR)( (PUCHAR)serviceTable + sizeof(ULONG_PTR) );
  436. }
  437. } except( EXCEPTION_EXECUTE_HANDLER ) {
  438. NOTHING;
  439. }
  440. //
  441. // Dereference the I/O completion port.
  442. //
  443. if( SpudCompletionPort != NULL ) {
  444. TRACE_OB_DEREFERENCE( SpudCompletionPort );
  445. ObDereferenceObject(SpudCompletionPort);
  446. SpudCompletionPort = NULL;
  447. }
  448. //
  449. // Destroy the non-paged data.
  450. //
  451. if( SpudNonpagedData != NULL ) {
  452. ExDeleteNPagedLookasideList( &SpudNonpagedData->ReqContextList );
  453. ExDeleteResourceLite( &SpudNonpagedData->ReqHandleTableLock );
  454. SPUD_FREE_POOL( SpudNonpagedData );
  455. SpudNonpagedData = NULL;
  456. }
  457. //
  458. // Nuke the device object.
  459. //
  460. IoDeleteDevice( SpudSelfDeviceObject );
  461. SpudSelfDeviceObject = NULL;
  462. //
  463. // Free the trace log.
  464. //
  465. #if ENABLE_OB_TRACING
  466. if( SpudTraceLog != NULL ) {
  467. DestroyRefTraceLog( SpudTraceLog );
  468. SpudTraceLog = NULL;
  469. }
  470. #endif
  471. } // SpudpUnload
  472. #endif // ALLOW_UNLOAD